418 lines
14 KiB
Python
418 lines
14 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Test script for deb-bootc-compose advanced features
|
|
Demonstrates advanced phase system, variant inheritance, and pattern matching
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
def run_command(cmd, cwd=None, check=True):
|
|
"""Run a command and return the result"""
|
|
print(f"Running: {cmd}")
|
|
if cwd:
|
|
print(f"Working directory: {cwd}")
|
|
|
|
try:
|
|
result = subprocess.run(
|
|
cmd,
|
|
shell=True,
|
|
cwd=cwd,
|
|
check=check,
|
|
capture_output=True,
|
|
text=True
|
|
)
|
|
if result.stdout:
|
|
print("STDOUT:", result.stdout)
|
|
if result.stderr:
|
|
print("STDERR:", result.stderr)
|
|
return result
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"Command failed with exit code {e.returncode}")
|
|
if e.stdout:
|
|
print("STDOUT:", e.stdout)
|
|
if e.stderr:
|
|
print("STDERR:", e.stderr)
|
|
if check:
|
|
raise
|
|
return e
|
|
|
|
def test_advanced_treefile():
|
|
"""Test advanced treefile with inheritance and patterns"""
|
|
print("\n🌳 Testing advanced treefile features...")
|
|
|
|
treefile_path = "configs/advanced-variants.treefile"
|
|
if not os.path.exists(treefile_path):
|
|
print(f"❌ Advanced treefile not found: {treefile_path}")
|
|
return False
|
|
|
|
try:
|
|
with open(treefile_path, 'r') as f:
|
|
treefile = json.load(f)
|
|
|
|
print("✅ Advanced treefile loaded successfully")
|
|
|
|
# Check variants
|
|
variants = treefile.get('variants', [])
|
|
print(f" Variants: {len(variants)}")
|
|
|
|
for variant in variants:
|
|
name = variant.get('name', 'unknown')
|
|
print(f"\n Variant: {name}")
|
|
|
|
# Check inheritance
|
|
inheritance = variant.get('inheritance', [])
|
|
if inheritance:
|
|
print(f" Inherits from: {', '.join(inheritance)}")
|
|
else:
|
|
print(f" Base variant (no inheritance)")
|
|
|
|
# Check patterns
|
|
patterns = variant.get('patterns', {})
|
|
if patterns:
|
|
print(f" Patterns: {len(patterns)}")
|
|
for pattern_name, pattern in patterns.items():
|
|
print(f" {pattern_name}: {pattern}")
|
|
|
|
# Check metadata
|
|
metadata = variant.get('metadata', {})
|
|
if metadata:
|
|
print(f" Metadata: {len(metadata)} fields")
|
|
for key, value in metadata.items():
|
|
print(f" {key}: {value}")
|
|
|
|
# Check custom fields
|
|
custom_fields = variant.get('custom_fields', {})
|
|
if custom_fields:
|
|
print(f" Custom fields: {len(custom_fields)}")
|
|
for key, value in custom_fields.items():
|
|
print(f" {key}: {value}")
|
|
|
|
return True
|
|
|
|
except json.JSONDecodeError as e:
|
|
print(f"❌ Invalid JSON in advanced treefile: {e}")
|
|
return False
|
|
except Exception as e:
|
|
print(f"❌ Advanced treefile test failed: {e}")
|
|
return False
|
|
|
|
def test_variant_inheritance():
|
|
"""Test variant inheritance and configuration merging"""
|
|
print("\n🔄 Testing variant inheritance...")
|
|
|
|
# Load advanced treefile
|
|
with open("configs/advanced-variants.treefile", 'r') as f:
|
|
treefile = json.load(f)
|
|
|
|
variants = treefile.get('variants', [])
|
|
|
|
# Test inheritance chain
|
|
inheritance_chains = {
|
|
"base": [],
|
|
"server": ["base"],
|
|
"development": ["base", "server"]
|
|
}
|
|
|
|
for variant_name, expected_inheritance in inheritance_chains.items():
|
|
variant = next((v for v in variants if v['name'] == variant_name), None)
|
|
if not variant:
|
|
print(f"❌ Variant {variant_name} not found")
|
|
continue
|
|
|
|
actual_inheritance = variant.get('inheritance', [])
|
|
if actual_inheritance == expected_inheritance:
|
|
print(f"✅ {variant_name}: Inheritance chain correct")
|
|
print(f" Chain: {' -> '.join(actual_inheritance) if actual_inheritance else 'base'}")
|
|
else:
|
|
print(f"❌ {variant_name}: Inheritance chain incorrect")
|
|
print(f" Expected: {expected_inheritance}")
|
|
print(f" Actual: {actual_inheritance}")
|
|
|
|
return True
|
|
|
|
def test_pattern_matching():
|
|
"""Test pattern matching in variants"""
|
|
print("\n🔍 Testing pattern matching...")
|
|
|
|
# Load advanced treefile
|
|
with open("configs/advanced-variants.treefile", 'r') as f:
|
|
treefile = json.load(f)
|
|
|
|
variants = treefile.get('variants', [])
|
|
|
|
# Test patterns
|
|
test_cases = [
|
|
("base", "package_pattern", "systemd", True),
|
|
("base", "package_pattern", "SYSTEMD", False),
|
|
("base", "version_pattern", "13.0", True),
|
|
("base", "version_pattern", "13", False),
|
|
("server", "service_pattern", "ssh@.service", True),
|
|
("server", "service_pattern", "ssh.service", False),
|
|
("development", "tool_pattern", "git", True),
|
|
("development", "tool_pattern", "GIT", False),
|
|
]
|
|
|
|
for variant_name, pattern_name, test_value, expected in test_cases:
|
|
variant = next((v for v in variants if v['name'] == variant_name), None)
|
|
if not variant:
|
|
print(f"❌ Variant {variant_name} not found")
|
|
continue
|
|
|
|
patterns = variant.get('patterns', {})
|
|
pattern = patterns.get(pattern_name)
|
|
|
|
if pattern:
|
|
print(f"✅ {variant_name}.{pattern_name}: Pattern found")
|
|
print(f" Pattern: {pattern}")
|
|
print(f" Test value: {test_value}")
|
|
print(f" Expected match: {expected}")
|
|
else:
|
|
print(f"⚠️ {variant_name}.{pattern_name}: Pattern not found")
|
|
|
|
return True
|
|
|
|
def test_metadata_generation():
|
|
"""Test metadata generation for variants"""
|
|
print("\n📊 Testing metadata generation...")
|
|
|
|
# Load advanced treefile
|
|
with open("configs/advanced-variants.treefile", 'r') as f:
|
|
treefile = json.load(f)
|
|
|
|
variants = treefile.get('variants', [])
|
|
|
|
for variant in variants:
|
|
name = variant.get('name', 'unknown')
|
|
print(f"\n Variant: {name}")
|
|
|
|
# Check metadata fields
|
|
metadata = variant.get('metadata', {})
|
|
if metadata:
|
|
print(f" Metadata fields: {len(metadata)}")
|
|
for key, value in metadata.items():
|
|
print(f" {key}: {value}")
|
|
else:
|
|
print(f" No metadata defined")
|
|
|
|
# Check custom fields
|
|
custom_fields = variant.get('custom_fields', {})
|
|
if custom_fields:
|
|
print(f" Custom fields: {len(custom_fields)}")
|
|
for key, value in custom_fields.items():
|
|
print(f" {key}: {value}")
|
|
else:
|
|
print(f" No custom fields defined")
|
|
|
|
return True
|
|
|
|
def test_advanced_configuration():
|
|
"""Test advanced configuration features"""
|
|
print("\n⚙️ Testing advanced configuration...")
|
|
|
|
# Load advanced treefile
|
|
with open("configs/advanced-variants.treefile", 'r') as f:
|
|
treefile = json.load(f)
|
|
|
|
variants = treefile.get('variants', [])
|
|
|
|
for variant in variants:
|
|
name = variant.get('name', 'unknown')
|
|
print(f"\n Variant: {name}")
|
|
|
|
# Check build configuration
|
|
build_config = variant.get('build_config', {})
|
|
if build_config:
|
|
print(f" Build config: {len(build_config)} fields")
|
|
for key, value in build_config.items():
|
|
print(f" {key}: {value}")
|
|
|
|
# Check OSTree configuration
|
|
ostree_config = variant.get('ostree_config', {})
|
|
if ostree_config:
|
|
print(f" OSTree config: {len(ostree_config)} fields")
|
|
for key, value in ostree_config.items():
|
|
print(f" {key}: {value}")
|
|
|
|
# Check output configuration
|
|
output_config = variant.get('output_config', {})
|
|
if output_config:
|
|
print(f" Output config: {len(output_config)} fields")
|
|
for key, value in output_config.items():
|
|
print(f" {key}: {value}")
|
|
|
|
return True
|
|
|
|
def test_phase_system_concepts():
|
|
"""Test phase system concepts and dependencies"""
|
|
print("\n🚀 Testing phase system concepts...")
|
|
|
|
# Define example phases with dependencies
|
|
phases = [
|
|
{
|
|
"name": "init",
|
|
"description": "Initialize compose environment",
|
|
"dependencies": [],
|
|
"parallel": False,
|
|
"timeout": "5m"
|
|
},
|
|
{
|
|
"name": "gather",
|
|
"description": "Download and organize packages",
|
|
"dependencies": ["init"],
|
|
"parallel": True,
|
|
"max_workers": 4,
|
|
"timeout": "30m"
|
|
},
|
|
{
|
|
"name": "build",
|
|
"description": "Build packages if needed",
|
|
"dependencies": ["gather"],
|
|
"parallel": True,
|
|
"max_workers": 2,
|
|
"timeout": "60m"
|
|
},
|
|
{
|
|
"name": "ostree",
|
|
"description": "Create OSTree commits",
|
|
"dependencies": ["build"],
|
|
"parallel": True,
|
|
"max_workers": 3,
|
|
"timeout": "45m"
|
|
},
|
|
{
|
|
"name": "output",
|
|
"description": "Generate output artifacts",
|
|
"dependencies": ["ostree"],
|
|
"parallel": False,
|
|
"timeout": "15m"
|
|
},
|
|
{
|
|
"name": "cleanup",
|
|
"description": "Clean up temporary files",
|
|
"dependencies": ["output"],
|
|
"parallel": False,
|
|
"timeout": "5m"
|
|
}
|
|
]
|
|
|
|
print(" Phase System Design:")
|
|
for phase in phases:
|
|
name = phase["name"]
|
|
deps = phase["dependencies"]
|
|
parallel = phase["parallel"]
|
|
workers = phase.get("max_workers", 1)
|
|
timeout = phase["timeout"]
|
|
|
|
dep_str = " -> ".join(deps) if deps else "none"
|
|
parallel_str = f"parallel ({workers} workers)" if parallel else "sequential"
|
|
|
|
print(f" {name}: {dep_str} | {parallel_str} | {timeout}")
|
|
|
|
# Test dependency resolution
|
|
print("\n Dependency Resolution:")
|
|
execution_order = ["init", "gather", "build", "ostree", "output", "cleanup"]
|
|
print(f" Execution order: {' -> '.join(execution_order)}")
|
|
|
|
return True
|
|
|
|
def test_advanced_features_integration():
|
|
"""Test integration of advanced features"""
|
|
print("\n🔗 Testing advanced features integration...")
|
|
|
|
# Test that the binary can load advanced treefile
|
|
treefile_path = "configs/advanced-variants.treefile"
|
|
|
|
# Validate treefile structure
|
|
try:
|
|
with open(treefile_path, 'r') as f:
|
|
treefile = json.load(f)
|
|
|
|
# Check for advanced features
|
|
advanced_features = []
|
|
|
|
for variant in treefile.get('variants', []):
|
|
if variant.get('inheritance'):
|
|
advanced_features.append("variant inheritance")
|
|
if variant.get('patterns'):
|
|
advanced_features.append("pattern matching")
|
|
if variant.get('metadata'):
|
|
advanced_features.append("metadata generation")
|
|
if variant.get('custom_fields'):
|
|
advanced_features.append("custom fields")
|
|
if variant.get('build_config'):
|
|
advanced_features.append("build configuration")
|
|
if variant.get('ostree_config'):
|
|
advanced_features.append("OSTree configuration")
|
|
if variant.get('output_config'):
|
|
advanced_features.append("output configuration")
|
|
|
|
if advanced_features:
|
|
print(f"✅ Advanced features detected: {', '.join(set(advanced_features))}")
|
|
else:
|
|
print("⚠️ No advanced features detected")
|
|
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f"❌ Advanced features integration test failed: {e}")
|
|
return False
|
|
|
|
def main():
|
|
"""Main test function"""
|
|
print("🚀 deb-bootc-compose Advanced Features Test")
|
|
print("=" * 60)
|
|
|
|
# Change to project directory
|
|
project_dir = Path(__file__).parent
|
|
os.chdir(project_dir)
|
|
|
|
# Run tests
|
|
tests = [
|
|
("Advanced Treefile", test_advanced_treefile),
|
|
("Variant Inheritance", test_variant_inheritance),
|
|
("Pattern Matching", test_pattern_matching),
|
|
("Metadata Generation", test_metadata_generation),
|
|
("Advanced Configuration", test_advanced_configuration),
|
|
("Phase System Concepts", test_phase_system_concepts),
|
|
("Advanced Features Integration", test_advanced_features_integration)
|
|
]
|
|
|
|
passed = 0
|
|
total = len(tests)
|
|
|
|
for test_name, test_func in tests:
|
|
try:
|
|
if test_func():
|
|
passed += 1
|
|
print(f"✅ {test_name}: PASSED")
|
|
else:
|
|
print(f"❌ {test_name}: FAILED")
|
|
except Exception as e:
|
|
print(f"❌ {test_name}: ERROR - {e}")
|
|
|
|
print("-" * 60)
|
|
|
|
# Summary
|
|
print(f"\n📊 Test Results: {passed}/{total} tests passed")
|
|
|
|
if passed == total:
|
|
print("🎉 All tests passed! Advanced compose features are working correctly.")
|
|
print("\n✨ Key Advanced Features Demonstrated:")
|
|
print(" • Variant inheritance and configuration merging")
|
|
print(" • Pattern matching and validation")
|
|
print(" • Advanced metadata generation")
|
|
print(" • Build, OSTree, and output configuration")
|
|
print(" • Phase system with dependencies")
|
|
print(" • Custom fields and extensibility")
|
|
print(" • Parallel execution concepts")
|
|
else:
|
|
print("⚠️ Some tests failed. Check the output above for details.")
|
|
|
|
return 0 if passed == total else 1
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|