Tests / test (push) Failing after 1m12s
Add opt-in SDL measurement sources and independent visualization toggles. Exclude balancing power from household telemetry and new household energy. Preserve custom views and cover measurement, migration and Symcon 8.0 behavior.
411 lines
18 KiB
PHP
411 lines
18 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Belevo\EnelixEMS\Tests;
|
|
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
final class ManagerModulstrukturTest extends TestCase
|
|
{
|
|
public function testManagerIstAlsSymconModulVollstaendig(): void
|
|
{
|
|
foreach (['module.json', 'form.json', 'module.php'] as $datei) {
|
|
self::assertFileExists(__DIR__ . '/../Manager/' . $datei);
|
|
}
|
|
|
|
$metadaten = json_decode(
|
|
(string) file_get_contents(__DIR__ . '/../Manager/module.json'),
|
|
true,
|
|
512,
|
|
JSON_THROW_ON_ERROR
|
|
);
|
|
self::assertSame('Manager', $metadaten['name']);
|
|
self::assertSame('Enelix', $metadaten['vendor']);
|
|
self::assertSame(['Manager'], $metadaten['aliases']);
|
|
self::assertSame(3, $metadaten['type']);
|
|
self::assertMatchesRegularExpression('/^\{[0-9A-F-]{36}\}$/', $metadaten['id']);
|
|
}
|
|
|
|
public function testFormularEnthaeltDieZentralenManagerProperties(): void
|
|
{
|
|
$formular = json_decode(
|
|
(string) file_get_contents(__DIR__ . '/../Manager/form.json'),
|
|
true,
|
|
512,
|
|
JSON_THROW_ON_ERROR
|
|
);
|
|
$json = json_encode($formular, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES);
|
|
|
|
foreach ([
|
|
'NetzleistungVariableID',
|
|
'VerbraucherZuordnung',
|
|
'AutomatischeVerbraucherZuordnung',
|
|
'Lastspitzenmodus',
|
|
'Monatsgrenzen',
|
|
'SollwertSolarladen',
|
|
'KeepAlive',
|
|
'VerbraucherTimeout',
|
|
'MesswertMaxAlter',
|
|
'Umschaltdifferenz',
|
|
'EinspeisebegrenzungAktiv',
|
|
'Einspeisegrenze',
|
|
'PrognoseAktiv',
|
|
'SDLAktiv',
|
|
'SDLLeistungVariableID',
|
|
'SDLLeistungsfaktor',
|
|
'SDLSOCVariableID',
|
|
'SDLEnergieflussAnzeigen',
|
|
'SDLDiagrammeAnzeigen',
|
|
'PrognoseLizenzInformation',
|
|
'NetzfahrplanAktiv',
|
|
'NetzbezugEnergieVariableID',
|
|
'NetzeinspeisungEnergieVariableID',
|
|
'IstleistungVariableID',
|
|
'ErzeugungsenergieVariableID',
|
|
'Erzeugungsenergiefaktor',
|
|
'BegrenzungVariableID',
|
|
'Begrenzungsart',
|
|
'DiagnosevariablenAnzeigen',
|
|
'LoggingEin',
|
|
'Lizenzcode',
|
|
'LizenzPruefen',
|
|
'LizenzVerwalten',
|
|
'LizenzInstallationID',
|
|
'LizenzInformation',
|
|
'VerbraucherAktualisieren',
|
|
'AnlagenWechselrichter',
|
|
'AnlagenPVFlaechen',
|
|
'AnlagenBatterien',
|
|
'Istleistungsfaktor',
|
|
'LeistungVariableID',
|
|
'Leistungsfaktor',
|
|
'SOCVariableID',
|
|
'LadeenergieVariableID',
|
|
'EntladeenergieVariableID',
|
|
'Energiefaktor',
|
|
'EnergyPieAnzeigen',
|
|
'EnergiediagrammeAnzeigen',
|
|
'FunFactsAnzeigen',
|
|
'EnergieflussAnzeigen',
|
|
'PrognoseSendeintervall',
|
|
'StoerueberwachungAktiv',
|
|
'StoerungsSendeintervall',
|
|
] as $property) {
|
|
self::assertStringContainsString($property, $json);
|
|
}
|
|
foreach (['Regelintervall', 'Vorgabeintervall', 'UmschaltschwelleUeberschuss',
|
|
'UmschaltschwelleLastspitze', 'Optionale obere Anschluesse', 'LizenzAnschluss',
|
|
'Einspeisetoleranz', 'ACEinspeisegrenze_kW', 'ACBezugsgrenze_kW'] as $entfernt
|
|
) {
|
|
self::assertStringNotContainsString($entfernt, $json);
|
|
}
|
|
foreach (['Grundeinstellungen', 'Erweiterte Einstellungen', 'Prognose / Forecast',
|
|
'SDL / VGT', 'Lizenzierung', 'Stoerueberwachung'] as $bereich
|
|
) {
|
|
self::assertStringContainsString($bereich, $json);
|
|
}
|
|
self::assertSame('Lizenzierung', $formular['elements'][0]['caption']);
|
|
self::assertStringContainsString('https://license.enelix.ch', $json);
|
|
self::assertStringContainsString('"link":true', $json);
|
|
self::assertStringContainsString(
|
|
"'SuchbereichID' => \$SuchbereichID",
|
|
$json
|
|
);
|
|
self::assertStringContainsString(
|
|
"'Zuordnung' => \$AutomatischeVerbraucherZuordnung",
|
|
$json
|
|
);
|
|
}
|
|
|
|
public function testManagerTrenntDiagnosevariablenUndDebugLogging(): void
|
|
{
|
|
$inhalt = (string) file_get_contents(__DIR__ . '/../Manager/module.php');
|
|
|
|
self::assertStringContainsString(
|
|
"RegisterPropertyBoolean('DiagnosevariablenAnzeigen', false)",
|
|
$inhalt
|
|
);
|
|
self::assertStringContainsString("ReadPropertyBoolean('DiagnosevariablenAnzeigen')", $inhalt);
|
|
self::assertStringContainsString('UnregisterVariable($ident)', $inhalt);
|
|
self::assertStringContainsString("ReadPropertyBoolean('LoggingEin')", $inhalt);
|
|
self::assertStringContainsString('SendDebug(', $inhalt);
|
|
}
|
|
|
|
public function testManagerBindetDieLizenzierungFailClosedAn(): void
|
|
{
|
|
$inhalt = (string) file_get_contents(__DIR__ . '/../Manager/module.php');
|
|
|
|
self::assertFileExists(__DIR__ . '/../libs/Lizenzpruefung.php');
|
|
self::assertStringContainsString(
|
|
"RegisterPropertyString('Lizenzcode', '')",
|
|
$inhalt
|
|
);
|
|
self::assertStringContainsString(
|
|
"https://license.enelix.ch/api/v1/licenses/activate",
|
|
$inhalt
|
|
);
|
|
self::assertStringContainsString("RegisterAttributeString('LizenzInstallationID'", $inhalt);
|
|
self::assertSame(
|
|
1,
|
|
preg_match('/public function Create\(\): void.*?public function ApplyChanges\(\): void/s', $inhalt, $treffer)
|
|
);
|
|
self::assertStringNotContainsString(
|
|
"WriteAttributeString('LizenzInstallationID'",
|
|
$treffer[0]
|
|
);
|
|
self::assertStringContainsString(
|
|
"parent::ApplyChanges();\n\n \$this->initialisiereLizenzInstallationID();",
|
|
$inhalt
|
|
);
|
|
self::assertSame(1, substr_count(
|
|
$inhalt,
|
|
"WriteAttributeString('LizenzInstallationID'"
|
|
));
|
|
self::assertStringContainsString("RegisterAttributeString('LizenzLease'", $inhalt);
|
|
self::assertStringContainsString("RegisterAttributeString('LizenzcodeHash'", $inhalt);
|
|
self::assertStringContainsString('STATUS_LIZENZ_UNGUELTIG', $inhalt);
|
|
self::assertStringContainsString('aktualisiereLizenzfreigabe(', $inhalt);
|
|
self::assertStringContainsString('pruefeVerbraucherlizenzen(', $inhalt);
|
|
self::assertStringContainsString('lizenzBerechtigungenPassen(', $inhalt);
|
|
self::assertStringContainsString('peakShavingLizenziert(', $inhalt);
|
|
self::assertStringContainsString('Aus (Peak-Shaving-Lizenz fehlt)', $inhalt);
|
|
self::assertStringContainsString('Aus (Peak-Shaving-Lizenz verfuegbar)', $inhalt);
|
|
self::assertStringContainsString(
|
|
'Konstant und Monatlich benoetigen eine Peak-Shaving-Lizenz.',
|
|
$inhalt
|
|
);
|
|
foreach (['battery', 'buffer_storage', 'ev_charger', 'consumer_single', 'heat_pump', 'boiler_multi'] as $katalog) {
|
|
self::assertStringContainsString("'Katalog' => '" . $katalog . "'", $inhalt);
|
|
}
|
|
foreach ([
|
|
'{B7C54AF4-AD7D-4FE4-B75D-203693906251}',
|
|
'{15879A4E-D0C2-4495-83DE-46E1E462591E}',
|
|
'{A31C9274-54F7-4BD2-9804-7AF23E86C4D1}',
|
|
'{0D94913C-0F31-4C29-A685-6EB4AE58E55D}',
|
|
'{32F65988-BE55-4FD6-9FFF-CF1C4C8628F8}',
|
|
'{C92D5EEF-9632-47A5-9659-4B02BF40FBE9}',
|
|
'{437FB683-517F-4FEC-8CCB-FE6B0A62B69E}',
|
|
] as $modulID) {
|
|
self::assertStringContainsString("'" . $modulID . "' =>", $inhalt);
|
|
}
|
|
self::assertStringContainsString("'Name' => 'Pufferspeicher'", $inhalt);
|
|
self::assertStringContainsString("'Name' => 'Batteriespeicher'", $inhalt);
|
|
self::assertStringContainsString(
|
|
'Bitte Auswahl reduzieren oder Lizenz erweitern.',
|
|
$inhalt
|
|
);
|
|
foreach ([
|
|
"'NichtGeregelt'",
|
|
"'NichtGeregelteGeraete'",
|
|
"'InstanzStatus'",
|
|
"'LetzteMeldung'",
|
|
"'GemeldeteBetriebsart'",
|
|
"'Verfuegbar'",
|
|
] as $detailfeld) {
|
|
self::assertStringContainsString($detailfeld, $inhalt);
|
|
}
|
|
self::assertStringNotContainsString("'publicKey' =>", $inhalt);
|
|
}
|
|
|
|
public function testManagerSynchronisiertDieTopologieMitSeparatemGeraetezugang(): void
|
|
{
|
|
$inhalt = (string) file_get_contents(__DIR__ . '/../Manager/module.php');
|
|
|
|
self::assertStringContainsString(
|
|
'https://license.enelix.ch/api/v1/installations/%s/prognosis/topology',
|
|
$inhalt
|
|
);
|
|
self::assertStringContainsString(
|
|
"RegisterAttributeString('PrognoseInstallationsToken', '')",
|
|
$inhalt
|
|
);
|
|
self::assertStringContainsString('JSON_PRESERVE_ZERO_FRACTION', $inhalt);
|
|
self::assertStringContainsString("'issueDeviceToken' =>", $inhalt);
|
|
self::assertStringContainsString("unset(\$neueLease['deviceToken'])", $inhalt);
|
|
self::assertStringContainsString(
|
|
"|| \$this->ReadPropertyBoolean('StoerueberwachungAktiv')",
|
|
$inhalt
|
|
);
|
|
self::assertGreaterThanOrEqual(
|
|
3,
|
|
substr_count($inhalt, '$this->geraetezugangBenoetigt()'),
|
|
'Der Geraetezugang muss beim Anwenden, Erneuern und Anfordern beruecksichtigt werden.'
|
|
);
|
|
self::assertStringContainsString(
|
|
"\$this->ReadPropertyString('Lizenzcode'),\n \$geraetezugangFehlt",
|
|
$inhalt
|
|
);
|
|
self::assertStringContainsString('synchronisiereAnlagentopologie()', $inhalt);
|
|
self::assertStringContainsString('private function geraetezugangBenoetigt(): bool', $inhalt);
|
|
self::assertStringContainsString(
|
|
"if (\$this->aktualisiereLizenzfreigabe(\$wert, true)) {",
|
|
$inhalt
|
|
);
|
|
self::assertStringNotContainsString(
|
|
"if (!\$this->ReadPropertyBoolean('PrognoseAktiv')) {\n \$this->setzeDiagnosewert('Prognosestatus', 'NichtVerwendet');\n return;\n }\n\n try {",
|
|
$inhalt
|
|
);
|
|
self::assertStringContainsString(
|
|
'https://license.enelix.ch/api/v1/installations/%s/prognosis/telemetry',
|
|
$inhalt
|
|
);
|
|
self::assertStringContainsString("'PrognoseSenden',", $inhalt);
|
|
self::assertStringContainsString("'capturedAt' => gmdate(", $inhalt);
|
|
foreach (["'PV'", "'Hausverbrauch'", "'Netzleistung'", "'SOC'"] as $messwert) {
|
|
self::assertStringContainsString($messwert, $inhalt);
|
|
}
|
|
self::assertStringContainsString("'Authorization: Bearer ' . \$token", $inhalt);
|
|
self::assertStringNotContainsString(
|
|
"protokolliere('Prognosesynchronisation', \$token)",
|
|
$inhalt
|
|
);
|
|
|
|
$leasePruefung = strpos($inhalt, 'Lizenzpruefung::pruefeLease(');
|
|
$tokenSpeicherung = strpos(
|
|
$inhalt,
|
|
"WriteAttributeString('PrognoseInstallationsToken', \$geraeteToken)"
|
|
);
|
|
self::assertNotFalse($leasePruefung);
|
|
self::assertNotFalse($tokenSpeicherung);
|
|
self::assertTrue(
|
|
$leasePruefung < $tokenSpeicherung,
|
|
'Der Gerätezugang darf erst nach validierter Lizenzantwort gespeichert werden.'
|
|
);
|
|
}
|
|
|
|
public function testManagerRegeltAktuelleVerbraucherTrotzFehlenderRueckmeldungen(): void
|
|
{
|
|
$inhalt = (string) file_get_contents(__DIR__ . '/../Manager/module.php');
|
|
|
|
self::assertStringNotContainsString("if (!\$synchronisiert) {", $inhalt);
|
|
self::assertStringContainsString(
|
|
"'Synchronisiert' => \$synchronisiert",
|
|
$inhalt
|
|
);
|
|
self::assertStringContainsString(
|
|
"'NichtGeregelt' => \$nichtGeregelt",
|
|
$inhalt
|
|
);
|
|
self::assertStringContainsString(
|
|
"\$ergebnis = ManagerRegler::verteile(",
|
|
$inhalt
|
|
);
|
|
}
|
|
|
|
public function testManagerUebertraegtStoerungsvollsnapshotsMitRetry(): void
|
|
{
|
|
$inhalt = (string) file_get_contents(__DIR__ . '/../Manager/module.php');
|
|
|
|
self::assertFileExists(__DIR__ . '/../libs/StoerungsSnapshot.php');
|
|
self::assertStringContainsString(
|
|
'https://license.enelix.ch/api/v1/installations/%s/faults',
|
|
$inhalt
|
|
);
|
|
foreach ([
|
|
"RegisterPropertyBoolean('StoerueberwachungAktiv', false)",
|
|
"RegisterPropertyInteger('StoerungsSendeintervall', 300)",
|
|
"RegisterAttributeString('StoerungsSnapshot', '{}')",
|
|
"RegisterAttributeString('StoerungsGesendeterHash', '')",
|
|
"RegisterAttributeInteger('StoerungsNaechsterVersuch', 0)",
|
|
"'StoerungenSenden',",
|
|
'StoerungsSnapshot::erstellen(',
|
|
'StoerungsSnapshot::zustandHash(',
|
|
"CURLOPT_CUSTOMREQUEST => 'PUT'",
|
|
] as $erwartet) {
|
|
self::assertStringContainsString($erwartet, $inhalt);
|
|
}
|
|
self::assertStringNotContainsString(
|
|
'"name":"StoermeldeAnschluss"',
|
|
str_replace(' ', '', (string) file_get_contents(__DIR__ . '/../Manager/form.json'))
|
|
);
|
|
self::assertStringContainsString(
|
|
"if (\$token === '') {\n"
|
|
. " \$this->aktualisiereLizenzfreigabe(\n"
|
|
. " \$this->ReadPropertyString('Lizenzcode'),\n"
|
|
. " true",
|
|
$inhalt
|
|
);
|
|
self::assertGreaterThanOrEqual(
|
|
3,
|
|
substr_count($inhalt, '$this->geraetezugangBenoetigt()'),
|
|
'Der Geraetezugang muss beim Anwenden, Erneuern und Anfordern beruecksichtigt werden.'
|
|
);
|
|
}
|
|
|
|
public function testManagerRegeltDieAnlagenweiteEinspeisegrenzeUndDenNetzfahrplan(): void
|
|
{
|
|
$inhalt = (string) file_get_contents(__DIR__ . '/../Manager/module.php');
|
|
|
|
self::assertFileExists(__DIR__ . '/../libs/EinspeiseRegler.php');
|
|
self::assertStringContainsString('EinspeiseRegler::verteile(', $inhalt);
|
|
self::assertStringContainsString('EinspeiseRegler::stellwert(', $inhalt);
|
|
self::assertStringContainsString("RegisterAttributeString('LetztePvGrenzen'", $inhalt);
|
|
self::assertStringContainsString("RegisterAttributeString('Netzfahrplan'", $inhalt);
|
|
self::assertStringContainsString(
|
|
'https://license.enelix.ch/api/v1/installations/%s/prognosis/schedule',
|
|
$inhalt
|
|
);
|
|
self::assertStringContainsString('Lizenzpruefung::NETZFAHRPLAN', $inhalt);
|
|
self::assertStringContainsString('Lizenzpruefung::PROGNOSE_PV', $inhalt);
|
|
self::assertStringContainsString('Lizenzpruefung::PROGNOSE_VERBRAUCH', $inhalt);
|
|
self::assertStringContainsString('prognoseLizenzStatustext(', $inhalt);
|
|
self::assertStringContainsString(
|
|
"foreach (['PeakShavingTitel', 'EinspeisebegrenzungAktiv', 'Einspeisegrenze']",
|
|
$inhalt
|
|
);
|
|
self::assertStringContainsString('aktuelleNetzfahrplanVorgabe()', $inhalt);
|
|
self::assertStringContainsString('gibEinspeisebegrenzungFrei()', $inhalt);
|
|
self::assertStringNotContainsString("RegisterPropertyFloat('Einspeisetoleranz'", $inhalt);
|
|
}
|
|
|
|
public function testManagerVerwendetDieNeuenZeitdefaults(): void
|
|
{
|
|
$inhalt = (string) file_get_contents(__DIR__ . '/../Manager/module.php');
|
|
|
|
self::assertStringContainsString("RegisterPropertyInteger('KeepAlive', 60)", $inhalt);
|
|
self::assertStringContainsString("RegisterPropertyInteger('VerbraucherTimeout', 60)", $inhalt);
|
|
self::assertStringContainsString("RegisterPropertyInteger('MesswertMaxAlter', 60)", $inhalt);
|
|
self::assertStringContainsString("RegisterPropertyFloat('Umschaltdifferenz', 5.0)", $inhalt);
|
|
self::assertStringNotContainsString("RegisterPropertyInteger('Regelintervall'", $inhalt);
|
|
self::assertStringNotContainsString("RegisterPropertyInteger('Vorgabeintervall'", $inhalt);
|
|
|
|
$verbraucherBasis = (string) file_get_contents(__DIR__ . '/../libs/VerbraucherBasisTrait.php');
|
|
self::assertStringContainsString(
|
|
"RegisterPropertyInteger('VorgabeTimeout', 120)",
|
|
$verbraucherBasis
|
|
);
|
|
}
|
|
|
|
public function testManagerImplementiertDenGemeinsamenEmpfangsvertrag(): void
|
|
{
|
|
$inhalt = (string) file_get_contents(__DIR__ . '/../Manager/module.php');
|
|
self::assertStringContainsString('implements ManagerSchnittstelle', $inhalt);
|
|
self::assertStringContainsString("require_once __DIR__ . '/../libs/Anlagentopologie.php'", $inhalt);
|
|
self::assertStringContainsString('public function AnlagentopologieExportieren(): string', $inhalt);
|
|
self::assertStringContainsString('VerbraucherdatenEmpfangen(array $daten)', $inhalt);
|
|
self::assertStringContainsString("'ManagerdatenEmpfangen'", $inhalt);
|
|
}
|
|
|
|
public function testVerbrauchermeldungPlantRegelungOhneSynchronenRueckruf(): void
|
|
{
|
|
$inhalt = (string) file_get_contents(__DIR__ . '/../Manager/module.php');
|
|
self::assertStringContainsString(
|
|
"RegisterTimer(\n 'RegelungVerzoegert'",
|
|
$inhalt
|
|
);
|
|
self::assertStringContainsString("case 'RegelnVerzoegert':", $inhalt);
|
|
self::assertSame(1, preg_match(
|
|
'/public function VerbraucherdatenEmpfangen\(array \$daten\): void(?<block>.*?)'
|
|
. 'private function aktualisiereVerbraucherEnergie/s',
|
|
$inhalt,
|
|
$treffer
|
|
));
|
|
self::assertStringContainsString(
|
|
"SetTimerInterval('RegelungVerzoegert', 100)",
|
|
$treffer['block']
|
|
);
|
|
self::assertStringNotContainsString('$this->regeln(false);', $treffer['block']);
|
|
}
|
|
}
|