mirror of
https://github.com/coollabsio/coolify.git
synced 2026-10-06 22:17:23 -04:00
Move database import temp/container cleanup into a queued listener with retries, and clear the import running state on failed restore starts. Tighten Cloudflare replace/delete to the current server IP and owning resource, notify when DNS jobs fail, and pass domain-removal confirmation through remove-by-key. Document import request oneOf schemas without extra properties.
101 lines
3.9 KiB
PHP
101 lines
3.9 KiB
PHP
<?php
|
|
|
|
use App\Events\DatabaseImportFinished;
|
|
use App\Listeners\CleanupDatabaseImport;
|
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Event;
|
|
use Tests\TestCase;
|
|
|
|
uses(TestCase::class, RefreshDatabase::class);
|
|
|
|
function importCleanupPayload(array $overrides = []): array
|
|
{
|
|
return array_merge([
|
|
'container' => 'postgres-abc',
|
|
'containerTmpPath' => '/tmp/restore_op',
|
|
'scriptPath' => '/tmp/restore_op.sh',
|
|
'serverId' => 1,
|
|
], $overrides);
|
|
}
|
|
|
|
test('the finished event keeps the payload and does not import Server', function () {
|
|
$data = importCleanupPayload(['serverTmpPath' => '/tmp/database-import-op']);
|
|
$event = new DatabaseImportFinished($data);
|
|
|
|
expect($event->data)->toBe($data)
|
|
->and(file_get_contents(app_path('Events/DatabaseImportFinished.php')))
|
|
->not->toContain('instant_remote_process')
|
|
->not->toContain('use App\Models\Server');
|
|
});
|
|
|
|
test('the cleanup listener is queued and discovered', function () {
|
|
expect(class_implements(CleanupDatabaseImport::class))->toContain(ShouldQueue::class);
|
|
|
|
$listener = new CleanupDatabaseImport;
|
|
expect($listener->tries)->toBe(3)
|
|
->and($listener->backoff)->toBe([5, 15, 30]);
|
|
|
|
Event::fake();
|
|
Event::assertListening(DatabaseImportFinished::class, CleanupDatabaseImport::class);
|
|
});
|
|
|
|
test('builds S3, upload, and server-path cleanup commands', function () {
|
|
$listener = new CleanupDatabaseImport;
|
|
|
|
expect($listener->commands(importCleanupPayload([
|
|
'containerName' => 's3-restore-op',
|
|
'serverTmpPath' => '/tmp/s3-restore-op',
|
|
])))->toBe([
|
|
'docker rm -f '.escapeshellarg('s3-restore-op').' 2>/dev/null || true',
|
|
'rm -f '.escapeshellarg('/tmp/s3-restore-op').' 2>/dev/null || true',
|
|
'docker exec '.escapeshellarg('postgres-abc').' rm -f '.escapeshellarg('/tmp/restore_op').' 2>/dev/null || true',
|
|
'docker exec '.escapeshellarg('postgres-abc').' rm -f '.escapeshellarg('/tmp/restore_op.sh').' 2>/dev/null || true',
|
|
]);
|
|
|
|
expect($listener->commands(importCleanupPayload([
|
|
'serverTmpPath' => '/tmp/database-import-op',
|
|
])))->toBe([
|
|
'rm -f '.escapeshellarg('/tmp/database-import-op').' 2>/dev/null || true',
|
|
'docker exec '.escapeshellarg('postgres-abc').' rm -f '.escapeshellarg('/tmp/restore_op').' 2>/dev/null || true',
|
|
'docker exec '.escapeshellarg('postgres-abc').' rm -f '.escapeshellarg('/tmp/restore_op.sh').' 2>/dev/null || true',
|
|
]);
|
|
|
|
expect($listener->commands(importCleanupPayload()))->toBe([
|
|
'docker exec '.escapeshellarg('postgres-abc').' rm -f '.escapeshellarg('/tmp/restore_op').' 2>/dev/null || true',
|
|
'docker exec '.escapeshellarg('postgres-abc').' rm -f '.escapeshellarg('/tmp/restore_op.sh').' 2>/dev/null || true',
|
|
]);
|
|
});
|
|
|
|
test('omits unsafe paths, missing container execs, and empty payloads', function () {
|
|
$listener = new CleanupDatabaseImport;
|
|
|
|
expect($listener->commands(importCleanupPayload([
|
|
'containerName' => 's3-restore-op',
|
|
'serverTmpPath' => '/tmp/../etc/passwd',
|
|
'containerTmpPath' => '/etc/shadow',
|
|
'scriptPath' => '/tmp/../../etc/shadow',
|
|
])))->toBe([
|
|
'docker rm -f '.escapeshellarg('s3-restore-op').' 2>/dev/null || true',
|
|
]);
|
|
|
|
expect($listener->commands([
|
|
'serverTmpPath' => '/tmp/database-import-op',
|
|
'containerTmpPath' => '/tmp/restore_op',
|
|
'scriptPath' => '/tmp/restore_op.sh',
|
|
]))->toBe([
|
|
'rm -f '.escapeshellarg('/tmp/database-import-op').' 2>/dev/null || true',
|
|
]);
|
|
|
|
expect($listener->commands([]))->toBe([]);
|
|
});
|
|
|
|
test('handle skips remote process when the server is missing', function () {
|
|
$event = new DatabaseImportFinished(importCleanupPayload([
|
|
'serverId' => 999999,
|
|
'containerName' => 's3-restore-op',
|
|
]));
|
|
|
|
expect(fn () => (new CleanupDatabaseImport)->handle($event))->not->toThrow(Throwable::class);
|
|
});
|