74 lines
2.9 KiB
Python
74 lines
2.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Check review cleanup scope without Docker or build output."""
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import subprocess
|
|
import tempfile
|
|
import unittest
|
|
|
|
SCRIPT = Path(__file__).with_name('cleanup-review-images.sh')
|
|
SHA = 'a' * 40
|
|
FAKE_DOCKER = '''#!/usr/bin/env python3
|
|
import json, os, sys
|
|
args=sys.argv[1:]
|
|
with open(os.environ['DOCKER_CALLS'], 'a') as output:
|
|
output.write(json.dumps(args)+'\\n')
|
|
if args[0]=='ps':
|
|
if os.environ.get('FAIL_INVENTORY'): sys.exit(1)
|
|
if os.environ.get('REFERENCED'): print('container-id')
|
|
elif args[0]=='inspect':
|
|
print('sha256:review-image')
|
|
elif args[:2]==['image','inspect']:
|
|
if os.environ.get('MISSING_IMAGE'): sys.exit(1)
|
|
print('sha256:review-image')
|
|
'''
|
|
|
|
|
|
class ReviewCleanupTests(unittest.TestCase):
|
|
def run_cleanup(self, sha=SHA, **extra):
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
root = Path(directory)
|
|
docker = root / 'docker'
|
|
docker.write_text(FAKE_DOCKER)
|
|
docker.chmod(0o700)
|
|
calls = root / 'calls'
|
|
result = subprocess.run(['bash', str(SCRIPT)], capture_output=True, env={
|
|
**os.environ, 'PATH': directory + os.pathsep + os.environ['PATH'],
|
|
'DOCKER_CALLS': str(calls), 'REVIEW_SHA': sha, **extra})
|
|
return result.returncode, [json.loads(line) for line in calls.read_text().splitlines()] if calls.exists() else []
|
|
|
|
def test_removes_only_exact_review_tags_without_force_and_keeps_parent_cache(self):
|
|
code, calls = self.run_cleanup()
|
|
self.assertEqual(code, 0)
|
|
self.assertEqual([args for args in calls if args[:2] == ['image', 'rm']], [
|
|
['image', 'rm', '--no-prune', name + ':' + SHA] for name in
|
|
['creative-studio-review', 'creative-wiki-tests', 'creative-wiki-review']])
|
|
self.assertFalse(any('-f' in args or 'prune' in args or 'volume' in args for args in calls))
|
|
|
|
def test_invalid_sha_never_contacts_docker(self):
|
|
for value in ['', 'main', 'a' * 39, 'a' * 41, 'A' * 40, '*' * 40]:
|
|
with self.subTest(value=value):
|
|
code, calls = self.run_cleanup(value)
|
|
self.assertNotEqual(code, 0)
|
|
self.assertEqual(calls, [])
|
|
|
|
def test_container_referenced_images_are_kept(self):
|
|
code, calls = self.run_cleanup(REFERENCED='1')
|
|
self.assertEqual(code, 0)
|
|
self.assertFalse(any(args[:2] == ['image', 'rm'] for args in calls))
|
|
|
|
def test_missing_tags_are_a_successful_noop(self):
|
|
code, calls = self.run_cleanup(MISSING_IMAGE='1')
|
|
self.assertEqual(code, 0)
|
|
self.assertFalse(any(args[:2] == ['image', 'rm'] for args in calls))
|
|
|
|
def test_inventory_failure_prevents_removal(self):
|
|
code, calls = self.run_cleanup(FAIL_INVENTORY='1')
|
|
self.assertNotEqual(code, 0)
|
|
self.assertEqual(len(calls), 1)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|