create(); $user = User::factory()->create(); $policies = Policy::factory()->count(3)->create(['tenant_id' => $tenant->id]); // Create versions for policies so they can be backed up $policies->each(function ($policy) use ($tenant) { PolicyVersion::create([ 'tenant_id' => $tenant->id, 'policy_id' => $policy->id, 'policy_type' => $policy->policy_type, 'version_number' => 1, 'snapshot' => ['name' => $policy->display_name], 'captured_at' => now(), ]); }); $policyIds = $policies->pluck('id')->toArray(); $service = app(BulkOperationService::class); $run = $service->createRun($tenant, $user, 'policy', 'export', $policyIds, 3); $job = new BulkPolicyExportJob($run->id, 'My Bulk Backup'); $job->handle($service); $run->refresh(); expect($run->status)->toBe('completed') ->and($run->processed_items)->toBe(3) ->and($run->succeeded)->toBe(3); // Verify BackupSet created $backupSet = BackupSet::where('name', 'My Bulk Backup')->first(); expect($backupSet)->not->toBeNull() ->and($backupSet->tenant_id)->toBe($tenant->id); // Verify BackupItems created expect(BackupItem::where('backup_set_id', $backupSet->id)->count())->toBe(3); }); test('job handles policies without versions gracefully', function () { $tenant = Tenant::factory()->create(); $user = User::factory()->create(); $policyWithVersion = Policy::factory()->create(['tenant_id' => $tenant->id]); PolicyVersion::create([ 'tenant_id' => $tenant->id, 'policy_id' => $policyWithVersion->id, 'policy_type' => $policyWithVersion->policy_type, 'version_number' => 1, 'snapshot' => ['name' => 'ok'], 'captured_at' => now(), ]); $policyNoVersion = Policy::factory()->create(['tenant_id' => $tenant->id]); $policyIds = [$policyWithVersion->id, $policyNoVersion->id]; $service = app(BulkOperationService::class); $run = $service->createRun($tenant, $user, 'policy', 'export', $policyIds, 2); $job = new BulkPolicyExportJob($run->id, 'Partial Backup'); $job->handle($service); $run->refresh(); expect($run->status)->toBe('completed_with_errors') ->and($run->processed_items)->toBe(2) ->and($run->succeeded)->toBe(1) ->and($run->failed)->toBe(1); expect($run->failures[0]['item_id'])->toBe((string) $policyNoVersion->id) ->and($run->failures[0]['reason'])->toContain('No versions available'); });