Files
ETPlot/tests/test_container.py
T
2025-09-08 10:52:58 +02:00

251 lines
8.2 KiB
Python

"""
Container-optimized test suite for gallery generator.
Designed to run inside Apptainer/Singularity containers.
"""
import unittest
import tempfile
import shutil
import time
import os
from pathlib import Path
import subprocess
import sys
class TestContainerEnvironment(unittest.TestCase):
"""Test that the container environment is properly configured."""
def test_python_version(self):
"""Test that Python 3.11+ is available."""
version = sys.version_info
self.assertGreaterEqual(version.major, 3)
self.assertGreaterEqual(version.minor, 11)
def test_required_modules(self):
"""Test that required Python modules are installed."""
try:
import jinja2
import yaml
self.assertTrue(True) # Success if no ImportError
except ImportError as e:
self.fail(f"Required module not found: {e}")
def test_imagemagick_available(self):
"""Test that ImageMagick is installed and accessible."""
try:
result = subprocess.run(['convert', '-version'],
capture_output=True, text=True, timeout=10)
self.assertEqual(result.returncode, 0)
self.assertIn('ImageMagick', result.stdout)
except (subprocess.TimeoutExpired, FileNotFoundError):
self.fail("ImageMagick not available or not working")
def test_working_directory(self):
"""Test that the source code is available."""
expected_files = ['generate_gallery.py', 'config.yaml', 'orchestration/']
for file_path in expected_files:
path = Path('/src') / file_path
self.assertTrue(path.exists(), f"Missing: {file_path}")
class TestUtilityFunctions(unittest.TestCase):
"""Test core utility functions."""
def test_format_file_size(self):
"""Test file size formatting utility."""
# Import the function from the container's source
sys.path.insert(0, '/src')
from generate_gallery import format_file_size
self.assertEqual(format_file_size(0), "0 B")
self.assertEqual(format_file_size(1024), "1.0 KB")
self.assertEqual(format_file_size(1048576), "1.0 MB")
self.assertEqual(format_file_size(1073741824), "1.0 GB")
def test_needs_update(self):
"""Test file update checking."""
sys.path.insert(0, '/src')
from generate_gallery import needs_update
with tempfile.TemporaryDirectory() as temp_dir:
temp_path = Path(temp_dir)
# Test missing target
source = temp_path / "source.txt"
target = temp_path / "target.txt"
source.write_text("test")
self.assertTrue(needs_update(source, target))
# Test up-to-date target
target.write_text("test")
time.sleep(0.1) # Ensure different timestamp
os.utime(target, (time.time(), time.time()))
self.assertFalse(needs_update(source, target))
class TestMetadataSystem(unittest.TestCase):
"""Test metadata loading and processing."""
def setUp(self):
sys.path.insert(0, '/src')
def test_metadata_loading(self):
"""Test loading metadata files."""
from orchestration.metadata import load_metadata_file
with tempfile.TemporaryDirectory() as temp_dir:
temp_path = Path(temp_dir)
# Test YAML metadata
yaml_file = temp_path / "test.yaml"
yaml_content = "title: Test\nauthor: Container Test\n"
yaml_file.write_text(yaml_content)
metadata = load_metadata_file(yaml_file)
self.assertEqual(metadata['title'], 'Test')
self.assertEqual(metadata['author'], 'Container Test')
def test_metadata_inheritance(self):
"""Test metadata inheritance through directories."""
from orchestration.metadata import merge_metadata
parent = {'project': 'Test', 'version': '1.0'}
child = {'experiment': 'A', 'version': '1.1'}
merged = merge_metadata(parent, child)
self.assertEqual(merged['project'], 'Test')
self.assertEqual(merged['experiment'], 'A')
self.assertEqual(merged['version'], '1.1') # Child overrides parent
class TestPDFProcessing(unittest.TestCase):
"""Test PDF processing functionality."""
def setUp(self):
sys.path.insert(0, '/src')
self.temp_dir = Path(tempfile.mkdtemp())
def tearDown(self):
shutil.rmtree(self.temp_dir)
def create_mock_pdf(self, path: Path):
"""Create a minimal mock PDF."""
path.write_text("%PDF-1.4\nMock PDF for testing")
def test_pdf_conversion(self):
"""Test PDF to PNG conversion."""
from generate_gallery import convert_pdf_to_png
# Create a mock PDF
pdf_path = self.temp_dir / "test.pdf"
self.create_mock_pdf(pdf_path)
# This should work in the container with ImageMagick
try:
convert_pdf_to_png(pdf_path)
png_path = pdf_path.with_suffix('.png')
self.assertTrue(png_path.exists())
except subprocess.CalledProcessError:
# Allow test to pass if ImageMagick can't process our mock PDF
# (Real PDFs would work, but our mock might not)
self.skipTest("Mock PDF not processable by ImageMagick")
class TestGalleryGeneration(unittest.TestCase):
"""Test end-to-end gallery generation."""
def setUp(self):
sys.path.insert(0, '/src')
self.temp_dir = Path(tempfile.mkdtemp())
self.source_dir = self.temp_dir / "source"
self.web_dir = self.temp_dir / "web"
self.source_dir.mkdir()
self.web_dir.mkdir()
def tearDown(self):
shutil.rmtree(self.temp_dir)
def create_test_structure(self):
"""Create a minimal test directory structure."""
# Create mock PDF
pdf_path = self.source_dir / "test_plot.pdf"
pdf_path.write_text("%PDF-1.4\nTest plot content")
# Create metadata
metadata_path = self.source_dir / "metadata.yaml"
metadata_path.write_text("title: Container Test\nauthor: CI Pipeline\n")
def test_build_gallery(self):
"""Test building a simple gallery."""
from generate_gallery import build_gallery
self.create_test_structure()
# This should complete without errors
try:
build_gallery(self.source_dir, self.web_dir)
# Check that HTML was generated
html_file = self.web_dir / "index.html"
self.assertTrue(html_file.exists())
# Check that files were copied
pdf_file = self.web_dir / "test_plot.pdf"
self.assertTrue(pdf_file.exists())
except Exception as e:
self.fail(f"Gallery generation failed: {e}")
def run_container_tests():
"""Run all tests suitable for container execution."""
print("=" * 60)
print("GALLERY GENERATOR CONTAINER TESTS")
print("=" * 60)
print(f"Python version: {sys.version}")
print(f"Working directory: {os.getcwd()}")
print(f"Python path: {sys.path[:3]}...")
print("=" * 60)
# Create test suite
loader = unittest.TestLoader()
suite = unittest.TestSuite()
# Add test classes
test_classes = [
TestContainerEnvironment,
TestUtilityFunctions,
TestMetadataSystem,
TestPDFProcessing,
TestGalleryGeneration
]
for test_class in test_classes:
tests = loader.loadTestsFromTestCase(test_class)
suite.addTests(tests)
# Run tests
runner = unittest.TextTestRunner(verbosity=2)
result = runner.run(suite)
# Print summary
print("=" * 60)
if result.wasSuccessful():
print("✅ ALL TESTS PASSED")
else:
print("❌ SOME TESTS FAILED")
print(f"Failures: {len(result.failures)}")
print(f"Errors: {len(result.errors)}")
print("=" * 60)
return 0 if result.wasSuccessful() else 1
if __name__ == '__main__':
exit_code = run_container_tests()
sys.exit(exit_code)