Files
coolify/tests/Feature/ContainerFilesystemServiceTest.php
T

100 lines
3.0 KiB
PHP

<?php
use App\Data\FileEntry;
use App\Models\PrivateKey;
use App\Models\Server;
use App\Models\Team;
use App\Services\ContainerFilesystemService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Process;
use Illuminate\Support\Facades\Storage;
uses(RefreshDatabase::class);
beforeEach(function () {
Storage::fake('ssh-keys');
});
function fsService(): ContainerFilesystemService
{
$server = Server::factory()->make(['id' => 999]);
return new ContainerFilesystemService($server, 'app-123');
}
function fsServer(): Server
{
$team = Team::factory()->create();
$privateKey = PrivateKey::factory()->create(['team_id' => $team->id]);
return Server::factory()->create([
'team_id' => $team->id,
'private_key_id' => $privateKey->id,
'ip' => '203.0.113.10',
]);
}
it('sorts directories before files, then by name case-insensitively', function () {
$entries = [
new FileEntry('README.md', 'file', 10, 100),
new FileEntry('src', 'dir', 0, 100),
new FileEntry('.env', 'file', 5, 100),
new FileEntry('assets', 'dir', 0, 100),
];
$names = array_map(fn (FileEntry $e) => $e->name, FileEntry::sort($entries));
expect($names)->toBe(['assets', 'src', '.env', 'README.md']);
});
it('builds a listing command with an escaped path and the container name', function () {
$cmd = fsService()->buildListCommand('/var/www/html');
expect($cmd)
->toContain('docker exec')
->toContain('app-123')
->toContain(escapeshellarg('/var/www/html'));
});
it('rejects an unsafe listing path', function () {
fsService()->buildListCommand('/tmp/$(reboot)');
})->throws(Exception::class);
it('parses a tab-delimited listing into sorted FileEntry rows', function () {
$raw = implode("\n", [
"file\t10\t1700000000\tREADME.md",
"dir\t0\t1700000001\tsrc",
"file\t5\t1700000002\t.env",
]);
$entries = fsService()->parseListing($raw);
expect($entries)->toHaveCount(3);
expect($entries[0]->name)->toBe('src');
expect($entries[0]->type)->toBe('dir');
expect($entries[1]->name)->toBe('.env');
expect($entries[2]->name)->toBe('README.md');
});
it('parses an empty listing to an empty array', function () {
expect(fsService()->parseListing(null))->toBe([]);
expect(fsService()->parseListing(''))->toBe([]);
});
it('lists a directory by running the built command over SSH', function () {
Process::fake(['*' => Process::result(output: "dir\t0\t1\tsrc\nfile\t10\t2\tREADME.md")]);
$server = fsServer();
$entries = (new ContainerFilesystemService($server, 'app-123'))->list('/app');
expect($entries)->toHaveCount(2);
expect($entries[0]->name)->toBe('src');
});
it('falls back to / when the container has no WorkingDir', function () {
Process::fake(['*' => Process::result(output: '')]);
$server = fsServer();
expect((new ContainerFilesystemService($server, 'app-123'))->defaultRoot())->toBe('/');
});