147 lines
4.9 KiB
PHP
147 lines
4.9 KiB
PHP
<?php
|
|
|
|
use App\Jobs\AddPoliciesToBackupSetJob;
|
|
use App\Models\BackupItem;
|
|
use App\Models\BackupSet;
|
|
use App\Models\BulkOperationRun;
|
|
use App\Models\Policy;
|
|
use App\Models\PolicyVersion;
|
|
use App\Services\BulkOperationService;
|
|
use App\Services\Intune\FoundationSnapshotService;
|
|
use App\Services\Intune\PolicyCaptureOrchestrator;
|
|
use App\Services\Intune\SnapshotValidator;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Mockery\MockInterface;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
it('records stable failure reason codes and keeps run counts consistent', function () {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
$this->actingAs($user);
|
|
|
|
$backupSet = BackupSet::factory()->create([
|
|
'tenant_id' => $tenant->id,
|
|
'name' => 'Test backup',
|
|
'status' => 'completed',
|
|
'metadata' => ['failures' => []],
|
|
]);
|
|
|
|
$policyA = Policy::factory()->create([
|
|
'tenant_id' => $tenant->id,
|
|
'ignored_at' => null,
|
|
]);
|
|
|
|
$policyB = Policy::factory()->create([
|
|
'tenant_id' => $tenant->id,
|
|
'ignored_at' => null,
|
|
]);
|
|
|
|
$versionA = PolicyVersion::factory()->create([
|
|
'tenant_id' => $tenant->id,
|
|
'policy_id' => $policyA->id,
|
|
'policy_type' => $policyA->policy_type,
|
|
'platform' => $policyA->platform,
|
|
'snapshot' => ['id' => $policyA->external_id],
|
|
]);
|
|
|
|
$run = BulkOperationRun::factory()->create([
|
|
'tenant_id' => $tenant->id,
|
|
'user_id' => $user->id,
|
|
'resource' => 'backup_set',
|
|
'action' => 'add_policies',
|
|
'status' => 'pending',
|
|
'total_items' => 2,
|
|
'item_ids' => [
|
|
'backup_set_id' => $backupSet->id,
|
|
'policy_ids' => [$policyA->id, $policyB->id],
|
|
'options' => [
|
|
'include_assignments' => true,
|
|
'include_scope_tags' => true,
|
|
'include_foundations' => false,
|
|
],
|
|
],
|
|
'failures' => [],
|
|
]);
|
|
|
|
$this->mock(PolicyCaptureOrchestrator::class, function (MockInterface $mock) use ($policyA, $policyB, $tenant, $versionA) {
|
|
$mock->shouldReceive('capture')
|
|
->twice()
|
|
->andReturnUsing(function (
|
|
Policy $policy,
|
|
\App\Models\Tenant $tenantArg,
|
|
bool $includeAssignments = false,
|
|
bool $includeScopeTags = false,
|
|
?string $createdBy = null,
|
|
array $metadata = []
|
|
) use ($policyA, $policyB, $tenant, $versionA) {
|
|
expect($tenantArg->id)->toBe($tenant->id);
|
|
expect($includeAssignments)->toBeTrue();
|
|
expect($includeScopeTags)->toBeTrue();
|
|
expect($metadata['backup_set_id'] ?? null)->not->toBeNull();
|
|
|
|
if ($policy->is($policyA)) {
|
|
return [
|
|
'version' => $versionA,
|
|
'captured' => [
|
|
'payload' => [
|
|
'id' => $policyA->external_id,
|
|
'@odata.type' => '#microsoft.graph.deviceManagementConfigurationPolicy',
|
|
],
|
|
'assignments' => [],
|
|
'scope_tags' => ['ids' => ['0'], 'names' => ['Default']],
|
|
'metadata' => [],
|
|
],
|
|
];
|
|
}
|
|
|
|
expect($policy->is($policyB))->toBeTrue();
|
|
|
|
return [
|
|
'failure' => [
|
|
'policy_id' => $policyB->id,
|
|
'reason' => 'Forbidden',
|
|
'status' => 403,
|
|
],
|
|
];
|
|
});
|
|
});
|
|
|
|
$job = new AddPoliciesToBackupSetJob(
|
|
bulkRunId: (int) $run->getKey(),
|
|
backupSetId: (int) $backupSet->getKey(),
|
|
includeAssignments: true,
|
|
includeScopeTags: true,
|
|
includeFoundations: false,
|
|
);
|
|
|
|
$job->handle(
|
|
bulkOperationService: app(BulkOperationService::class),
|
|
captureOrchestrator: app(PolicyCaptureOrchestrator::class),
|
|
foundationSnapshots: $this->mock(FoundationSnapshotService::class),
|
|
snapshotValidator: app(SnapshotValidator::class),
|
|
);
|
|
|
|
$run->refresh();
|
|
$backupSet->refresh();
|
|
|
|
expect($run->status)->toBe('completed_with_errors');
|
|
expect($run->total_items)->toBe(2);
|
|
expect($run->processed_items)->toBe(2);
|
|
expect($run->succeeded)->toBe(1);
|
|
expect($run->failed)->toBe(1);
|
|
expect($run->skipped)->toBe(0);
|
|
|
|
expect(BackupItem::query()
|
|
->where('backup_set_id', $backupSet->id)
|
|
->where('policy_id', $policyA->id)
|
|
->exists())->toBeTrue();
|
|
|
|
$failureEntry = collect($run->failures ?? [])
|
|
->firstWhere('item_id', (string) $policyB->id);
|
|
|
|
expect($failureEntry)->not->toBeNull();
|
|
expect($failureEntry['reason_code'] ?? null)->toBe('graph_forbidden');
|
|
|
|
expect($backupSet->status)->toBe('partial');
|
|
});
|