Files
Enelix-EMS/services/netplan-v4/tests/test_forecast_acceptance.py
T

81 lines
3.4 KiB
Python

import ast
import hashlib
import importlib.util
import json
from pathlib import Path
from tempfile import TemporaryDirectory
import unittest
from forecast_acceptance import source_paths, verify_forecast_bundle
ROOT = Path(__file__).resolve().parents[1]
spec = importlib.util.spec_from_file_location('forecast_release_test', ROOT / 'release_preflight.py')
preflight = importlib.util.module_from_spec(spec)
spec.loader.exec_module(preflight)
class ForecastAcceptanceTest(unittest.TestCase):
def fixture(self, root):
src, bundle = root / 'source', root / 'bundle'
for path in (src, bundle):
path.mkdir()
for name, value in {'main.py': 'x=1\n', 'telemetry_quality.py': 'x=2\n', 'requirements.txt': 'pandas\n'}.items():
(path / name).write_text(value)
manifest = {p.name: hashlib.sha256(p.read_bytes()).hexdigest() for p in source_paths(src)}
(bundle / 'SOURCE_MANIFEST.json').write_text(json.dumps(manifest))
return src, bundle
def test_exact_source_is_verified(self):
with TemporaryDirectory() as d:
src, bundle = self.fixture(Path(d))
self.assertEqual(len(verify_forecast_bundle(bundle, src)), 3)
def test_modified_development_source_blocks_test(self):
with TemporaryDirectory() as d:
src, bundle = self.fixture(Path(d))
(src / 'main.py').write_text('x=3\n')
with self.assertRaises(ValueError):
verify_forecast_bundle(bundle, src)
def test_extra_staged_python_file_blocks_test(self):
with TemporaryDirectory() as d:
src, bundle = self.fixture(Path(d))
(bundle / 'surprise.py').write_text('x=3\n')
with self.assertRaises(ValueError):
verify_forecast_bundle(bundle, src)
def test_symlink_is_rejected(self):
with TemporaryDirectory() as d:
src, bundle = self.fixture(Path(d))
(bundle / 'main.py').unlink()
(bundle / 'main.py').symlink_to(src / 'main.py')
with self.assertRaises(ValueError):
verify_forecast_bundle(bundle, src)
def test_models_secrets_and_databases_not_staged(self):
with TemporaryDirectory() as d:
src, bundle = self.fixture(Path(d))
for name in ('.env', 'model.pkl', 'users.db'):
(src / name).write_text('not a source file')
self.assertEqual(len(verify_forecast_bundle(bundle, src)), 3)
def test_forecast_checks_have_no_network_or_live_mounts(self):
args = next(args for name,args,cwd,timeout in preflight.command_list('p') if name=='forecast_candidate_python311')
self.assertEqual(args[args.index('--network')+1], 'none')
self.assertEqual(args[args.index('--user')+1], '1000:1000')
self.assertIn('--read-only', args)
for forbidden in ('--volume', '-v', '--env-file', '--privileged', 'up', 'restart'):
self.assertNotIn(forbidden, args)
def test_runner_does_not_import_application_main(self):
source = (ROOT / 'acceptance/check_forecast.py').read_text()
tree = ast.parse(source)
imports = {a.name for node in ast.walk(tree) if isinstance(node, ast.Import) for a in node.names}
self.assertNotIn('main', imports)
self.assertNotIn('run_forecast(', source)
self.assertNotIn('get_configs(', source)
if __name__ == '__main__':
unittest.main()