\$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(?.*?)' . 'private function aktualisiereVerbraucherEnergie/s', $inhalt, $treffer )); self::assertStringContainsString( "SetTimerInterval('RegelungVerzoegert', 100)", $treffer['block'] ); self::assertStringNotContainsString('$this->regeln(false);', $treffer['block']); } }