feat(workflow): publish verified forecast controls and consolidated docs
Tests / test (push) Successful in 1m1s
Tests / test (push) Successful in 1m1s
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.
This commit is contained in:
@@ -26,14 +26,10 @@ require_once __DIR__ . '/../../Manager/module.php';
|
||||
final class ManagerFormHarness extends Manager
|
||||
{
|
||||
public array $calls = [];
|
||||
public bool $reject = false;
|
||||
public function V4ManagerAktivtestSchalten(bool $aktiv): void
|
||||
{
|
||||
$this->calls[] = $aktiv;
|
||||
if ($this->reject) {
|
||||
throw new RuntimeException('Existing backend refused start');
|
||||
}
|
||||
$this->values['NetzfahrplanV4Aktivtest'] = $aktiv;
|
||||
throw new RuntimeException('The normal form must never invoke the legacy trial controller.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +49,7 @@ function fixture(): ManagerFormHarness
|
||||
'NetzfahrplanV4EmpfangAktiv', 'NetzfahrplanV4MessdatenAktiv', 'NetzfahrplanV4RegeltestErlaubt',
|
||||
'NetzfahrplanV4AktivtestErlaubt', 'NetzfahrplanV4WatchdogVerzichtErlaubt'], true);
|
||||
$h->props['NetzfahrplanAktiv'] = false;
|
||||
$h->props['NetzfahrplanRegelungAktiv'] = false;
|
||||
// Synthetic fixture, not a license or credential from an installation.
|
||||
$h->props['Lizenzcode'] = 'ENX' . str_repeat('A', 16);
|
||||
$h->attrs['LizenzcodeHash'] = hash('sha256', $h->props['Lizenzcode']);
|
||||
@@ -67,6 +64,8 @@ function fixture(): ManagerFormHarness
|
||||
],
|
||||
], JSON_THROW_ON_ERROR);
|
||||
$h->attrs['NetzfahrplanV4AktivtestEnde'] = time() + 600;
|
||||
$h->attrs['PrognoseV4Serverstatus'] = json_encode(['receivedAt' => time(),
|
||||
'workflow' => ['planningReady' => false, 'state' => 'collecting', 'reason' => 'Messdaten werden gesammelt.']], JSON_THROW_ON_ERROR);
|
||||
$h->values = ['Aktiv' => true, 'NetzfahrplanV4Aktivtest' => false];
|
||||
$GLOBALS['instanceStatus'] = 102;
|
||||
return $h;
|
||||
@@ -74,58 +73,63 @@ function fixture(): ManagerFormHarness
|
||||
|
||||
function rejected(ManagerFormHarness $h, $value, string $name): void
|
||||
{
|
||||
$before = [$h->props, $h->attrs, $h->values];
|
||||
try {
|
||||
$h->RequestAction('FormNetzfahrplanSchalten', $value);
|
||||
} catch (RuntimeException | InvalidArgumentException $e) {
|
||||
check($h->calls === [], $name);
|
||||
check($h->calls === [] && [$h->props, $h->attrs, $h->values] === $before, $name);
|
||||
return;
|
||||
}
|
||||
check(false, $name);
|
||||
}
|
||||
|
||||
rejected(fixture(), true, 'old test permissions cannot bypass missing workflow readiness');
|
||||
foreach ([1, 0, 'true', 'false', null, []] as $value) {
|
||||
rejected(fixture(), $value, 'nonboolean compatibility action rejected: ' . gettype($value));
|
||||
}
|
||||
$h = fixture();
|
||||
$before = [$h->props, $h->attrs];
|
||||
$h->RequestAction('FormNetzfahrplanSchalten', true);
|
||||
check($h->calls === [true], 'real manager action delegates exactly one explicit start');
|
||||
check(!$h->fields['PrognoseNetzfahrplanStart']['enabled'], 'started session cannot be restarted from form');
|
||||
check([$h->props, $h->attrs] === $before, 'form action changes no configuration, expiry or license');
|
||||
$h->props['Lizenzcode'] = '';
|
||||
$before = [$h->props, $h->attrs, $h->values];
|
||||
$h->RequestAction('FormNetzfahrplanSchalten', false);
|
||||
check($h->calls === [true, false], 'stop still delegates after license loss');
|
||||
check(!$h->values['NetzfahrplanV4Aktivtest'], 'stop status is refreshed');
|
||||
foreach ([1, 'true', 'false', null, []] as $value) {
|
||||
rejected(fixture(), $value, 'nonboolean input rejected: ' . gettype($value));
|
||||
}
|
||||
foreach (['PrognoseAktiv', 'NetzfahrplanV4SchattenAktiv', 'NetzfahrplanV4EmpfangAktiv',
|
||||
'NetzfahrplanV4RegeltestErlaubt', 'NetzfahrplanV4AktivtestErlaubt', 'NetzfahrplanV4WatchdogVerzichtErlaubt'] as $prop) {
|
||||
$h = fixture(); $h->props[$prop] = false;
|
||||
rejected($h, true, 'server-side start guard checks ' . $prop);
|
||||
}
|
||||
check($h->fields['NetzfahrplanRegelungAktiv']['value'] === false, 'compatibility disable updates the saved-property form field');
|
||||
check($h->calls === [], 'compatibility form action invokes no legacy trial controller');
|
||||
check([$h->props, $h->attrs, $h->values] === $before, 'form preview changes no properties, authority or device values');
|
||||
|
||||
$h = fixture(); $h->props['Lizenzcode'] = '';
|
||||
rejected($h, true, 'missing license cannot be bypassed by calling the action directly');
|
||||
rejected($h, true, 'missing license cannot be bypassed through the old action');
|
||||
$h->RequestAction('FormNetzfahrplanSchalten', false);
|
||||
check($h->fields['NetzfahrplanRegelungAktiv']['value'] === false && $h->calls === [], 'disable preview remains possible after license loss');
|
||||
$h = fixture(); $lease = json_decode($h->attrs['LizenzLease'], true);
|
||||
$lease['entitlements'][1]['quantity'] = 0; $h->attrs['LizenzLease'] = json_encode($lease);
|
||||
rejected($h, true, 'manager license alone does not grant grid schedule');
|
||||
$h = fixture(); $h->props['NetzfahrplanAktiv'] = true;
|
||||
rejected($h, true, 'competing legacy controller blocks action');
|
||||
$h = fixture(); $h->attrs['NetzfahrplanV4AktivtestEnde'] = time() - 1;
|
||||
rejected($h, true, 'expired consent cannot be renewed by the form');
|
||||
$h = fixture(); $GLOBALS['instanceStatus'] = 203;
|
||||
rejected($h, true, 'inactive or faulty manager cannot start');
|
||||
$h = fixture(); $h->values['Aktiv'] = false;
|
||||
rejected($h, true, 'disabled manager cannot start');
|
||||
$h = fixture(); $h->values['NetzfahrplanV4Aktivtest'] = true;
|
||||
rejected($h, true, 'existing session cannot be restarted');
|
||||
$h = fixture(); $h->reject = true;
|
||||
try {
|
||||
$h->RequestAction('FormNetzfahrplanSchalten', true);
|
||||
check(false, 'backend rejection preserved');
|
||||
} catch (RuntimeException $e) {
|
||||
check($e->getMessage() === 'Existing backend refused start' && $h->calls === [true], 'backend rejection preserved without retry or bypass');
|
||||
}
|
||||
$h = fixture(); $h->RequestAction('FormPrognoseAktiv', false);
|
||||
check(!$h->fields['PrognoseNetzfahrplanStart']['enabled'] && $h->calls === [], 'unsaved forecast disable prevents start without a control call');
|
||||
$h = fixture(); $h->props['PrognoseAktiv'] = false;
|
||||
rejected($h, true, 'stored learning consent is required');
|
||||
$h = fixture(); $h->attrs['PrognoseV4Serverstatus'] = '{}';
|
||||
rejected($h, true, 'missing server workflow is not ready');
|
||||
$h = fixture(); $h->attrs['PrognoseV4Serverstatus'] = json_encode(['receivedAt' => time() - 100,
|
||||
'workflow' => ['planningReady' => true]], JSON_THROW_ON_ERROR);
|
||||
rejected($h, true, 'stale server readiness cannot start control');
|
||||
$h = fixture(); $h->attrs['PrognoseV4Einrichtungsfehler'] = 'Batteriezuordnung unvollstaendig.';
|
||||
rejected($h, true, 'setup errors block the compatibility start action');
|
||||
|
||||
$h = fixture();
|
||||
$h->RequestAction('FormPrognoseAktiv', false);
|
||||
check(!$h->fields['NetzfahrplanRegelungAktiv']['enabled'] && $h->calls === [], 'unsaved learning disable prevents a new control request without dispatch');
|
||||
check($h->fields['NetzfahrplanRegelungAktiv']['value'] === false, 'learning disable clears the form control request');
|
||||
$h = fixture(); $h->props['PrognoseAktiv'] = false;
|
||||
$h->RequestAction('FormPrognoseAktiv', true);
|
||||
check(!$h->fields['PrognoseNetzfahrplanStart']['enabled'] && $h->calls === [], 'unsaved forecast enable does not grant stored permission');
|
||||
echo "Total: $count checks. Real RequestAction and license checks; mocked IPS and control delegate.\n";
|
||||
check(!$h->fields['NetzfahrplanRegelungAktiv']['enabled'] && $h->calls === [], 'unsaved learning enable does not grant stored readiness');
|
||||
foreach (['license', 'setup', 'learning'] as $failure) {
|
||||
$h = fixture(); $h->props['NetzfahrplanRegelungAktiv'] = true;
|
||||
if ($failure === 'license') $h->props['Lizenzcode'] = '';
|
||||
if ($failure === 'setup') $h->attrs['PrognoseV4Einrichtungsfehler'] = 'Zuordnung fehlt.';
|
||||
if ($failure === 'learning') $h->props['PrognoseAktiv'] = false;
|
||||
$h->RequestAction('FormPrognoseAktiv', false);
|
||||
check($h->fields['NetzfahrplanRegelungAktiv']['enabled'] === true && $h->calls === [],
|
||||
'already requested control remains switchable off after ' . $failure . ' failure');
|
||||
}
|
||||
$h = fixture(); $h->RequestAction('FormPrognoseAktiv', true);
|
||||
check(str_contains($h->fields['PrognoseNetzfahrplanStatus']['caption'], 'Messdaten werden gesammelt.'), 'manager form displays the current workflow reason');
|
||||
foreach (['PrognoseNetzfahrplanStart', 'PrognoseNetzfahrplanStop', 'PrognoseNetzfahrplanPruefen', 'NetzfahrplanV4EmpfangAktiv'] as $name) {
|
||||
check(!isset($h->fields[$name]), 'form refresh no longer updates removed field: ' . $name);
|
||||
}
|
||||
echo "Total: $count checks. Real RequestAction and license checks; mocked IPS, no device calls.\n";
|
||||
|
||||
Reference in New Issue
Block a user