6700ff145d
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
103 lines
4.4 KiB
PHP
103 lines
4.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace KTXT\Unit\Service;
|
|
|
|
use KTXC\Context\IdentityContextInterface;
|
|
use KTXC\Context\TenantContextInterface;
|
|
use KTXC\Models\Tenant\TenantConfiguration;
|
|
use KTXC\Service\FirewallStatusService;
|
|
use KTXC\Service\SystemFirewallLogService;
|
|
use KTXC\Service\SystemFirewallStatusService;
|
|
use KTXC\Service\TenantFirewallLogService;
|
|
use KTXC\Service\TenantFirewallStatusService;
|
|
use KTXC\Stores\FirewallStore;
|
|
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
|
|
use PHPUnit\Framework\Attributes\TestDox;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
#[AllowMockObjectsWithoutExpectations]
|
|
final class FirewallStatusServicesTest extends TestCase
|
|
{
|
|
#[TestDox('Tenant metrics and configuration derive their tenant context')]
|
|
public function testTenantStatus(): void
|
|
{
|
|
$store = $this->createMock(FirewallStore::class);
|
|
$tenant = $this->createStub(TenantContextInterface::class);
|
|
$tenant->method('requireIdentifier')->willReturn('tenant-a');
|
|
$tenant->method('configuration')->willReturn(
|
|
(new TenantConfiguration())->jsonDeserialize([
|
|
'firewall' => ['enabled' => false, 'maxAuthFailures' => 8],
|
|
])
|
|
);
|
|
$identity = $this->createStub(IdentityContextInterface::class);
|
|
$identity->method('hasPermission')->willReturn(true);
|
|
$store->expects(self::once())
|
|
->method('countBlockedRequests')
|
|
->with('tenant-a', self::isInstanceOf(\DateTimeImmutable::class))
|
|
->willReturn(7);
|
|
$service = new TenantFirewallStatusService(new FirewallStatusService($store), $tenant, $identity);
|
|
|
|
self::assertSame(7, $service->metrics('2026-08-01T00:00:00+00:00')['blockedRequests']);
|
|
self::assertFalse($service->configuration()['enabled']);
|
|
self::assertSame(8, $service->configuration()['maxAuthFailures']);
|
|
}
|
|
|
|
#[TestDox('System metrics and maintenance status expose operational state')]
|
|
public function testSystemStatus(): void
|
|
{
|
|
$store = $this->createMock(FirewallStore::class);
|
|
$identity = $this->createStub(IdentityContextInterface::class);
|
|
$identity->method('hasPermission')->willReturn(true);
|
|
$store->expects(self::once())
|
|
->method('countSystemBlockedRequests')
|
|
->with('tenant-a', null)
|
|
->willReturn(12);
|
|
$store->method('maintenanceStatus')->willReturn(['status' => 'success']);
|
|
$service = new SystemFirewallStatusService(new FirewallStatusService($store), $identity);
|
|
|
|
self::assertSame(12, $service->metrics('tenant-a')['blockedRequests']);
|
|
self::assertSame('success', $service->maintenanceStatus()['status']);
|
|
}
|
|
|
|
#[TestDox('Maintenance reports an explicit state before its first run')]
|
|
public function testNeverRunStatus(): void
|
|
{
|
|
$store = $this->createStub(FirewallStore::class);
|
|
|
|
self::assertSame('never_run', (new FirewallStatusService($store))->maintenanceStatus()['status']);
|
|
}
|
|
|
|
#[TestDox('Status reads require their dedicated permissions')]
|
|
public function testPermissions(): void
|
|
{
|
|
$store = $this->createMock(FirewallStore::class);
|
|
$identity = $this->createStub(IdentityContextInterface::class);
|
|
$identity->method('hasPermission')->willReturn(false);
|
|
$tenant = $this->createStub(TenantContextInterface::class);
|
|
$store->expects(self::never())->method('countBlockedRequests');
|
|
$store->expects(self::never())->method('maintenanceStatus');
|
|
|
|
try {
|
|
(new TenantFirewallStatusService(new FirewallStatusService($store), $tenant, $identity))->metrics();
|
|
self::fail('Tenant metrics should be rejected.');
|
|
} catch (\RuntimeException $error) {
|
|
self::assertStringContainsString(TenantFirewallLogService::PERMISSION_READ, $error->getMessage());
|
|
}
|
|
|
|
$this->expectExceptionMessage(SystemFirewallStatusService::PERMISSION_MAINTENANCE_READ);
|
|
(new SystemFirewallStatusService(new FirewallStatusService($store), $identity))->maintenanceStatus();
|
|
}
|
|
|
|
#[TestDox('Metrics reject invalid dates before querying storage')]
|
|
public function testMetricValidation(): void
|
|
{
|
|
$store = $this->createMock(FirewallStore::class);
|
|
$store->expects(self::never())->method('countSystemBlockedRequests');
|
|
$this->expectException(\InvalidArgumentException::class);
|
|
|
|
(new FirewallStatusService($store))->systemMetrics(null, 'not-a-date');
|
|
}
|
|
}
|