set('enhance.disk', 'public'); Storage::fake('public'); Queue::fake(); }); it('increments retry metadata and clears failure fields on retry', function (): void { $owner = User::factory()->create(); Storage::disk('public')->put('enhance/sources/10/source.png', 'source'); Storage::disk('public')->put('enhance/outputs/10/output.webp', 'output'); $job = EnhanceJob::query()->create([ 'user_id' => $owner->id, 'status' => EnhanceJob::STATUS_FAILED, 'engine' => EnhanceJob::ENGINE_STUB, 'mode' => 'standard', 'scale' => 2, 'source_disk' => 'public', 'source_path' => 'enhance/sources/10/source.png', 'output_disk' => 'public', 'output_path' => 'enhance/outputs/10/output.webp', 'error_message' => 'Example failure', 'started_at' => now()->subMinute(), 'finished_at' => now()->subSeconds(5), ]); $this->actingAs($owner) ->post(route('enhance.retry', ['enhanceJob' => $job])) ->assertRedirect(route('enhance.show', ['enhanceJob' => $job])); $job->refresh(); expect($job->status)->toBe(EnhanceJob::STATUS_QUEUED); expect($job->error_message)->toBeNull(); expect($job->started_at)->toBeNull(); expect($job->finished_at)->toBeNull(); expect($job->metadata['retry_count'])->toBe(1); expect($job->metadata['last_retried_at'])->not->toBeNull(); Queue::assertPushed(ProcessEnhanceJob::class); }); it('does not dispatch retry when the source file is missing', function (): void { $owner = User::factory()->create(); $job = EnhanceJob::query()->create([ 'user_id' => $owner->id, 'status' => EnhanceJob::STATUS_FAILED, 'engine' => EnhanceJob::ENGINE_STUB, 'mode' => 'standard', 'scale' => 2, 'source_disk' => 'public', 'source_path' => 'enhance/sources/11/missing.png', 'error_message' => 'Example failure', ]); $this->from(route('enhance.show', ['enhanceJob' => $job])) ->actingAs($owner) ->post(route('enhance.retry', ['enhanceJob' => $job])) ->assertRedirect(route('enhance.show', ['enhanceJob' => $job])) ->assertSessionHasErrors([ 'job' => 'This enhance job can no longer be retried because the original source file was cleaned up.', ]); $job->refresh(); expect($job->status)->toBe(EnhanceJob::STATUS_FAILED); Queue::assertNothingPushed(); }); it('rejects retrying non failed jobs', function (): void { $owner = User::factory()->create(); Storage::disk('public')->put('enhance/sources/12/source.png', 'source'); $job = EnhanceJob::query()->create([ 'user_id' => $owner->id, 'status' => EnhanceJob::STATUS_COMPLETED, 'engine' => EnhanceJob::ENGINE_STUB, 'mode' => 'standard', 'scale' => 2, 'source_disk' => 'public', 'source_path' => 'enhance/sources/12/source.png', ]); $this->from(route('enhance.show', ['enhanceJob' => $job])) ->actingAs($owner) ->post(route('enhance.retry', ['enhanceJob' => $job])) ->assertForbidden(); Queue::assertNothingPushed(); });