repository = $this->createMock(MediaRepositoryInterface::class); $this->mediaUsageReader = $this->createMock(MediaUsageReaderInterface::class); $this->uploadDir = sys_get_temp_dir() . '/slim_media_race_' . uniqid('', true); @mkdir($this->uploadDir, 0755, true); $storage = new LocalMediaStorage($this->uploadDir); $this->service = new MediaApplicationService( $this->repository, $this->mediaUsageReader, new StoreMedia($this->repository, $storage, '/media', 5 * 1024 * 1024), new DeleteMedia($this->repository, $storage), ); } protected function tearDown(): void { foreach (glob($this->uploadDir . '/*') ?: [] as $file) { @unlink($file); } @rmdir($this->uploadDir); } public function testReturnsDuplicateUrlWhenInsertRaceOccurs(): void { $tmpFile = $this->createMinimalGif(); $hash = hash_file('sha256', $tmpFile); self::assertNotFalse($hash); $duplicate = new Media(77, 'existing.gif', '/media/existing.gif', $hash, 1); $this->repository->expects($this->exactly(2)) ->method('findByHashForUser') ->with($hash, 1) ->willReturnOnConsecutiveCalls(null, $duplicate); $this->repository->expects($this->once()) ->method('create') ->willThrowException(new PDOException('duplicate key')); $file = $this->makeUploadedFileFromPath($tmpFile, filesize($tmpFile)); $media = $this->service->store($file, 1); self::assertSame('/media/existing.gif', $media->getUrl()); self::assertSame(77, $media->getId()); self::assertCount(0, glob($this->uploadDir . '/*') ?: []); @unlink($tmpFile); } private function makeUploadedFileFromPath(string $path, int $size): UploadedMediaInterface { $file = $this->createMock(UploadedMediaInterface::class); $file->method('getSize')->willReturn($size); $file->method('getTemporaryPath')->willReturn($path); $file->method('moveTo')->willReturnCallback(static function (string $dest) use ($path): void { copy($path, $dest); }); return $file; } private function createMinimalGif(): string { $tmpFile = tempnam(sys_get_temp_dir(), 'slim_gif_'); self::assertNotFalse($tmpFile); file_put_contents($tmpFile, base64_decode('R0lGODdhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==')); return $tmpFile; } }