Ctrl K
ComunidadGuías…

tests/Feature/ApplicationSettingsAuditTest.php

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
<?php

use App\Enums\ApplicationDeploymentStatus;
use App\Livewire\Project\Application\DeploymentNavbar;
use App\Livewire\Project\Application\Domains;
use App\Livewire\Project\Application\General;
use App\Livewire\Project\Application\PreviewDomains;
use App\Livewire\Project\Application\Previews;
use App\Livewire\Project\Application\Rollback;
use App\Livewire\Project\Application\Swarm;
use App\Livewire\Project\Shared\EnvironmentVariable\All;
use App\Models\Application;
use App\Models\ApplicationDeploymentQueue;
use App\Models\ApplicationPreview;
use App\Models\AuditEvent;
use App\Models\Environment;
use App\Models\InstanceSettings;
use App\Models\Project;
use App\Models\Server;
use App\Models\StandaloneDocker;
use App\Models\Team;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Queue;
use Livewire\Livewire;

uses(RefreshDatabase::class);

beforeEach(function () {
    $this->withoutDefer();
    $this->withoutVite();
    Server::flushIdentityMap();
    Queue::fake();
    config(['app.maintenance.driver' => 'file']);

    InstanceSettings::unguarded(fn () => InstanceSettings::updateOrCreate(
        ['id' => 0],
        ['id' => 0, 'is_dns_validation_enabled' => false],
    ));

    $this->team = Team::factory()->create();
    $this->user = User::factory()->create();
    $this->team->members()->attach($this->user->id, ['role' => 'owner']);
    $this->actingAs($this->user);
    session(['currentTeam' => $this->team]);

    $this->server = Server::factory()->create(['team_id' => $this->team->id]);
    $this->destination = StandaloneDocker::query()->where('server_id', $this->server->id)->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([
        'name' => 'Audited App',
        'environment_id' => $this->environment->id,
        'destination_id' => $this->destination->id,
        'destination_type' => $this->destination->getMorphClass(),
        'fqdn' => null,
        'redirect' => 'both',
        'build_pack' => 'nixpacks',
        'static_image' => 'nginx:alpine',
        'base_directory' => '/',
        'is_http_basic_auth_enabled' => false,
        'git_repository' => 'coollabsio/coolify',
        'git_branch' => 'main',
        'ports_exposes' => '3000',
        'swarm_replicas' => 1,
    ]);
});

function applicationSettingsAuditEvents(string $event): Collection
{
    return AuditEvent::query()->where('event', $event)->orderBy('id')->get();
}

function createAuditedApplicationPreview(Application $application, int $pullRequestId, array $attributes = []): ApplicationPreview
{
    return ApplicationPreview::create(array_merge([
        'application_id' => $application->id,
        'pull_request_id' => $pullRequestId,
        'pull_request_html_url' => "https://github.com/coollabsio/coolify/pull/{$pullRequestId}",
    ], $attributes));
}

it('audits preview deployment settings and skips the audit when nothing changed', function () {
    $component = Livewire::test(Previews::class, ['application' => $this->application])
        ->set('isPreviewDeploymentsEnabled', true)
        ->set('isPrDeploymentsPublicEnabled', true)
        ->call('savePreviewSettings')
        ->assertHasNoErrors();

    $events = applicationSettingsAuditEvents('ui.application.settings_updated');
    expect($events)->toHaveCount(1)
        ->and($events->first()->team_id)->toBe($this->team->id)
        ->and($events->first()->resource_uuid)->toBe($this->application->uuid)
        ->and($events->first()->metadata['application_name'])->toBe('Audited App')
        ->and($events->first()->metadata['changed_fields'])
        ->toEqualCanonicalizing(['is_preview_deployments_enabled', 'is_pr_deployments_public_enabled']);

    $component->call('savePreviewSettings')->assertHasNoErrors();

    expect(applicationSettingsAuditEvents('ui.application.settings_updated'))->toHaveCount(1);
});

it('does not audit preview settings when the user cannot update the application', function () {
    $this->team->members()->updateExistingPivot($this->user->id, ['role' => 'member']);

    Livewire::test(Previews::class, ['application' => $this->application])
        ->set('isPreviewDeploymentsEnabled', true)
        ->call('savePreviewSettings')
        ->assertForbidden();

    expect(AuditEvent::query()->where('event', 'ui.application.settings_updated')->exists())->toBeFalse();
});

it('audits adding, retagging and deleting a preview', function () {
    $component = Livewire::test(Previews::class, ['application' => $this->application])
        ->set('parameters', [
            'project_uuid' => $this->project->uuid,
            'environment_uuid' => $this->environment->uuid,
            'application_uuid' => $this->application->uuid,
        ])
        ->call('add', 42, 'https://github.com/coollabsio/coolify/pull/42');

    $created = applicationSettingsAuditEvents('ui.application.preview_created');
    expect($created)->toHaveCount(1)
        ->and($created->first()->metadata['pull_request_id'])->toBe(42)
        ->and($created->first()->resource_uuid)->toBe($this->application->uuid);

    $component->set('previewDockerTags.'.ApplicationPreview::query()->where('pull_request_id', 42)->value('id'), 'pr-42')
        ->call('save_preview', ApplicationPreview::query()->where('pull_request_id', 42)->value('id'));

    $updated = applicationSettingsAuditEvents('ui.application.preview_updated');
    expect($updated)->toHaveCount(1)
        ->and($updated->first()->metadata['pull_request_id'])->toBe(42)
        ->and($updated->first()->metadata['changed_fields'])->toBe(['docker_registry_image_tag']);

    $component->call('delete', 42);

    $deleted = applicationSettingsAuditEvents('ui.application.preview_deleted');
    expect($deleted)->toHaveCount(1)
        ->and($deleted->first()->metadata['pull_request_id'])->toBe(42);
});

it('audits preview domain changes', function () {
    $preview = createAuditedApplicationPreview($this->application, 7, [
        'fqdn' => 'https://one-pr-7.example.com,https://two-pr-7.example.com',
    ]);

    Livewire::test(PreviewDomains::class, ['preview' => $preview])
        ->call('removeDomain', 1)
        ->assertHasNoErrors();

    $events = applicationSettingsAuditEvents('ui.application.preview_updated');
    expect($preview->fresh()->fqdn)->toBe('https://one-pr-7.example.com')
        ->and($events)->toHaveCount(1)
        ->and($events->first()->metadata['pull_request_id'])->toBe(7)
        ->and($events->first()->metadata['changed_fields'])->toBe(['fqdn']);
});

it('audits application setting changes from each settings control', function (Closure $change, string $field) {
    $change->call($this);

    $events = applicationSettingsAuditEvents('ui.application.settings_updated');
    expect($events)->toHaveCount(1)
        ->and($events->first()->resource_uuid)->toBe($this->application->uuid)
        ->and($events->first()->metadata['changed_fields'])->toBe([$field]);
})->with([
    'general settings' => [function () {
        Livewire::test(General::class, ['application' => $this->application])
            ->set('isPreserveRepositoryEnabled', true)
            ->call('instantSave')
            ->assertHasNoErrors();
    }, 'is_preserve_repository_enabled'],
    'force https' => [function () {
        $this->application->update(['fqdn' => 'https://app.example.com']);
        Livewire::test(Domains::class, ['application' => $this->application->fresh()])
            ->set('isForceHttpsEnabled', false)
            ->call('updateForceHttps')
            ->assertHasNoErrors();
    }, 'is_force_https_enabled'],
    'swarm worker nodes' => [function () {
        $current = (bool) $this->application->settings->is_swarm_only_worker_nodes;
        Livewire::test(Swarm::class, ['application' => $this->application])
            ->set('isSwarmOnlyWorkerNodes', ! $current)
            ->call('instantSave')
            ->assertHasNoErrors();
    }, 'is_swarm_only_worker_nodes'],
    'deployment debug logs' => [function () {
        $deployment = ApplicationDeploymentQueue::create([
            'application_id' => $this->application->id,
            'deployment_uuid' => 'audit-debug-toggle',
            'server_id' => $this->server->id,
            'destination_id' => $this->destination->id,
            'status' => ApplicationDeploymentStatus::FINISHED->value,
        ]);
        Livewire::test(DeploymentNavbar::class, ['application_deployment_queue' => $deployment])
            ->call('show_debug');
    }, 'is_debug_enabled'],
    'rollback image retention' => [function () {
        Livewire::test(Rollback::class, ['application' => $this->application])
            ->set('dockerImagesToKeep', 5)
            ->call('saveSettings')
            ->assertHasNoErrors();
    }, 'docker_images_to_keep'],
    'build secrets' => [function () {
        Livewire::test(All::class, ['resource' => $this->application])
            ->set('use_build_secrets', true)
            ->call('instantSave')
            ->assertHasNoErrors();
    }, 'use_build_secrets'],
]);