set('user_id', 1); $s->set('username', 'u'); $s->set('role', $role); $s->set('csrf', 'tok'); return $s; } public function testListRequiresAuth(): void { $repo = new InMemoryEventRepository(); $c = new EventListController($repo, new ArraySessionStore()); $this->assertSame(401, $c->json(new Request('GET', '/api/events', [], '', [], []))->status()); } public function testListReturnsRecent(): void { $repo = new InMemoryEventRepository(); $repo->insert(['severity' => 'high', 'event_type' => 'fall']); $c = new EventListController($repo, $this->authed()); $res = $c->json(new Request('GET', '/api/events', [], '', [], [])); $this->assertSame(200, $res->status()); $this->assertCount(1, json_decode($res->body(), true)['events']); } public function testAcknowledgeRequiresPermissionAndSetsUser(): void { $repo = new InMemoryEventRepository(); $id = $repo->insert(['severity' => 'critical', 'event_type' => 'no_motion']); $req = new Request('POST', "/events/$id/ack", ['X-Csrf-Token' => 'tok'], '', [], []); // viewer denied (RBAC check fires before CSRF) $cv = new EventDetailController($repo, new InMemorySnapshotRepository(), new InMemoryAuditRepository(), $this->authed('viewer')); $this->assertSame(403, $cv->acknowledge($req, ['id' => (string)$id])->status()); // operator allowed $co = new EventDetailController($repo, new InMemorySnapshotRepository(), new InMemoryAuditRepository(), $this->authed('operator')); $this->assertSame(200, $co->acknowledge($req, ['id' => (string)$id])->status()); $this->assertSame('u', $repo->find($id)['acknowledged_by']); } public function testAcknowledgeRejectsMissingOrWrongCsrfToken(): void { $repo = new InMemoryEventRepository(); $id = $repo->insert(['severity' => 'critical', 'event_type' => 'no_motion']); $c = new EventDetailController($repo, new InMemorySnapshotRepository(), new InMemoryAuditRepository(), $this->authed('operator')); // missing header $missing = new Request('POST', "/events/$id/ack", [], '', [], []); $this->assertSame(403, $c->acknowledge($missing, ['id' => (string)$id])->status()); // wrong token $wrong = new Request('POST', "/events/$id/ack", ['X-Csrf-Token' => 'nope'], '', [], []); $this->assertSame(403, $c->acknowledge($wrong, ['id' => (string)$id])->status()); // acknowledge did not proceed $this->assertNull($repo->find($id)['acknowledged_by']); } public function testSnapshotProxyAuthAnd404(): void { $snaps = new InMemorySnapshotRepository(); $proxy = new SnapshotProxy($snaps, new ArraySessionStore()); // unauth $this->assertSame(401, $proxy->serve(new Request('GET', '/snap/x', [], '', [], []), ['uuid' => 'x'])->status()); $proxy2 = new SnapshotProxy($snaps, $this->authed()); $this->assertSame(404, $proxy2->serve(new Request('GET', '/snap/missing', [], '', [], []), ['uuid' => 'missing'])->status()); } }