#!/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()