tickets = new TicketRepository($db); $this->hooksPath = sys_get_temp_dir() . '/monitor-stream-hooks-' . uniqid() . '/hooks-count'; $this->changeFeed = new ChangeFeed( $this->tickets, new EventRepository($db), new SystemRepository($db), new KpiRepository($db), new AgentRepository($db), new HookCounter($this->hooksPath) ); } protected function tearDown(): void { if (file_exists($this->hooksPath)) { unlink($this->hooksPath); } if (is_dir(dirname($this->hooksPath))) { rmdir(dirname($this->hooksPath)); } } public function testStreamSendsHeartbeatsWhenNothingChanges(): void { $controller = new StreamController( $this->changeFeed, maxIterations: 2, pollIntervalSeconds: 0, sleep: function (int $seconds): void { }, ); $response = $controller->stream(Request::create('GET', '/api/v1/stream')); self::assertTrue($response->isStream()); $output = $this->captureWriterOutput($response->writer()); self::assertStringContainsString(': heartbeat', $output); self::assertStringNotContainsString('event: update', $output); } public function testStreamEmitsUpdateEventWhenAResourceChangesBetweenPolls(): void { $tickets = $this->tickets; $pollCount = 0; $controller = new StreamController( $this->changeFeed, maxIterations: 2, pollIntervalSeconds: 0, sleep: function (int $seconds) use (&$pollCount, $tickets): void { $pollCount++; if ($pollCount === 1) { $tickets->create(['title' => 'Neu waehrend des Wartens']); } }, ); $response = $controller->stream(Request::create('GET', '/api/v1/stream')); $output = $this->captureWriterOutput($response->writer()); self::assertStringContainsString('event: update', $output); self::assertStringContainsString('"tickets"', $output); self::assertSame(2, $pollCount); } public function testStreamStopsAfterMaxIterations(): void { $pollCount = 0; $controller = new StreamController( $this->changeFeed, maxIterations: 3, pollIntervalSeconds: 0, sleep: function (int $seconds) use (&$pollCount): void { $pollCount++; }, ); $this->captureWriterOutput($controller->stream(Request::create('GET', '/api/v1/stream'))->writer()); self::assertSame(3, $pollCount); } private function captureWriterOutput(\Closure $writer): string { ob_start(); $writer(); return (string) ob_get_clean(); } }