create([ 'tenant_id' => $tenant->id, 'user_id' => $user->id, 'type' => 'restore_run.delete', 'status' => 'queued', 'summary_counts' => [], 'context' => [ 'target_scope' => [ 'entra_tenant_id' => (string) ($tenant->tenant_id ?? $tenant->external_id), ], ], ]); Bus::fake(); $job = new BulkRestoreRunDeleteJob( tenantId: (int) $tenant->getKey(), userId: (int) $user->getKey(), restoreRunIds: [3, 2, 1], operationRun: $run, context: [], ); $job->handle(app(OperationRunService::class)); $run = $run->fresh(); expect($run)->not->toBeNull(); expect($run?->status)->toBe('running'); expect($run?->summary_counts['total'] ?? null)->toBe(3); Bus::assertDispatched(RestoreRunDeleteWorkerJob::class, 3); })->group('ops-ux'); it('archives only deletable restore runs and updates summary counts', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); $deletable = RestoreRun::factory()->create([ 'tenant_id' => $tenant->id, 'status' => 'completed', 'deleted_at' => null, ]); $alreadyArchived = RestoreRun::factory()->create([ 'tenant_id' => $tenant->id, 'status' => 'completed', 'deleted_at' => now(), ]); $notDeletable = RestoreRun::factory()->create([ 'tenant_id' => $tenant->id, 'status' => 'running', 'deleted_at' => null, ]); $run = OperationRun::factory()->create([ 'tenant_id' => $tenant->id, 'user_id' => $user->id, 'type' => 'restore_run.delete', 'status' => 'running', 'summary_counts' => [ 'total' => 3, 'processed' => 0, 'failed' => 0, ], 'context' => [ 'target_scope' => [ 'entra_tenant_id' => (string) ($tenant->tenant_id ?? $tenant->external_id), ], ], ]); $lock = new class implements Lock { public function get($callback = null): bool { return true; } public function block($seconds, $callback = null): bool { return true; } public function release(): bool { return true; } public function owner(): string { return 'test'; } public function forceRelease(): void { // no-op } }; Cache::partialMock() ->shouldReceive('lock') ->andReturn($lock); (new RestoreRunDeleteWorkerJob( tenantId: (int) $tenant->getKey(), userId: (int) $user->getKey(), restoreRunId: (int) $deletable->getKey(), operationRun: $run, ))->handle(app(OperationRunService::class), app(TargetScopeConcurrencyLimiter::class)); (new RestoreRunDeleteWorkerJob( tenantId: (int) $tenant->getKey(), userId: (int) $user->getKey(), restoreRunId: (int) $alreadyArchived->getKey(), operationRun: $run, ))->handle(app(OperationRunService::class), app(TargetScopeConcurrencyLimiter::class)); (new RestoreRunDeleteWorkerJob( tenantId: (int) $tenant->getKey(), userId: (int) $user->getKey(), restoreRunId: (int) $notDeletable->getKey(), operationRun: $run, ))->handle(app(OperationRunService::class), app(TargetScopeConcurrencyLimiter::class)); $run = $run->fresh(); expect(RestoreRun::withTrashed()->whereKey($deletable->getKey())->first()?->trashed())->toBeTrue(); expect(RestoreRun::withTrashed()->whereKey($alreadyArchived->getKey())->first()?->trashed())->toBeTrue(); expect(RestoreRun::withTrashed()->whereKey($notDeletable->getKey())->first()?->trashed())->toBeFalse(); expect($run)->not->toBeNull(); expect($run?->status)->toBe('completed'); expect($run?->outcome)->toBe('succeeded'); expect($run?->summary_counts['processed'] ?? null)->toBe(3); expect($run?->summary_counts['succeeded'] ?? null)->toBe(1); expect($run?->summary_counts['deleted'] ?? null)->toBe(1); expect($run?->summary_counts['skipped'] ?? null)->toBe(2); expect($run?->summary_counts['failed'] ?? null)->toBe(0); })->group('ops-ux');