create([ 'name' => 'primary-postgres', 'category' => ServiceCategory::DATABASE, 'type' => ServiceType::POSTGRES, 'version' => '18', 'version_track' => '18', 'driver_name' => 'postgres.18', 'deploy_policy' => DeployPolicy::DEPENDENCY_ONLY, 'credentials' => [ 'user' => 'keystone', 'password' => 'secret', 'db' => 'keystone', ], 'default_cpu_limit' => 1.5, 'default_memory_limit_mb' => 1024, ]); $compose = app(ComposeRenderer::class)->render($service); expect($compose) ->toContain('services:') ->toContain('primary_postgres:') ->toContain('image: "postgres:18"') ->toContain('cpus: 1.500') ->toContain('mem_limit: "1024m"') ->toContain("keystone_service_{$service->id}_postgres_data:"); }); it('renders compose for caddy gateway with public ports and named volumes', function () { $service = Service::factory()->create([ 'name' => 'gateway', 'category' => ServiceCategory::GATEWAY, 'type' => ServiceType::CADDY, 'version' => '2', 'version_track' => '2', 'driver_name' => 'caddy.2', ]); $compose = app(ComposeRenderer::class)->render($service); expect($compose) ->toContain('image: "caddy:2"') ->toContain('- "80:80"') ->toContain('- "443:443"') ->toContain("keystone_service_{$service->id}_caddy_data:"); }); it('renders laravel scheduler and worker runtime roles into compose', function () { $environment = Environment::factory()->create([ 'scheduler_enabled' => true, 'scheduler_mode' => SchedulerMode::SINGLE, ]); $web = Service::factory()->for($environment)->create([ 'name' => 'web', 'category' => ServiceCategory::APPLICATION, 'type' => ServiceType::LARAVEL, 'version' => 'php-8.4', 'version_track' => 'php-8.4', 'driver_name' => 'laravel.php-8.4', 'process_roles' => ['web', 'scheduler'], 'desired_replicas' => 1, ]); $environment->forceFill(['scheduler_target_service_id' => $web->id])->save(); $worker = Service::factory()->for($environment)->create([ 'name' => 'worker', 'category' => ServiceCategory::APPLICATION, 'type' => ServiceType::LARAVEL, 'version' => 'php-8.4', 'version_track' => 'php-8.4', 'driver_name' => 'laravel.php-8.4', 'process_roles' => ['worker'], 'config' => [ 'command' => 'php artisan queue:work --sleep=3 --tries=3', ], ]); expect(app(ComposeRenderer::class)->render($web)) ->toContain('AUTORUN_LARAVEL_SCHEDULER: "true"') ->toContain('healthcheck:') ->and(app(ComposeRenderer::class)->render($worker)) ->toContain('command: "php artisan queue:work --sleep=3 --tries=3"') ->not->toContain('healthcheck:'); }); it('enforces scheduler mode when rendering laravel runtime env', function () { $environment = Environment::factory()->create([ 'scheduler_enabled' => true, 'scheduler_mode' => SchedulerMode::SINGLE, ]); $target = Service::factory()->for($environment)->create([ 'name' => 'web', 'category' => ServiceCategory::APPLICATION, 'type' => ServiceType::LARAVEL, 'version' => 'php-8.4', 'version_track' => 'php-8.4', 'driver_name' => 'laravel.php-8.4', 'process_roles' => ['web', 'scheduler'], 'desired_replicas' => 1, ]); $nonTarget = Service::factory()->for($environment)->create([ 'name' => 'worker', 'category' => ServiceCategory::APPLICATION, 'type' => ServiceType::LARAVEL, 'version' => 'php-8.4', 'version_track' => 'php-8.4', 'driver_name' => 'laravel.php-8.4', 'process_roles' => ['worker', 'scheduler'], 'desired_replicas' => 1, ]); $environment->forceFill(['scheduler_target_service_id' => $target->id])->save(); expect(app(ComposeRenderer::class)->render($target->refresh())) ->toContain('AUTORUN_LARAVEL_SCHEDULER: "true"') ->and(app(ComposeRenderer::class)->render($nonTarget->refresh())) ->not->toContain('AUTORUN_LARAVEL_SCHEDULER'); $environment->forceFill([ 'scheduler_mode' => SchedulerMode::EVERY_REPLICA, 'scheduler_target_service_id' => null, ])->save(); expect(app(ComposeRenderer::class)->render($target->refresh())) ->toContain('AUTORUN_LARAVEL_SCHEDULER: "true"') ->and(app(ComposeRenderer::class)->render($nonTarget->refresh())) ->toContain('AUTORUN_LARAVEL_SCHEDULER: "true"'); }); it('renders environment variables into laravel runtime compose', function () { $environment = Environment::factory()->create(['name' => 'production']); $environment->variables()->create([ 'key' => 'DB_CONNECTION', 'value' => 'pgsql', 'source' => EnvironmentVariableSource::MANAGED_ATTACHMENT, 'overridable' => false, ]); $environment->variables()->create([ 'key' => 'FEATURE_FLAG', 'value' => 'enabled', 'source' => EnvironmentVariableSource::USER, 'overridable' => true, ]); $service = Service::factory()->for($environment)->create([ 'name' => 'web', 'category' => ServiceCategory::APPLICATION, 'type' => ServiceType::LARAVEL, 'version' => 'php-8.4', 'version_track' => 'php-8.4', 'driver_name' => 'laravel.php-8.4', 'process_roles' => ['web'], ]); expect(app(ComposeRenderer::class)->render($service)) ->toContain('DB_CONNECTION: "pgsql"') ->toContain('FEATURE_FLAG: "enabled"') ->toContain('APP_ENV: "production"'); expect(app(ComposeRenderer::class)->renderEnvironmentFile($service)) ->toContain('DB_CONNECTION=pgsql') ->toContain('FEATURE_FLAG=enabled') ->toContain('APP_ENV=production'); });