$root, 'uploads.readonly_backup_originals_root' => storage_path('framework/testing/artwork-readonly-backup'), 'uploads.legacy_originals_root' => $legacyRoot, 'uploads.object_storage.disk' => 's3', ]); File::deleteDirectory($root); File::deleteDirectory($legacyRoot); File::deleteDirectory(storage_path('framework/testing/artwork-readonly-backup')); File::makeDirectory($root, 0755, true); File::makeDirectory($legacyRoot, 0755, true); Storage::fake('s3'); }); afterEach(function (): void { File::deleteDirectory(storage_path('framework/testing/artwork-originals')); File::deleteDirectory(storage_path('framework/testing/artwork-legacy')); File::deleteDirectory(storage_path('framework/testing/artwork-readonly-backup')); }); function locatorLocalPath(string $hash, string $extension): string { return storage_path("framework/testing/artwork-originals/{$hash[0]}{$hash[1]}/{$hash[2]}{$hash[3]}/{$hash}.{$extension}"); } it('infers a missing extension and resolves a hashed local original', function (): void { $hash = str_repeat('a', 40); File::ensureDirectoryExists(dirname(locatorLocalPath($hash, 'jpg'))); File::put(locatorLocalPath($hash, 'jpg'), 'local'); $artwork = Artwork::factory()->create(['hash' => $hash, 'file_ext' => null, 'file_name' => 'Something.JPG', 'file_path' => '']); expect(app(ArtworkOriginalFileLocator::class)->resolve($artwork))->toMatchArray([ 'status' => 'available', 'source' => 'local', 'file_ext' => 'jpg', ]); }); it('infers a missing extension and resolves a hashed object original', function (): void { $hash = str_repeat('b', 40); Storage::disk('s3')->put("artworks/original/bb/bb/{$hash}.png", 'object'); $artwork = Artwork::factory()->create(['hash' => $hash, 'file_ext' => null, 'file_name' => 'Image.PNG', 'file_path' => '']); expect(app(ArtworkOriginalFileLocator::class)->resolve($artwork))->toMatchArray([ 'status' => 'available', 'source' => 'object', 'file_ext' => 'png', ]); }); it('infers a missing extension and resolves a hashed readonly backup original', function (): void { $hash = str_repeat('d', 40); $root = (string) config('uploads.readonly_backup_originals_root'); $path = $root . DIRECTORY_SEPARATOR . 'dd' . DIRECTORY_SEPARATOR . 'dd' . DIRECTORY_SEPARATOR . $hash . '.jpeg'; File::ensureDirectoryExists(dirname($path)); File::put($path, 'backup'); $artwork = Artwork::factory()->create(['hash' => $hash, 'file_ext' => null, 'file_name' => 'backup.JPEG', 'file_path' => '']); expect(app(ArtworkOriginalFileLocator::class)->resolve($artwork))->toMatchArray([ 'status' => 'available', 'source' => 'legacy', 'file_ext' => 'jpeg', ]); }); it('resolves a hashless legacy upload from the authoritative legacy filesystem root', function (): void { $relative = 'legacy/uploads/old-image.jpg'; $path = storage_path("framework/testing/artwork-legacy/{$relative}"); File::ensureDirectoryExists(dirname($path)); File::put($path, 'legacy'); $artwork = Artwork::factory()->create(['hash' => null, 'file_ext' => null, 'file_name' => 'old-image.jpg', 'file_path' => $relative]); expect(app(ArtworkOriginalFileLocator::class)->resolve($artwork))->toMatchArray([ 'status' => 'available', 'source' => 'legacy', 'file_ext' => 'jpg', ]); }); it('resolves a hashless legacy upload from the authoritative object disk', function (): void { $relative = 'legacy/uploads/old-image.jpg'; Storage::disk('s3')->put($relative, 'legacy'); $artwork = Artwork::factory()->create(['hash' => null, 'file_ext' => null, 'file_name' => 'old-image.jpg', 'file_path' => $relative]); expect(app(ArtworkOriginalFileLocator::class)->resolve($artwork))->toMatchArray([ 'status' => 'available', 'source' => 'object', 'object_key' => $relative, 'file_ext' => 'jpg', ]); }); it('does not use the canonical readonly backup root as a legacy filename root', function (): void { config(['uploads.legacy_originals_root' => '']); $relative = 'legacy/uploads/not-migrated.jpg'; $path = storage_path("framework/testing/artwork-readonly-backup/{$relative}"); File::ensureDirectoryExists(dirname($path)); File::put($path, 'not authoritative'); $artwork = Artwork::factory()->create(['hash' => null, 'file_ext' => null, 'file_name' => 'not-migrated.jpg', 'file_path' => $relative]); expect(app(ArtworkOriginalFileLocator::class)->resolve($artwork)['status'])->toBe('unknown'); }); it('keeps a genuine pending placeholder pending', function (): void { $artwork = Artwork::factory()->create(['file_name' => 'pending', 'file_path' => '', 'hash' => null, 'file_ext' => null]); expect(app(ArtworkOriginalFileLocator::class)->resolve($artwork)['status'])->toBe('pending'); }); it('classifies unresolved incomplete legacy metadata as unknown', function (): void { $artwork = Artwork::factory()->create(['file_name' => 'old-image.jpg', 'file_path' => 'legacy/uploads/old-image.jpg', 'hash' => null, 'file_ext' => null]); expect(app(ArtworkOriginalFileLocator::class)->resolve($artwork)['status'])->toBe('unknown'); }); it('does not infer unsupported or executable extensions', function (): void { $artwork = Artwork::factory()->create(['file_name' => 'CIH.php', 'file_path' => 'legacy/uploads/CIH.php', 'hash' => null, 'file_ext' => null]); expect(app(ArtworkOriginalFileLocator::class)->resolve($artwork)['status'])->toBe('unknown'); }); it('keeps complete metadata missing everywhere as missing', function (): void { $hash = str_repeat('c', 40); $artwork = Artwork::factory()->create(['hash' => $hash, 'file_ext' => 'jpg', 'file_name' => 'missing.jpg', 'file_path' => '']); expect(app(ArtworkOriginalFileLocator::class)->resolve($artwork)['status'])->toBe('missing'); }); it('keeps a valid SHA-1 BMP original missing when all sources are absent', function (): void { $hash = str_repeat('e', 40); $artwork = Artwork::factory()->create(['hash' => $hash, 'file_ext' => null, 'file_name' => 'preview.bmp', 'file_path' => '']); expect(app(ArtworkOriginalFileLocator::class)->resolve($artwork))->toMatchArray([ 'status' => 'missing', 'file_ext' => 'bmp', ]); }); it('classifies a short hash as unknown and does not construct a canonical path', function (): void { $artwork = Artwork::factory()->create(['hash' => 'ddeeff112233', 'file_ext' => null, 'file_name' => 'rose-closeup.jpg', 'file_path' => 'uploads/artworks/image.jpg']); expect(app(ArtworkOriginalFileLocator::class)->resolve($artwork))->toMatchArray([ 'status' => 'unknown', 'path' => '', 'object_key' => '', ]); }); it('classifies a non-hex 40-character hash as unknown', function (): void { $artwork = Artwork::factory()->create(['hash' => str_repeat('g', 40), 'file_ext' => 'jpg', 'file_name' => 'invalid.jpg', 'file_path' => '']); expect(app(ArtworkOriginalFileLocator::class)->resolve($artwork))->toMatchArray([ 'status' => 'unknown', 'path' => '', 'object_key' => '', ]); });