team = Team::factory()->create(); $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]); }); it('creates User with all fillable attributes', function () { $user = User::create([ 'name' => 'Test User', 'email' => 'fillable-test@example.com', 'password' => bcrypt('password123'), 'force_password_reset' => true, 'marketing_emails' => false, 'pending_email' => 'newemail@example.com', 'email_change_code' => 'ABC123', 'email_change_code_expires_at' => now()->addHour(), ]); expect($user->exists)->toBeTrue(); expect($user->name)->toBe('Test User'); expect($user->email)->toBe('fillable-test@example.com'); expect($user->force_password_reset)->toBeTrue(); expect($user->marketing_emails)->toBeFalse(); expect($user->pending_email)->toBe('newemail@example.com'); expect($user->email_change_code)->toBe('ABC123'); expect($user->email_change_code_expires_at)->not->toBeNull(); }); it('creates Server with all fillable attributes', function () { $cloudToken = CloudProviderToken::create([ 'team_id' => $this->team->id, 'provider' => 'hetzner', 'token' => 'test-token', 'name' => 'test-cloud', ]); $server = Server::create([ 'name' => 'fillable-test-server', 'ip' => '10.0.0.99', 'port' => 2222, 'user' => 'deployer', 'description' => 'A test server with all fillable attrs', 'private_key_id' => $this->server->private_key_id, 'cloud_provider_token_id' => $cloudToken->id, 'team_id' => $this->team->id, 'hetzner_server_id' => 'htz-12345', 'hetzner_server_status' => 'running', 'is_validating' => false, 'detected_traefik_version' => 'v2.10.0', 'traefik_outdated_info' => 'Up to date', 'server_metadata' => '{"region":"eu-central"}', 'ip_previous' => '10.0.0.1', ]); expect($server->exists)->toBeTrue(); expect((string) $server->name)->toBe('fillable-test-server'); expect((string) $server->ip)->toBe('10.0.0.99'); expect($server->port)->toBe(2222); expect((string) $server->user)->toBe('deployer'); expect((string) $server->description)->toBe('A test server with all fillable attrs'); expect($server->private_key_id)->toBe($this->server->private_key_id); expect($server->cloud_provider_token_id)->toBe($cloudToken->id); expect($server->hetzner_server_id)->toBe('htz-12345'); expect($server->hetzner_server_status)->toBe('running'); expect($server->ip_previous)->toBe('10.0.0.1'); }); it('creates Project with all fillable attributes', function () { $project = Project::create([ 'name' => 'Fillable Test Project', 'description' => 'Testing all fillable attrs', 'team_id' => $this->team->id, 'uuid' => 'custom-project-uuid', ]); expect($project->exists)->toBeTrue(); expect($project->name)->toBe('Fillable Test Project'); expect($project->description)->toBe('Testing all fillable attrs'); expect($project->team_id)->toBe($this->team->id); expect($project->uuid)->toBe('custom-project-uuid'); }); it('creates Environment with all fillable attributes', function () { $env = Environment::create([ 'name' => 'staging', 'description' => 'Staging environment', 'project_id' => $this->project->id, 'uuid' => 'custom-env-uuid', ]); expect($env->exists)->toBeTrue(); expect($env->name)->toBe('staging'); expect($env->description)->toBe('Staging environment'); expect($env->project_id)->toBe($this->project->id); expect($env->uuid)->toBe('custom-env-uuid'); }); it('creates ProjectSetting with all fillable attributes', function () { $setting = ProjectSetting::create([ 'project_id' => $this->project->id, ]); expect($setting->exists)->toBeTrue(); expect($setting->project_id)->toBe($this->project->id); }); it('creates Application with all fillable attributes', function () { $application = Application::create([ 'uuid' => 'custom-app-uuid', 'name' => 'Full Fillable App', 'description' => 'App with every fillable attr set', 'fqdn' => 'https://app.example.com', 'git_repository' => 'https://github.com/coollabsio/coolify', 'git_branch' => 'main', 'git_commit_sha' => 'abc123def456', 'git_full_url' => 'https://github.com/coollabsio/coolify.git', 'docker_registry_image_name' => 'ghcr.io/coollabsio/coolify', 'docker_registry_image_tag' => 'latest', 'build_pack' => 'nixpacks', 'static_image' => 'nginx:alpine', 'install_command' => 'npm install', 'build_command' => 'npm run build', 'start_command' => 'npm start', 'ports_exposes' => '3000', 'ports_mappings' => '3000:3000', 'base_directory' => '/', 'publish_directory' => '/dist', 'health_check_enabled' => true, 'health_check_path' => '/health', 'health_check_port' => '3000', 'health_check_host' => 'localhost', 'health_check_method' => 'GET', 'health_check_return_code' => 200, 'health_check_scheme' => 'http', 'health_check_response_text' => 'ok', 'health_check_interval' => 30, 'health_check_timeout' => 5, 'health_check_retries' => 3, 'health_check_start_period' => 10, 'health_check_type' => 'http', 'health_check_command' => 'curl -f http://localhost:3000/health', 'limits_memory' => '512m', 'limits_memory_swap' => '1g', 'limits_memory_swappiness' => 60, 'limits_memory_reservation' => '256m', 'limits_cpus' => '2', 'limits_cpuset' => '0-1', 'limits_cpu_shares' => 1024, 'status' => 'running', 'preview_url_template' => '{{pr_id}}.{{domain}}', 'dockerfile' => 'FROM node:18\nRUN npm install', 'dockerfile_location' => '/Dockerfile', 'dockerfile_target_build' => 'production', 'custom_labels' => 'traefik.enable=true', 'custom_docker_run_options' => '--cap-add=NET_ADMIN', 'post_deployment_command' => 'php artisan migrate', 'post_deployment_command_container' => 'app', 'pre_deployment_command' => 'php artisan down', 'pre_deployment_command_container' => 'app', 'manual_webhook_secret_github' => 'gh-secret-123', 'manual_webhook_secret_gitlab' => 'gl-secret-456', 'manual_webhook_secret_bitbucket' => 'bb-secret-789', 'manual_webhook_secret_gitea' => 'gt-secret-012', 'docker_compose_location' => '/docker-compose.yml', 'docker_compose' => 'services: {}', 'docker_compose_raw' => 'services:\n app:\n image: nginx', 'docker_compose_domains' => '{"app":"https://app.example.com"}', 'docker_compose_custom_start_command' => 'docker compose up -d', 'docker_compose_custom_build_command' => 'docker compose build', 'swarm_replicas' => 3, 'swarm_placement_constraints' => 'node.role==worker', 'watch_paths' => 'src/**,package.json', 'redirect' => 'www', 'compose_parsing_version' => '2', 'custom_nginx_configuration' => 'location / { proxy_pass http://localhost:3000; }', 'custom_network_aliases' => 'app-alias', 'custom_healthcheck_found' => false, // Note: nixpkgsarchive, connect_to_docker_network, force_domain_override, // is_container_label_escape_enabled, use_build_server are in $fillable but // their migration columns may not exist in the test SQLite schema yet. 'is_http_basic_auth_enabled' => false, 'http_basic_auth_username' => 'admin', 'http_basic_auth_password' => 'secret', 'config_hash' => 'sha256:abc123', 'last_online_at' => now()->subMinutes(5)->toISOString(), 'restart_count' => 2, 'last_restart_at' => now()->subHour()->toISOString(), 'last_restart_type' => 'manual', 'environment_id' => $this->environment->id, 'destination_id' => $this->destination->id, 'destination_type' => $this->destination->getMorphClass(), 'source_id' => null, 'source_type' => null, 'repository_project_id' => null, 'private_key_id' => null, ]); expect($application->exists)->toBeTrue(); expect($application->uuid)->toBe('custom-app-uuid'); expect($application->name)->toBe('Full Fillable App'); expect((string) $application->git_repository)->toBe('https://github.com/coollabsio/coolify'); expect($application->build_pack)->toBe('nixpacks'); expect($application->ports_exposes)->toBe('3000'); expect($application->environment_id)->toBe($this->environment->id); expect($application->destination_id)->toBe($this->destination->id); expect($application->health_check_enabled)->toBeTrue(); expect($application->limits_memory)->toBe('512m'); expect($application->swarm_replicas)->toBe(3); expect($application->restart_count)->toBe(2); }); it('creates ApplicationSetting with all fillable attributes', function () { $app = Application::create([ 'name' => 'settings-test-app', 'git_repository' => 'https://github.com/test/repo', 'git_branch' => 'main', 'build_pack' => 'nixpacks', 'ports_exposes' => '3000', 'environment_id' => $this->environment->id, 'destination_id' => $this->destination->id, 'destination_type' => $this->destination->getMorphClass(), ]); // Delete auto-created setting so we can create one with all attrs ApplicationSetting::where('application_id', $app->id)->delete(); $setting = ApplicationSetting::create([ 'application_id' => $app->id, 'is_static' => true, 'is_git_submodules_enabled' => true, 'is_git_lfs_enabled' => true, 'is_auto_deploy_enabled' => false, 'is_force_https_enabled' => true, 'is_debug_enabled' => true, 'is_preview_deployments_enabled' => false, 'is_log_drain_enabled' => true, 'is_gpu_enabled' => true, 'gpu_driver' => 'nvidia', 'gpu_count' => '2', 'gpu_device_ids' => 'GPU-abc,GPU-def', 'gpu_options' => '--gpus all', 'is_include_timestamps' => true, 'is_swarm_only_worker_nodes' => false, 'is_raw_compose_deployment_enabled' => false, 'is_build_server_enabled' => false, 'is_consistent_container_name_enabled' => true, 'is_gzip_enabled' => true, 'is_stripprefix_enabled' => true, 'connect_to_docker_network' => false, 'custom_internal_name' => 'my-custom-app', 'is_container_label_escape_enabled' => true, 'is_env_sorting_enabled' => true, 'is_container_label_readonly_enabled' => false, 'is_preserve_repository_enabled' => false, 'disable_build_cache' => false, 'is_spa' => true, 'is_git_shallow_clone_enabled' => true, 'is_pr_deployments_public_enabled' => false, 'use_build_secrets' => false, 'inject_build_args_to_dockerfile' => true, 'include_source_commit_in_build' => true, 'docker_images_to_keep' => 5, ]); expect($setting->exists)->toBeTrue(); expect($setting->application_id)->toBe($app->id); expect($setting->is_static)->toBeTrue(); expect($setting->is_gpu_enabled)->toBeTrue(); expect($setting->gpu_driver)->toBe('nvidia'); expect($setting->custom_internal_name)->toBe('my-custom-app'); expect($setting->is_spa)->toBeTrue(); expect($setting->docker_images_to_keep)->toBe(5); }); it('creates ServerSetting with all fillable attributes', function () { // Delete auto-created setting ServerSetting::where('server_id', $this->server->id)->delete(); $setting = ServerSetting::create([ 'server_id' => $this->server->id, 'is_swarm_manager' => false, 'is_jump_server' => false, 'is_build_server' => true, 'is_reachable' => true, 'is_usable' => true, 'wildcard_domain' => '*.example.com', 'is_cloudflare_tunnel' => false, 'is_logdrain_newrelic_enabled' => true, 'logdrain_newrelic_license_key' => 'nr-license-key-123', 'logdrain_newrelic_base_uri' => 'https://log-api.newrelic.com', 'is_logdrain_highlight_enabled' => false, 'logdrain_highlight_project_id' => 'hl-proj-123', 'is_logdrain_axiom_enabled' => true, 'logdrain_axiom_dataset_name' => 'coolify-logs', 'logdrain_axiom_api_key' => 'axiom-key-456', 'is_swarm_worker' => false, 'is_logdrain_custom_enabled' => false, 'logdrain_custom_config' => '{"endpoint":"https://logs.example.com"}', 'logdrain_custom_config_parser' => 'json', 'concurrent_builds' => 4, 'dynamic_timeout' => 600, 'force_disabled' => false, 'is_metrics_enabled' => true, 'generate_exact_labels' => true, 'force_docker_cleanup' => false, 'docker_cleanup_frequency' => '0 2 * * *', 'docker_cleanup_threshold' => 80, 'server_timezone' => 'UTC', 'delete_unused_volumes' => true, 'delete_unused_networks' => true, 'is_sentinel_enabled' => true, 'sentinel_token' => 'sentinel-token-789', 'sentinel_metrics_refresh_rate_seconds' => 30, 'sentinel_metrics_history_days' => 7, 'sentinel_push_interval_seconds' => 60, 'sentinel_custom_url' => 'https://sentinel.example.com', 'server_disk_usage_notification_threshold' => 90, 'is_sentinel_debug_enabled' => false, 'server_disk_usage_check_frequency' => '*/5 * * * *', 'is_terminal_enabled' => true, 'deployment_queue_limit' => 10, 'disable_application_image_retention' => false, ]); expect($setting->exists)->toBeTrue(); expect($setting->server_id)->toBe($this->server->id); expect($setting->is_build_server)->toBeTrue(); expect($setting->wildcard_domain)->toBe('*.example.com'); expect($setting->concurrent_builds)->toBe(4); expect($setting->sentinel_token)->toBe('sentinel-token-789'); expect($setting->deployment_queue_limit)->toBe(10); }); it('creates Service with all fillable attributes', function () { $service = Service::create([ 'uuid' => 'custom-service-uuid', 'name' => 'Full Fillable Service', 'description' => 'Service with all fillable attrs', 'docker_compose_raw' => "services:\n app:\n image: nginx", 'docker_compose' => "services:\n app:\n image: nginx", 'connect_to_docker_network' => true, 'service_type' => 'test-service', 'config_hash' => 'sha256:svc123', 'compose_parsing_version' => '2', 'is_container_label_escape_enabled' => true, 'environment_id' => $this->environment->id, 'server_id' => $this->server->id, 'destination_id' => $this->destination->id, 'destination_type' => $this->destination->getMorphClass(), ]); expect($service->exists)->toBeTrue(); expect($service->uuid)->toBe('custom-service-uuid'); expect($service->name)->toBe('Full Fillable Service'); expect($service->docker_compose_raw)->not->toBeNull(); expect($service->service_type)->toBe('test-service'); expect($service->environment_id)->toBe($this->environment->id); expect($service->server_id)->toBe($this->server->id); }); it('creates ApplicationPreview with all fillable attributes', function () { $app = Application::create([ 'name' => 'preview-test-app', 'git_repository' => 'https://github.com/test/repo', 'git_branch' => 'main', 'build_pack' => 'nixpacks', 'ports_exposes' => '3000', 'environment_id' => $this->environment->id, 'destination_id' => $this->destination->id, 'destination_type' => $this->destination->getMorphClass(), ]); $preview = ApplicationPreview::create([ 'uuid' => 'custom-preview-uuid', 'application_id' => $app->id, 'pull_request_id' => 42, 'pull_request_html_url' => 'https://github.com/test/repo/pull/42', 'pull_request_issue_comment_id' => 12345, 'fqdn' => 'https://pr-42.app.example.com', 'status' => 'queued', 'git_type' => 'github', 'docker_compose_domains' => '{"app":"https://pr-42.example.com"}', 'docker_registry_image_tag' => 'pr-42', 'last_online_at' => now()->toISOString(), ]); expect($preview->exists)->toBeTrue(); expect($preview->uuid)->toBe('custom-preview-uuid'); expect($preview->application_id)->toBe($app->id); expect($preview->pull_request_id)->toBe(42); expect($preview->fqdn)->toBe('https://pr-42.app.example.com'); expect($preview->git_type)->toBe('github'); expect($preview->docker_registry_image_tag)->toBe('pr-42'); }); it('creates ServiceApplication with all fillable attributes', function () { $service = Service::create([ 'docker_compose_raw' => 'services: {}', 'environment_id' => $this->environment->id, 'server_id' => $this->server->id, 'destination_id' => $this->destination->id, 'destination_type' => $this->destination->getMorphClass(), ]); $svcApp = ServiceApplication::create([ 'service_id' => $service->id, 'name' => 'web', 'human_name' => 'Web Server', 'description' => 'Main web application', 'fqdn' => 'https://web.example.com', 'ports' => '80,443', 'exposes' => '80', 'status' => 'running', 'exclude_from_status' => false, 'required_fqdn' => true, 'image' => 'nginx:latest', 'is_log_drain_enabled' => true, 'is_include_timestamps' => true, 'is_gzip_enabled' => true, 'is_stripprefix_enabled' => true, 'last_online_at' => now()->toISOString(), 'is_migrated' => false, ]); expect($svcApp->exists)->toBeTrue(); expect($svcApp->service_id)->toBe($service->id); expect($svcApp->name)->toBe('web'); expect($svcApp->human_name)->toBe('Web Server'); expect($svcApp->image)->toBe('nginx:latest'); expect($svcApp->is_log_drain_enabled)->toBeTrue(); }); it('creates ServiceDatabase with all fillable attributes', function () { $service = Service::create([ 'docker_compose_raw' => 'services: {}', 'environment_id' => $this->environment->id, 'server_id' => $this->server->id, 'destination_id' => $this->destination->id, 'destination_type' => $this->destination->getMorphClass(), ]); $svcDb = ServiceDatabase::create([ 'service_id' => $service->id, 'name' => 'postgres', 'human_name' => 'PostgreSQL', 'description' => 'Main database', 'ports' => '5432', 'exposes' => '5432', 'status' => 'running', 'exclude_from_status' => false, 'image' => 'postgres:16', 'public_port' => 15432, 'is_public' => true, 'is_log_drain_enabled' => true, 'is_include_timestamps' => true, 'is_gzip_enabled' => false, 'is_stripprefix_enabled' => false, 'last_online_at' => now()->toISOString(), 'is_migrated' => false, 'custom_type' => 'postgresql', 'public_port_timeout' => 3600, ]); expect($svcDb->exists)->toBeTrue(); expect($svcDb->service_id)->toBe($service->id); expect($svcDb->name)->toBe('postgres'); expect($svcDb->public_port)->toBe(15432); expect($svcDb->is_public)->toBeTrue(); expect($svcDb->custom_type)->toBe('postgresql'); }); it('creates StandalonePostgresql with all fillable attributes', function () { $db = StandalonePostgresql::create([ 'uuid' => 'custom-pg-uuid', 'name' => 'Full Fillable Postgres', 'description' => 'PG with all attrs', 'postgres_user' => 'testuser', 'postgres_password' => 'testpass123', 'postgres_db' => 'testdb', 'postgres_initdb_args' => '--encoding=UTF8', 'postgres_host_auth_method' => 'scram-sha-256', 'postgres_conf' => 'max_connections=200', 'init_scripts' => 'CREATE TABLE test (id int);', 'status' => 'running', 'image' => 'postgres:16-alpine', 'is_public' => true, 'public_port' => 25432, 'ports_mappings' => '25432:5432', 'limits_memory' => '1g', 'limits_memory_swap' => '2g', 'limits_memory_swappiness' => 50, 'limits_memory_reservation' => '512m', 'limits_cpus' => '2', 'limits_cpuset' => '0-1', 'limits_cpu_shares' => 1024, 'started_at' => now()->subDay()->toISOString(), 'restart_count' => 1, 'last_restart_at' => now()->subHours(6)->toISOString(), 'last_restart_type' => 'manual', 'last_online_at' => now()->toISOString(), 'public_port_timeout' => 7200, 'enable_ssl' => true, 'ssl_mode' => 'verify-full', 'is_log_drain_enabled' => true, 'is_include_timestamps' => true, 'custom_docker_run_options' => '--shm-size=256m', 'destination_type' => $this->destination->getMorphClass(), 'destination_id' => $this->destination->id, 'environment_id' => $this->environment->id, ]); expect($db->exists)->toBeTrue(); expect($db->uuid)->toBe('custom-pg-uuid'); expect($db->postgres_user)->toBe('testuser'); expect($db->postgres_db)->toBe('testdb'); expect($db->is_public)->toBeTrue(); expect($db->public_port)->toBe(25432); expect($db->enable_ssl)->toBeTrue(); expect($db->environment_id)->toBe($this->environment->id); }); it('creates StandaloneMysql with all fillable attributes', function () { $db = StandaloneMysql::create([ 'uuid' => 'custom-mysql-uuid', 'name' => 'Full Fillable MySQL', 'description' => 'MySQL with all attrs', 'mysql_root_password' => 'rootpass123', 'mysql_user' => 'testuser', 'mysql_password' => 'testpass123', 'mysql_database' => 'testdb', 'mysql_conf' => '[mysqld]\nmax_connections=200', 'status' => 'running', 'image' => 'mysql:8.0', 'is_public' => false, 'public_port' => 23306, 'ports_mappings' => '23306:3306', 'limits_memory' => '1g', 'limits_memory_swap' => '2g', 'limits_memory_swappiness' => 50, 'limits_memory_reservation' => '512m', 'limits_cpus' => '2', 'limits_cpuset' => '0-1', 'limits_cpu_shares' => 1024, 'started_at' => now()->subDay()->toISOString(), 'restart_count' => 0, 'last_restart_at' => null, 'last_restart_type' => null, 'last_online_at' => now()->toISOString(), 'public_port_timeout' => 3600, 'enable_ssl' => true, 'ssl_mode' => 'REQUIRED', 'is_log_drain_enabled' => false, 'is_include_timestamps' => false, 'custom_docker_run_options' => '--ulimit nofile=65535:65535', 'destination_type' => $this->destination->getMorphClass(), 'destination_id' => $this->destination->id, 'environment_id' => $this->environment->id, ]); expect($db->exists)->toBeTrue(); expect($db->uuid)->toBe('custom-mysql-uuid'); expect($db->mysql_root_password)->toBe('rootpass123'); expect($db->mysql_database)->toBe('testdb'); expect($db->enable_ssl)->toBeTrue(); expect($db->environment_id)->toBe($this->environment->id); }); it('creates StandaloneMariadb with all fillable attributes', function () { $db = StandaloneMariadb::create([ 'uuid' => 'custom-maria-uuid', 'name' => 'Full Fillable MariaDB', 'description' => 'MariaDB with all attrs', 'mariadb_root_password' => 'rootpass123', 'mariadb_user' => 'testuser', 'mariadb_password' => 'testpass123', 'mariadb_database' => 'testdb', 'mariadb_conf' => '[mysqld]\nmax_connections=200', 'status' => 'running', 'image' => 'mariadb:11', 'is_public' => false, 'public_port' => 23307, 'ports_mappings' => '23307:3306', 'limits_memory' => '1g', 'limits_memory_swap' => '2g', 'limits_memory_swappiness' => 50, 'limits_memory_reservation' => '512m', 'limits_cpus' => '2', 'limits_cpuset' => '0-1', 'limits_cpu_shares' => 1024, 'started_at' => now()->subDay()->toISOString(), 'restart_count' => 0, 'last_restart_at' => null, 'last_restart_type' => null, 'last_online_at' => now()->toISOString(), 'public_port_timeout' => 3600, 'enable_ssl' => false, 'is_log_drain_enabled' => false, 'custom_docker_run_options' => '', 'destination_type' => $this->destination->getMorphClass(), 'destination_id' => $this->destination->id, 'environment_id' => $this->environment->id, ]); expect($db->exists)->toBeTrue(); expect($db->uuid)->toBe('custom-maria-uuid'); expect($db->mariadb_root_password)->toBe('rootpass123'); expect($db->mariadb_database)->toBe('testdb'); expect($db->environment_id)->toBe($this->environment->id); }); it('creates StandaloneMongodb with all fillable attributes', function () { $db = StandaloneMongodb::create([ 'uuid' => 'custom-mongo-uuid', 'name' => 'Full Fillable MongoDB', 'description' => 'MongoDB with all attrs', 'mongo_conf' => '{"storage":{"dbPath":"/data/db"}}', 'mongo_initdb_root_username' => 'mongoadmin', 'mongo_initdb_root_password' => 'mongopass123', 'mongo_initdb_database' => 'testdb', 'status' => 'running', 'image' => 'mongo:7', 'is_public' => false, 'public_port' => 27018, 'ports_mappings' => '27018:27017', 'limits_memory' => '2g', 'limits_memory_swap' => '4g', 'limits_memory_swappiness' => 60, 'limits_memory_reservation' => '1g', 'limits_cpus' => '4', 'limits_cpuset' => '0-3', 'limits_cpu_shares' => 2048, 'started_at' => now()->subDay()->toISOString(), 'restart_count' => 0, 'last_restart_at' => null, 'last_restart_type' => null, 'last_online_at' => now()->toISOString(), 'public_port_timeout' => 3600, 'enable_ssl' => false, 'ssl_mode' => 'prefer', 'is_log_drain_enabled' => false, 'is_include_timestamps' => false, 'custom_docker_run_options' => '', 'destination_type' => $this->destination->getMorphClass(), 'destination_id' => $this->destination->id, 'environment_id' => $this->environment->id, ]); expect($db->exists)->toBeTrue(); expect($db->uuid)->toBe('custom-mongo-uuid'); expect($db->mongo_initdb_root_username)->toBe('mongoadmin'); expect($db->mongo_initdb_database)->toBe('testdb'); expect($db->environment_id)->toBe($this->environment->id); }); it('creates StandaloneRedis with all fillable attributes', function () { $db = StandaloneRedis::create([ 'uuid' => 'custom-redis-uuid', 'name' => 'Full Fillable Redis', 'description' => 'Redis with all attrs', 'redis_conf' => 'maxmemory 256mb\nmaxmemory-policy allkeys-lru', 'status' => 'running', 'image' => 'redis:7-alpine', 'is_public' => true, 'public_port' => 26379, 'ports_mappings' => '26379:6379', 'limits_memory' => '512m', 'limits_memory_swap' => '1g', 'limits_memory_swappiness' => 30, 'limits_memory_reservation' => '256m', 'limits_cpus' => '1', 'limits_cpuset' => '0', 'limits_cpu_shares' => 512, 'started_at' => now()->subDay()->toISOString(), 'restart_count' => 0, 'last_restart_at' => null, 'last_restart_type' => null, 'last_online_at' => now()->toISOString(), 'public_port_timeout' => 3600, 'enable_ssl' => false, 'is_log_drain_enabled' => false, 'is_include_timestamps' => false, 'custom_docker_run_options' => '', 'destination_type' => $this->destination->getMorphClass(), 'destination_id' => $this->destination->id, 'environment_id' => $this->environment->id, ]); expect($db->exists)->toBeTrue(); expect($db->uuid)->toBe('custom-redis-uuid'); expect($db->redis_conf)->toContain('maxmemory'); expect($db->is_public)->toBeTrue(); expect($db->environment_id)->toBe($this->environment->id); }); it('creates StandaloneKeydb with all fillable attributes', function () { $db = StandaloneKeydb::create([ 'uuid' => 'custom-keydb-uuid', 'name' => 'Full Fillable KeyDB', 'description' => 'KeyDB with all attrs', 'keydb_password' => 'keydbpass123', 'keydb_conf' => 'server-threads 4', 'is_log_drain_enabled' => false, 'is_include_timestamps' => false, 'status' => 'running', 'image' => 'eqalpha/keydb:latest', 'is_public' => false, 'public_port' => 26380, 'ports_mappings' => '26380:6379', 'limits_memory' => '512m', 'limits_memory_swap' => '1g', 'limits_memory_swappiness' => 30, 'limits_memory_reservation' => '256m', 'limits_cpus' => '2', 'limits_cpuset' => '0-1', 'limits_cpu_shares' => 512, 'started_at' => now()->subDay()->toISOString(), 'restart_count' => 0, 'last_restart_at' => null, 'last_restart_type' => null, 'last_online_at' => now()->toISOString(), 'public_port_timeout' => 3600, 'enable_ssl' => false, 'custom_docker_run_options' => '', 'destination_type' => $this->destination->getMorphClass(), 'destination_id' => $this->destination->id, 'environment_id' => $this->environment->id, ]); expect($db->exists)->toBeTrue(); expect($db->uuid)->toBe('custom-keydb-uuid'); expect($db->keydb_password)->toBe('keydbpass123'); expect($db->environment_id)->toBe($this->environment->id); }); it('creates StandaloneDragonfly with all fillable attributes', function () { $db = StandaloneDragonfly::create([ 'uuid' => 'custom-dragonfly-uuid', 'name' => 'Full Fillable Dragonfly', 'description' => 'Dragonfly with all attrs', 'dragonfly_password' => 'dragonflypass123', 'is_log_drain_enabled' => false, 'is_include_timestamps' => false, 'status' => 'running', 'image' => 'docker.dragonflydb.io/dragonflydb/dragonfly:latest', 'is_public' => false, 'public_port' => 26381, 'ports_mappings' => '26381:6379', 'limits_memory' => '1g', 'limits_memory_swap' => '2g', 'limits_memory_swappiness' => 30, 'limits_memory_reservation' => '512m', 'limits_cpus' => '2', 'limits_cpuset' => '0-1', 'limits_cpu_shares' => 512, 'started_at' => now()->subDay()->toISOString(), 'restart_count' => 0, 'last_restart_at' => null, 'last_restart_type' => null, 'last_online_at' => now()->toISOString(), 'public_port_timeout' => 3600, 'enable_ssl' => false, 'custom_docker_run_options' => '', 'destination_type' => $this->destination->getMorphClass(), 'destination_id' => $this->destination->id, 'environment_id' => $this->environment->id, ]); expect($db->exists)->toBeTrue(); expect($db->uuid)->toBe('custom-dragonfly-uuid'); expect($db->dragonfly_password)->toBe('dragonflypass123'); expect($db->environment_id)->toBe($this->environment->id); }); it('creates StandaloneClickhouse with all fillable attributes', function () { $db = StandaloneClickhouse::create([ 'uuid' => 'custom-ch-uuid', 'name' => 'Full Fillable ClickHouse', 'description' => 'ClickHouse with all attrs', 'clickhouse_admin_user' => 'chadmin', 'clickhouse_admin_password' => 'chpass123', 'is_log_drain_enabled' => false, 'is_include_timestamps' => false, 'status' => 'running', 'image' => 'clickhouse/clickhouse-server:latest', 'is_public' => false, 'public_port' => 28123, 'ports_mappings' => '28123:8123', 'limits_memory' => '2g', 'limits_memory_swap' => '4g', 'limits_memory_swappiness' => 30, 'limits_memory_reservation' => '1g', 'limits_cpus' => '4', 'limits_cpuset' => '0-3', 'limits_cpu_shares' => 2048, 'started_at' => now()->subDay()->toISOString(), 'restart_count' => 0, 'last_restart_at' => null, 'last_restart_type' => null, 'last_online_at' => now()->toISOString(), 'public_port_timeout' => 3600, 'custom_docker_run_options' => '', 'clickhouse_db' => 'testdb', 'destination_type' => $this->destination->getMorphClass(), 'destination_id' => $this->destination->id, 'environment_id' => $this->environment->id, ]); expect($db->exists)->toBeTrue(); expect($db->uuid)->toBe('custom-ch-uuid'); expect($db->clickhouse_admin_user)->toBe('chadmin'); expect($db->clickhouse_db)->toBe('testdb'); expect($db->environment_id)->toBe($this->environment->id); }); it('creates SwarmDocker with all fillable attributes', function () { $swarm = SwarmDocker::create([ 'server_id' => $this->server->id, 'name' => 'swarm-dest', 'network' => 'coolify-swarm', ]); expect($swarm->exists)->toBeTrue(); expect($swarm->server_id)->toBe($this->server->id); expect($swarm->name)->toBe('swarm-dest'); expect($swarm->network)->toBe('coolify-swarm'); }); it('creates StandaloneDocker with all fillable attributes', function () { $docker = StandaloneDocker::create([ 'server_id' => $this->server->id, 'name' => 'standalone-dest', 'network' => 'coolify-standalone', ]); expect($docker->exists)->toBeTrue(); expect($docker->server_id)->toBe($this->server->id); expect($docker->name)->toBe('standalone-dest'); expect($docker->network)->toBe('coolify-standalone'); }); it('creates ScheduledTask with all fillable attributes', function () { $app = Application::create([ 'name' => 'task-test-app', 'git_repository' => 'https://github.com/test/repo', 'git_branch' => 'main', 'build_pack' => 'nixpacks', 'ports_exposes' => '3000', 'environment_id' => $this->environment->id, 'destination_id' => $this->destination->id, 'destination_type' => $this->destination->getMorphClass(), ]); $task = ScheduledTask::create([ 'uuid' => 'custom-task-uuid', 'enabled' => true, 'name' => 'Full Fillable Task', 'command' => 'php artisan schedule:run', 'frequency' => '* * * * *', 'container' => 'app', 'timeout' => 300, 'team_id' => $this->team->id, 'application_id' => $app->id, 'service_id' => null, ]); expect($task->exists)->toBeTrue(); expect($task->uuid)->toBe('custom-task-uuid'); expect($task->name)->toBe('Full Fillable Task'); expect($task->command)->toBe('php artisan schedule:run'); expect($task->frequency)->toBe('* * * * *'); expect($task->container)->toBe('app'); expect($task->timeout)->toBe(300); expect($task->team_id)->toBe($this->team->id); expect($task->application_id)->toBe($app->id); }); it('creates ScheduledDatabaseBackup with all fillable attributes', function () { $db = StandalonePostgresql::create([ 'name' => 'backup-test-pg', 'postgres_user' => 'user', 'postgres_password' => 'pass', 'postgres_db' => 'testdb', 'destination_type' => $this->destination->getMorphClass(), 'destination_id' => $this->destination->id, 'environment_id' => $this->environment->id, ]); $backup = ScheduledDatabaseBackup::create([ 'uuid' => 'custom-backup-uuid', 'team_id' => $this->team->id, 'description' => 'Full fillable backup', 'enabled' => true, 'save_s3' => false, 'frequency' => '0 2 * * *', 'database_backup_retention_amount_locally' => 10, 'database_type' => $db->getMorphClass(), 'database_id' => $db->id, 's3_storage_id' => null, 'databases_to_backup' => 'testdb', 'dump_all' => false, 'database_backup_retention_days_locally' => 30, 'database_backup_retention_max_storage_locally' => 5000, 'database_backup_retention_amount_s3' => 20, 'database_backup_retention_days_s3' => 60, 'database_backup_retention_max_storage_s3' => 10000, 'timeout' => 600, 'disable_local_backup' => false, ]); expect($backup->exists)->toBeTrue(); expect($backup->uuid)->toBe('custom-backup-uuid'); expect($backup->frequency)->toBe('0 2 * * *'); expect($backup->database_backup_retention_amount_locally)->toBe(10); expect($backup->databases_to_backup)->toBe('testdb'); expect($backup->timeout)->toBe(600); }); it('creates ScheduledDatabaseBackupExecution with all fillable attributes', function () { $db = StandalonePostgresql::create([ 'name' => 'exec-test-pg', 'postgres_user' => 'user', 'postgres_password' => 'pass', 'postgres_db' => 'testdb', 'destination_type' => $this->destination->getMorphClass(), 'destination_id' => $this->destination->id, 'environment_id' => $this->environment->id, ]); $backup = ScheduledDatabaseBackup::create([ 'frequency' => '0 2 * * *', 'database_type' => $db->getMorphClass(), 'database_id' => $db->id, 'team_id' => $this->team->id, ]); $execution = ScheduledDatabaseBackupExecution::create([ 'uuid' => 'custom-exec-uuid', 'scheduled_database_backup_id' => $backup->id, 'status' => 'success', 'message' => 'Backup completed successfully', 'size' => 1048576, 'filename' => 'backup-2026-03-31.sql.gz', 'database_name' => 'testdb', 'finished_at' => now()->toISOString(), 'local_storage_deleted' => false, 's3_storage_deleted' => false, 's3_uploaded' => false, ]); expect($execution->exists)->toBeTrue(); expect($execution->uuid)->toBe('custom-exec-uuid'); expect($execution->status)->toBe('success'); expect($execution->filename)->toBe('backup-2026-03-31.sql.gz'); expect($execution->database_name)->toBe('testdb'); expect($execution->size)->toBe(1048576); }); it('creates ScheduledTaskExecution with all fillable attributes', function () { $app = Application::create([ 'name' => 'task-exec-app', 'git_repository' => 'https://github.com/test/repo', 'git_branch' => 'main', 'build_pack' => 'nixpacks', 'ports_exposes' => '3000', 'environment_id' => $this->environment->id, 'destination_id' => $this->destination->id, 'destination_type' => $this->destination->getMorphClass(), ]); $task = ScheduledTask::create([ 'name' => 'exec-test-task', 'command' => 'echo hello', 'frequency' => '* * * * *', 'timeout' => 60, 'team_id' => $this->team->id, 'application_id' => $app->id, ]); $execution = ScheduledTaskExecution::create([ 'scheduled_task_id' => $task->id, 'status' => 'success', 'message' => 'Task completed successfully', 'finished_at' => now()->toISOString(), 'started_at' => now()->subMinute()->toISOString(), 'retry_count' => 0, 'duration' => 60, 'error_details' => null, ]); expect($execution->exists)->toBeTrue(); expect($execution->scheduled_task_id)->toBe($task->id); expect($execution->status)->toBe('success'); expect((float) $execution->duration)->toBe(60.0); expect($execution->retry_count)->toBe(0); }); it('creates GithubApp with all fillable attributes', function () { $githubApp = GithubApp::create([ 'team_id' => $this->team->id, 'private_key_id' => $this->server->private_key_id, 'name' => 'Full Fillable GH App', 'organization' => 'coollabsio', 'api_url' => 'https://api.github.com', 'html_url' => 'https://github.com', 'custom_user' => 'git', 'custom_port' => 22, 'app_id' => 12345, 'installation_id' => 67890, 'client_id' => 'Iv1.abc123', 'client_secret' => 'secret-456', 'webhook_secret' => 'whsec-789', 'is_system_wide' => false, 'is_public' => false, 'contents' => 'read', 'metadata' => 'read', 'pull_requests' => 'write', 'administration' => 'read', ]); expect($githubApp->exists)->toBeTrue(); expect($githubApp->name)->toBe('Full Fillable GH App'); expect($githubApp->organization)->toBe('coollabsio'); expect($githubApp->app_id)->toBe(12345); expect($githubApp->installation_id)->toBe(67890); expect($githubApp->client_id)->toBe('Iv1.abc123'); expect($githubApp->team_id)->toBe($this->team->id); expect($githubApp->private_key_id)->toBe($this->server->private_key_id); }); it('creates Subscription with all fillable attributes', function () { $sub = Subscription::create([ 'team_id' => $this->team->id, 'stripe_invoice_paid' => true, 'stripe_subscription_id' => 'sub_1234567890', 'stripe_customer_id' => 'cus_1234567890', 'stripe_cancel_at_period_end' => false, 'stripe_plan_id' => 'price_1234567890', 'stripe_feedback' => 'Great service', 'stripe_comment' => 'Will renew', 'stripe_trial_already_ended' => true, 'stripe_past_due' => false, 'stripe_refunded_at' => null, ]); expect($sub->exists)->toBeTrue(); expect($sub->team_id)->toBe($this->team->id); expect($sub->stripe_subscription_id)->toBe('sub_1234567890'); expect($sub->stripe_customer_id)->toBe('cus_1234567890'); expect($sub->stripe_plan_id)->toBe('price_1234567890'); expect($sub->stripe_invoice_paid)->toBeTrue(); }); it('creates CloudProviderToken with all fillable attributes', function () { $token = CloudProviderToken::create([ 'team_id' => $this->team->id, 'provider' => 'hetzner', 'token' => 'hcloud-token-abc123', 'name' => 'My Hetzner Token', ]); expect($token->exists)->toBeTrue(); expect($token->team_id)->toBe($this->team->id); expect($token->provider)->toBe('hetzner'); expect($token->token)->toBe('hcloud-token-abc123'); expect($token->name)->toBe('My Hetzner Token'); }); it('creates Tag with all fillable attributes', function () { $tag = Tag::create([ 'name' => 'production', 'team_id' => $this->team->id, ]); expect($tag->exists)->toBeTrue(); expect($tag->name)->toBe('production'); expect($tag->team_id)->toBe($this->team->id); });