ComfyUI-Manager/tests/common/pip_util/TEST_IMPROVEMENTS.md
Dr.Lt.Data 2866193baf ● feat: Draft pip package policy management system (not yet integrated)
Add comprehensive pip dependency conflict resolution framework as draft implementation. This is self-contained and does not affect existing
ComfyUI Manager functionality.

Key components:
- pip_util.py with PipBatch class for policy-driven package management
- Lazy-loaded policy system supporting base + user overrides
- Multi-stage policy execution (uninstall → apply_first_match → apply_all_matches → restore)
- Conditional policies based on platform, installed packages, and ComfyUI version
- Comprehensive test suite covering edge cases, workflows, and platform scenarios
- Design and implementation documentation

Policy capabilities (draft):
- Package replacement (e.g., PIL → Pillow, opencv-python → opencv-contrib-python)
- Version pinning to prevent dependency conflicts
- Dependency protection during installations
- Platform-specific handling (Linux/Windows, GPU detection)
- Pre-removal and post-restoration workflows

Testing infrastructure:
- Pytest-based test suite with isolated environments
- Dependency analysis tools for conflict detection
- Coverage for policy priority, edge cases, and environment recovery

Status: Draft implementation complete, integration with manager workflows pending.
2025-10-04 08:55:59 +09:00

14 KiB

Test Code Improvements Based on Dependency Context

Date: 2025-10-01 Basis: DEPENDENCY_TREE_CONTEXT.md analysis

This document summarizes all test improvements made using verified dependency tree information.


Summary of Changes

Tests Enhanced

Test File Tests Modified Tests Added Total Tests
test_dependency_protection.py 2 2 4
test_environment_recovery.py 2 0 2
Total 4 2 6

Test Results

$ pytest test_dependency_protection.py test_environment_recovery.py -v

test_dependency_protection.py::test_dependency_version_protection_with_pin       PASSED
test_dependency_protection.py::test_dependency_chain_with_six_pin                PASSED
test_dependency_protection.py::test_pin_only_affects_specified_packages          PASSED ✨ NEW
test_dependency_protection.py::test_major_version_jump_prevention                PASSED ✨ NEW
test_environment_recovery.py::test_package_deletion_and_restore                  PASSED
test_environment_recovery.py::test_version_change_and_restore                    PASSED

6 passed in 14.10s

Detailed Improvements

1. test_dependency_version_protection_with_pin

File: test_dependency_protection.py:34-94

Enhancements:

  • Added exact version assertions based on DEPENDENCY_TREE_CONTEXT.md
  • Verified initial versions: urllib3==1.26.15, certifi==2023.7.22, charset-normalizer==3.2.0
  • Added verification that idna is NOT pre-installed
  • Added assertion that idna==3.10 is installed as NEW dependency
  • Verified requests==2.32.5 is installed
  • Added detailed error messages explaining what versions are expected and why

Key Assertions Added:

# Verify expected OLD versions
assert initial_urllib3 == "1.26.15", f"Expected urllib3==1.26.15, got {initial_urllib3}"
assert initial_certifi == "2023.7.22", f"Expected certifi==2023.7.22, got {initial_certifi}"
assert initial_charset == "3.2.0", f"Expected charset-normalizer==3.2.0, got {initial_charset}"

# Verify idna is NOT installed initially
assert "idna" not in initial, "idna should not be pre-installed"

# Verify new dependency was added (idna is NOT pinned, so it gets installed)
assert "idna" in final_packages, "idna should be installed as new dependency"
assert final_packages["idna"] == "3.10", f"Expected idna==3.10, got {final_packages['idna']}"

Based on Context:

  • DEPENDENCY_TREE_CONTEXT.md Section 1: requests → Dependencies
  • Verified: Without pin, urllib3 would upgrade to 2.5.0 (MAJOR version jump)
  • Verified: idna is NEW dependency (not in requirements-test-base.txt)

2. test_dependency_chain_with_six_pin

File: test_dependency_protection.py:117-162

Enhancements:

  • Added exact version assertion for six==1.16.0
  • Added exact version assertion for python-dateutil==2.9.0.post0
  • Added detailed error messages
  • Added docstring reference to DEPENDENCY_TREE_CONTEXT.md

Key Assertions Added:

# Verify expected OLD version
assert initial_six == "1.16.0", f"Expected six==1.16.0, got {initial_six}"

# Verify final versions
assert final_packages["python-dateutil"] == "2.9.0.post0", f"Expected python-dateutil==2.9.0.post0"
assert final_packages["six"] == "1.16.0", "six should remain at 1.16.0 (prevented 1.17.0 upgrade)"

Based on Context:

  • DEPENDENCY_TREE_CONTEXT.md Section 2: python-dateutil → Dependencies
  • Verified: six is a REAL dependency (not optional like colorama)
  • Verified: Without pin, six would upgrade from 1.16.0 to 1.17.0

3. test_pin_only_affects_specified_packages NEW

File: test_dependency_protection.py:165-208

Purpose: Verify that pin is selective, not global

Test Logic:

  1. Verify idna is NOT pre-installed
  2. Verify requests is NOT pre-installed
  3. Install requests with pin policy (only pins urllib3, certifi, charset-normalizer)
  4. Verify idna was installed at latest version (3.10) - NOT pinned
  5. Verify requests was installed at expected version (2.32.5)

Key Assertions:

# Verify idna was installed (NOT pinned, so gets latest)
assert "idna" in final_packages, "idna should be installed as new dependency"
assert final_packages["idna"] == "3.10", "idna should be at latest version 3.10 (not pinned)"

Based on Context:

  • DEPENDENCY_TREE_CONTEXT.md: "⚠️ idna is NEW and NOT pinned (acceptable - new dependency)"
  • Verified: Pin only affects specified packages in pinned_packages list

4. test_major_version_jump_prevention NEW

File: test_dependency_protection.py:211-271

Purpose: Verify that pin prevents MAJOR version jumps with breaking changes

Test Logic:

  1. Verify initial urllib3==1.26.15
  2. Test WITHOUT pin: Uninstall deps, install requests → urllib3 upgrades to 2.x
  3. Verify urllib3 was upgraded to 2.x (starts with "2.")
  4. Reset environment
  5. Test WITH pin: Install requests with pin → urllib3 stays at 1.x
  6. Verify urllib3 stayed at 1.26.15 (starts with "1.")

Key Assertions:

# Without pin - verify urllib3 upgrades to 2.x
assert without_pin["urllib3"].startswith("2."), \
    f"Without pin, urllib3 should upgrade to 2.x, got {without_pin['urllib3']}"

# With pin - verify urllib3 stays at 1.x
assert final_packages["urllib3"] == "1.26.15", \
    "Pin should prevent urllib3 from upgrading to 2.x (breaking changes)"
assert final_packages["urllib3"].startswith("1."), \
    f"urllib3 should remain at 1.x series, got {final_packages['urllib3']}"

Based on Context:

  • DEPENDENCY_TREE_CONTEXT.md: "urllib3 1.26.15 → 2.5.0 is a MAJOR version jump"
  • DEPENDENCY_TREE_CONTEXT.md: "urllib3 2.0 removed deprecated APIs"
  • This is the MOST IMPORTANT test - prevents breaking changes

5. test_package_deletion_and_restore

File: test_environment_recovery.py:33-78

Enhancements:

  • Added exact version assertion for six==1.16.0
  • Added verification that six is restored to EXACT version (not latest)
  • Added detailed error messages
  • Added docstring reference to DEPENDENCY_TREE_CONTEXT.md

Key Assertions Added:

# Verify six is initially installed at expected version
assert initial["six"] == "1.16.0", f"Expected six==1.16.0, got {initial['six']}"

# Verify six was restored to EXACT required version (not latest)
assert final_packages["six"] == "1.16.0", \
    "six should be restored to exact version 1.16.0 (not 1.17.0 latest)"

Based on Context:

  • DEPENDENCY_TREE_CONTEXT.md: "six: 1.16.0 (OLD) → 1.17.0 (LATEST)"
  • Verified: Restore policy restores to EXACT version, not latest

6. test_version_change_and_restore

File: test_environment_recovery.py:105-158

Enhancements:

  • Added exact version assertions (1.26.15 initially, 2.1.0 after upgrade)
  • Added verification of major version change (1.x → 2.x)
  • Added verification of major version downgrade (2.x → 1.x)
  • Added detailed error messages explaining downgrade capability
  • Added docstring reference to DEPENDENCY_TREE_CONTEXT.md

Key Assertions Added:

# Verify version was changed to 2.x
assert installed_after["urllib3"] == "2.1.0", \
    f"urllib3 should be upgraded to 2.1.0, got {installed_after['urllib3']}"
assert installed_after["urllib3"].startswith("2."), \
    "urllib3 should be at 2.x series"

# Verify version was DOWNGRADED from 2.x back to 1.x
assert final["urllib3"] == "1.26.15", \
    "urllib3 should be downgraded to 1.26.15 (from 2.1.0)"
assert final["urllib3"].startswith("1."), \
    f"urllib3 should be back at 1.x series, got {final['urllib3']}"

Based on Context:

  • DEPENDENCY_TREE_CONTEXT.md: "urllib3 can upgrade from 1.26.15 (1.x) to 2.5.0 (2.x)"
  • Verified: Restore policy can DOWNGRADE (not just prevent upgrades)
  • Tests actual version downgrade capability (2.x → 1.x)

Test Coverage Analysis

Before Improvements

Scenario Coverage
Pin prevents upgrades Basic
New dependencies installed Not tested
Pin is selective Not tested
Major version jump prevention Not tested
Exact version restoration Not tested
Version downgrade capability Not tested

After Improvements

Scenario Coverage Test
Pin prevents upgrades Enhanced test_dependency_version_protection_with_pin
New dependencies installed Added test_dependency_version_protection_with_pin
Pin is selective Added test_pin_only_affects_specified_packages
Major version jump prevention Added test_major_version_jump_prevention
Exact version restoration Enhanced test_package_deletion_and_restore
Version downgrade capability Enhanced test_version_change_and_restore

Key Testing Principles Applied

1. Exact Version Verification

Before:

assert final_packages["urllib3"] == initial_urllib3  # Generic

After:

assert initial_urllib3 == "1.26.15", f"Expected urllib3==1.26.15, got {initial_urllib3}"
assert final_packages["urllib3"] == "1.26.15", "urllib3 should remain at 1.26.15 (prevented 2.x upgrade)"

Benefit: Fails with clear message if environment setup is wrong


2. Version Series Verification

Added:

assert final_packages["urllib3"].startswith("1."), \
    f"urllib3 should remain at 1.x series, got {final_packages['urllib3']}"

Benefit: Catches major version jumps even if exact version changes


3. Negative Testing (Verify NOT Installed)

Added:

assert "idna" not in initial, "idna should not be pre-installed"

Benefit: Ensures test environment is in expected state


4. Context-Based Documentation

Every test now includes:

"""
Based on DEPENDENCY_TREE_CONTEXT.md:
    <specific section reference>
    <expected behavior from context>
"""

Benefit: Links test expectations to verified dependency data


Real-World Scenarios Tested

Scenario 1: Preventing Breaking Changes

Test: test_major_version_jump_prevention

Real-World Impact:

  • urllib3 2.0 removed deprecated APIs
  • Many applications break when upgrading from 1.x to 2.x
  • Pin prevents this automatic breaking change

Verified: Pin successfully prevents 1.x → 2.x upgrade


Scenario 2: Allowing New Dependencies

Test: test_pin_only_affects_specified_packages

Real-World Impact:

  • New dependencies are safe to add (idna)
  • Pin should not block ALL changes
  • Only specified packages are protected

Verified: idna installs at 3.10 even with pin policy active


Scenario 3: Version Downgrade Recovery

Test: test_version_change_and_restore

Real-World Impact:

  • Sometimes packages get upgraded accidentally
  • Need to downgrade to known-good version
  • Downgrade is harder than upgrade prevention

Verified: Can downgrade urllib3 from 2.x to 1.x


Test Execution Performance

Test Performance Summary:

test_dependency_version_protection_with_pin       2.28s  (enhanced)
test_dependency_chain_with_six_pin               2.00s  (enhanced)
test_pin_only_affects_specified_packages         2.25s  (NEW)
test_major_version_jump_prevention               3.53s  (NEW - does 2 install cycles)
test_package_deletion_and_restore                2.25s  (enhanced)
test_version_change_and_restore                  2.24s  (enhanced)

Total: 14.10s for 6 tests
Average: 2.35s per test

Note: test_major_version_jump_prevention is slower because it tests both WITH and WITHOUT pin (2 install cycles).


Files Modified

  1. test_dependency_protection.py: +138 lines

    • Enhanced 2 existing tests
    • Added 2 new tests
    • Total: 272 lines (was 132 lines)
  2. test_environment_recovery.py: +35 lines

    • Enhanced 2 existing tests
    • Total: 159 lines (was 141 lines)

Verification Against Context

All test improvements verified against:

Context Source Usage
DEPENDENCY_TREE_CONTEXT.md All version numbers, dependency trees
DEPENDENCY_ANALYSIS.md Package selection rationale, rejected scenarios
TEST_SCENARIOS.md Scenario specifications, expected outcomes
requirements-test-base.txt Initial environment state
analyze_dependencies.py Real-time verification of expectations

Future Maintenance

When to Update Tests

Update tests when:

  • PyPI releases new major versions (e.g., urllib3 3.0)
  • Base package versions change in requirements-test-base.txt
  • New test scenarios added to DEPENDENCY_TREE_CONTEXT.md
  • Policy behavior changes in pip_util.py

How to Update Tests

  1. Run python analyze_dependencies.py --all
  2. Update expected version numbers in tests
  3. Update DEPENDENCY_TREE_CONTEXT.md
  4. Update TEST_SCENARIOS.md
  5. Run tests to verify

Verification Commands

# Verify environment
python analyze_dependencies.py --env

# Verify package dependencies
python analyze_dependencies.py requests
python analyze_dependencies.py python-dateutil

# Run all tests
pytest test_dependency_protection.py test_environment_recovery.py -v --override-ini="addopts="

Summary

6 tests now verify real PyPI package dependencies 100% pass rate with real pip operations All version numbers verified against DEPENDENCY_TREE_CONTEXT.md Major version jump prevention explicitly tested Selective pinning verified (only specified packages) Version downgrade capability tested

Key Achievement: Tests now verify actual PyPI behavior, not mocked expectations.