| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- <?php
- declare(strict_types=1);
- namespace App\Tests\Integration\Admin;
- use App\Domain\Auth\Role;
- use App\Domain\Auth\TokenKind;
- use App\Tests\Integration\Support\AppTestCase;
- /**
- * `/api/v1/admin/maintenance/{purge,seed-demo}` — admin-only one-shot
- * data tools used by the Settings page for demos and resets.
- */
- final class MaintenanceControllerTest extends AppTestCase
- {
- public function testPurgeRequiresAdmin(): void
- {
- $token = $this->createToken(TokenKind::Admin, Role::Operator);
- $resp = $this->request(
- 'POST',
- '/api/v1/admin/maintenance/purge',
- ['Authorization' => 'Bearer ' . $token, 'Content-Type' => 'application/json'],
- '{"confirm": "PURGE"}',
- );
- self::assertSame(403, $resp->getStatusCode());
- }
- public function testPurgeRequiresLiteralConfirmString(): void
- {
- $token = $this->createToken(TokenKind::Admin, Role::Admin);
- $resp = $this->request(
- 'POST',
- '/api/v1/admin/maintenance/purge',
- ['Authorization' => 'Bearer ' . $token, 'Content-Type' => 'application/json'],
- '{"confirm": "yes"}',
- );
- self::assertSame(400, $resp->getStatusCode());
- self::assertSame('validation_failed', $this->decode($resp)['error']);
- }
- public function testPurgeWipesOperationalDataButPreservesServiceToken(): void
- {
- // Seed a service token (bypassing the controller; the API protects it).
- $this->db->insert('api_tokens', [
- 'kind' => TokenKind::Service->value,
- 'token_hash' => str_repeat('a', 64),
- 'token_prefix' => 'irdb_svc',
- ]);
- // And one operational token, plus a reporter and a stray report.
- $reporterId = $this->createReporter('purge-victim');
- $catRow = $this->db->fetchAssociative('SELECT id FROM categories LIMIT 1');
- self::assertNotFalse($catRow);
- $this->db->insert('reports', [
- 'ip_bin' => str_repeat("\x00", 12) . "\x00\x00\x00\x01",
- 'ip_text' => '0.0.0.1',
- 'category_id' => (int) $catRow['id'],
- 'reporter_id' => $reporterId,
- 'weight_at_report' => '1.00',
- ]);
- $token = $this->createToken(TokenKind::Admin, Role::Admin);
- $resp = $this->request(
- 'POST',
- '/api/v1/admin/maintenance/purge',
- ['Authorization' => 'Bearer ' . $token, 'Content-Type' => 'application/json'],
- '{"confirm": "PURGE"}',
- );
- self::assertSame(200, $resp->getStatusCode());
- $body = $this->decode($resp);
- self::assertSame('purged', $body['status']);
- self::assertGreaterThanOrEqual(1, (int) $body['deleted']['reports']);
- // Service token survives, the admin token does not.
- $svcCount = (int) $this->db->fetchOne(
- 'SELECT COUNT(*) FROM api_tokens WHERE kind = :k',
- ['k' => TokenKind::Service->value],
- );
- self::assertSame(1, $svcCount);
- $allTokens = (int) $this->db->fetchOne('SELECT COUNT(*) FROM api_tokens');
- self::assertSame(1, $allTokens, 'only the service token should remain');
- // Reporters / reports gone.
- self::assertSame(0, (int) $this->db->fetchOne('SELECT COUNT(*) FROM reporters'));
- self::assertSame(0, (int) $this->db->fetchOne('SELECT COUNT(*) FROM reports'));
- // Categories preserved.
- self::assertGreaterThan(0, (int) $this->db->fetchOne('SELECT COUNT(*) FROM categories'));
- }
- public function testSeedDemoPopulatesDataAndIsIdempotent(): void
- {
- $token = $this->createToken(TokenKind::Admin, Role::Admin);
- $first = $this->request(
- 'POST',
- '/api/v1/admin/maintenance/seed-demo',
- ['Authorization' => 'Bearer ' . $token],
- );
- self::assertSame(200, $first->getStatusCode());
- $body = $this->decode($first);
- self::assertSame('seeded', $body['status']);
- self::assertGreaterThan(0, (int) $body['summary']['reporters']);
- self::assertGreaterThan(0, (int) $body['summary']['ips']);
- self::assertGreaterThan(0, (int) $body['summary']['reports']);
- // Real rows landed.
- self::assertGreaterThan(0, (int) $this->db->fetchOne('SELECT COUNT(*) FROM reporters'));
- self::assertGreaterThan(0, (int) $this->db->fetchOne('SELECT COUNT(*) FROM reports'));
- // Second call short-circuits with 409.
- $second = $this->request(
- 'POST',
- '/api/v1/admin/maintenance/seed-demo',
- ['Authorization' => 'Bearer ' . $token],
- );
- self::assertSame(409, $second->getStatusCode());
- self::assertSame('already_seeded', $this->decode($second)['error']);
- }
- public function testSeedDemoForbiddenForViewer(): void
- {
- $token = $this->createToken(TokenKind::Admin, Role::Viewer);
- $resp = $this->request(
- 'POST',
- '/api/v1/admin/maintenance/seed-demo',
- ['Authorization' => 'Bearer ' . $token],
- );
- self::assertSame(403, $resp->getStatusCode());
- }
- }
|