monitor/api/tests/Unit/Sync/RepoHealthCheckerTest.php
fds2610-bot f14d851410 Offene PRs als Tickets in der Spalte Fertig darstellen
PRs werden beim Sync als Tickets (is_pull_request) angelegt, mit
Projektfarbe, schwarzen Querstreifen und PR-Nummer; im Spalten-Modal
mit Link auf den PR.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 11:27:27 +02:00

135 lines
4.9 KiB
PHP

<?php
declare(strict_types=1);
namespace Monitor\Api\Tests\Sync;
use Monitor\Api\Sync\CodebergApiException;
use Monitor\Api\Sync\CodebergClient;
use Monitor\Api\Sync\RepoHealthChecker;
use PHPUnit\Framework\TestCase;
use RuntimeException;
final class RepoHealthCheckerTest extends TestCase
{
public function testWriteAccessOkWhenPushPermissionTrue(): void
{
$client = $this->fakeClient(repoPermissions: ['push' => true]);
$checks = (new RepoHealthChecker($client))->check('fds2610', 'monitor');
self::assertTrue($checks['write_access']['ok']);
}
public function testWriteAccessFailsWhenPushPermissionFalse(): void
{
$client = $this->fakeClient(repoPermissions: ['push' => false]);
$checks = (new RepoHealthChecker($client))->check('fds2610', 'monitor');
self::assertFalse($checks['write_access']['ok']);
self::assertStringContainsString('keine Schreibrechte', $checks['write_access']['message']);
}
public function testWriteAccessFailsWithNotFoundMessageOn404(): void
{
$client = $this->fakeClient(repoPermissionsException: new CodebergApiException(404, 'nope'));
$checks = (new RepoHealthChecker($client))->check('fds2610', 'unbekannt');
self::assertFalse($checks['write_access']['ok']);
self::assertStringContainsString('nicht gefunden', $checks['write_access']['message']);
}
public function testWebhookOkWhenActiveJsonHookPointsToOwnEndpoint(): void
{
$client = $this->fakeClient(listWebhooks: [
['active' => true, 'url' => 'https://monitor.example.org/api/v1/webhooks/codeberg', 'content_type' => 'json'],
]);
$checks = (new RepoHealthChecker($client))->check('fds2610', 'monitor');
self::assertTrue($checks['webhook']['ok']);
}
public function testWebhookFailsWhenNoMatchingHookPresent(): void
{
$client = $this->fakeClient(listWebhooks: [
['active' => true, 'url' => 'https://example.org/other', 'content_type' => 'json'],
['active' => false, 'url' => 'https://monitor.example.org/api/v1/webhooks/codeberg', 'content_type' => 'json'],
]);
$checks = (new RepoHealthChecker($client))->check('fds2610', 'monitor');
self::assertFalse($checks['webhook']['ok']);
}
public function testWebhookFailsWithPermissionMessageOn403(): void
{
$client = $this->fakeClient(listWebhooksException: new CodebergApiException(403, 'forbidden'));
$checks = (new RepoHealthChecker($client))->check('fds2610', 'monitor');
self::assertFalse($checks['webhook']['ok']);
self::assertStringContainsString('keine Admin-Rechte', $checks['webhook']['message']);
}
public function testFailsGracefullyWhenCodebergUnreachable(): void
{
$client = $this->fakeClient(repoPermissionsException: new RuntimeException('Codeberg-API nicht erreichbar: timeout'));
$checks = (new RepoHealthChecker($client))->check('fds2610', 'monitor');
self::assertFalse($checks['write_access']['ok']);
self::assertStringContainsString('nicht erreichbar', $checks['write_access']['message']);
}
/**
* @param array{push: bool}|null $repoPermissions
* @param array<int, array{active: bool, url: string, content_type: string}>|null $listWebhooks
*/
private function fakeClient(
?array $repoPermissions = null,
?RuntimeException $repoPermissionsException = null,
?array $listWebhooks = null,
?RuntimeException $listWebhooksException = null,
): CodebergClient {
return new class ($repoPermissions, $repoPermissionsException, $listWebhooks, $listWebhooksException) implements CodebergClient {
public function __construct(
private readonly ?array $repoPermissions,
private readonly ?RuntimeException $repoPermissionsException,
private readonly ?array $listWebhooks,
private readonly ?RuntimeException $listWebhooksException,
) {
}
public function listIssues(string $owner, string $repo, string $state): array
{
return [];
}
public function repoPermissions(string $owner, string $repo): array
{
if ($this->repoPermissionsException !== null) {
throw $this->repoPermissionsException;
}
return $this->repoPermissions ?? ['push' => true];
}
public function listWebhooks(string $owner, string $repo): array
{
if ($this->listWebhooksException !== null) {
throw $this->listWebhooksException;
}
return $this->listWebhooks ?? [];
}
public function listOpenPullRequests(string $owner, string $repo): array
{
return [];
}
};
}
}