37 lines
1.5 KiB
Python
37 lines
1.5 KiB
Python
"""Offline candidate-forecast tests: no telemetry, model loading or publication.
|
|
Run in an unprivileged, networkless test container with no live data volumes.
|
|
"""
|
|
from pathlib import Path
|
|
import ast
|
|
import hashlib
|
|
import json
|
|
import sys
|
|
import unittest
|
|
|
|
|
|
def main():
|
|
root = Path('/app/forecast')
|
|
sys.path.insert(0, str(root))
|
|
manifest = json.loads((root / 'SOURCE_MANIFEST.json').read_text())
|
|
for relative, expected in manifest.items():
|
|
p = root / relative
|
|
if Path(relative).is_absolute() or '..' in Path(relative).parts or not p.resolve().is_relative_to(root):
|
|
raise ValueError('Unsafe manifest path')
|
|
raw = p.read_bytes()
|
|
if hashlib.sha256(raw).hexdigest() != expected:
|
|
raise ValueError('Test image source checksum mismatch')
|
|
if p.suffix == '.py':
|
|
ast.parse(raw, filename=str(p))
|
|
import pandas, numpy, scipy, sklearn
|
|
versions = {'python': sys.version.split()[0], 'pandas': pandas.__version__,
|
|
'numpy': numpy.__version__, 'scipy': scipy.__version__, 'sklearn': sklearn.__version__}
|
|
print('Candidate forecast runtime:', json.dumps(versions), flush=True)
|
|
suite = unittest.defaultTestLoader.discover(str(root / 'tests'))
|
|
result = unittest.TextTestRunner(verbosity=2).run(suite)
|
|
print('Forecast tests only; no live data, no publication, no training job.', flush=True)
|
|
return 0 if result.wasSuccessful() else 1
|
|
|
|
|
|
if __name__ == '__main__':
|
|
raise SystemExit(main())
|