129 lines
4.0 KiB
PHP
129 lines
4.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Models\Artwork;
|
|
use App\Models\User;
|
|
use App\Services\Vision\AiArtworkVectorSearchService;
|
|
use App\Services\Vision\ArtworkVectorIndexService;
|
|
use App\Services\Vision\ArtworkVectorMetadataService;
|
|
use App\Services\Vision\ArtworkVisionImageUrl;
|
|
use App\Services\Vision\VectorGatewayClient;
|
|
use App\Services\Vision\VectorService;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Artisan;
|
|
use Illuminate\Support\Str;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
function bindVectorService(): void
|
|
{
|
|
$imageUrl = new ArtworkVisionImageUrl();
|
|
|
|
app()->instance(VectorService::class, new VectorService(
|
|
new AiArtworkVectorSearchService(new VectorGatewayClient(), $imageUrl),
|
|
new ArtworkVectorIndexService(new VectorGatewayClient(), $imageUrl, new ArtworkVectorMetadataService()),
|
|
));
|
|
}
|
|
|
|
it('indexes artworks by latest updated_at descending by default', function (): void {
|
|
$user = User::factory()->create();
|
|
|
|
$oldest = Artwork::factory()->for($user)->create([
|
|
'title' => 'Oldest artwork',
|
|
'slug' => 'oldest-artwork',
|
|
'hash' => str_repeat('a', 32),
|
|
'is_public' => true,
|
|
'is_approved' => true,
|
|
'published_at' => now()->subDays(3),
|
|
'updated_at' => now()->subDays(3),
|
|
]);
|
|
|
|
$middle = Artwork::factory()->for($user)->create([
|
|
'title' => 'Middle artwork',
|
|
'slug' => 'middle-artwork',
|
|
'hash' => str_repeat('b', 32),
|
|
'is_public' => true,
|
|
'is_approved' => true,
|
|
'published_at' => now()->subDays(2),
|
|
'updated_at' => now()->subDays(2),
|
|
]);
|
|
|
|
$latest = Artwork::factory()->for($user)->create([
|
|
'title' => 'Latest artwork',
|
|
'slug' => 'latest-artwork',
|
|
'hash' => str_repeat('c', 32),
|
|
'is_public' => true,
|
|
'is_approved' => true,
|
|
'published_at' => now()->subDay(),
|
|
'updated_at' => now()->subHour(),
|
|
]);
|
|
|
|
bindVectorService();
|
|
|
|
$code = Artisan::call('artworks:vectors-index', [
|
|
'--dry-run' => true,
|
|
'--public-only' => true,
|
|
'--limit' => 3,
|
|
'--batch' => 3,
|
|
]);
|
|
|
|
$output = Artisan::output();
|
|
|
|
expect($code)->toBe(0);
|
|
|
|
$latestPos = strpos($output, 'Processing artwork=' . $latest->id);
|
|
$middlePos = strpos($output, 'Processing artwork=' . $middle->id);
|
|
$oldestPos = strpos($output, 'Processing artwork=' . $oldest->id);
|
|
|
|
expect($latestPos)->not->toBeFalse()
|
|
->and($middlePos)->not->toBeFalse()
|
|
->and($oldestPos)->not->toBeFalse()
|
|
->and($latestPos)->toBeLessThan($middlePos)
|
|
->and($middlePos)->toBeLessThan($oldestPos);
|
|
});
|
|
|
|
it('supports legacy id ascending order when explicitly requested', function (): void {
|
|
$user = User::factory()->create();
|
|
|
|
$first = Artwork::factory()->for($user)->create([
|
|
'title' => 'First artwork',
|
|
'slug' => 'first-artwork-' . Str::lower(Str::random(4)),
|
|
'hash' => str_repeat('d', 32),
|
|
'is_public' => true,
|
|
'is_approved' => true,
|
|
'published_at' => now()->subDay(),
|
|
'updated_at' => now(),
|
|
]);
|
|
|
|
$second = Artwork::factory()->for($user)->create([
|
|
'title' => 'Second artwork',
|
|
'slug' => 'second-artwork-' . Str::lower(Str::random(4)),
|
|
'hash' => str_repeat('e', 32),
|
|
'is_public' => true,
|
|
'is_approved' => true,
|
|
'published_at' => now()->subDays(2),
|
|
'updated_at' => now()->subDays(2),
|
|
]);
|
|
|
|
bindVectorService();
|
|
|
|
$code = Artisan::call('artworks:vectors-index', [
|
|
'--dry-run' => true,
|
|
'--public-only' => true,
|
|
'--limit' => 2,
|
|
'--batch' => 2,
|
|
'--order' => 'id-asc',
|
|
]);
|
|
|
|
$output = Artisan::output();
|
|
|
|
expect($code)->toBe(0);
|
|
|
|
$firstPos = strpos($output, 'Processing artwork=' . $first->id);
|
|
$secondPos = strpos($output, 'Processing artwork=' . $second->id);
|
|
|
|
expect($firstPos)->not->toBeFalse()
|
|
->and($secondPos)->not->toBeFalse()
|
|
->and($firstPos)->toBeLessThan($secondPos);
|
|
}); |