create(); // Upload a real file so a corresponding "uploaded" action log // exists for the destroy path to find. $this->actingAs($actor) ->post(route('ui.files.store', ['object_type' => 'assets', 'id' => $asset->id]), [ 'file' => [UploadedFile::fake()->create('test.pdf', 10)], ]) ->assertRedirect(); $log = Actionlog::where('item_type', Asset::class) ->where('item_id', $asset->id) ->where('action_type', 'uploaded') ->latest() ->first(); return [$asset, $log]; } private function mockStorageToFailDelete(): void { // Storage::exists returns true (file is present), Storage::delete // returns false (silent-fail). All other calls pass through. Storage::fake(); $default = Storage::disk(); Storage::shouldReceive('exists')->andReturn(true); Storage::shouldReceive('delete')->andReturn(false); Storage::shouldReceive('disk')->andReturn($default); Storage::shouldReceive('makeDirectory')->andReturnUsing(fn (...$a) => $default->makeDirectory(...$a)); } public function test_web_delete_does_not_log_deletion_when_physical_delete_fails(): void { $user = User::factory()->superuser()->create(); [$asset, $log] = $this->seedAssetWithUpload($user); $this->mockStorageToFailDelete(); $response = $this->actingAs($user) ->delete(route('ui.files.destroy', ['object_type' => 'assets', 'id' => $asset->id, 'file_id' => $log->id])); $response->assertSessionHas('error'); $this->assertDatabaseMissing('action_logs', [ 'item_type' => Asset::class, 'item_id' => $asset->id, 'action_type' => 'upload deleted', 'filename' => $log->filename, ]); } public function test_api_delete_does_not_log_deletion_when_physical_delete_fails(): void { $user = User::factory()->superuser()->create(); [$asset, $log] = $this->seedAssetWithUpload($user); $this->mockStorageToFailDelete(); $response = $this->actingAsForApi($user) ->deleteJson(route('api.files.destroy', ['object_type' => 'assets', 'id' => $asset->id, 'file_id' => $log->id])); $response->assertStatus(500); $this->assertDatabaseMissing('action_logs', [ 'item_type' => Asset::class, 'item_id' => $asset->id, 'action_type' => 'upload deleted', 'filename' => $log->filename, ]); } }