Files
coolify/tests/Feature/Server/ServerSettingSentinelRestartTest.php
T
Aditya Tripathi 19752da6af feat(analytics): lazy-load traffic pages and batch Sentinel calls
- Mark Analytics, Dashboard\TrafficAnalytics and Project\Application\Analytics
  Livewire components #[Lazy] with skeleton placeholder() views so pages render
  instantly while Sentinel data loads in a deferred request
- Add SentinelTrafficClient::prefetchServerWide() to warm all server-wide
  endpoints in a single batched docker exec instead of ~14-15 serial SSH
  round-trips, and refactor overview/paths/breakdown URL building into shared
  helpers
- Cap per-app leaderboard overviews fetched via MAX_LEADERBOARD_APPS to bound
  requests on servers with many apps
- Add hasRequestSeries() to detect empty request charts and render a no-data
  state instead of a blank chart
- Gate ServerSetting's automatic Sentinel restart on is_sentinel_enabled so
  tuning geoip/traffic settings no longer silently enables Sentinel
- Add reusable skeleton UI components (skeleton, skeleton/table, skeleton/tiles)
  for the new placeholder views
2026-08-22 11:13:49 +00:00

195 lines
5.9 KiB
PHP

<?php
use App\Actions\Server\StartSentinel;
use App\Models\Server;
use App\Models\ServerSetting;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Queue;
use Lorisleiva\Actions\Decorators\JobDecorator;
uses(RefreshDatabase::class);
function isStartSentinelJob($job): bool
{
return $job instanceof JobDecorator && $job->getAction() instanceof StartSentinel;
}
beforeEach(function () {
Queue::fake();
// Create user (which automatically creates a team)
$user = User::factory()->create();
$this->team = $user->teams()->first();
// Create server with the team
$this->server = Server::factory()->create([
'team_id' => $this->team->id,
]);
});
it('detects sentinel_token changes with wasChanged', function () {
$changeDetected = false;
// Register a test listener that will be called after the model's booted listeners
ServerSetting::updated(function ($settings) use (&$changeDetected) {
if ($settings->wasChanged('sentinel_token')) {
$changeDetected = true;
}
});
$settings = $this->server->settings;
$settings->sentinel_token = 'new-token-value';
$settings->save();
expect($changeDetected)->toBeTrue();
});
it('detects sentinel_custom_url changes with wasChanged', function () {
$changeDetected = false;
ServerSetting::updated(function ($settings) use (&$changeDetected) {
if ($settings->wasChanged('sentinel_custom_url')) {
$changeDetected = true;
}
});
$settings = $this->server->settings;
$settings->sentinel_custom_url = 'https://new-url.com';
$settings->save();
expect($changeDetected)->toBeTrue();
});
it('detects sentinel_metrics_refresh_rate_seconds changes with wasChanged', function () {
$changeDetected = false;
ServerSetting::updated(function ($settings) use (&$changeDetected) {
if ($settings->wasChanged('sentinel_metrics_refresh_rate_seconds')) {
$changeDetected = true;
}
});
$settings = $this->server->settings;
$settings->sentinel_metrics_refresh_rate_seconds = 60;
$settings->save();
expect($changeDetected)->toBeTrue();
});
it('detects sentinel_metrics_history_days changes with wasChanged', function () {
$changeDetected = false;
ServerSetting::updated(function ($settings) use (&$changeDetected) {
if ($settings->wasChanged('sentinel_metrics_history_days')) {
$changeDetected = true;
}
});
$settings = $this->server->settings;
$settings->sentinel_metrics_history_days = 14;
$settings->save();
expect($changeDetected)->toBeTrue();
});
it('detects sentinel_push_interval_seconds changes with wasChanged', function () {
$changeDetected = false;
ServerSetting::updated(function ($settings) use (&$changeDetected) {
if ($settings->wasChanged('sentinel_push_interval_seconds')) {
$changeDetected = true;
}
});
$settings = $this->server->settings;
$settings->sentinel_push_interval_seconds = 30;
$settings->save();
expect($changeDetected)->toBeTrue();
});
it('does not detect changes when unrelated field is changed', function () {
$changeDetected = false;
ServerSetting::updated(function ($settings) use (&$changeDetected) {
if (
$settings->wasChanged('sentinel_token') ||
$settings->wasChanged('sentinel_custom_url') ||
$settings->wasChanged('sentinel_metrics_refresh_rate_seconds') ||
$settings->wasChanged('sentinel_metrics_history_days') ||
$settings->wasChanged('sentinel_push_interval_seconds') ||
$settings->wasChanged('traffic_topn') ||
$settings->wasChanged('traffic_sample_threshold') ||
$settings->wasChanged('traffic_retention_1h_days') ||
$settings->wasChanged('traffic_retention_1d_days') ||
$settings->wasChanged('is_geoip_enabled') ||
$settings->wasChanged('geoip_refresh_days') ||
$settings->wasChanged('geoip_maxmind_license_key')
) {
$changeDetected = true;
}
});
$settings = $this->server->settings;
$settings->is_reachable = ! $settings->is_reachable;
$settings->save();
expect($changeDetected)->toBeFalse();
});
it('detects traffic analytics setting changes with wasChanged', function () {
$changeDetected = false;
ServerSetting::updated(function ($settings) use (&$changeDetected) {
if ($settings->wasChanged('traffic_topn')) {
$changeDetected = true;
}
});
$settings = $this->server->settings;
$settings->traffic_topn = 200;
$settings->save();
expect($changeDetected)->toBeTrue();
});
it('does not restart sentinel when a traffic knob changes while sentinel is disabled', function () {
$settings = $this->server->settings;
$settings->is_sentinel_enabled = false;
$settings->save();
$settings->traffic_topn = 999;
$settings->save();
Queue::assertNotPushed(JobDecorator::class, fn ($job) => isStartSentinelJob($job));
});
it('restarts sentinel when a traffic knob changes while sentinel is enabled', function () {
$settings = $this->server->settings;
$settings->is_sentinel_enabled = true;
$settings->save();
$settings->traffic_topn = 888;
$settings->save();
Queue::assertPushed(JobDecorator::class, fn ($job) => isStartSentinelJob($job));
});
it('does not detect changes when sentinel field is set to same value', function () {
$changeDetected = false;
ServerSetting::updated(function ($settings) use (&$changeDetected) {
if ($settings->wasChanged('sentinel_token')) {
$changeDetected = true;
}
});
$settings = $this->server->settings;
$currentToken = $settings->sentinel_token;
$settings->sentinel_token = $currentToken;
$settings->save();
expect($changeDetected)->toBeFalse();
});