feat(ai): finalize AI magic edits epic rollout and operations
This commit is contained in:
126
tests/Unit/Services/AiBudgetGuardServiceTest.php
Normal file
126
tests/Unit/Services/AiBudgetGuardServiceTest.php
Normal file
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services;
|
||||
|
||||
use App\Models\AiUsageLedger;
|
||||
use App\Models\Event;
|
||||
use App\Models\User;
|
||||
use App\Services\AiEditing\AiBudgetGuardService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AiBudgetGuardServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
Cache::flush();
|
||||
}
|
||||
|
||||
public function test_it_allows_requests_when_spend_is_below_caps(): void
|
||||
{
|
||||
$event = Event::factory()->create(['status' => 'published']);
|
||||
|
||||
$settings = (array) ($event->tenant->settings ?? []);
|
||||
data_set($settings, 'ai_editing.budget.soft_cap_usd', 10.0);
|
||||
data_set($settings, 'ai_editing.budget.hard_cap_usd', 20.0);
|
||||
$event->tenant->update(['settings' => $settings]);
|
||||
|
||||
AiUsageLedger::query()->create([
|
||||
'tenant_id' => $event->tenant_id,
|
||||
'event_id' => $event->id,
|
||||
'entry_type' => AiUsageLedger::TYPE_DEBIT,
|
||||
'quantity' => 1,
|
||||
'unit_cost_usd' => 3.0,
|
||||
'amount_usd' => 3.0,
|
||||
'currency' => 'USD',
|
||||
'recorded_at' => now(),
|
||||
]);
|
||||
|
||||
$decision = app(AiBudgetGuardService::class)->evaluateForEvent($event->fresh('tenant'));
|
||||
|
||||
$this->assertTrue($decision['allowed']);
|
||||
$this->assertFalse($decision['budget']['soft_reached']);
|
||||
$this->assertFalse($decision['budget']['hard_reached']);
|
||||
$this->assertSame(3.0, $decision['budget']['current_spend_usd']);
|
||||
}
|
||||
|
||||
public function test_it_blocks_requests_when_hard_cap_is_reached_without_override(): void
|
||||
{
|
||||
$event = Event::factory()->create(['status' => 'published']);
|
||||
$owner = User::factory()->create();
|
||||
$event->tenant->update(['user_id' => $owner->id]);
|
||||
|
||||
$settings = (array) ($event->tenant->settings ?? []);
|
||||
data_set($settings, 'ai_editing.budget.hard_cap_usd', 5.0);
|
||||
$event->tenant->update(['settings' => $settings]);
|
||||
|
||||
AiUsageLedger::query()->create([
|
||||
'tenant_id' => $event->tenant_id,
|
||||
'event_id' => $event->id,
|
||||
'entry_type' => AiUsageLedger::TYPE_DEBIT,
|
||||
'quantity' => 1,
|
||||
'unit_cost_usd' => 5.0,
|
||||
'amount_usd' => 5.0,
|
||||
'currency' => 'USD',
|
||||
'recorded_at' => now(),
|
||||
]);
|
||||
|
||||
$decision = app(AiBudgetGuardService::class)->evaluateForEvent($event->fresh('tenant'));
|
||||
|
||||
$this->assertFalse($decision['allowed']);
|
||||
$this->assertSame('budget_hard_cap_reached', $decision['reason_code']);
|
||||
$this->assertTrue($decision['budget']['hard_reached']);
|
||||
$this->assertFalse($decision['budget']['override_active']);
|
||||
|
||||
$this->assertDatabaseHas('tenant_notification_logs', [
|
||||
'tenant_id' => $event->tenant_id,
|
||||
'type' => 'ai_budget_hard_cap',
|
||||
'channel' => 'system',
|
||||
'status' => 'sent',
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('tenant_notification_receipts', [
|
||||
'tenant_id' => $event->tenant_id,
|
||||
'user_id' => $owner->id,
|
||||
'status' => 'delivered',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_it_throttles_soft_cap_notifications_with_cooldown(): void
|
||||
{
|
||||
$event = Event::factory()->create(['status' => 'published']);
|
||||
|
||||
$settings = (array) ($event->tenant->settings ?? []);
|
||||
data_set($settings, 'ai_editing.budget.soft_cap_usd', 2.0);
|
||||
data_set($settings, 'ai_editing.budget.hard_cap_usd', 100.0);
|
||||
$event->tenant->update(['settings' => $settings]);
|
||||
|
||||
AiUsageLedger::query()->create([
|
||||
'tenant_id' => $event->tenant_id,
|
||||
'event_id' => $event->id,
|
||||
'entry_type' => AiUsageLedger::TYPE_DEBIT,
|
||||
'quantity' => 1,
|
||||
'unit_cost_usd' => 3.0,
|
||||
'amount_usd' => 3.0,
|
||||
'currency' => 'USD',
|
||||
'recorded_at' => now(),
|
||||
]);
|
||||
|
||||
$service = app(AiBudgetGuardService::class);
|
||||
$service->evaluateForEvent($event->fresh('tenant'));
|
||||
$service->evaluateForEvent($event->fresh('tenant'));
|
||||
|
||||
$this->assertSame(
|
||||
1,
|
||||
\App\Models\TenantNotificationLog::query()
|
||||
->where('tenant_id', $event->tenant_id)
|
||||
->where('type', 'ai_budget_soft_cap')
|
||||
->count()
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user