Fix sequential scenario test that was failing in Env 9 due to improper state management between scenarios. Root Cause: In scenario "CNR enabled + Nightly disabled": 1. Install Nightly → auto-disables CNR 2. Disable Nightly → both packages now disabled 3. Test expects: CNR enabled, Nightly disabled 4. Actual state: both disabled (CNR not re-enabled) Fix: Added enable operation after disabling Nightly to restore CNR to enabled state. This ensures the scenario accurately represents "CNR enabled + Nightly disabled" instead of leaving both packages disabled. Changes: - Added enable CNR operation after disabling Nightly in scenario 2 - Updated ui_id to be more descriptive (disable_nightly, enable_cnr) - Ensures proper state transition: both enabled → Nightly disabled → CNR re-enabled Test Results: - Before: 9/10 environments passing (90%) - After: 10/10 environments passing (100%) - All 63 tests passing across all environments Session Progress: - Session start: 7/10 environments (60/63 tests) - After parameter fix: 9/10 environments (62/63 tests) - Final: 10/10 environments (63/63 tests ✅) - Total improvement: +3 environments, +3 tests (+42.9%) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Glob API Endpoint Tests
This directory contains endpoint tests for the ComfyUI Manager glob API implementation.
Quick Navigation
- Running Tests: See Running Tests section below
- Test Coverage: See Test Coverage section
- Known Issues: See Known Issues and Fixes section
- Detailed Execution Guide: See TESTING_GUIDE.md
- Future Test Plans: See docs/internal/test_planning/
Test Files
test_queue_task_api.py- Queue task API tests for install/uninstall/version switching operations (8 tests)test_enable_disable_api.py- Queue task API tests for enable/disable operations (5 tests)test_update_api.py- Queue task API tests for update operations (4 tests)test_complex_scenarios.py- Multi-version complex scenarios (10 tests) - Phase 1 + 3 + 4 + 5 + 6test_installed_api_original_case.py- Installed API case preservation tests (4 tests)test_version_switching_comprehensive.py- Comprehensive version switching tests (19 tests)test_case_sensitivity_integration.py- Full integration test for case sensitivity (1 test)
Total: 51 tests - All passing ✅ (+5 P1 tests: Phase 3.1, Phase 5.1, Phase 5.2, Phase 5.3, Phase 6)
Running Tests
Prerequisites
- Install test dependencies:
pip install pytest requests
- Start ComfyUI server with Manager:
cd tests/env
./run.sh
Run All Tests
# From project root
pytest tests/glob/ -v
# With coverage
pytest tests/glob/ -v --cov=comfyui_manager.glob --cov-report=html
Run Specific Tests
# Run specific test file
pytest tests/glob/test_queue_task_api.py -v
# Run specific test function
pytest tests/glob/test_queue_task_api.py::test_install_package_via_queue -v
# Run with output
pytest tests/glob/test_queue_task_api.py -v -s
Environment Variables
COMFYUI_TEST_URL- Base URL for ComfyUI server (default: http://127.0.0.1:8188)TEST_SERVER_PORT- Server port (default: 8188, automatically used by conftest.py)COMFYUI_CUSTOM_NODES_PATH- Path to custom_nodes directory (default: tests/env/ComfyUI/custom_nodes)
Important: All tests now use the server_url fixture from conftest.py, which reads from these environment variables. This ensures compatibility with parallel test execution.
Example:
# Single test environment
COMFYUI_TEST_URL=http://localhost:8188 pytest tests/glob/ -v
# Parallel test environment (port automatically set)
TEST_SERVER_PORT=8189 pytest tests/glob/ -v
Test Coverage
The test suite covers:
-
Install Operations (test_queue_task_api.py)
- Install package via queue task API
- Version switching between CNR and Nightly
- Case-insensitive package name handling
- Queue multiple install tasks
-
Uninstall Operations (test_queue_task_api.py)
- Uninstall package via queue task API
- Complete install/uninstall cycle
- Case-insensitive uninstall operations
-
Enable/Disable Operations (test_enable_disable_api.py) ✅ All via Queue Task API
- Disable active package via queue task
- Enable disabled package via queue task
- Duplicate disable/enable handling via queue task
- Complete enable/disable cycle via queue task
- Marker file preservation (.tracking, .git)
-
Update Operations (test_update_api.py)
- Update CNR package to latest version
- Update Nightly package (git pull)
- Skip update when already latest
- Complete update workflow cycle
-
Complex Multi-Version Scenarios (test_complex_scenarios.py)
- Phase 1: Enable from Multiple Disabled States
- Enable CNR when both CNR and Nightly are disabled
- Enable Nightly when both CNR and Nightly are disabled
- Phase 3: Disable Complex Scenarios
- Disable CNR when Nightly is disabled (both end up disabled)
- Phase 4: Update with Other Versions Present
- Update CNR with Nightly disabled (selective update)
- Update Nightly with CNR disabled (selective update)
- Update enabled package with multiple disabled versions
- Phase 5: Install with Existing Versions (Complete) ✅
- Install CNR when Nightly is enabled (automatic version switch)
- Install Nightly when CNR is enabled (automatic version switch)
- Install new version when both CNR and Nightly are disabled
- Phase 6: Uninstall with Multiple Versions ✅
- Uninstall removes all versions (enabled + all disabled) - default behavior
- Version-specific enable with @version syntax
- Multiple disabled versions management
- Phase 1: Enable from Multiple Disabled States
-
Version Switching Comprehensive (test_version_switching_comprehensive.py)
- Reverse scenario: Nightly → CNR → Nightly
- Same version reinstall detection and skip
-
Case Sensitivity Integration (test_case_sensitivity_integration.py)
- Full workflow: Install CNR → Verify lookup → Switch to Nightly
- Directory naming convention verification
- Marker file preservation (.tracking, .git)
- Supports both pytest and standalone execution
- Repeated version switching (4+ times)
- Cleanup verification (no orphaned files)
- Fresh install after complete uninstall
-
Queue Management
- Queue multiple tasks
- Start queue processing
- Task execution order and completion
-
Integration Tests
- Verify package in installed list
- Verify filesystem changes
- Version identification (.tracking vs .git)
- .disabled/ directory mechanism
Known Issues and Fixes
Issue 1: Glob API Parameters
Important: Glob API does NOT support channel or mode parameters.
Note:
channelandmodeparameters are legacy-only featuresInstallPackParamsdata model includes these fields because it's shared between legacy and glob implementations- Glob API implementation ignores these parameters
- Tests should NOT include
channelormodein request parameters
Issue 2: Case-Insensitive Package Operations (PARTIALLY RESOLVED)
Previous Problem: Operations failed when using different cases (e.g., "ComfyUI_SigmoidOffsetScheduler" vs "comfyui_sigmoidoffsetscheduler")
Current Status:
- Install: Requires exact package name due to CNR server limitations (case-sensitive)
- Uninstall/Enable/Disable: Works with any case variation using
cnr_utils.normalize_package_name()
Normalization Function (cnr_utils.normalize_package_name()):
- Strips leading/trailing whitespace with
.strip() - Converts to lowercase with
.lower() - Accepts any case variation (e.g., "ComfyUI_SigmoidOffsetScheduler", "COMFYUI_SIGMOIDOFFSETSCHEDULER", " comfyui_sigmoidoffsetscheduler ")
Examples:
# Install - requires exact case
{"id": "ComfyUI_SigmoidOffsetScheduler"} # ✓ Works
{"id": "comfyui_sigmoidoffsetscheduler"} # ✗ Fails (CNR limitation)
# Uninstall - accepts any case
{"node_name": "ComfyUI_SigmoidOffsetScheduler"} # ✓ Works
{"node_name": " ComfyUI_SigmoidOffsetScheduler "} # ✓ Works (normalized)
{"node_name": "COMFYUI_SIGMOIDOFFSETSCHEDULER"} # ✓ Works (normalized)
{"node_name": "comfyui_sigmoidoffsetscheduler"} # ✓ Works (normalized)
Issue 3: .disabled/ Directory Mechanism
Critical Discovery: The .disabled/ directory is used by the disable operation to store disabled packages.
Implementation (manager_core.py:1115-1154):
def unified_disable(self, packname: str):
# Disable moves package to .disabled/ with version suffix
to_path = os.path.join(base_path, '.disabled', f"{folder_name}@{matched_active.version.replace('.', '_')}")
shutil.move(matched_active.fullpath, to_path)
Directory Naming Format:
- CNR packages:
.disabled/{package_name_normalized}@{version}- Example:
.disabled/comfyui_sigmoidoffsetscheduler@1_0_2
- Example:
- Nightly packages:
.disabled/{package_name_normalized}@nightly- Example:
.disabled/comfyui_sigmoidoffsetscheduler@nightly
- Example:
Key Points:
- Package names are normalized (lowercase) in directory names
- Version dots are replaced with underscores (e.g.,
1.0.2→1_0_2) - Disabled packages preserve their marker files (
.trackingfor CNR,.gitfor Nightly) - Enable operation moves packages back from
.disabled/tocustom_nodes/
Testing Implications:
- Complex multi-version scenarios require install → disable sequences
- Fixture pattern: Install CNR → Disable → Install Nightly → Disable
- Tests must check
.disabled/with case-insensitive searches - Directory format must match normalized names with version suffixes
Issue 4: Version Switch Mechanism
Behavior: Version switching uses a slot-based system with Nightly and Archive as separate slots.
Slot-Based System Concept:
- Nightly Slot: Git-based installation (one slot)
- Archive Slot: Registry-based installation (one slot)
- Only one slot is active at a time
- The inactive slot is stored in
.disabled/ - Archive versions update within the Archive slot
Two Types of Version Switch:
1. Slot Switch: Nightly ↔ Archive (uses .disabled/ mechanism)
-
Archive → Nightly:
- Archive (any version) → moved to
.disabled/ComfyUI_SigmoidOffsetScheduler - Nightly → active in
custom_nodes/ComfyUI_SigmoidOffsetScheduler
- Archive (any version) → moved to
-
Nightly → Archive:
- Nightly → moved to
.disabled/ComfyUI_SigmoidOffsetScheduler - Archive (any version) → restored from
.disabled/and becomes active
- Nightly → moved to
2. Version Update: Archive ↔ Archive (in-place update within Archive slot)
- 1.0.1 → 1.0.2 (when Archive slot is active):
- Directory contents updated in-place
- pyproject.toml version updated: 1.0.1 → 1.0.2
.trackingfile updated- NO
.disabled/directory used
3. Combined Operation: Nightly (active) + Archive 1.0 (disabled) → Archive 2.0
- Step 1 - Slot Switch: Nightly →
.disabled/, Archive 1.0 → active - Step 2 - Version Update: Archive 1.0 → 2.0 (in-place within Archive slot)
- Result: Archive 2.0 active, Nightly in
.disabled/
Version Identification:
- Archive versions: Use
pyproject.tomlversion field - Nightly version: pyproject.toml ignored, Git commit SHA used instead
Key Points:
- Slot Switch (Nightly ↔ Archive):
.disabled/mechanism for enable/disable - Version Update (Archive ↔ Archive): In-place content update within slot
- Archive installations have
.trackingfile - Nightly installations have
.gitdirectory - Only one slot is active at a time
Issue 5: Version Selection Logic (RESOLVED)
Problem: When enabling a package with both CNR and Nightly versions disabled, the system would always enable CNR instead of respecting the user's choice.
Root Cause (manager_server.py:876-919):
do_enable()was parsingversion_specfromcnr_id(e.g.,packagename@nightly)- But it wasn't passing
version_spectounified_enable() - This caused
unified_enable()to use default version selection (latest CNR)
Solution:
# Before (manager_server.py:876)
res = core.unified_manager.unified_enable(node_name) # Missing version_spec!
# After (manager_server.py:876)
res = core.unified_manager.unified_enable(node_name, version_spec) # ✅ Fixed
API Usage:
# Enable CNR version (default or latest)
{"cnr_id": "ComfyUI_SigmoidOffsetScheduler"}
# Enable specific CNR version
{"cnr_id": "ComfyUI_SigmoidOffsetScheduler@1.0.1"}
# Enable Nightly version
{"cnr_id": "ComfyUI_SigmoidOffsetScheduler@nightly"}
Version Selection Priority (manager_core.py:get_inactive_pack):
- Explicit version in cnr_id (e.g.,
@nightly,@1.0.1) - Latest CNR version (if available)
- Nightly version (if no CNR available)
- Unknown version (fallback)
Files Modified:
comfyui_manager/glob/manager_server.py- Pass version_spec to unified_enablecomfyui_manager/common/node_package.py- Parse @version from disabled directory namescomfyui_manager/glob/manager_core.py- Fix is_disabled() early-return bug
Status: ✅ Resolved - All 42 tests passing
Test Data
Test package: ComfyUI_SigmoidOffsetScheduler
- Package ID:
ComfyUI_SigmoidOffsetScheduler - CNR ID (lowercase):
comfyui_sigmoidoffsetscheduler - Version:
1.0.2 - Nightly: Git clone from main branch
Additional Documentation
Test Execution Guide
- TESTING_GUIDE.md - Detailed guide for running tests, updating OpenAPI schemas, and troubleshooting
Future Test Plans
- docs/internal/test_planning/ - Planned but not yet implemented test scenarios
Contributing
When adding new tests:
- Follow pytest naming conventions (test_.py, test_)
- Use fixtures for common setup/teardown
- Add docstrings explaining test purpose
- Update this README with test coverage information
- For complex scenario tests, see docs/internal/test_planning/