Files
Enelix-EMS/services/netplan-v4/tests/test_release_preflight.py
T
dh 74a2d6c685
Tests / test (push) Successful in 1m1s
feat(workflow): publish verified forecast controls and consolidated docs
Approved by Daniel Haefliger for develop and beta. Author dh_Agent, authenticated account dh. Preserve published battery, charging and overall Energy Pie changes. No deployment or plant control authorization.
2026-10-08 10:02:58 +00:00

68 lines
4.0 KiB
Python

import ast
import hashlib
import importlib.util
import json
from pathlib import Path
from tempfile import TemporaryDirectory
from unittest.mock import patch
import unittest
ROOT=Path(__file__).resolve().parents[1]
spec=importlib.util.spec_from_file_location('release_preflight_test',ROOT/'release_preflight.py')
preflight=importlib.util.module_from_spec(spec);spec.loader.exec_module(preflight)
class ReleasePreflightTest(unittest.TestCase):
def test_preflight_never_restarts_existing_services(self):
for name,args,cwd,timeout in preflight.command_list('e3a08f9e-af12-4695-99bd-8b51c0520021'):
self.assertNotIn('up',args);self.assertNotIn('restart',args);self.assertNotIn('--with-bridges',args)
self.assertGreater(timeout,0)
first=preflight.command_list('e3a08f9e-af12-4695-99bd-8b51c0520021')[0][1]
self.assertIn('--test-only',first)
def test_php_runs_without_network_or_writeable_root(self):
args=next(args for name,args,cwd,timeout in preflight.command_list('p') if name=='php83_offline')
self.assertIn('--read-only',args);self.assertEqual(args[args.index('--network')+1],'none')
self.assertEqual(args[args.index('--user')+1],'1000:1000')
def test_native_bundle_requires_same_development_source(self):
with TemporaryDirectory() as d:
root=Path(d)/'root';repo=Path(d)/'repo';out=root/'acceptance/php-src'
out.mkdir(parents=True);repo.mkdir()
source=b'<?php // test';(out/'a.php').write_bytes(source);(repo/'a.php').write_bytes(source)
(out/'SOURCE_MANIFEST.json').write_text(json.dumps({'a.php':hashlib.sha256(source).hexdigest()}))
with patch.object(preflight,'ROOT',root),patch.object(preflight,'REPO',repo):
preflight.verify_native_bundle()
(repo/'a.php').write_text('<?php // changed')
with self.assertRaises(ValueError):preflight.verify_native_bundle()
def test_native_probe_has_no_training_or_publish_calls(self):
tree=ast.parse((ROOT/'acceptance/read_native_forecasts.py').read_text())
calls={n.func.attr for n in ast.walk(tree) if isinstance(n,ast.Call) and isinstance(n.func,ast.Attribute)}
self.assertFalse(calls & {'train','run_forecast','run_forecast_isolated','get_configs','publish_forecasts','write_api'})
text=(ROOT/'acceptance/read_native_forecasts.py').read_text()
self.assertIn('?mode=ro',text);self.assertNotIn('ALTER TABLE',text)
def test_gui_labels_estimates_and_incomplete_features(self):
text=(ROOT/'gui/netplan-v4.js').read_text()
self.assertIn('Die Kurven zeigen berechnete Plaene, keine nachgewiesene Ausfuehrung',text)
self.assertIn('Geraete- und Netzgrenzen behalten Vorrang',text)
self.assertIn('Planempfang ist kein Ausfuehrungsnachweis',text)
self.assertIn('kein Nachweis realisierter Einsparungen',text)
self.assertIn('Planung mit geschaetzter Peakbasis',text)
self.assertIn('kein Abrechnungsnachweis',text)
self.assertIn('measurementPolicy',text)
self.assertIn('erstellt vergleichbare Kosten-Replays',text)
self.assertIn('keine vollstaendige Nachbildung laufender Neuoptimierungen',text)
self.assertIn('forecastSource',text)
self.assertIn('trainingCadence',text)
self.assertIn('Restmonatsbewertung ist keine bereits bezahlte Peakfreigabe',text)
def test_gui_separates_planning_from_confirmed_manager_control(self):
text=(ROOT/'gui/netplan-v4.js').read_text()
self.assertIn('Betriebsstatus nicht bestaetigt',text)
self.assertIn('workflow.controlActive && workflow.controlRequested && workflow.planningReady',text)
self.assertIn('workflow.reportFresh !== true',text)
self.assertIn('Date.parse(workflow.sourceFreshUntil) <= now',text)
self.assertIn("state: 'interrupted'",text)
self.assertIn('controlActive: false',text)
self.assertIn('lokale Schutzpruefung bleibt erforderlich',text)
self.assertIn("setTimeout(showWorkflow",text)
if __name__=='__main__':unittest.main()