create(); $application = Application::factory()->for($organisation)->create(['name' => 'Billing API']); $environment = Environment::factory()->for($application)->create(['name' => 'production']); $service = Service::factory()->for($environment)->create([ 'organisation_id' => $organisation->id, 'name' => 'postgres', 'category' => ServiceCategory::DATABASE, 'type' => ServiceType::POSTGRES, 'version' => '18', 'version_track' => '18', 'driver_name' => 'postgres.18', ]); $attachment = app(AttachManagedService::class)->execute( environment: $environment, service: $service, role: EnvironmentAttachmentRole::DATABASE, ); expect($attachment->serviceSlice) ->not->toBeNull() ->and($attachment->serviceSlice->type)->toBe('database_user') ->and($environment->variables()->where('key', 'DB_CONNECTION')->first()->value)->toBe('pgsql') ->and($environment->variables()->where('key', 'DB_PASSWORD')->first()->source)->toBe(EnvironmentVariableSource::MANAGED_ATTACHMENT) ->and($environment->variables()->where('key', 'DB_PASSWORD')->first()->overridable)->toBeFalse() ->and($attachment->serviceSlice->operations()->first()->kind)->toBe(OperationKind::SLICE_PROVISION) ->and($attachment->serviceSlice->operations()->first()->steps()->first()->script)->toContain('CREATE DATABASE'); }); it('creates a valkey logical slice without silently changing queue behavior', function () { $organisation = Organisation::factory()->create(); $application = Application::factory()->for($organisation)->create(); $environment = Environment::factory()->for($application)->create(); $service = Service::factory()->for($environment)->create([ 'organisation_id' => $organisation->id, 'name' => 'valkey', 'category' => ServiceCategory::CACHE, 'type' => ServiceType::VALKEY, 'version' => '8', 'version_track' => '8', 'driver_name' => 'valkey.8', ]); app(AttachManagedService::class)->execute( environment: $environment, service: $service, role: EnvironmentAttachmentRole::CACHE, ); expect($environment->variables()->pluck('key')->all()) ->toContain('REDIS_HOST', 'REDIS_PORT', 'REDIS_DB', 'CACHE_STORE') ->not->toContain('QUEUE_CONNECTION'); $slice = $service->slices()->first(); expect($slice->config['database'])->toBe(1) ->and($slice->operations()->first()->kind)->toBe(OperationKind::SLICE_PROVISION) ->and($slice->operations()->first()->steps()->first()->script)->toContain('valkey-cli'); }); it('creates a caddy route slice with an independent provision operation', function () { $organisation = Organisation::factory()->create(); $application = Application::factory()->for($organisation)->create(); $environment = Environment::factory()->for($application)->create(); $service = Service::factory()->for($environment)->create([ 'organisation_id' => $organisation->id, 'name' => 'gateway', 'category' => ServiceCategory::GATEWAY, 'type' => ServiceType::CADDY, 'version' => '2', 'version_track' => '2', 'driver_name' => 'caddy.2', ]); $attachment = app(AttachManagedService::class)->execute( environment: $environment, service: $service, role: EnvironmentAttachmentRole::GATEWAY, name: 'example.com', ); expect($attachment->serviceSlice->type)->toBe('route') ->and($attachment->serviceSlice->operations()->first()->kind)->toBe(OperationKind::SLICE_PROVISION) ->and($attachment->serviceSlice->operations()->first()->steps()->first()->script)->toContain('/home/keystone/gateway/Caddyfile.d'); });