TenantAtlas/tests/Unit/Audit/AuditRecorderTest.php
2026-03-11 10:35:32 +01:00

80 lines
3.0 KiB
PHP

<?php
declare(strict_types=1);
use App\Models\OperationRun;
use App\Services\Audit\AuditRecorder;
use App\Support\Audit\AuditActorSnapshot;
use App\Support\Audit\AuditActorType;
use App\Support\Audit\AuditOutcome;
use App\Support\Audit\AuditTargetSnapshot;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
it('records workspace and tenant audit rows through the shared recorder', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
$run = OperationRun::factory()->create([
'tenant_id' => (int) $tenant->getKey(),
'workspace_id' => (int) $tenant->workspace_id,
'user_id' => (int) $user->getKey(),
'type' => 'backup_create',
]);
$audit = app(AuditRecorder::class)->record(
action: 'backup.created',
context: [
'item_count' => 3,
'client_secret' => 'super-secret',
],
workspace: $tenant->workspace,
tenant: $tenant,
actor: AuditActorSnapshot::human($user),
target: new AuditTargetSnapshot(
type: 'backup_set',
id: '42',
label: 'Nightly backup',
),
outcome: 'completed',
summary: null,
operationRunId: (int) $run->getKey(),
)->refresh();
expect((int) $audit->workspace_id)->toBe((int) $tenant->workspace_id)
->and((int) $audit->tenant_id)->toBe((int) $tenant->getKey())
->and($audit->actorSnapshot()->type)->toBe(AuditActorType::Human)
->and($audit->actorDisplayLabel())->toBe($user->name)
->and($audit->resource_type)->toBe('backup_set')
->and((string) $audit->resource_id)->toBe('42')
->and($audit->targetDisplayLabel())->toBe('Nightly backup')
->and($audit->summaryText())->toBe('Backup set created for Nightly backup')
->and($audit->normalizedOutcome())->toBe(AuditOutcome::Success)
->and((int) $audit->operation_run_id)->toBe((int) $run->getKey())
->and(data_get($audit->metadata, 'client_secret'))->toBe('[REDACTED]')
->and(data_get($audit->metadata, 'item_count'))->toBe(3);
});
it('infers actor kind, target identity, and normalized outcome when snapshots are omitted', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
$audit = app(AuditRecorder::class)->record(
action: 'backup_schedule.run_failed',
context: [
'_actor_type' => 'scheduled',
'backup_schedule_id' => 123,
'status' => 'failed',
'token' => 'top-secret',
],
workspace: $tenant->workspace,
tenant: $tenant,
)->refresh();
expect($audit->actorSnapshot()->type)->toBe(AuditActorType::Scheduled)
->and($audit->resource_type)->toBe('backup_schedule')
->and((string) $audit->resource_id)->toBe('123')
->and($audit->targetDisplayLabel())->toBe('Backup schedule #123')
->and($audit->normalizedOutcome())->toBe(AuditOutcome::Failed)
->and(data_get($audit->metadata, 'token'))->toBe('[REDACTED]');
});