create(); $tenant->makeCurrent(); $user = User::factory()->create(); $this->actingAs($user); $backupSet = BackupSet::factory()->create([ 'tenant_id' => $tenant->id, 'status' => 'completed', ]); $policy = Policy::factory()->create([ 'tenant_id' => $tenant->id, 'last_synced_at' => now(), 'ignored_at' => null, ]); $existingVersion = PolicyVersion::factory()->create([ 'tenant_id' => $tenant->id, 'policy_id' => $policy->id, 'captured_at' => now(), 'snapshot' => ['id' => $policy->external_id, 'name' => $policy->display_name], 'assignments' => null, 'scope_tags' => null, ]); $this->mock(PolicyCaptureOrchestrator::class, function (MockInterface $mock) use ($existingVersion) { $mock->shouldReceive('capture') ->once() ->andReturn([ 'version' => $existingVersion, 'captured' => [ 'payload' => $existingVersion->snapshot, 'assignments' => $existingVersion->assignments, 'scope_tags' => $existingVersion->scope_tags, 'metadata' => [], ], ]); }); $service = app(BackupService::class); $service->addPoliciesToSet( tenant: $tenant, backupSet: $backupSet, policyIds: [$policy->id], actorEmail: $user->email, actorName: $user->name, includeAssignments: false, includeScopeTags: false, includeFoundations: false, ); expect(PolicyVersion::query()->where('policy_id', $policy->id)->count())->toBe(1); $item = $backupSet->items()->first(); expect($item)->not->toBeNull(); expect($item->policy_version_id)->toBe($existingVersion->id); }); it('captures a new policy version for backup when no suitable existing version is available', function () { $tenant = Tenant::factory()->create(); $tenant->makeCurrent(); $user = User::factory()->create(); $this->actingAs($user); $backupSet = BackupSet::factory()->create([ 'tenant_id' => $tenant->id, 'status' => 'completed', ]); $policy = Policy::factory()->create([ 'tenant_id' => $tenant->id, 'last_synced_at' => now(), 'ignored_at' => null, ]); $staleVersion = PolicyVersion::factory()->create([ 'tenant_id' => $tenant->id, 'policy_id' => $policy->id, 'version_number' => 1, 'captured_at' => now()->subDays(2), 'snapshot' => ['id' => $policy->external_id, 'name' => $policy->display_name], ]); $policy->update(['last_synced_at' => now()]); $this->mock(PolicyCaptureOrchestrator::class, function (MockInterface $mock) use ($policy, $tenant) { $mock->shouldReceive('capture') ->once() ->andReturnUsing(function () use ($policy, $tenant) { $newVersion = PolicyVersion::factory()->create([ 'tenant_id' => $tenant->id, 'policy_id' => $policy->id, 'version_number' => 2, 'captured_at' => now(), 'snapshot' => ['id' => $policy->external_id, 'name' => $policy->display_name, 'changed' => true], ]); return [ 'version' => $newVersion, 'captured' => [ 'payload' => $newVersion->snapshot, 'assignments' => null, 'scope_tags' => null, 'metadata' => [], ], ]; }); }); $service = app(BackupService::class); $service->addPoliciesToSet( tenant: $tenant, backupSet: $backupSet, policyIds: [$policy->id], actorEmail: $user->email, actorName: $user->name, includeAssignments: false, includeScopeTags: false, includeFoundations: false, ); $item = $backupSet->items()->first(); expect($item)->not->toBeNull(); expect($item->policy_version_id)->not->toBe($staleVersion->id); });