"""Exercise updates and launch guards using isolated files and command stubs.""" import os from pathlib import Path import subprocess import tarfile import tempfile import unittest PROJECT = Path(__file__).resolve().parents[2] class DeploymentTest(unittest.TestCase): def test_update_preserves_state_and_an_independent_rollback_environment(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) target = root / 'radar_system' release = root / 'release/radar_system' for tree in (target, release): (tree / 'python_app').mkdir(parents=True) (tree / 'run_config_examples').mkdir(parents=True) (tree / 'run_config_examples/device.json').write_text(tree.name) (tree / 'run_config.json').write_text(str(tree)) (release / 'start.sh').write_text('#!/bin/bash\n') (target / 'run_config_examples/device.json').write_text('device settings') (target / 'loose_recording.bin').write_bytes(b'original data') (target / 'python_app/data/calibration').mkdir(parents=True) (target / 'python_app/data/calibration/set.npz').write_bytes(b'calibration') (target / 'python_app/runtime/logs').mkdir(parents=True) (target / 'python_app/runtime/gui_session_state.json').write_text('session') (target / 'python_app/runtime/logs/old.log').write_text('log') (target / '.venv/bin').mkdir(parents=True) (target / '.venv/state').write_text('old environment') interpreter = target / '.venv/bin/python' interpreter.write_text('''#!/bin/bash if [[ "$1" == --version ]]; then echo Python-test; exit; fi printf 'updated environment' > "$(dirname -- "$0")/../state" ''') interpreter.chmod(0o755) commands = root / 'commands' commands.mkdir() for name, text in {'systemctl': 'exit 3', 'make': 'printf "%s\\n" "$@" > "$RADAR_TEST_BUILD_LOG"'}.items(): path = commands / name path.write_text('#!/bin/bash\n' + text + '\n') path.chmod(0o755) archive = root / 'release.tar.gz' with tarfile.open(archive, 'w:gz') as handle: handle.add(release, arcname='radar_system') log = root / 'build.log' completed = subprocess.run( ['bash', str(PROJECT / 'deploy/update.sh'), archive.name], cwd=root, env={**os.environ, 'RADAR_DIR': str(target), 'PATH': f'{commands}:{os.environ["PATH"]}', 'RADAR_TEST_BUILD_LOG': str(log)}, capture_output=True, text=True, timeout=10, ) self.assertEqual(completed.returncode, 0, completed.stdout + completed.stderr) backup = root / 'radar_system1' self.assertEqual((target / '.venv/state').read_text(), 'updated environment') self.assertEqual((backup / '.venv/state').read_text(), 'old environment') self.assertEqual((target / 'loose_recording.bin').read_bytes(), b'original data') self.assertEqual((target / 'python_app/data/calibration/set.npz').read_bytes(), b'calibration') self.assertEqual((target / 'run_config.json').read_text(), str(target)) self.assertEqual((target / 'run_config_examples/device.json').read_text(), 'device settings') self.assertTrue((target / 'run_config_examples/device.json.new').exists()) self.assertEqual((target / 'python_app/runtime/gui_session_state.json').read_text(), 'session') self.assertFalse((target / 'python_app/runtime/logs').exists()) self.assertIn('kamil_adc_collector', log.read_text().splitlines())