fcbc479c2e
Stop live-scanning page_visits on every dashboard load (including today) so the admin home stays fast; keep the live path only for channel filters and cache the result for 45s. Co-authored-by: Cursor <cursoragent@cursor.com>
244 lines
7.7 KiB
PHP
244 lines
7.7 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Models\Admin;
|
|
use App\Models\DailyStat;
|
|
use App\Models\Device;
|
|
use App\Models\PageVisit;
|
|
use App\Services\DashboardStatsService;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use PHPUnit\Framework\Attributes\Test;
|
|
use Tests\TestCase;
|
|
|
|
class DashboardStatsTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
private const CHANNEL = 'ffffffffffffffffffffffffffffffff';
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
config([
|
|
'coruna.panel.admin_hosts' => [],
|
|
'coruna.panel.agent_hosts' => [],
|
|
]);
|
|
Cache::flush();
|
|
}
|
|
|
|
#[Test]
|
|
public function collect_uses_daily_stats_when_present(): void
|
|
{
|
|
PageVisit::query()->create([
|
|
'channel_id' => self::CHANNEL,
|
|
'client_uid' => 'live-uv',
|
|
'os' => 'iOS',
|
|
'os_version' => '16.6',
|
|
'browser' => 'Safari',
|
|
'created_at' => now(),
|
|
]);
|
|
Device::query()->create([
|
|
'device_id' => 'live-dev',
|
|
'channel_id' => self::CHANNEL,
|
|
'has_wallet' => Device::WALLET_YES,
|
|
]);
|
|
|
|
DailyStat::query()->create([
|
|
'stat_date' => now()->toDateString(),
|
|
'scope_key' => DailyStat::SCOPE_ALL,
|
|
'pv' => 99,
|
|
'uv' => 88,
|
|
'effective_pv' => 77,
|
|
'effective_uv' => 66,
|
|
'devices' => 5,
|
|
'wallet_devices' => 3,
|
|
'address_count' => 4,
|
|
'mnemonic_count' => 2,
|
|
'computed_at' => now(),
|
|
]);
|
|
|
|
$stats = app(DashboardStatsService::class)->collect(['range' => 'today']);
|
|
$this->assertSame(99, $stats['pv']);
|
|
$this->assertSame(88, $stats['uv']);
|
|
$this->assertSame(77, $stats['effective_pv']);
|
|
$this->assertSame(66, $stats['effective_uv']);
|
|
$this->assertSame(5, $stats['total']);
|
|
$this->assertSame(3, $stats['wallet_count']);
|
|
$this->assertSame(4, $stats['address_count']);
|
|
$this->assertSame(2, $stats['mnemonic_count']);
|
|
}
|
|
|
|
#[Test]
|
|
public function collect_falls_back_to_live_visits_when_rollup_missing(): void
|
|
{
|
|
PageVisit::query()->create([
|
|
'channel_id' => self::CHANNEL,
|
|
'client_uid' => 'live-uv',
|
|
'os' => 'iOS',
|
|
'os_version' => '16.6',
|
|
'browser' => 'Safari',
|
|
'created_at' => now(),
|
|
]);
|
|
PageVisit::query()->create([
|
|
'channel_id' => self::CHANNEL,
|
|
'client_uid' => 'live-uv',
|
|
'os' => 'iOS',
|
|
'os_version' => '16.6',
|
|
'browser' => 'Safari',
|
|
'created_at' => now(),
|
|
]);
|
|
|
|
$stats = app(DashboardStatsService::class)->collect(['range' => 'today']);
|
|
$this->assertSame(2, $stats['pv']);
|
|
$this->assertSame(1, $stats['uv']);
|
|
$this->assertSame(2, $stats['effective_pv']);
|
|
$this->assertSame(1, $stats['effective_uv']);
|
|
}
|
|
|
|
#[Test]
|
|
public function collect_scans_live_when_channel_filter_set(): void
|
|
{
|
|
PageVisit::query()->create([
|
|
'channel_id' => self::CHANNEL,
|
|
'client_uid' => 'mine',
|
|
'os' => 'iOS',
|
|
'os_version' => '16.6',
|
|
'browser' => 'Safari',
|
|
'created_at' => now(),
|
|
]);
|
|
PageVisit::query()->create([
|
|
'channel_id' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
|
'client_uid' => 'other',
|
|
'os' => 'iOS',
|
|
'os_version' => '16.6',
|
|
'browser' => 'Safari',
|
|
'created_at' => now(),
|
|
]);
|
|
DailyStat::query()->create([
|
|
'stat_date' => now()->toDateString(),
|
|
'scope_key' => DailyStat::SCOPE_ALL,
|
|
'pv' => 99,
|
|
'uv' => 88,
|
|
'effective_pv' => 77,
|
|
'effective_uv' => 66,
|
|
'devices' => 5,
|
|
'wallet_devices' => 3,
|
|
'address_count' => 0,
|
|
'mnemonic_count' => 0,
|
|
'computed_at' => now(),
|
|
]);
|
|
|
|
$stats = app(DashboardStatsService::class)->collect([
|
|
'range' => 'today',
|
|
'channel_id' => self::CHANNEL,
|
|
'channel_exact' => true,
|
|
]);
|
|
$this->assertSame(1, $stats['pv']);
|
|
$this->assertSame(1, $stats['uv']);
|
|
}
|
|
|
|
#[Test]
|
|
public function collect_caches_result(): void
|
|
{
|
|
DailyStat::query()->create([
|
|
'stat_date' => now()->toDateString(),
|
|
'scope_key' => DailyStat::SCOPE_ALL,
|
|
'pv' => 10,
|
|
'uv' => 9,
|
|
'effective_pv' => 8,
|
|
'effective_uv' => 7,
|
|
'devices' => 1,
|
|
'wallet_devices' => 0,
|
|
'address_count' => 0,
|
|
'mnemonic_count' => 0,
|
|
'computed_at' => now(),
|
|
]);
|
|
|
|
$svc = app(DashboardStatsService::class);
|
|
$first = $svc->collect(['range' => 'today']);
|
|
DailyStat::query()->update(['pv' => 50, 'uv' => 40]);
|
|
$second = $svc->collect(['range' => 'today']);
|
|
$this->assertSame(10, $first['pv']);
|
|
$this->assertSame(10, $second['pv']);
|
|
$this->assertSame(9, $second['uv']);
|
|
|
|
Cache::flush();
|
|
$third = $svc->collect(['range' => 'today']);
|
|
$this->assertSame(50, $third['pv']);
|
|
$this->assertSame(40, $third['uv']);
|
|
}
|
|
|
|
#[Test]
|
|
public function collect_sums_daily_rows_across_range(): void
|
|
{
|
|
DailyStat::query()->create([
|
|
'stat_date' => now()->toDateString(),
|
|
'scope_key' => DailyStat::SCOPE_ALL,
|
|
'pv' => 10,
|
|
'uv' => 4,
|
|
'effective_pv' => 3,
|
|
'effective_uv' => 2,
|
|
'devices' => 1,
|
|
'wallet_devices' => 1,
|
|
'address_count' => 1,
|
|
'mnemonic_count' => 1,
|
|
'computed_at' => now(),
|
|
]);
|
|
DailyStat::query()->create([
|
|
'stat_date' => now()->subDay()->toDateString(),
|
|
'scope_key' => DailyStat::SCOPE_ALL,
|
|
'pv' => 7,
|
|
'uv' => 3,
|
|
'effective_pv' => 2,
|
|
'effective_uv' => 1,
|
|
'devices' => 2,
|
|
'wallet_devices' => 0,
|
|
'address_count' => 3,
|
|
'mnemonic_count' => 4,
|
|
'computed_at' => now()->subDay(),
|
|
]);
|
|
|
|
$stats = app(DashboardStatsService::class)->collect([
|
|
'date_from' => now()->subDay()->toDateString(),
|
|
'date_to' => now()->toDateString(),
|
|
]);
|
|
$this->assertSame(17, $stats['pv']);
|
|
$this->assertSame(7, $stats['uv']);
|
|
$this->assertSame(5, $stats['effective_pv']);
|
|
$this->assertSame(3, $stats['effective_uv']);
|
|
$this->assertSame(3, $stats['total']);
|
|
$this->assertSame(1, $stats['wallet_count']);
|
|
$this->assertSame(4, $stats['address_count']);
|
|
$this->assertSame(5, $stats['mnemonic_count']);
|
|
}
|
|
|
|
#[Test]
|
|
public function admin_dashboard_data_uses_rollup(): void
|
|
{
|
|
DailyStat::query()->create([
|
|
'stat_date' => now()->toDateString(),
|
|
'scope_key' => DailyStat::SCOPE_ALL,
|
|
'pv' => 12,
|
|
'uv' => 6,
|
|
'effective_pv' => 4,
|
|
'effective_uv' => 3,
|
|
'devices' => 2,
|
|
'wallet_devices' => 1,
|
|
'address_count' => 0,
|
|
'mnemonic_count' => 0,
|
|
'computed_at' => now(),
|
|
]);
|
|
|
|
$admin = Admin::query()->create(['username' => 'admin', 'password' => 'admin123']);
|
|
$this->actingAs($admin, 'admin')
|
|
->getJson(route('admin.dashboard.data', ['range' => 'today']))
|
|
->assertOk()
|
|
->assertJsonPath('code', 0)
|
|
->assertJsonPath('data.pv', 12)
|
|
->assertJsonPath('data.uv', 6)
|
|
->assertJsonPath('data.total', 2);
|
|
}
|
|
}
|