pdo()->exec('DELETE FROM repo_configs'); $db->pdo()->exec('DELETE FROM tickets'); $this->tickets = new TicketRepository($db); $healthChecker = new RepoHealthChecker(new class implements CodebergClient { public function listIssues(string $owner, string $repo, string $state): array { return []; } public function repoPermissions(string $owner, string $repo): array { return ['push' => true]; } public function listWebhooks(string $owner, string $repo): array { return [['active' => true, 'url' => 'https://monitor.example.org/api/v1/webhooks/codeberg', 'content_type' => 'json']]; } }); $this->controller = new RepoConfigController(new RepoConfigRepository($db), $this->tickets, $healthChecker); } public function testIndexReturnsEmptyListInitially(): void { $response = $this->controller->index(Request::create('GET', '/api/v1/repo-configs')); self::assertSame(200, $response->status); self::assertSame([], $response->body()['repos']); } public function testCreateReturns201WithNewRepo(): void { $response = $this->controller->create(Request::create('POST', '/api/v1/repo-configs', body: [ 'owner' => 'fds2610', 'repo' => 'monitor', 'color' => '#fbca04', ])); self::assertSame(201, $response->status); self::assertSame('fds2610', $response->body()['repo']['owner']); } public function testCreateRejectsInvalidColorWith422(): void { $response = $this->controller->create(Request::create('POST', '/api/v1/repo-configs', body: [ 'owner' => 'fds2610', 'repo' => 'monitor', 'color' => 'nope', ])); self::assertSame(422, $response->status); } public function testUpdateReturnsUpdatedRepo(): void { $created = $this->controller->create(Request::create('POST', '/api/v1/repo-configs', body: [ 'owner' => 'fds2610', 'repo' => 'monitor', 'color' => '#fbca04', ]))->body()['repo']; $response = $this->controller->update( Request::create('PATCH', '/api/v1/repo-configs/' . $created['id'], body: [ 'owner' => 'fds2610', 'repo' => 'monitor', 'color' => '#000000', ]), ['id' => (string) $created['id']] ); self::assertSame(200, $response->status); self::assertSame('#000000', $response->body()['repo']['color']); } public function testDeleteReturnsDeletedTrue(): void { $created = $this->controller->create(Request::create('POST', '/api/v1/repo-configs', body: [ 'owner' => 'fds2610', 'repo' => 'monitor', 'color' => '#fbca04', ]))->body()['repo']; $response = $this->controller->delete( Request::create('DELETE', '/api/v1/repo-configs/' . $created['id']), ['id' => (string) $created['id']] ); self::assertSame(200, $response->status); self::assertTrue($response->body()['deleted']); } public function testDeleteRemovesTicketsOfTheProjectFromTheKanban(): void { $created = $this->controller->create(Request::create('POST', '/api/v1/repo-configs', body: [ 'owner' => 'fds2610', 'repo' => 'monitor', 'color' => '#fbca04', ]))->body()['repo']; $orphaned = $this->tickets->create(['title' => 'A', 'repo' => 'fds2610/monitor']); $unrelated = $this->tickets->create(['title' => 'B', 'repo' => 'fds2610/anderes-projekt']); $manual = $this->tickets->create(['title' => 'C']); $this->controller->delete( Request::create('DELETE', '/api/v1/repo-configs/' . $created['id']), ['id' => (string) $created['id']] ); self::assertNull($this->tickets->find((int) $orphaned['id'])); self::assertNotNull($this->tickets->find((int) $unrelated['id'])); self::assertNotNull($this->tickets->find((int) $manual['id'])); } public function testCheckReturnsWriteAccessAndWebhookResults(): void { $created = $this->controller->create(Request::create('POST', '/api/v1/repo-configs', body: [ 'owner' => 'fds2610', 'repo' => 'monitor', 'color' => '#fbca04', ]))->body()['repo']; $response = $this->controller->check( Request::create('POST', '/api/v1/repo-configs/' . $created['id'] . '/check'), ['id' => (string) $created['id']] ); self::assertSame(200, $response->status); self::assertTrue($response->body()['checks']['write_access']['ok']); self::assertTrue($response->body()['checks']['webhook']['ok']); } public function testCheckThrowsNotFoundForUnknownRepo(): void { $this->expectException(NotFoundException::class); $this->controller->check( Request::create('POST', '/api/v1/repo-configs/999/check'), ['id' => '999'] ); } }