actingAs($user); $backupSet = \App\Models\BackupSet::factory()->create([ 'tenant_id' => $tenant->id, ]); $restoreRun = RestoreRun::factory()->create([ 'tenant_id' => $tenant->id, 'backup_set_id' => $backupSet->id, 'status' => 'queued', 'started_at' => null, 'completed_at' => null, ]); // Canonical OperationRun must exist at dispatch time and be passed into the job. $operationRun = app(OperationRunService::class)->ensureRun( tenant: $tenant, type: 'restore.execute', inputs: [ 'restore_run_id' => $restoreRun->id, 'backup_set_id' => $backupSet->id, 'is_dry_run' => (bool) ($restoreRun->is_dry_run ?? false), ], initiator: $user, ); expect($operationRun)->not->toBeNull(); expect($operationRun?->status)->toBe('queued'); // Simulate downstream code updating RestoreRun status via query builder (no model events). $this->mock(RestoreService::class, function ($mock) use ($restoreRun): void { $mock->shouldReceive('executeForRun') ->once() ->andReturnUsing(function () use ($restoreRun): RestoreRun { RestoreRun::query()->whereKey($restoreRun->id)->update([ 'status' => 'completed', 'completed_at' => now(), ]); return RestoreRun::query()->findOrFail($restoreRun->id); }); }); $job = new ExecuteRestoreRunJob($restoreRun->id, null, null, $operationRun); $job->handle( app(RestoreService::class), app(AuditLogger::class), ); $operationRun = $operationRun?->fresh(); expect($operationRun)->not->toBeNull(); expect($operationRun?->status)->toBe('completed'); expect($operationRun?->outcome)->toBe('succeeded'); expect($operationRun?->completed_at)->not->toBeNull(); })->group('ops-ux');