148 lines
4.9 KiB
PHP
148 lines
4.9 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature\Ai;
|
|
|
|
use App\Models\AiEditOutput;
|
|
use App\Models\AiEditRequest;
|
|
use App\Models\AiProviderRun;
|
|
use App\Models\AiStyle;
|
|
use App\Models\AiUsageLedger;
|
|
use App\Models\Photo;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Schema;
|
|
use Tests\TestCase;
|
|
|
|
class AiEditingDataModelTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
public function test_ai_tables_exist_with_expected_key_columns(): void
|
|
{
|
|
$this->assertTrue(Schema::hasTable('ai_styles'));
|
|
$this->assertTrue(Schema::hasTable('ai_edit_requests'));
|
|
$this->assertTrue(Schema::hasTable('ai_edit_outputs'));
|
|
$this->assertTrue(Schema::hasTable('ai_provider_runs'));
|
|
$this->assertTrue(Schema::hasTable('ai_usage_ledgers'));
|
|
|
|
foreach ([
|
|
'key',
|
|
'provider',
|
|
'provider_model',
|
|
'requires_source_image',
|
|
'is_premium',
|
|
] as $column) {
|
|
$this->assertTrue(Schema::hasColumn('ai_styles', $column));
|
|
}
|
|
|
|
foreach ([
|
|
'tenant_id',
|
|
'event_id',
|
|
'photo_id',
|
|
'style_id',
|
|
'provider',
|
|
'idempotency_key',
|
|
'safety_state',
|
|
'status',
|
|
] as $column) {
|
|
$this->assertTrue(Schema::hasColumn('ai_edit_requests', $column));
|
|
}
|
|
|
|
foreach ([
|
|
'request_id',
|
|
'provider',
|
|
'provider_task_id',
|
|
'request_payload',
|
|
'response_payload',
|
|
'cost_usd',
|
|
] as $column) {
|
|
$this->assertTrue(Schema::hasColumn('ai_provider_runs', $column));
|
|
}
|
|
}
|
|
|
|
public function test_ai_edit_flow_records_request_run_output_and_usage_with_relations(): void
|
|
{
|
|
$photo = Photo::factory()->create();
|
|
$event = $photo->event;
|
|
$tenant = $event->tenant;
|
|
$user = User::factory()->create(['tenant_id' => $tenant->id]);
|
|
|
|
$style = AiStyle::query()->create([
|
|
'key' => 'bg-colosseum',
|
|
'name' => 'Colosseum Background',
|
|
'provider' => 'runware',
|
|
'provider_model' => 'runware-default',
|
|
'requires_source_image' => true,
|
|
'is_active' => true,
|
|
]);
|
|
|
|
$request = AiEditRequest::query()->create([
|
|
'tenant_id' => $tenant->id,
|
|
'event_id' => $event->id,
|
|
'photo_id' => $photo->id,
|
|
'style_id' => $style->id,
|
|
'requested_by_user_id' => $user->id,
|
|
'provider' => 'runware',
|
|
'provider_model' => 'runware-default',
|
|
'status' => AiEditRequest::STATUS_QUEUED,
|
|
'safety_state' => 'pending',
|
|
'prompt' => 'Replace background with Colosseum in Rome.',
|
|
'idempotency_key' => 'req-'.$photo->id.'-1',
|
|
'queued_at' => now(),
|
|
'metadata' => ['source' => 'guest_pwa'],
|
|
]);
|
|
|
|
$run = AiProviderRun::query()->create([
|
|
'request_id' => $request->id,
|
|
'provider' => 'runware',
|
|
'attempt' => 1,
|
|
'provider_task_id' => 'task-123',
|
|
'status' => AiProviderRun::STATUS_RUNNING,
|
|
'request_payload' => ['positivePrompt' => 'Rome Colosseum'],
|
|
'response_payload' => ['status' => 'processing'],
|
|
'started_at' => now(),
|
|
]);
|
|
|
|
$output = AiEditOutput::query()->create([
|
|
'request_id' => $request->id,
|
|
'storage_disk' => 'public',
|
|
'storage_path' => 'ai/outputs/final.jpg',
|
|
'mime_type' => 'image/jpeg',
|
|
'width' => 1024,
|
|
'height' => 1024,
|
|
'is_primary' => true,
|
|
'generated_at' => now(),
|
|
'metadata' => ['variant' => 'v1'],
|
|
]);
|
|
|
|
$ledger = AiUsageLedger::query()->create([
|
|
'tenant_id' => $tenant->id,
|
|
'event_id' => $event->id,
|
|
'request_id' => $request->id,
|
|
'entry_type' => AiUsageLedger::TYPE_DEBIT,
|
|
'quantity' => 1,
|
|
'unit_cost_usd' => 0.015,
|
|
'amount_usd' => 0.015,
|
|
'recorded_at' => now(),
|
|
'metadata' => ['provider' => 'runware'],
|
|
]);
|
|
|
|
$request->refresh();
|
|
$run->refresh();
|
|
$output->refresh();
|
|
$ledger->refresh();
|
|
|
|
$this->assertSame($style->id, $request->style?->id);
|
|
$this->assertSame($tenant->id, $request->tenant?->id);
|
|
$this->assertSame($event->id, $request->event?->id);
|
|
$this->assertSame($photo->id, $request->photo?->id);
|
|
$this->assertSame(1, $request->providerRuns()->count());
|
|
$this->assertSame(1, $request->outputs()->count());
|
|
$this->assertSame(1, $request->usageLedgers()->count());
|
|
$this->assertIsArray($run->request_payload);
|
|
$this->assertIsArray($run->response_payload);
|
|
$this->assertIsArray($ledger->metadata);
|
|
$this->assertGreaterThan(0, (float) $ledger->amount_usd);
|
|
}
|
|
}
|