Files
ladill-meet/tests/Feature/MeetBillingTest.php
T
isaaccladandCursor 59b59cb70e
Deploy Ladill Meet / deploy (push) Successful in 54s
Bill Meet streaming hourly and storage per GB like Transfer.
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>
2026-07-01 16:33:45 +00:00

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);
}
}