86 lines
3.8 KiB
Python
86 lines
3.8 KiB
Python
import importlib.util
|
|
from pathlib import Path
|
|
import subprocess
|
|
import tempfile
|
|
import unittest
|
|
|
|
spec = importlib.util.spec_from_file_location('contract_checker', Path(__file__).with_name('check-current-contracts.py'))
|
|
checker = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(checker)
|
|
URL = 'git@gitee.com:zzmbac/sip-contracts.git'
|
|
|
|
|
|
class ContractCheckoutTest(unittest.TestCase):
|
|
def git(self, cwd, *args):
|
|
return subprocess.check_output(['git', '-c', 'user.name=Contract Test', '-c', 'user.email=contracts@example.invalid', '-C', str(cwd), *args], stderr=subprocess.STDOUT, text=True).strip()
|
|
|
|
def setUp(self):
|
|
self.temp = tempfile.TemporaryDirectory()
|
|
self.addCleanup(self.temp.cleanup)
|
|
base = Path(self.temp.name)
|
|
source = base / 'source'
|
|
source.mkdir()
|
|
self.git(source, 'init', '-q')
|
|
(source / 'test.schema.json').write_text('{}\n')
|
|
self.git(source, 'add', '.')
|
|
self.git(source, 'commit', '-qm', 'initial')
|
|
self.root = base / 'consumer'
|
|
self.root.mkdir()
|
|
self.git(self.root, 'init', '-q')
|
|
self.git(self.root, '-c', 'protocol.file.allow=always', 'submodule', 'add', '-q', str(source), 'contracts/schema')
|
|
self.sub = self.root / 'contracts/schema'
|
|
self.git(self.sub, 'remote', 'set-url', 'origin', URL)
|
|
self.git(self.root, 'config', '-f', '.gitmodules', 'submodule.contracts/schema.url', URL)
|
|
self.git(self.root, 'add', '.')
|
|
self.git(self.root, 'commit', '-qm', 'pin contract')
|
|
|
|
def test_clean_pinned_checkout(self):
|
|
self.assertEqual(checker.check_checkout(self.root), self.git(self.sub, 'rev-parse', 'HEAD'))
|
|
|
|
def test_uninitialized_submodule_is_rejected(self):
|
|
self.git(self.root, 'submodule', 'deinit', '-f', '--', 'contracts/schema')
|
|
with self.assertRaisesRegex(ValueError, 'not initialized'):
|
|
checker.check_checkout(self.root)
|
|
|
|
def test_unpinned_commit_is_rejected(self):
|
|
(self.sub / 'test.schema.json').write_text('{"changed": true}\n')
|
|
self.git(self.sub, 'add', '.')
|
|
self.git(self.sub, 'commit', '-qm', 'changed')
|
|
with self.assertRaisesRegex(ValueError, 'does not match'):
|
|
checker.check_checkout(self.root)
|
|
|
|
def test_update_rechecks_an_unstaged_fast_forward(self):
|
|
(self.sub / 'test.schema.json').write_text('{"changed": true}\n')
|
|
self.git(self.sub, 'add', '.')
|
|
self.git(self.sub, 'commit', '-qm', 'changed')
|
|
self.assertEqual(checker.check_checkout(self.root, updating=True), self.git(self.sub, 'rev-parse', 'HEAD'))
|
|
(self.sub / 'untracked.txt').write_text('unexpected\n')
|
|
with self.assertRaisesRegex(ValueError, 'uncommitted'):
|
|
checker.check_checkout(self.root, updating=True)
|
|
|
|
def test_update_rejects_divergent_contract_history(self):
|
|
self.git(self.sub, 'checkout', '--orphan', 'unrelated')
|
|
self.git(self.sub, 'add', '.')
|
|
self.git(self.sub, 'commit', '-qm', 'unrelated root')
|
|
with self.assertRaises(subprocess.CalledProcessError):
|
|
checker.check_checkout(self.root, updating=True)
|
|
|
|
def test_dirty_submodule_is_rejected(self):
|
|
(self.sub / 'untracked.txt').write_text('unexpected\n')
|
|
with self.assertRaisesRegex(ValueError, 'uncommitted'):
|
|
checker.check_checkout(self.root)
|
|
|
|
def test_wrong_origin_is_rejected(self):
|
|
self.git(self.sub, 'remote', 'set-url', 'origin', 'https://example.invalid/other.git')
|
|
with self.assertRaisesRegex(ValueError, 'origin'):
|
|
checker.check_checkout(self.root)
|
|
|
|
def test_parallel_local_contract_is_rejected(self):
|
|
(self.root / 'contracts/local').mkdir()
|
|
with self.assertRaisesRegex(ValueError, 'parallel'):
|
|
checker.check_checkout(self.root)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|