photoWithFile('dev-keep'); [$gone] = $this->photoWithoutFile('dev-gone'); $this->artisan('coruna:prune-missing-photo-files')->assertSuccessful(); $this->assertDatabaseHas('photos', ['id' => $keep->id]); $this->assertDatabaseHas('photos', ['id' => $gone->id]); } #[Test] public function execute_deletes_only_rows_whose_file_is_gone(): void { Storage::fake('local'); [$keep, $keepPath] = $this->photoWithFile('dev-keep'); [$gone] = $this->photoWithoutFile('dev-gone'); $empty = $this->photoRow('dev-empty', ''); $this->artisan('coruna:prune-missing-photo-files', ['--execute' => true]) ->assertSuccessful(); $this->assertDatabaseHas('photos', ['id' => $keep->id]); $this->assertDatabaseMissing('photos', ['id' => $gone->id]); $this->assertDatabaseMissing('photos', ['id' => $empty->id]); Storage::disk('local')->assertExists($keepPath); } /** * @return array{0: Photo, 1: string} */ private function photoWithFile(string $key): array { $device = Device::query()->create(['device_id' => $key]); $path = 'c2/photos/'.$key.'/shot.jpg'; Storage::disk('local')->put($path, 'jpeg'); $photo = Photo::query()->create([ 'device_id' => $device->id, 'sha256' => hash('sha256', $key), 'path' => $path, 'size' => 4, ]); return [$photo, $path]; } /** @return array{0: Photo} */ private function photoWithoutFile(string $key): array { return [$this->photoRow($key, 'c2/photos/'.$key.'/missing.jpg')]; } private function photoRow(string $key, string $path): Photo { $device = Device::query()->create(['device_id' => $key]); return Photo::query()->create([ 'device_id' => $device->id, 'sha256' => hash('sha256', $key.'-missing'), 'path' => $path, 'size' => 0, ]); } }