debian-atomic-config/test-all-variants.py
2025-08-26 10:16:43 -07:00

261 lines
10 KiB
Python

#!/usr/bin/env python3
"""
Comprehensive Test Script for Debian Atomic Variants
Tests all variants using the alternative debootstrap + ostree solution
"""
import os
import sys
import subprocess
import tempfile
import time
from pathlib import Path
from typing import List, Dict, Any
class DebianAtomicTester:
"""Test all Debian Atomic variants"""
def __init__(self, work_dir: str = None):
self.work_dir = Path(work_dir) if work_dir else Path(tempfile.mkdtemp(prefix="debian-atomic-test-"))
self.results = {}
def test_variant(self, variant: str) -> Dict[str, Any]:
"""Test a specific variant"""
print(f"\n{'='*60}")
print(f"Testing variant: {variant}")
print(f"{'='*60}")
start_time = time.time()
result = {
"variant": variant,
"status": "unknown",
"start_time": start_time,
"end_time": None,
"duration": None,
"errors": [],
"warnings": [],
"output": {}
}
try:
# Test the variant build
cmd = [
"python3", "create-debian-atomic.py", variant, str(self.work_dir / variant)
]
print(f"Running: {' '.join(cmd)}")
process = subprocess.run(
cmd,
capture_output=True,
text=True,
cwd=Path(__file__).parent
)
result["output"]["stdout"] = process.stdout
result["output"]["stderr"] = process.stderr
result["output"]["returncode"] = process.returncode
if process.returncode == 0:
result["status"] = "success"
print(f"{variant} variant built successfully")
# Verify the repository was created
repo_path = self.work_dir / variant / "repo"
if repo_path.exists():
# Test OSTree operations
self.test_ostree_operations(repo_path, variant, result)
else:
result["warnings"].append("Repository directory not found")
else:
result["status"] = "failed"
result["errors"].append(f"Build failed with return code {process.returncode}")
print(f"{variant} variant build failed")
if process.stderr:
print(f"Error: {process.stderr}")
except Exception as e:
result["status"] = "error"
result["errors"].append(f"Exception during build: {str(e)}")
print(f"{variant} variant build error: {e}")
finally:
end_time = time.time()
result["end_time"] = end_time
result["duration"] = end_time - start_time
return result
def test_ostree_operations(self, repo_path: Path, variant: str, result: Dict[str, Any]):
"""Test basic OSTree operations on the repository"""
try:
print(f"Testing OSTree operations for {variant}")
# Test listing refs
cmd = ["ostree", "refs", "--repo", str(repo_path)]
process = subprocess.run(cmd, capture_output=True, text=True, check=True)
refs = process.stdout.strip().split('\n') if process.stdout.strip() else []
result["output"]["ostree_refs"] = refs
print(f"OSTree refs: {refs}")
# Test listing commits
if refs:
ref = refs[0] # Use first ref
cmd = ["ostree", "log", "--repo", str(repo_path), ref]
process = subprocess.run(cmd, capture_output=True, text=True, check=True)
result["output"]["ostree_log"] = process.stdout
print(f"OSTree log for {ref}: {process.stdout[:200]}...")
# Test commit info
cmd = ["ostree", "show", "--repo", str(repo_path), ref]
process = subprocess.run(cmd, capture_output=True, text=True, check=True)
result["output"]["ostree_show"] = process.stdout
print(f"OSTree commit info: {process.stdout[:200]}...")
except subprocess.CalledProcessError as e:
result["warnings"].append(f"OSTree operation failed: {e}")
print(f"Warning: OSTree operation failed: {e}")
except Exception as e:
result["warnings"].append(f"OSTree test error: {e}")
print(f"Warning: OSTree test error: {e}")
def test_all_variants(self) -> Dict[str, Any]:
"""Test all supported variants"""
variants = ["minimal", "gnome", "plasma", "cosmic", "sway", "budgie"]
print(f"Testing all Debian Atomic variants")
print(f"Work directory: {self.work_dir}")
print(f"Variants to test: {', '.join(variants)}")
for variant in variants:
self.results[variant] = self.test_variant(variant)
return self.results
def generate_report(self) -> str:
"""Generate a comprehensive test report"""
report = []
report.append("# Debian Atomic Variants Test Report")
report.append(f"Generated: {time.strftime('%Y-%m-%d %H:%M:%S')}")
report.append(f"Work directory: {self.work_dir}")
report.append("")
# Summary
total = len(self.results)
successful = sum(1 for r in self.results.values() if r["status"] == "success")
failed = sum(1 for r in self.results.values() if r["status"] == "failed")
errors = sum(1 for r in self.results.values() if r["status"] == "error")
report.append("## Summary")
report.append(f"- Total variants tested: {total}")
report.append(f"- Successful builds: {successful}")
report.append(f"- Failed builds: {failed}")
report.append(f"- Build errors: {errors}")
report.append(f"- Success rate: {(successful/total)*100:.1f}%")
report.append("")
# Detailed results
report.append("## Detailed Results")
for variant, result in self.results.items():
status_emoji = "" if result["status"] == "success" else ""
report.append(f"### {status_emoji} {variant}")
report.append(f"- Status: {result['status']}")
report.append(f"- Duration: {result['duration']:.2f}s")
if result["errors"]:
report.append("- Errors:")
for error in result["errors"]:
report.append(f" - {error}")
if result["warnings"]:
report.append("- Warnings:")
for warning in result["warnings"]:
report.append(f" - {warning}")
if result["status"] == "success":
repo_path = self.work_dir / variant / "repo"
report.append(f"- Repository: {repo_path}")
if "ostree_refs" in result["output"]:
report.append(f"- OSTree refs: {', '.join(result['output']['ostree_refs'])}")
report.append("")
# Recommendations
report.append("## Recommendations")
if successful == total:
report.append("🎉 All variants built successfully! The alternative solution is working perfectly.")
elif successful > total / 2:
report.append("⚠️ Most variants built successfully, but some issues need investigation.")
else:
report.append("🚨 Multiple variants failed. The alternative solution needs significant work.")
report.append("")
report.append("## Next Steps")
if successful > 0:
report.append("1. Test bootable image generation with successful variants")
report.append("2. Integrate with deb-bootc-image-builder")
report.append("3. Validate system boot and functionality")
else:
report.append("1. Investigate and fix build failures")
report.append("2. Verify dependencies and environment")
report.append("3. Test individual components")
return "\n".join(report)
def cleanup(self):
"""Clean up test artifacts"""
try:
if self.work_dir.exists():
import shutil
shutil.rmtree(self.work_dir)
print(f"Cleaned up test directory: {self.work_dir}")
except Exception as e:
print(f"Warning: Could not clean up {self.work_dir}: {e}")
def main():
"""Main function"""
if len(sys.argv) > 1 and sys.argv[1] == "--keep":
work_dir = None
cleanup = False
print("Keeping test artifacts (--keep specified)")
else:
work_dir = None
cleanup = True
print("Test artifacts will be cleaned up automatically")
tester = DebianAtomicTester(work_dir)
try:
# Test all variants
results = tester.test_all_variants()
# Generate and display report
report = tester.generate_report()
print("\n" + "="*80)
print(report)
print("="*80)
# Save report to file
report_file = Path(__file__).parent / "test-report.md"
with open(report_file, 'w') as f:
f.write(report)
print(f"\nTest report saved to: {report_file}")
# Exit with appropriate code
successful = sum(1 for r in results.values() if r["status"] == "success")
total = len(results)
if successful == total:
print(f"\n🎉 All {total} variants tested successfully!")
sys.exit(0)
else:
print(f"\n⚠️ {successful}/{total} variants tested successfully")
sys.exit(1)
finally:
if cleanup:
tester.cleanup()
if __name__ == "__main__":
main()