coolify/tests/Unit/ServerQueryScopeTest.php
Andras Bacsai 1dacb94860 fix(performance): eliminate N+1 query in CheckTraefikVersionJob
This commit fixes a critical N+1 query issue in CheckTraefikVersionJob
that was loading ALL proxy servers into memory then filtering in PHP,
causing potential OOM errors with thousands of servers.

Changes:
- Added scopeWhereProxyType() query scope to Server model for
  database-level filtering using JSON column arrow notation
- Updated CheckTraefikVersionJob to use new scope instead of
  collection filter, moving proxy type filtering into the SQL query
- Added comprehensive unit tests for the new query scope

Performance impact:
- Before: SELECT * FROM servers WHERE proxy IS NOT NULL (all servers)
- After: SELECT * FROM servers WHERE proxy->>'type' = 'TRAEFIK' (filtered)
- Eliminates memory overhead of loading non-Traefik servers
- Critical for cloud instances with thousands of connected servers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 14:53:49 +01:00

62 lines
1.9 KiB
PHP

<?php
use App\Enums\ProxyTypes;
use App\Models\Server;
use Illuminate\Database\Eloquent\Builder;
use Mockery;
it('filters servers by proxy type using whereProxyType scope', function () {
// Mock the Builder
$mockBuilder = Mockery::mock(Builder::class);
// Expect the where method to be called with the correct parameters
$mockBuilder->shouldReceive('where')
->once()
->with('proxy->type', ProxyTypes::TRAEFIK->value)
->andReturnSelf();
// Create a server instance and call the scope
$server = new Server;
$result = $server->scopeWhereProxyType($mockBuilder, ProxyTypes::TRAEFIK->value);
// Assert the builder is returned
expect($result)->toBe($mockBuilder);
});
it('can chain whereProxyType scope with other query methods', function () {
// Mock the Builder
$mockBuilder = Mockery::mock(Builder::class);
// Expect multiple chained calls
$mockBuilder->shouldReceive('where')
->once()
->with('proxy->type', ProxyTypes::CADDY->value)
->andReturnSelf();
// Create a server instance and call the scope
$server = new Server;
$result = $server->scopeWhereProxyType($mockBuilder, ProxyTypes::CADDY->value);
// Assert the builder is returned for chaining
expect($result)->toBe($mockBuilder);
});
it('accepts any proxy type string value', function () {
// Mock the Builder
$mockBuilder = Mockery::mock(Builder::class);
// Test with a custom proxy type
$customProxyType = 'custom-proxy';
$mockBuilder->shouldReceive('where')
->once()
->with('proxy->type', $customProxyType)
->andReturnSelf();
// Create a server instance and call the scope
$server = new Server;
$result = $server->scopeWhereProxyType($mockBuilder, $customProxyType);
// Assert the builder is returned
expect($result)->toBe($mockBuilder);
});