77 lines
3.2 KiB
Python
77 lines
3.2 KiB
Python
import os
|
|
import shutil
|
|
import subprocess
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
|
|
class EngineBuildTests(unittest.TestCase):
|
|
def setUp(self):
|
|
self.temporary = tempfile.TemporaryDirectory()
|
|
self.root = Path(self.temporary.name)
|
|
engine = Path(__file__).resolve().parents[1]
|
|
for name in ['engine-fingerprint.sh', 'ensure-engine.sh']:
|
|
shutil.copyfile(engine / name, self.root / name)
|
|
for name in ['engine.py', 'exports.py', 'requirements.txt', 'requirements.lock.txt',
|
|
'personal-expense-template.xlsx', 'helper.entitlements']:
|
|
(self.root / name).write_text('fixture\n')
|
|
self.binary = self.root / 'dist/receipt-engine-helper.app/Contents/MacOS/receipt-engine-helper'
|
|
(self.root / 'build-engine.sh').write_text('''#!/bin/bash
|
|
set -euo pipefail
|
|
cd "$(dirname "$0")"
|
|
echo build >> builds.log
|
|
mkdir -p dist/receipt-engine-helper.app/Contents/MacOS
|
|
printf 'fixture engine\\n' > dist/receipt-engine-helper.app/Contents/MacOS/receipt-engine-helper
|
|
chmod +x dist/receipt-engine-helper.app/Contents/MacOS/receipt-engine-helper
|
|
SOURCE_HASH="$(bash engine-fingerprint.sh)"
|
|
BINARY_HASH="$(shasum -a 256 dist/receipt-engine-helper.app/Contents/MacOS/receipt-engine-helper | cut -d ' ' -f 1)"
|
|
printf '%s\\n%s\\n' "$SOURCE_HASH" "$BINARY_HASH" > dist/receipt-engine-helper.source.sha256
|
|
''')
|
|
|
|
def tearDown(self):
|
|
self.temporary.cleanup()
|
|
|
|
def ensure(self):
|
|
return subprocess.run(['bash', str(self.root / 'ensure-engine.sh')],
|
|
capture_output=True, text=True, timeout=20)
|
|
|
|
def build_count(self):
|
|
return len((self.root / 'builds.log').read_text().splitlines())
|
|
|
|
def test_missing_engine_builds_and_unchanged_engine_is_reused(self):
|
|
self.assertEqual(self.ensure().returncode, 0)
|
|
self.assertEqual(self.build_count(), 1)
|
|
self.assertEqual(self.ensure().returncode, 0)
|
|
self.assertEqual(self.build_count(), 1)
|
|
|
|
def test_changed_sources_rebuild_even_when_timestamp_is_unchanged(self):
|
|
self.assertEqual(self.ensure().returncode, 0)
|
|
source = self.root / 'exports.py'
|
|
original = source.stat()
|
|
source.write_text('new grouping implementation\n')
|
|
os.utime(source, ns=(original.st_atime_ns, original.st_mtime_ns))
|
|
self.assertEqual(self.ensure().returncode, 0)
|
|
self.assertEqual(self.build_count(), 2)
|
|
|
|
def test_replaced_binary_rebuilds(self):
|
|
self.assertEqual(self.ensure().returncode, 0)
|
|
self.binary.write_text('old engine\n')
|
|
self.assertEqual(self.ensure().returncode, 0)
|
|
self.assertEqual(self.build_count(), 2)
|
|
|
|
def test_missing_stamp_rebuilds(self):
|
|
self.assertEqual(self.ensure().returncode, 0)
|
|
(self.root / 'dist/receipt-engine-helper.source.sha256').unlink()
|
|
self.assertEqual(self.ensure().returncode, 0)
|
|
self.assertEqual(self.build_count(), 2)
|
|
|
|
def test_failed_rebuild_does_not_accept_old_engine(self):
|
|
self.assertEqual(self.ensure().returncode, 0)
|
|
(self.root / 'build-engine.sh').write_text('exit 17\n')
|
|
self.assertEqual(self.ensure().returncode, 17)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|