mirror of
https://github.com/tiennm99/coolify.git
synced 2026-06-21 03:46:25 +00:00
2692496726
Handle database status updates more reliably by listening for `ServiceChecked` and using explicit `refresh()` handlers in Livewire database components. Also switch guarded clone/create paths to `forceFill`/`forceCreate` in helper flows to avoid missing persisted attributes during app/service cloning. Update log/terminal font stacks to Geist (with bundled variable fonts) and add coverage for SSL status refresh, persistent volume UUID cloning, and log font styling.
161 lines
5.7 KiB
PHP
161 lines
5.7 KiB
PHP
<?php
|
|
|
|
use App\Models\Application;
|
|
use App\Models\ApplicationPreview;
|
|
use App\Models\ApplicationSetting;
|
|
use App\Models\Environment;
|
|
use App\Models\LocalPersistentVolume;
|
|
use App\Models\Project;
|
|
use App\Models\ScheduledTask;
|
|
use App\Models\Server;
|
|
use App\Models\Team;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
beforeEach(function () {
|
|
$this->user = User::factory()->create();
|
|
$this->team = Team::factory()->create();
|
|
$this->user->teams()->attach($this->team, ['role' => 'owner']);
|
|
|
|
$this->server = Server::factory()->create(['team_id' => $this->team->id]);
|
|
$this->destination = $this->server->standaloneDockers()->firstOrFail();
|
|
$this->project = Project::factory()->create(['team_id' => $this->team->id]);
|
|
$this->environment = Environment::factory()->create(['project_id' => $this->project->id]);
|
|
|
|
$this->application = Application::factory()->create([
|
|
'environment_id' => $this->environment->id,
|
|
'destination_id' => $this->destination->id,
|
|
'destination_type' => $this->destination->getMorphClass(),
|
|
'redirect' => 'both',
|
|
]);
|
|
|
|
$this->application->settings->forceFill([
|
|
'is_container_label_readonly_enabled' => false,
|
|
])->save();
|
|
|
|
$this->actingAs($this->user);
|
|
session(['currentTeam' => $this->team]);
|
|
});
|
|
|
|
test('cloning application generates new uuid for persistent volumes', function () {
|
|
$volume = LocalPersistentVolume::create([
|
|
'name' => $this->application->uuid.'-data',
|
|
'mount_path' => '/data',
|
|
'resource_id' => $this->application->id,
|
|
'resource_type' => $this->application->getMorphClass(),
|
|
]);
|
|
|
|
$originalUuid = $volume->uuid;
|
|
|
|
$newApp = clone_application($this->application, $this->destination, [
|
|
'environment_id' => $this->environment->id,
|
|
]);
|
|
|
|
$clonedVolume = $newApp->persistentStorages()->first();
|
|
|
|
expect($clonedVolume)->not->toBeNull();
|
|
expect($clonedVolume->uuid)->not->toBe($originalUuid);
|
|
expect($clonedVolume->mount_path)->toBe('/data');
|
|
});
|
|
|
|
test('cloning application with multiple persistent volumes generates unique uuids', function () {
|
|
$volume1 = LocalPersistentVolume::create([
|
|
'name' => $this->application->uuid.'-data',
|
|
'mount_path' => '/data',
|
|
'resource_id' => $this->application->id,
|
|
'resource_type' => $this->application->getMorphClass(),
|
|
]);
|
|
|
|
$volume2 = LocalPersistentVolume::create([
|
|
'name' => $this->application->uuid.'-config',
|
|
'mount_path' => '/config',
|
|
'resource_id' => $this->application->id,
|
|
'resource_type' => $this->application->getMorphClass(),
|
|
]);
|
|
|
|
$newApp = clone_application($this->application, $this->destination, [
|
|
'environment_id' => $this->environment->id,
|
|
]);
|
|
|
|
$clonedVolumes = $newApp->persistentStorages()->get();
|
|
|
|
expect($clonedVolumes)->toHaveCount(2);
|
|
|
|
$clonedUuids = $clonedVolumes->pluck('uuid')->toArray();
|
|
$originalUuids = [$volume1->uuid, $volume2->uuid];
|
|
|
|
// All cloned UUIDs should be unique and different from originals
|
|
expect($clonedUuids)->each->not->toBeIn($originalUuids);
|
|
expect(array_unique($clonedUuids))->toHaveCount(2);
|
|
});
|
|
|
|
test('cloning application reassigns settings to the cloned application', function () {
|
|
$this->application->settings->forceFill([
|
|
'is_static' => true,
|
|
'is_spa' => true,
|
|
'is_build_server_enabled' => true,
|
|
])->save();
|
|
|
|
$newApp = clone_application($this->application, $this->destination, [
|
|
'environment_id' => $this->environment->id,
|
|
]);
|
|
|
|
$sourceSettingsCount = ApplicationSetting::query()
|
|
->where('application_id', $this->application->id)
|
|
->count();
|
|
$clonedSettings = ApplicationSetting::query()
|
|
->where('application_id', $newApp->id)
|
|
->first();
|
|
|
|
expect($sourceSettingsCount)->toBe(1)
|
|
->and($clonedSettings)->not->toBeNull()
|
|
->and($clonedSettings?->application_id)->toBe($newApp->id)
|
|
->and($clonedSettings?->is_static)->toBeTrue()
|
|
->and($clonedSettings?->is_spa)->toBeTrue()
|
|
->and($clonedSettings?->is_build_server_enabled)->toBeTrue();
|
|
});
|
|
|
|
test('cloning application reassigns scheduled tasks and previews to the cloned application', function () {
|
|
$scheduledTask = ScheduledTask::forceCreate([
|
|
'uuid' => 'scheduled-task-original',
|
|
'application_id' => $this->application->id,
|
|
'team_id' => $this->team->id,
|
|
'name' => 'nightly-task',
|
|
'command' => 'php artisan schedule:run',
|
|
'frequency' => '* * * * *',
|
|
'container' => 'app',
|
|
'timeout' => 120,
|
|
]);
|
|
|
|
$preview = ApplicationPreview::forceCreate([
|
|
'uuid' => 'preview-original',
|
|
'application_id' => $this->application->id,
|
|
'pull_request_id' => 123,
|
|
'pull_request_html_url' => 'https://example.com/pull/123',
|
|
'fqdn' => 'https://preview.example.com',
|
|
'status' => 'running',
|
|
]);
|
|
|
|
$newApp = clone_application($this->application, $this->destination, [
|
|
'environment_id' => $this->environment->id,
|
|
]);
|
|
|
|
$clonedTask = ScheduledTask::query()
|
|
->where('application_id', $newApp->id)
|
|
->first();
|
|
$clonedPreview = ApplicationPreview::query()
|
|
->where('application_id', $newApp->id)
|
|
->first();
|
|
|
|
expect($clonedTask)->not->toBeNull()
|
|
->and($clonedTask?->uuid)->not->toBe($scheduledTask->uuid)
|
|
->and($clonedTask?->application_id)->toBe($newApp->id)
|
|
->and($clonedTask?->team_id)->toBe($this->team->id)
|
|
->and($clonedPreview)->not->toBeNull()
|
|
->and($clonedPreview?->uuid)->not->toBe($preview->uuid)
|
|
->and($clonedPreview?->application_id)->toBe($newApp->id)
|
|
->and($clonedPreview?->status)->toBe('exited');
|
|
});
|