From 0ca5596b1f78550bf8cacc96a5ea7c4a427befb7 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Tue, 3 Mar 2026 17:03:59 +0100 Subject: [PATCH] fix(server-limit): re-enable force-disabled servers at limit Handle non-positive disable counts with `<= 0` so teams at or under the server limit correctly re-enable force-disabled servers. Add a feature test suite for ServerLimitCheckJob covering under-limit, at-limit, over-limit, and no-op behavior. --- app/Jobs/ServerLimitCheckJob.php | 2 +- tests/Feature/ServerLimitCheckJobTest.php | 83 +++++++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 tests/Feature/ServerLimitCheckJobTest.php diff --git a/app/Jobs/ServerLimitCheckJob.php b/app/Jobs/ServerLimitCheckJob.php index aa82c6dad..06e94fc93 100644 --- a/app/Jobs/ServerLimitCheckJob.php +++ b/app/Jobs/ServerLimitCheckJob.php @@ -38,7 +38,7 @@ public function handle() $server->forceDisableServer(); $this->team->notify(new ForceDisabled($server)); }); - } elseif ($number_of_servers_to_disable === 0) { + } elseif ($number_of_servers_to_disable <= 0) { $servers->each(function ($server) { if ($server->isForceDisabled()) { $server->forceEnableServer(); diff --git a/tests/Feature/ServerLimitCheckJobTest.php b/tests/Feature/ServerLimitCheckJobTest.php new file mode 100644 index 000000000..6b2c074be --- /dev/null +++ b/tests/Feature/ServerLimitCheckJobTest.php @@ -0,0 +1,83 @@ +set('constants.coolify.self_hosted', false); + + Notification::fake(); + + $this->team = Team::factory()->create(['custom_server_limit' => 5]); +}); + +function createServerForTeam(Team $team, bool $forceDisabled = false): Server +{ + $server = Server::factory()->create(['team_id' => $team->id]); + if ($forceDisabled) { + $server->settings()->update(['force_disabled' => true]); + } + + return $server->fresh(['settings']); +} + +it('re-enables force-disabled servers when under the limit', function () { + createServerForTeam($this->team); + $server2 = createServerForTeam($this->team, forceDisabled: true); + $server3 = createServerForTeam($this->team, forceDisabled: true); + + expect($server2->settings->force_disabled)->toBeTruthy(); + expect($server3->settings->force_disabled)->toBeTruthy(); + + // 3 servers, limit 5 → all should be re-enabled + ServerLimitCheckJob::dispatchSync($this->team); + + expect($server2->fresh()->settings->force_disabled)->toBeFalsy(); + expect($server3->fresh()->settings->force_disabled)->toBeFalsy(); +}); + +it('re-enables force-disabled servers when exactly at the limit', function () { + $this->team->update(['custom_server_limit' => 3]); + + createServerForTeam($this->team); + createServerForTeam($this->team); + $server3 = createServerForTeam($this->team, forceDisabled: true); + + // 3 servers, limit 3 → disabled one should be re-enabled + ServerLimitCheckJob::dispatchSync($this->team); + + expect($server3->fresh()->settings->force_disabled)->toBeFalsy(); +}); + +it('disables newest servers when over the limit', function () { + $this->team->update(['custom_server_limit' => 2]); + + $oldest = createServerForTeam($this->team); + sleep(1); + $middle = createServerForTeam($this->team); + sleep(1); + $newest = createServerForTeam($this->team); + + // 3 servers, limit 2 → newest 1 should be disabled + ServerLimitCheckJob::dispatchSync($this->team); + + expect($oldest->fresh()->settings->force_disabled)->toBeFalsy(); + expect($middle->fresh()->settings->force_disabled)->toBeFalsy(); + expect($newest->fresh()->settings->force_disabled)->toBeTruthy(); +}); + +it('does not change servers when under limit and none are force-disabled', function () { + $server1 = createServerForTeam($this->team); + $server2 = createServerForTeam($this->team); + + // 2 servers, limit 5 → nothing to do + ServerLimitCheckJob::dispatchSync($this->team); + + expect($server1->fresh()->settings->force_disabled)->toBeFalsy(); + expect($server2->fresh()->settings->force_disabled)->toBeFalsy(); +});