use sqlx::postgres::Postgres; use sqlx::Pool; use windmill_test_utils::{initialize_tracing, ApiServer}; /// Integration test: exercises every explicit-column query in `tarball_workspace`. /// /// Creates one entity of each type (folder, script, resource, resource_type, /// variable, schedule, group) in the test workspace, then calls the tarball /// export endpoint with all include_* flags enabled. Success means every /// `SELECT col1, col2, ...` list matches the database schema. /// /// Tables exercised (one explicit-column query each): /// folder, script, resource, resource_type, variable, schedule, usr, group_ #[sqlx::test(fixtures("base"))] async fn test_tarball_export_all_tables(db: Pool) -> anyhow::Result<()> { initialize_tracing().await; let server = ApiServer::start(db.clone()).await?; let port = server.addr.port(); let base_url = format!("http://localhost:{port}"); let client = windmill_api_client::create_client(&base_url, "SECRET_TOKEN".to_string()); let http = client.client(); // ---- folder ---- sqlx::query( r#"INSERT INTO folder (workspace_id, name, display_name, owners, extra_perms, summary) VALUES ($1, $2, $3, $4, '{}'::jsonb, $5)"#, ) .bind("test-workspace") .bind("test_folder") .bind("Test Folder") .bind(vec!["u/test-user"]) .bind("a test folder") .execute(&db) .await?; // ---- script (exercises the 30-column Script query) ---- client .create_script( "test-workspace", &windmill_api_client::types::NewScript { draft_only: None, content: "export function main() { return 42; }".to_string(), language: windmill_api_client::types::ScriptLang::Bun, path: "f/test_folder/test_script".to_string(), summary: "test script".to_string(), description: "script for export test".to_string(), kind: Some("script".to_string()), tag: Some("test".to_string()), lock: None, parent_hash: None, schema: Default::default(), is_template: None, dedicated_worker: None, ws_error_handler_muted: None, priority: None, cache_ttl: None, concurrent_limit: None, concurrency_time_window_s: None, timeout: None, delete_after_secs: None, restart_unless_cancelled: None, visible_to_runner_only: None, auto_kind: None, on_behalf_of_email: None, has_preprocessor: None, codebase: None, envs: vec![], deployment_message: None, assets: vec![], modules: None, concurrency_key: None, }, ) .await?; // ---- resource ---- sqlx::query( r#"INSERT INTO resource (workspace_id, path, value, description, resource_type, created_by) VALUES ($1, $2, $3, $4, $5, $6)"#, ) .bind("test-workspace") .bind("f/test_folder/test_res") .bind(serde_json::json!({"url": "http://example.com"})) .bind("test resource") .bind("http") .bind("test-user") .execute(&db) .await?; // ---- resource_type ---- sqlx::query( r#"INSERT INTO resource_type (workspace_id, name, schema, description, created_by) VALUES ($1, $2, $3, $4, $5)"#, ) .bind("test-workspace") .bind("http") .bind(serde_json::json!({"type": "object"})) .bind("HTTP resource type") .bind("system") .execute(&db) .await?; // ---- variable ---- sqlx::query( r#"INSERT INTO variable (workspace_id, path, value, is_secret, description, account) VALUES ($1, $2, $3, $4, $5, $6)"#, ) .bind("test-workspace") .bind("f/test_folder/test_var") .bind("test_value") .bind(false) .bind("test variable") .bind(None::) .execute(&db) .await?; // ---- schedule ---- client .create_schedule( "test-workspace", &windmill_api_client::types::NewSchedule { schedule: "0 0 0 * * *".to_string(), script_path: "f/test_folder/test_script".to_string(), path: "f/test_folder/test_schedule".to_string(), is_flow: false, timezone: "UTC".to_string(), args: Default::default(), enabled: Some(false), description: Some("test schedule".to_string()), summary: Some("test schedule".to_string()), tag: None, cron_version: Some("v2".to_string()), on_failure: None, on_failure_times: None, on_failure_exact: None, on_failure_extra_args: None, on_recovery: None, on_recovery_times: None, on_recovery_extra_args: None, on_success: None, on_success_extra_args: None, ws_error_handler_muted: None, retry: None, no_flow_overlap: None, }, ) .await?; // ---- group_ (base fixture already has "all", create one more for include_groups) ---- sqlx::query( "INSERT INTO group_ (workspace_id, name, summary, extra_perms) VALUES ($1, $2, $3, '{}'::jsonb)", ) .bind("test-workspace") .bind("testgroup") .bind("test group") .execute(&db) .await?; // ---- tarball export: hits ALL explicit-column queries at once ---- let params = [ "archive_type=tar", "include_schedules=true", "include_users=true", "include_groups=true", "include_settings=true", "include_workspace_dependencies=true", "settings_version=v1", ]; let resp = http .get(format!( "{}/api/w/test-workspace/workspaces/tarball?{}", base_url, params.join("&") )) .bearer_auth("SECRET_TOKEN") .send() .await?; assert_eq!( resp.status(), 200, "tarball export failed: {}", resp.text().await.unwrap_or_default() ); // Verify we got actual bytes back let body = resp.bytes().await?; assert!(!body.is_empty(), "tarball export returned empty body"); Ok(()) }