ComfyUI-Manager/tests/glob/TESTING_GUIDE.md
Dr.Lt.Data 43647249cf refactor: remove package-level caching to support dynamic installation
Remove package-level caching in cnr_utils and node_package modules to enable
proper dynamic custom node installation and version switching without ComfyUI
server restarts.

Key Changes:
- Remove @lru_cache decorators from version-sensitive functions
- Remove cached_property from NodePackage for dynamic state updates
- Add comprehensive test suite with parallel execution support
- Implement version switching tests (CNR ↔ Nightly)
- Add case sensitivity integration tests
- Improve error handling and logging

API Priority Rules (manager_core.py:1801):
- Enabled-Priority: Show only enabled version when both exist
- CNR-Priority: Show only CNR when both CNR and Nightly are disabled
- Prevents duplicate package entries in /v2/customnode/installed API
- Cross-match using cnr_id and aux_id for CNR ↔ Nightly detection

Test Infrastructure:
- 8 test files with 59 comprehensive test cases
- Parallel test execution across 5 isolated environments
- Automated test scripts with environment setup
- Configurable timeout (60 minutes default)
- Support for both master and dr-support-pip-cm branches

Bug Fixes:
- Fix COMFYUI_CUSTOM_NODES_PATH environment variable export
- Resolve test fixture regression with module-level variables
- Fix import timing issues in test configuration
- Register pytest integration marker to eliminate warnings
- Fix POSIX compliance in shell scripts (((var++)) → $((var + 1)))

Documentation:
- CNR_VERSION_MANAGEMENT_DESIGN.md v1.0 → v1.1 with API priority rules
- Add test guides and execution documentation (TESTING_PROMPT.md)
- Add security-enhanced installation guide
- Create CLI migration guides and references
- Document package version management

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 09:07:09 +09:00

497 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Testing Guide for ComfyUI Manager
## Code Update and Testing Workflow
When you modify code that affects the API or data models, follow this **mandatory workflow** to ensure your changes are properly tested:
### 1. OpenAPI Spec Modification
If you change data being sent or received:
```bash
# Edit openapi.yaml
vim openapi.yaml
# Verify YAML syntax
python3 -c "import yaml; yaml.safe_load(open('openapi.yaml'))"
```
### 2. Regenerate Data Models
```bash
# Generate Pydantic models from OpenAPI spec
datamodel-codegen \
--use-subclass-enum \
--field-constraints \
--strict-types bytes \
--use-double-quotes \
--input openapi.yaml \
--output comfyui_manager/data_models/generated_models.py \
--output-model-type pydantic_v2.BaseModel
# Verify Python syntax
python3 -m py_compile comfyui_manager/data_models/generated_models.py
# Format and lint
ruff format comfyui_manager/data_models/generated_models.py
ruff check comfyui_manager/data_models/generated_models.py --fix
```
### 3. Update Exports (if needed)
```bash
# Update __init__.py if new models were added
vim comfyui_manager/data_models/__init__.py
```
### 4. **CRITICAL**: Reinstall Package
⚠️ **You MUST reinstall the package before restarting the server!**
```bash
# Reinstall package in development mode
uv pip install .
```
**Why this is critical**: The server loads modules from `site-packages`, not from your source directory. If you don't reinstall, the server will use old models and you'll see Pydantic errors.
### 5. Restart ComfyUI Server
```bash
# Stop existing servers
ps aux | grep "main.py" | grep -v grep | awk '{print $2}' | xargs -r kill
sleep 3
# Start new server
cd tests/env
python ComfyUI/main.py \
--enable-compress-response-body \
--enable-manager \
--front-end-root front \
> /tmp/comfyui-server.log 2>&1 &
# Wait for server to be ready
sleep 10
grep -q "To see the GUI" /tmp/comfyui-server.log && echo "✓ Server ready" || echo "Waiting..."
```
### 6. Run Tests
```bash
# Run all queue task API tests
python -m pytest tests/glob/test_queue_task_api.py -v
# Run specific test
python -m pytest tests/glob/test_queue_task_api.py::test_install_package_via_queue -v
# Run with verbose output
python -m pytest tests/glob/test_queue_task_api.py -v -s
```
### 7. Check Test Results and Logs
```bash
# View server logs for errors
tail -100 /tmp/comfyui-server.log | grep -E "exception|error|failed"
# Check for specific test task
tail -100 /tmp/comfyui-server.log | grep "test_task_id"
```
## Complete Workflow Script
Here's the complete workflow in a single script:
```bash
#!/bin/bash
set -e
echo "=== Step 1: Verify OpenAPI Spec ==="
python3 -c "import yaml; yaml.safe_load(open('openapi.yaml'))"
echo "✓ YAML valid"
echo ""
echo "=== Step 2: Regenerate Data Models ==="
datamodel-codegen \
--use-subclass-enum \
--field-constraints \
--strict-types bytes \
--use-double-quotes \
--input openapi.yaml \
--output comfyui_manager/data_models/generated_models.py \
--output-model-type pydantic_v2.BaseModel
python3 -m py_compile comfyui_manager/data_models/generated_models.py
ruff format comfyui_manager/data_models/generated_models.py
ruff check comfyui_manager/data_models/generated_models.py --fix
echo "✓ Models regenerated and formatted"
echo ""
echo "=== Step 3: Reinstall Package ==="
uv pip install .
echo "✓ Package reinstalled"
echo ""
echo "=== Step 4: Restart Server ==="
ps aux | grep "main.py" | grep -v grep | awk '{print $2}' | xargs -r kill
sleep 3
cd tests/env
python ComfyUI/main.py \
--enable-compress-response-body \
--enable-manager \
--front-end-root front \
> /tmp/comfyui-server.log 2>&1 &
sleep 10
grep -q "To see the GUI" /tmp/comfyui-server.log && echo "✓ Server ready" || echo "⚠ Server still starting..."
cd ../..
echo ""
echo "=== Step 5: Run Tests ==="
python -m pytest tests/glob/test_queue_task_api.py -v
echo ""
echo "=== Workflow Complete ==="
```
## Common Issues
### Issue 1: Pydantic Validation Errors
**Symptom**: `AttributeError: 'UpdateComfyUIParams' object has no attribute 'id'`
**Cause**: Server is using old data models from site-packages
**Solution**:
```bash
uv pip install . # Reinstall package
# Then restart server
```
### Issue 2: Server Using Old Code
**Symptom**: Changes don't take effect even after editing files
**Cause**: Server needs to be restarted to load new code
**Solution**:
```bash
ps aux | grep "main.py" | grep -v grep | awk '{print $2}' | xargs -r kill
# Then start server again
```
### Issue 3: Union Type Discrimination
**Symptom**: Wrong params type selected in Union
**Cause**: Pydantic matches Union types in order; types with all optional fields match everything
**Solution**: Place specific types first, types with all optional fields last:
```python
# Good
params: Union[
InstallPackParams, # Has required fields
UpdatePackParams, # Has required fields
UpdateComfyUIParams, # All optional - place last
UpdateAllPacksParams, # All optional - place last
]
# Bad
params: Union[
UpdateComfyUIParams, # All optional - matches everything!
InstallPackParams, # Never reached
]
```
## Testing Checklist
Before committing code changes:
- [ ] OpenAPI spec validated (`yaml.safe_load`)
- [ ] Data models regenerated
- [ ] Generated models verified (syntax check)
- [ ] Code formatted and linted
- [ ] Package reinstalled (`uv pip install .`)
- [ ] Server restarted with new code
- [ ] All tests passing
- [ ] Server logs checked for errors
- [ ] Manual testing of changed functionality
## Adding New Tests
When you add new tests or significantly modify existing ones, follow these steps to maintain optimal test performance.
### 1. Write Your Test
Create or modify test files in `tests/glob/`:
```python
# tests/glob/test_my_new_feature.py
import pytest
from tests.glob.conftest import *
def test_my_new_feature(session, base_url):
"""Test description."""
# Your test implementation
response = session.get(f"{base_url}/my/endpoint")
assert response.status_code == 200
```
### 2. Run Tests to Verify
```bash
# Quick verification with automated script
./tests/run_automated_tests.sh
# Or manually
cd /mnt/teratera/git/comfyui-manager
source ~/venv/bin/activate
uv pip install .
./tests/run_parallel_tests.sh
```
### 3. Check Load Balancing
After tests complete, check the load balance variance in the report:
```bash
# Look for "Load Balancing Analysis" section in:
cat .claude/livecontext/automated_test_*.md | grep -A 20 "Load Balance"
```
**Thresholds**:
-**Excellent**: Variance < 1.2x (no action needed)
- **Good**: Variance 1.2x - 2.0x (consider updating)
- **Poor**: Variance > 2.0x (update required)
### 4. Update Test Durations (If Needed)
**When to update**:
- Added 3+ new tests
- Significantly modified test execution time
- Load balance variance increased above 2.0x
- Tests redistributed unevenly
**How to update**:
```bash
# Run the duration update script (takes ~15-20 minutes)
./tests/update_test_durations.sh
# This will:
# 1. Run all tests sequentially
# 2. Measure each test's execution time
# 3. Generate .test_durations file
# 4. Enable pytest-split to optimize distribution
```
**Commit the results**:
```bash
git add .test_durations
git commit -m "chore: update test duration data for optimal load balancing"
```
### 5. Verify Optimization
Run tests again to verify improved load balancing:
```bash
./tests/run_automated_tests.sh
# Check new variance in report - should be < 1.2x
```
### Example: Adding 5 New Tests
```bash
# 1. Write tests
vim tests/glob/test_new_api_feature.py
# 2. Run and check results
./tests/run_automated_tests.sh
# Output shows: "Load Balance: 2.3x variance (poor)"
# 3. Update durations
./tests/update_test_durations.sh
# Wait ~15-20 minutes
# 4. Commit duration data
git add .test_durations
git commit -m "chore: update test durations after adding 5 new API tests"
# 5. Verify improvement
./tests/run_automated_tests.sh
# Output shows: "Load Balance: 1.08x variance (excellent)"
```
### Load Balancing Optimization Timeline
| Tests Added | Action | Reason |
|-------------|--------|--------|
| 1-2 tests | No update needed | Minimal impact on distribution |
| 3-5 tests | Consider updating | May cause slight imbalance |
| 6+ tests | **Update required** | Significant distribution changes |
| Major refactor | **Update required** | Test times may have changed |
### Current Status (2025-11-06)
```
Total Tests: 54
Execution Time: ~140-160s (2.3-2.7 minutes)
Load Balance: 1.2x variance (excellent)
Speedup: 9x+ vs sequential
Parallel Efficiency: >90%
Pass Rate: 100%
```
**Recent Updates**:
- **P1 Implementation Complete**: Added 5 new complex scenario tests
- Phase 3.1: Disable CNR when Nightly disabled
- Phase 5.1: Install CNR when Nightly enabled (automatic version switch)
- Phase 5.2: Install Nightly when CNR enabled (automatic version switch)
- Phase 5.3: Install new version when both disabled
- Phase 6: Uninstall removes all versions
**Recent Fixes** (2025-11-06):
- Fixed `test_case_sensitivity_full_workflow` - migrated to queue API
- Fixed `test_enable_package` - added pre-test cleanup
- Increased timeouts for parallel execution reliability
- Enhanced fixture cleanup with filesystem sync delays
**No duration update needed** - test distribution remains optimal after fixes.
## Test Documentation
For details about specific test failures and known issues, see:
- [README.md](./README.md) - Test suite overview and known issues
- [../README.md](../README.md) - Main testing guide with Quick Start
## API Usage Patterns
### Correct Queue API Usage
**Install Package**:
```python
# Queue install task
response = api_client.queue_task(
kind="install",
ui_id="unique_test_id",
params={
"id": "ComfyUI_PackageName", # Original case
"version": "1.0.2",
"selected_version": "latest"
}
)
assert response.status_code == 200
# Start queue
response = api_client.start_queue()
assert response.status_code in [200, 201]
# Wait for completion
time.sleep(10)
```
**Switch to Nightly**:
```python
# Queue install with version=nightly
response = api_client.queue_task(
kind="install",
ui_id="unique_test_id",
params={
"id": "ComfyUI_PackageName",
"version": "nightly",
"selected_version": "nightly"
}
)
```
**Uninstall Package**:
```python
response = api_client.queue_task(
kind="uninstall",
ui_id="unique_test_id",
params={
"node_name": "ComfyUI_PackageName" # Can use lowercase
}
)
```
**Enable/Disable Package**:
```python
# Enable
response = api_client.queue_task(
kind="enable",
ui_id="unique_test_id",
params={
"cnr_id": "comfyui_packagename" # Lowercase
}
)
# Disable
response = api_client.queue_task(
kind="disable",
ui_id="unique_test_id",
params={
"node_name": "ComfyUI_PackageName"
}
)
```
### Common Pitfalls
**Don't use non-existent endpoints**:
```python
# WRONG - This endpoint doesn't exist!
url = f"{server_url}/customnode/install"
requests.post(url, json={"id": "PackageName"})
```
**Always use the queue API**:
```python
# CORRECT
api_client.queue_task(kind="install", ...)
api_client.start_queue()
```
**Don't use short timeouts in parallel tests**:
```python
time.sleep(5) # Too short for parallel execution
```
**Use adequate timeouts**:
```python
time.sleep(20-30) # Better for parallel execution
```
### Test Fixture Best Practices
**Always cleanup before AND after tests**:
```python
@pytest.fixture
def my_fixture(custom_nodes_path):
def _cleanup():
# Remove test artifacts
if package_path.exists():
shutil.rmtree(package_path)
time.sleep(0.5) # Filesystem sync
# Cleanup BEFORE test
_cleanup()
# Setup test state
# ...
yield
# Cleanup AFTER test
_cleanup()
```
## Additional Resources
- [data_models/README.md](../../comfyui_manager/data_models/README.md) - Data model generation guide
- [update_test_durations.sh](../update_test_durations.sh) - Duration update script
- [../TESTING_PROMPT.md](../TESTING_PROMPT.md) - Claude Code automation guide