diff --git a/src/Jobs/DetectionJob.php b/src/Jobs/DetectionJob.php index 203aaca..7eba342 100644 --- a/src/Jobs/DetectionJob.php +++ b/src/Jobs/DetectionJob.php @@ -9,7 +9,6 @@ use File; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; -use Queue; abstract class DetectionJob implements ShouldQueue { @@ -217,6 +216,9 @@ protected function createMaiaAnnotations(array $annotations) return $this->createMaiaAnnotation($annotation); }, $annotations); + $existingIds = $this->job->volume->images()->pluck('id', 'id')->toArray(); + $maiaAnnotations = array_filter($maiaAnnotations, fn ($a) => array_key_exists($a['image_id'], $existingIds)); + // Chunk the insert because PDO's maximum number of query parameters is // 65535. Each annotation has 7 parameters so we can store roughly 9000 // annotations in one call. diff --git a/tests/Jobs/ObjectDetectionTest.php b/tests/Jobs/ObjectDetectionTest.php index c67e961..9c6ad47 100644 --- a/tests/Jobs/ObjectDetectionTest.php +++ b/tests/Jobs/ObjectDetectionTest.php @@ -20,6 +20,7 @@ use Illuminate\Support\Facades\Queue; use Str; use TestCase; +use Biigle\Image; class ObjectDetectionTest extends TestCase { @@ -128,6 +129,31 @@ public function testHandle() } } + public function testDeletedImage() + { + FileCache::fake(); + + $job = MaiaJobTest::create(); + $image = ImageTest::create(['volume_id' => $job->volume_id]); + $image2 = ImageTest::create(['volume_id' => $job->volume_id, 'filename' => 'a']); + + config(['maia.tmp_dir' => '/tmp']); + $tmpDir = "/tmp/maia-{$job->id}-object-detection"; + + try { + $request = new OdJobStub($job); + $request->deleteImage = true; + $request->handle(); + + $annotations = $job->annotationCandidates()->get(); + // One image was deleted, only one image and annotation remains. + $this->assertEquals(1, $annotations->count()); + $this->assertEquals($image2->id, $annotations[0]->image_id); + } finally { + File::deleteDirectory($tmpDir); + } + } + public function testHandleKnowledgeTransfer() { FileCache::fake(); @@ -383,6 +409,7 @@ class OdJobStub extends ObjectDetection public $commands = []; public $cleanup = false; public $crash = false; + public $deleteImage = false; protected function maybeDownloadWeights($from, $to) { @@ -418,4 +445,13 @@ protected function updateJobState() return parent::updateJobState(); } + + public function createMaiaAnnotations($annotations) + { + // Simulate image removal after saving its annotations + if ($this->deleteImage && !empty($annotations)) { + Image::where('id', '=', $annotations[0][0])->delete(); + } + parent::createMaiaAnnotations($annotations); + } }