S19: establish engineering repository
This commit is contained in:
95
tests/test_bootstrap.py
Normal file
95
tests/test_bootstrap.py
Normal file
@@ -0,0 +1,95 @@
|
||||
"""Exercise release pinning, drift detection, replacement and recovery without network."""
|
||||
import importlib.util
|
||||
import json
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
HOME = Path(__file__).resolve().parents[1]
|
||||
spec = importlib.util.spec_from_file_location('bootstrap', HOME / 'bootstrap.py')
|
||||
bootstrap = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(bootstrap)
|
||||
|
||||
|
||||
class BootstrapTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.temporary = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(self.temporary.cleanup)
|
||||
self.root = Path(self.temporary.name)
|
||||
self.source = self.root / 'engineering'
|
||||
self.source.mkdir()
|
||||
self.git('init', '-q')
|
||||
self.git('config', 'user.email', 'test@example.invalid')
|
||||
self.git('config', 'user.name', 'Engineering test')
|
||||
(self.source / 'resources').mkdir()
|
||||
(self.source / 'resources/tool').write_text('version one\n')
|
||||
self.commit = self.release('v1.0.0')
|
||||
self.project = self.root / 'consumer'
|
||||
self.project.mkdir()
|
||||
self.lock = {'repository': str(self.source), 'tag': 'v1.0.0', 'commit': self.commit}
|
||||
self.save_lock()
|
||||
|
||||
def git(self, *args):
|
||||
return subprocess.check_output(['git', '-C', str(self.source), *args], text=True, stderr=subprocess.DEVNULL).strip()
|
||||
|
||||
def release(self, tag):
|
||||
self.git('add', '.')
|
||||
self.git('commit', '-qm', tag)
|
||||
self.git('tag', tag)
|
||||
return self.git('rev-parse', 'HEAD')
|
||||
|
||||
def save_lock(self):
|
||||
(self.project / 'engineering.lock.json').write_text(json.dumps(self.lock))
|
||||
|
||||
def test_absent_generated_and_repeat_are_deterministic(self):
|
||||
bootstrap.materialize(self.project)
|
||||
first = bootstrap.files(self.project / 'generated')
|
||||
bootstrap.materialize(self.project)
|
||||
self.assertEqual(first, bootstrap.files(self.project / 'generated'))
|
||||
bootstrap.materialize(self.project, True)
|
||||
|
||||
def test_drift_includes_modified_added_and_missing_files(self):
|
||||
bootstrap.materialize(self.project)
|
||||
target = self.project / 'generated/tool'
|
||||
for operation in ('modify', 'remove', 'add'):
|
||||
with self.subTest(operation=operation):
|
||||
bootstrap.materialize(self.project)
|
||||
if operation == 'modify': target.write_text('hand edit')
|
||||
elif operation == 'remove': target.unlink()
|
||||
else: (target.parent / 'extra').write_text('untracked')
|
||||
before = bootstrap.files(target.parent)
|
||||
with self.assertRaisesRegex(ValueError, 'differ'):
|
||||
bootstrap.materialize(self.project, True)
|
||||
self.assertEqual(before, bootstrap.files(target.parent))
|
||||
|
||||
def test_update_removes_obsolete_files_and_preserves_project_files(self):
|
||||
bootstrap.materialize(self.project)
|
||||
(self.project / 'pom.xml').write_text('owned by project')
|
||||
(self.source / 'resources/tool').unlink()
|
||||
(self.source / 'resources/new').write_text('new release')
|
||||
self.lock.update(tag='v1.1.0', commit=self.release('v1.1.0'))
|
||||
self.save_lock()
|
||||
bootstrap.materialize(self.project)
|
||||
self.assertFalse((self.project / 'generated/tool').exists())
|
||||
self.assertEqual('owned by project', (self.project / 'pom.xml').read_text())
|
||||
|
||||
def test_moved_tag_fails_before_replacing_existing_content(self):
|
||||
bootstrap.materialize(self.project)
|
||||
before = bootstrap.files(self.project / 'generated')
|
||||
(self.source / 'resources/tool').write_text('different commit')
|
||||
self.release('v1.1.0')
|
||||
self.git('tag', '-f', 'v1.0.0')
|
||||
with self.assertRaisesRegex(ValueError, 'tag moved'):
|
||||
bootstrap.materialize(self.project)
|
||||
self.assertEqual(before, bootstrap.files(self.project / 'generated'))
|
||||
|
||||
def test_symlink_output_is_rejected(self):
|
||||
(self.project / 'generated').symlink_to(self.source / 'resources', target_is_directory=True)
|
||||
with self.assertRaisesRegex(ValueError, 'symlink'):
|
||||
bootstrap.materialize(self.project)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user