Resolve local and object-storage originals, persist download status, and audit missing files without guessing from a single path.
74 lines
2.5 KiB
PHP
74 lines
2.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Models\Artwork;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Facades\Artisan;
|
|
use Illuminate\Support\Facades\File;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
it('processes an explicit artwork id exactly once with a chunk of one', function (string $status, ?string $source, string $expected): void {
|
|
Storage::fake('s3');
|
|
config(['uploads.object_storage.disk' => 's3']);
|
|
$hash = $status === 'pending'
|
|
? null
|
|
: str_repeat($source === 'local' ? 'a' : ($source === 'object' ? 'b' : 'c'), 40);
|
|
$ext = $status === 'pending' ? null : 'jpg';
|
|
|
|
if ($source === 'local') {
|
|
$root = (string) config('uploads.local_originals_root');
|
|
$path = $root . DIRECTORY_SEPARATOR . 'aa' . DIRECTORY_SEPARATOR . 'aa' . DIRECTORY_SEPARATOR . $hash . '.jpg';
|
|
File::ensureDirectoryExists(dirname($path));
|
|
File::put($path, 'local');
|
|
} elseif ($source === 'object') {
|
|
Storage::disk('s3')->put("artworks/original/bb/bb/{$hash}.jpg", 'object');
|
|
}
|
|
|
|
$artwork = Artwork::factory()->create([
|
|
'file_name' => $status === 'pending' ? 'pending' : 'audit-' . $status,
|
|
'hash' => $hash,
|
|
'file_ext' => $ext,
|
|
'file_path' => '',
|
|
]);
|
|
|
|
$exit = Artisan::call('artworks:audit-download-files', [
|
|
'--id' => $artwork->id,
|
|
'--chunk' => 1,
|
|
]);
|
|
$output = Artisan::output();
|
|
|
|
expect($exit)->toBe(Command::SUCCESS)
|
|
->and($output)->toContain("classification={$expected} count=1")
|
|
->and($output)->toContain('processed=1');
|
|
})->with([
|
|
['available', 'local', 'LOCAL_OK'],
|
|
['available', 'object', 'OBJECT_OK'],
|
|
['pending', null, 'PENDING'],
|
|
['missing', null, 'MISSING_EVERYWHERE'],
|
|
]);
|
|
|
|
it('marks an explicit id once when requested', function (): void {
|
|
Storage::fake('s3');
|
|
config(['uploads.object_storage.disk' => 's3']);
|
|
$hash = str_repeat('cd', 20);
|
|
Storage::disk('s3')->put("artworks/original/cd/cd/{$hash}.jpg", 'object');
|
|
|
|
$artwork = Artwork::factory()->create([
|
|
'hash' => $hash,
|
|
'file_ext' => 'jpg',
|
|
'file_path' => '',
|
|
]);
|
|
|
|
expect(Artisan::call('artworks:audit-download-files', [
|
|
'--id' => $artwork->id,
|
|
'--chunk' => 1,
|
|
'--mark-status' => true,
|
|
]))->toBe(Command::SUCCESS);
|
|
|
|
$artwork->refresh();
|
|
expect($artwork->download_status)->toBe('available')
|
|
->and($artwork->download_source)->toBe('object')
|
|
->and(Artisan::output())->toContain('processed=1');
|
|
});
|