mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-29 06:01:26 +00:00
168 lines
5.8 KiB
PHP
168 lines
5.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Unit;
|
|
|
|
use App\Models\UserActivityStat;
|
|
use App\Services\UserStatsService;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Database\Schema\Blueprint;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Schema;
|
|
use Tests\TestCase;
|
|
|
|
final class UserActivityStatsTest extends TestCase
|
|
{
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
config([
|
|
'database.default' => 'sqlite',
|
|
'database.connections.sqlite.database' => ':memory:',
|
|
'cache.default' => 'array',
|
|
]);
|
|
DB::purge();
|
|
DB::reconnect();
|
|
Cache::flush();
|
|
Carbon::setTestNow('2026-07-20 14:37:00');
|
|
|
|
Schema::create('users', function (Blueprint $table): void {
|
|
$table->id();
|
|
$table->dateTime('deleted_at')->nullable();
|
|
});
|
|
Schema::create('settings', function (Blueprint $table): void {
|
|
$table->string('name')->primary();
|
|
$table->text('value')->nullable();
|
|
});
|
|
Schema::create('user_requests', function (Blueprint $table): void {
|
|
$table->id();
|
|
$table->unsignedBigInteger('users_id');
|
|
$table->text('request');
|
|
$table->dateTime('timestamp');
|
|
});
|
|
Schema::create('user_downloads', function (Blueprint $table): void {
|
|
$table->id();
|
|
$table->unsignedBigInteger('users_id');
|
|
$table->dateTime('timestamp');
|
|
});
|
|
Schema::create('user_activity_stats', function (Blueprint $table): void {
|
|
$table->id();
|
|
$table->date('stat_date')->unique();
|
|
$table->integer('downloads_count')->default(0);
|
|
$table->integer('api_hits_count')->default(0);
|
|
$table->timestamps();
|
|
});
|
|
Schema::create('user_activity_stats_hourly', function (Blueprint $table): void {
|
|
$table->id();
|
|
$table->dateTime('stat_hour')->unique();
|
|
$table->integer('downloads_count')->default(0);
|
|
$table->integer('api_hits_count')->default(0);
|
|
$table->timestamps();
|
|
});
|
|
|
|
DB::table('users')->insert(['id' => 1]);
|
|
DB::table('settings')->insert([
|
|
['name' => 'categorizeforeign', 'value' => '0'],
|
|
['name' => 'catwebdl', 'value' => '0'],
|
|
['name' => 'delaytime', 'value' => '0'],
|
|
['name' => 'innerfileblacklist', 'value' => ''],
|
|
]);
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
Carbon::setTestNow();
|
|
|
|
parent::tearDown();
|
|
}
|
|
|
|
public function test_summary_and_charts_combine_hourly_api_and_rss_hits_with_the_live_hour(): void
|
|
{
|
|
$this->insertHourly('2026-07-14 09:00:00', 3, 7);
|
|
$this->insertHourly('2026-07-20 13:00:00', 2, 4);
|
|
|
|
DB::table('user_activity_stats')->insert([
|
|
'stat_date' => '2026-07-19',
|
|
'downloads_count' => 999,
|
|
'api_hits_count' => 999,
|
|
]);
|
|
DB::table('user_requests')->insert([
|
|
['users_id' => 1, 'request' => '/api/v2/search?id=one', 'timestamp' => '2026-07-20 14:37:00'],
|
|
['users_id' => 1, 'request' => '/rss/full-feed?api_token=test', 'timestamp' => '2026-07-20 14:37:30'],
|
|
]);
|
|
DB::table('user_downloads')->insert([
|
|
'users_id' => 1,
|
|
'timestamp' => '2026-07-20 14:36:00',
|
|
]);
|
|
|
|
$service = new UserStatsService;
|
|
$summary = $service->getSummaryStats();
|
|
|
|
$this->assertSame(6, $summary['api_hits_today']);
|
|
$this->assertSame(13, $summary['api_hits_week']);
|
|
$this->assertSame(3, $summary['downloads_today']);
|
|
$this->assertSame(6, $summary['downloads_week']);
|
|
|
|
$hourly = $service->getApiHitsPerHour(2);
|
|
$this->assertSame([4, 2], array_column($hourly, 'count'));
|
|
|
|
$daily = $service->getApiHitsPerDay(7);
|
|
$this->assertSame(7, $daily[0]['count']);
|
|
$this->assertSame(6, $daily[6]['count']);
|
|
|
|
$perMinute = $service->getApiHitsPerMinute(60);
|
|
$this->assertSame(2, $perMinute[59]['count']);
|
|
}
|
|
|
|
public function test_daily_rollup_remains_stable_after_raw_rows_are_pruned(): void
|
|
{
|
|
$this->insertHourly('2026-07-19 01:00:00', 2, 3);
|
|
$this->insertHourly('2026-07-19 23:00:00', 4, 5);
|
|
DB::table('user_requests')->insert([
|
|
'users_id' => 1,
|
|
'request' => '/api/v1/api?t=search',
|
|
'timestamp' => '2026-07-19 23:30:00',
|
|
]);
|
|
|
|
UserActivityStat::collectDailyStats('2026-07-19');
|
|
DB::table('user_requests')->delete();
|
|
UserActivityStat::collectDailyStats('2026-07-19');
|
|
|
|
$daily = DB::table('user_activity_stats')->where('stat_date', '2026-07-19')->first();
|
|
$this->assertSame(6, $daily->downloads_count);
|
|
$this->assertSame(8, $daily->api_hits_count);
|
|
}
|
|
|
|
public function test_forced_daily_backfill_rebuilds_retained_history_from_hourly_totals(): void
|
|
{
|
|
$this->insertHourly('2026-07-19 10:00:00', 11, 17);
|
|
DB::table('user_activity_stats')->insert([
|
|
'stat_date' => '2026-07-19',
|
|
'downloads_count' => 1,
|
|
'api_hits_count' => 1,
|
|
]);
|
|
|
|
$this->artisan('nntmux:backfill-user-activity-stats', [
|
|
'--type' => 'daily',
|
|
'--days' => 2,
|
|
'--force' => true,
|
|
])->assertSuccessful();
|
|
|
|
$daily = DB::table('user_activity_stats')->where('stat_date', '2026-07-19')->first();
|
|
$this->assertSame(11, $daily->downloads_count);
|
|
$this->assertSame(17, $daily->api_hits_count);
|
|
}
|
|
|
|
private function insertHourly(string $hour, int $downloads, int $apiHits): void
|
|
{
|
|
DB::table('user_activity_stats_hourly')->insert([
|
|
'stat_hour' => $hour,
|
|
'downloads_count' => $downloads,
|
|
'api_hits_count' => $apiHits,
|
|
]);
|
|
}
|
|
}
|