Deploy Ladill Meet / deploy (push) Successful in 54s
Wallet debits at session end, on recording/file storage, and via daily renewals with grace period before asset deletion. Co-authored-by: Cursor <cursoragent@cursor.com>
121 lines
3.7 KiB
PHP
121 lines
3.7 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Models\Organization;
|
|
use App\Models\Room;
|
|
use App\Models\Session;
|
|
use App\Services\Meet\MeetBillingService;
|
|
use App\Services\Meet\UsageMeteringService;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Tests\TestCase;
|
|
|
|
class MeetBillingTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
protected function fakeAffordableBilling(): void
|
|
{
|
|
$base = rtrim((string) config('billing.api_url'), '/');
|
|
|
|
Http::fake([
|
|
$base.'/can-afford*' => Http::response(['affordable' => true]),
|
|
$base.'/debit' => Http::response(['ok' => true]),
|
|
]);
|
|
}
|
|
|
|
public function test_session_end_records_streaming_usage_and_debits_wallet(): void
|
|
{
|
|
$this->fakeAffordableBilling();
|
|
|
|
$organization = Organization::create([
|
|
'owner_ref' => 'owner-001',
|
|
'name' => 'Billing Org',
|
|
'slug' => 'billing-org',
|
|
'timezone' => 'UTC',
|
|
]);
|
|
|
|
$room = Room::create([
|
|
'owner_ref' => 'owner-001',
|
|
'organization_id' => $organization->id,
|
|
'host_user_ref' => 'owner-001',
|
|
'title' => 'Billing Room',
|
|
'type' => 'instant',
|
|
'status' => 'live',
|
|
'settings' => config('meet.default_settings'),
|
|
]);
|
|
|
|
$session = Session::create([
|
|
'owner_ref' => 'owner-001',
|
|
'room_id' => $room->id,
|
|
'media_room_name' => 'room-test',
|
|
'status' => 'ended',
|
|
'started_at' => now()->subHour(),
|
|
'ended_at' => now(),
|
|
]);
|
|
|
|
app(UsageMeteringService::class)->recordSessionUsage($session);
|
|
|
|
$this->assertDatabaseHas('meet_usage_records', [
|
|
'organization_id' => $organization->id,
|
|
'metric' => 'streaming_hours',
|
|
]);
|
|
|
|
Http::assertSent(fn ($request) => str_contains($request->url(), '/debit')
|
|
&& ($request->data()['source'] ?? '') === 'meet_streaming');
|
|
}
|
|
|
|
public function test_storage_renewal_enters_grace_when_wallet_is_empty(): void
|
|
{
|
|
$base = rtrim((string) config('billing.api_url'), '/');
|
|
Http::fake([
|
|
$base.'/can-afford*' => Http::response(['affordable' => false]),
|
|
]);
|
|
|
|
$organization = Organization::create([
|
|
'owner_ref' => 'owner-002',
|
|
'name' => 'Grace Org',
|
|
'slug' => 'grace-org',
|
|
'timezone' => 'UTC',
|
|
]);
|
|
|
|
$room = Room::create([
|
|
'owner_ref' => 'owner-002',
|
|
'organization_id' => $organization->id,
|
|
'host_user_ref' => 'owner-002',
|
|
'title' => 'Grace Room',
|
|
'type' => 'instant',
|
|
'status' => 'ended',
|
|
'settings' => config('meet.default_settings'),
|
|
]);
|
|
|
|
$session = Session::create([
|
|
'owner_ref' => 'owner-002',
|
|
'room_id' => $room->id,
|
|
'media_room_name' => 'room-grace',
|
|
'status' => 'ended',
|
|
'started_at' => now()->subDay(),
|
|
'ended_at' => now()->subDay(),
|
|
]);
|
|
|
|
$file = \App\Models\SessionFile::create([
|
|
'owner_ref' => 'owner-002',
|
|
'room_id' => $room->id,
|
|
'session_id' => $session->id,
|
|
'uploaded_by_ref' => 'owner-002',
|
|
'uploaded_by_name' => 'Host',
|
|
'original_name' => 'notes.pdf',
|
|
'storage_path' => 'meet-files/test/notes.pdf',
|
|
'file_size' => 1073741824,
|
|
'storage_paid_until' => now()->subMinute(),
|
|
]);
|
|
|
|
$result = app(MeetBillingService::class)->processDueStorageRenewals();
|
|
|
|
$file->refresh();
|
|
$this->assertSame(1, $result['graced']);
|
|
$this->assertNotNull($file->storage_grace_ends_at);
|
|
}
|
|
}
|