TenantAtlas/apps/platform/tests/Feature/Operations/Spec362SelectedFamilyRenderGuardTest.php
Ahmed Darrazi 0eda669d38
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 3m42s
feat: implement sync capture backup operation semantics
2026-06-07 03:17:08 +02:00

148 lines
5.6 KiB
PHP

<?php
declare(strict_types=1);
use App\Models\BackupSet;
use App\Models\BaselineProfile;
use App\Models\BaselineSnapshot;
use App\Models\OperationRun;
use App\Services\Graph\GraphClientInterface;
use App\Services\OperationRunService;
use App\Support\Inventory\InventoryCoverage;
use App\Support\OperationRunLinks;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Facades\Filament;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
it('renders selected-family reconciled operations DB-only on list and detail surfaces in Spec362', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
$profile = BaselineProfile::factory()->active()->create([
'workspace_id' => (int) $tenant->workspace_id,
]);
$snapshot = BaselineSnapshot::factory()->complete()->create([
'workspace_id' => (int) $tenant->workspace_id,
'baseline_profile_id' => (int) $profile->getKey(),
]);
$backupSet = BackupSet::factory()->for($tenant)->create();
$inventoryRun = OperationRun::factory()->forTenant($tenant)->create([
'type' => 'inventory.sync',
'status' => OperationRunStatus::Queued->value,
'outcome' => OperationRunOutcome::Pending->value,
'context' => [
'policy_types' => ['deviceConfiguration'],
'inventory' => [
'coverage' => InventoryCoverage::buildPayload([
'deviceConfiguration' => 'succeeded',
], []),
],
],
]);
$baselineRun = OperationRun::factory()->forTenant($tenant)->create([
'type' => 'baseline.capture',
'status' => OperationRunStatus::Queued->value,
'outcome' => OperationRunOutcome::Pending->value,
'context' => [
'baseline_profile_id' => (int) $profile->getKey(),
'baseline_snapshot_id' => (int) $snapshot->getKey(),
],
]);
$backupRun = OperationRun::factory()->forTenant($tenant)->create([
'type' => 'backup.schedule.execute',
'status' => OperationRunStatus::Queued->value,
'outcome' => OperationRunOutcome::Pending->value,
'context' => [
'backup_set_id' => (int) $backupSet->getKey(),
],
]);
$service = app(OperationRunService::class);
$service->updateRunWithReconciliation(
run: $inventoryRun,
status: OperationRunStatus::Completed->value,
outcome: OperationRunOutcome::PartiallySucceeded->value,
summaryCounts: ['total' => 1, 'succeeded' => 1, 'failed' => 0],
failures: [[
'code' => 'inventory.partial',
'reason_code' => 'run.adapter_out_of_sync',
'message' => 'Usable coverage exists, but not every type completed cleanly.',
]],
reasonCode: 'run.adapter_out_of_sync',
reasonMessage: 'Usable coverage exists, but not every type completed cleanly.',
source: 'adapter_reconciler',
evidence: ['adapter' => 'inventory_sync'],
adapter: 'inventory_sync',
decision: 'reconciled_partially_succeeded',
);
$service->updateRunWithReconciliation(
run: $baselineRun,
status: OperationRunStatus::Completed->value,
outcome: OperationRunOutcome::Succeeded->value,
summaryCounts: ['total' => 1, 'succeeded' => 1, 'failed' => 0],
failures: [],
reasonCode: 'run.adapter_out_of_sync',
reasonMessage: 'A matching baseline snapshot was already available.',
source: 'adapter_reconciler',
evidence: ['adapter' => 'baseline_capture'],
adapter: 'baseline_capture',
decision: 'reconciled_succeeded',
related: [
'type' => 'baseline_snapshot',
'id' => (int) $snapshot->getKey(),
'lifecycle_state' => 'complete',
],
);
$service->updateRunWithReconciliation(
run: $backupRun,
status: OperationRunStatus::Completed->value,
outcome: OperationRunOutcome::Succeeded->value,
summaryCounts: ['total' => 1, 'succeeded' => 1, 'failed' => 0],
failures: [],
reasonCode: 'run.adapter_out_of_sync',
reasonMessage: 'A matching backup set was already available.',
source: 'adapter_reconciler',
evidence: ['adapter' => 'backup_schedule_execution'],
adapter: 'backup_schedule_execution',
decision: 'reconciled_succeeded',
related: [
'type' => 'backup_set',
'id' => (int) $backupSet->getKey(),
'status' => 'completed',
],
);
$this->mock(GraphClientInterface::class, function ($mock): void {
$mock->shouldReceive('listPolicies')->never();
$mock->shouldReceive('getPolicy')->never();
$mock->shouldReceive('getOrganization')->never();
$mock->shouldReceive('applyPolicy')->never();
$mock->shouldReceive('getServicePrincipalPermissions')->never();
$mock->shouldReceive('request')->never();
});
Filament::setTenant(null, true);
$this->actingAs($user)
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
->get(route('admin.operations.index', ['workspace' => $tenant->workspace]))
->assertSuccessful()
->assertSee('Inventory sync')
->assertSee('Baseline capture')
->assertSee('Backup schedule run');
foreach ([$inventoryRun, $baselineRun, $backupRun] as $run) {
$this->actingAs($user)
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
->get(OperationRunLinks::tenantlessView($run->fresh()))
->assertSuccessful();
}
});