* feat: add optional labels to scripts, flows, apps, raw apps, schedules, and triggers
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: update sqlx cache, make labels optional in openapi, regenerate system prompts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add minimal labels input UI to script, flow, and schedule editors
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: reduce gap between summary and labels input
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add labels to script/flow detail pages and summary/path popover
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: move labels inside SummaryPathDisplay trigger for clickable area, reduce gap
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: display labels inline to the right of summary, not below
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: increase gap between summary and labels
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add labels to resources/variables, make labels nullable, add home page label filter badges
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add labels to workspace export/import, resources, variables + test coverage
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: make migration idempotent, regenerate sqlx cache after merge
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: pass labels in script create and flow create/update API calls
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add labels input UI to resource and variable editors
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove negative margin from LabelsInput to prevent overlap
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add top and left margin to LabelsInput for better spacing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: reduce left margin on LabelsInput
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: widen label input to w-32
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use inline-flex so LabelsInput doesn't stretch full width
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove flex-wrap so label input stays on same line as badges
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add label filter presets to resources, variables, and schedules search
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use max-w-32 on label input to prevent stretching
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: pull labels closer to summary with negative top margin
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: increase negative margin to pull labels even closer to summary
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: pass labels in schedule create/update API calls
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use COALESCE to preserve existing labels when not provided in schedule/flow update
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add labels to CreateResource, EditResource, CreateVariable, EditVariable in OpenAPI spec
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: display label badges on resource and variable list pages
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: display label badges on schedule and all trigger list pages
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add folder and label presets to schedules search filter
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: apply user_folders_only filter on all workspaces including admins
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add label presets to resources and variables search filters
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: derive folder presets from loaded items, not all workspace folders
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add label query parameter to resource and variable list endpoints in OpenAPI
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: display label filter badges inline with folder filters on home page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Revert "feat: display label filter badges inline with folder filters on home page"
This reverts commit 6767a50aa6.
* feat: support comma-separated label filters (allowMultiple) in all list endpoints
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: append label presets with comma for allowMultiple filters instead of duplicating key
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: hide label presets that are already in the comma-separated filter value
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: replace unsafe manual SQL ARRAY construction with parameterized queries, add labels to ScriptWDraft
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: complete down migration, add labels to Resource/Variable OpenAPI schemas, remove type cast, add label length validation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add labels field to Schedule test fixture
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add labels field to Rust client struct constructions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: regenerate sqlx cache with --all-features for EE builds
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: regenerate sqlx cache and package-lock after merge with main
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: squash two migrations into one, use IF NOT EXISTS for idempotency
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: track label changes in SummaryPathDisplay to enable save button
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use JSON string comparison for label dirty tracking in popover
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: navigate to script by path after save from popover to load new version
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: update initialLabels after save so subsequent label changes enable save again
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use onchange callback for label dirty tracking instead of derived comparison
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: reload script by path after label save to fetch new version
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: propagate script/flow labels to jobs at push time
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: show script/flow labels on runs page, merge with wm_labels for completed jobs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: change job labels type from JSONB to text[], show labels on job detail page, fix type mismatch
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add labels to QueuedJob struct, fix get_job queries to return v2_job.labels
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: replace +Label text with icon only
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add tag icon before labels on job detail page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: move tag icon inside badge on job detail page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use blue badge with tag icon in RunBadges, remove duplicate labels from JobDetailHeader
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: set icon position to left so tag icon renders in badge
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: render Tag icon inline in badge children instead of via icon prop
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: retry icon prop with small badge and position left
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add hover tooltip showing "Label: X" on job label badges
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: include v2_job.labels in runs page label filter and broad search
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: regenerate sqlx cache and system prompts after merge with main
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add labels to EE JobPayload constructions, regenerate sqlx cache with --all-features
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: regenerate sqlx cache CE-only (without EE symlinks that cause conflicts)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: update remaining wm_labels JSONB queries to use text[] merge expression
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: simplify job labels to just read v2_job.labels (wm_labels already merged at completion)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: consistent label badge spacing with gap-0.5 wrapper and px-0.5 on badges
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add labels: None to test utils JobPayload construction
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add labels to all test fixture JobPayload/NewFlow/EditApp constructions, regenerate sqlx cache
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: fix vertical content shift by fixing container and input height to h-5
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: npm_check errors - unused imports, combinedItems order, flow.labels type, badge px-1 padding
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove unused FolderService imports, fix label badge alignment in RunBadges
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: restore deleted service imports in variables page, remove empty loadFolders
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: trigger CI with updated ee-repo-ref
* chore: update ee-repo-ref to merged EE companion PR
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: trigger fresh CI run for updated ee-repo-ref
* fix: match label badge size with other badges in RunBadges using {large} prop
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove icon from RunBadges label badge to fix vertical alignment
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: shorten "Job kind" to "Kind" in run badges
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add small inline tag icon (10px, -mt-px) to label badge without disrupting height
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add "Label: X" hover tooltip to all label badges, show hidden labels on +N hover
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add tag icon and "Label: X" tooltip to home page label filter badges
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: show LabelsInput even when path is hidden in ResourceEditor
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add labels input to new resource creation drawer (AppConnectInner)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* iterate
* fix: add LabelsInput to all resource creation steps in AppConnectInner
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: reduce LabelsInput top margin from -mt-3 to -mt-1
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: increase negative margin to -mt-2 for tighter spacing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: split the difference with -mt-1.5
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: adjust to -mt-1 for label spacing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: per-site label spacing via class prop instead of global negative margin
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: make label badges clickable to toggle label filter on resources, variables, schedules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use proper array indexOf for label filter toggle, set undefined correctly on removal
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use delete instead of undefined to properly clear label filter
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add /labels/list endpoint and autocomplete dropdown to LabelsInput
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use inline preventDefault for Svelte 5 event handling
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add "Create new" option in label autocomplete, regenerate sqlx cache with update_sqlx.sh
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add GIN indexes on labels column for all 16 tables
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove CONCURRENTLY from GIN index creation in migration
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: add comprehensive label coverage for pull, edit, removal across all item types
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: simplify job label filters to only use v2_job.labels, remove wm_labels back-compat
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: add integration tests for job label propagation, display, and filtering
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address PR review findings — missing labels in fetch_script_for_update, app rename, escape key bug
- Add `labels` to SELECT in `fetch_script_for_update` to prevent lost labels on script clone
- Pass `labels` in app branch of `moveRenameManager.ts` so app renames preserve labels
- Clear `inputValue` before `adding = false` in LabelsInput escape handler to prevent accidental label add via onblur
- Fix `test_job_label_filter` to complete jobs via SQL (label filtering only works on completed jobs)
- Add `test_wm_labels_from_result_merged_with_static_labels` integration test using Bun
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1024 lines
39 KiB
Rust
1024 lines
39 KiB
Rust
mod job_payload {
|
|
use serde_json::json;
|
|
use sqlx::{Pool, Postgres};
|
|
use windmill_common::flow_status::RestartedFrom;
|
|
use windmill_common::flows::{FlowModule, FlowModuleValue, FlowValue};
|
|
use windmill_common::jobs::JobPayload;
|
|
use windmill_common::scripts::{ScriptHash, ScriptLang};
|
|
|
|
use windmill_common::min_version::{
|
|
MIN_VERSION, MIN_VERSION_IS_AT_LEAST_1_427, MIN_VERSION_IS_AT_LEAST_1_432,
|
|
MIN_VERSION_IS_AT_LEAST_1_440,
|
|
};
|
|
use windmill_test_utils::*;
|
|
|
|
pub async fn initialize_tracing() {
|
|
use std::sync::Once;
|
|
|
|
static ONCE: Once = Once::new();
|
|
ONCE.call_once(|| {
|
|
let _ = windmill_common::tracing_init::initialize_tracing(
|
|
"test",
|
|
&windmill_common::utils::Mode::Standalone,
|
|
"test",
|
|
);
|
|
});
|
|
}
|
|
|
|
use windmill_common::cache;
|
|
use windmill_common::flows::FlowNodeId;
|
|
use windmill_common::min_version::VersionConstraint;
|
|
|
|
const VERSION_FLAGS: [&VersionConstraint; 3] = [
|
|
&MIN_VERSION_IS_AT_LEAST_1_427,
|
|
&MIN_VERSION_IS_AT_LEAST_1_432,
|
|
&MIN_VERSION_IS_AT_LEAST_1_440,
|
|
];
|
|
|
|
#[cfg(feature = "deno_core")]
|
|
#[sqlx::test(fixtures("base", "hello"))]
|
|
async fn test_script_hash_payload(db: Pool<Postgres>) -> anyhow::Result<()> {
|
|
initialize_tracing().await;
|
|
let server = ApiServer::start(db.clone()).await?;
|
|
let port = server.addr.port();
|
|
|
|
let test = || async {
|
|
let result = RunJob::from(JobPayload::ScriptHash {
|
|
hash: ScriptHash(123412),
|
|
path: "f/system/hello".to_string(),
|
|
concurrency_settings:
|
|
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
|
|
debouncing_settings:
|
|
windmill_common::runnable_settings::DebouncingSettings::default(), labels: None,
|
|
cache_ttl: None,
|
|
cache_ignore_s3_path: None,
|
|
dedicated_worker: None,
|
|
language: ScriptLang::Deno,
|
|
priority: None,
|
|
apply_preprocessor: false,
|
|
})
|
|
.arg("world", json!("foo"))
|
|
.run_until_complete(&db, false, port)
|
|
.await
|
|
.json_result()
|
|
.unwrap();
|
|
|
|
assert_eq!(result, json!("Hello foo!"));
|
|
};
|
|
test_for_versions(VERSION_FLAGS.iter().copied(), test).await;
|
|
Ok(())
|
|
}
|
|
|
|
#[sqlx::test(fixtures("base", "hello"))]
|
|
async fn test_script_hash_payload_with_preprocessor(db: Pool<Postgres>) -> anyhow::Result<()> {
|
|
initialize_tracing().await;
|
|
let server = ApiServer::start(db.clone()).await?;
|
|
let port = server.addr.port();
|
|
|
|
let test = || async {
|
|
let db = &db;
|
|
let job = RunJob::from(JobPayload::ScriptHash {
|
|
hash: ScriptHash(123413),
|
|
path: "f/system/hello_with_preprocessor".to_string(),
|
|
cache_ttl: None,
|
|
cache_ignore_s3_path: None,
|
|
dedicated_worker: None,
|
|
language: ScriptLang::Deno,
|
|
priority: None,
|
|
apply_preprocessor: true,
|
|
concurrency_settings:
|
|
windmill_common::runnable_settings::ConcurrencySettings::default(),
|
|
debouncing_settings:
|
|
windmill_common::runnable_settings::DebouncingSettings::default(), labels: None,
|
|
})
|
|
.run_until_complete_with(db, false, port, |id| async move {
|
|
let job = sqlx::query!("SELECT preprocessed FROM v2_job WHERE id = $1", id)
|
|
.fetch_one(db)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(job.preprocessed, Some(false));
|
|
})
|
|
.await;
|
|
|
|
let args = job.args.as_ref().unwrap();
|
|
assert_eq!(args.get("foo"), Some(&json!("bar")));
|
|
assert_eq!(args.get("bar"), Some(&json!("baz")));
|
|
assert_eq!(job.json_result().unwrap(), json!("Hello bar baz"));
|
|
let job = sqlx::query!("SELECT preprocessed FROM v2_job WHERE id = $1", job.id)
|
|
.fetch_one(db)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(job.preprocessed, Some(true));
|
|
};
|
|
test_for_versions(VERSION_FLAGS.iter().copied(), test).await;
|
|
Ok(())
|
|
}
|
|
|
|
#[sqlx::test(fixtures("base", "hello"))]
|
|
async fn test_flow_script_payload(db: Pool<Postgres>) -> anyhow::Result<()> {
|
|
initialize_tracing().await;
|
|
let server = ApiServer::start(db.clone()).await?;
|
|
let port = server.addr.port();
|
|
|
|
// Deploy the flow to produce the "lite" version.
|
|
let _ = RunJob::from(JobPayload::FlowDependencies {
|
|
path: "f/system/hello_with_nodes_flow".to_string(),
|
|
dedicated_worker: None,
|
|
version: 1443253234253454,
|
|
debouncing_settings: Default::default(),
|
|
})
|
|
.run_until_complete(&db, false, port)
|
|
.await
|
|
.json_result()
|
|
.unwrap();
|
|
|
|
let flow_data = cache::flow::fetch_version_lite(&db, 1443253234253454)
|
|
.await
|
|
.unwrap();
|
|
let flow_value = flow_data.value();
|
|
let flow_scripts = {
|
|
async fn load(db: &Pool<Postgres>, modules: &[FlowModule]) -> Vec<FlowNodeId> {
|
|
let mut res = vec![];
|
|
for module in modules {
|
|
let value =
|
|
serde_json::from_str::<FlowModuleValue>(module.value.get()).unwrap();
|
|
match value {
|
|
FlowModuleValue::FlowScript { id, .. } => res.push(id),
|
|
FlowModuleValue::ForloopFlow { modules_node: Some(flow_node), .. } => {
|
|
let flow_data = cache::flow::fetch_flow(db, flow_node).await.unwrap();
|
|
res.extend(Box::pin(load(db, &flow_data.value().modules)).await);
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
res
|
|
}
|
|
|
|
load(&db, &flow_value.modules).await
|
|
};
|
|
assert_eq!(flow_scripts.len(), 2);
|
|
|
|
let test = || async {
|
|
let result = RunJob::from(JobPayload::FlowScript {
|
|
id: flow_scripts[0],
|
|
language: ScriptLang::Deno,
|
|
concurrency_settings:
|
|
windmill_common::runnable_settings::ConcurrencySettings::default(),
|
|
cache_ttl: None,
|
|
cache_ignore_s3_path: None,
|
|
dedicated_worker: None,
|
|
path: "f/system/hello/test-0".into(),
|
|
})
|
|
.arg("world", json!("foo"))
|
|
.run_until_complete(&db, false, port)
|
|
.await
|
|
.json_result()
|
|
.unwrap();
|
|
|
|
assert_eq!(result, json!("Hello foo!"));
|
|
};
|
|
test_for_versions(VERSION_FLAGS.iter().copied(), test).await;
|
|
let test = || async {
|
|
let result = RunJob::from(JobPayload::FlowScript {
|
|
id: flow_scripts[1],
|
|
language: ScriptLang::Deno,
|
|
concurrency_settings:
|
|
windmill_common::runnable_settings::ConcurrencySettings::default(),
|
|
cache_ttl: None,
|
|
cache_ignore_s3_path: None,
|
|
dedicated_worker: None,
|
|
path: "f/system/hello/test-0".into(),
|
|
})
|
|
.arg("hello", json!("You know nothing Jean Neige"))
|
|
.run_until_complete(&db, false, port)
|
|
.await
|
|
.json_result()
|
|
.unwrap();
|
|
|
|
assert_eq!(
|
|
result,
|
|
json!("Did you just say \"You know nothing Jean Neige\"??!")
|
|
);
|
|
};
|
|
test_for_versions(VERSION_FLAGS.iter().copied(), test).await;
|
|
Ok(())
|
|
}
|
|
|
|
#[cfg(feature = "deno_core")]
|
|
#[sqlx::test(fixtures("base", "hello"))]
|
|
async fn test_flow_node_payload(db: Pool<Postgres>) -> anyhow::Result<()> {
|
|
initialize_tracing().await;
|
|
let server = ApiServer::start(db.clone()).await?;
|
|
let port = server.addr.port();
|
|
|
|
// Deploy the flow to produce the "lite" version.
|
|
let _ = RunJob::from(JobPayload::FlowDependencies {
|
|
path: "f/system/hello_with_nodes_flow".to_string(),
|
|
dedicated_worker: None,
|
|
version: 1443253234253454,
|
|
debouncing_settings: Default::default(),
|
|
})
|
|
.run_until_complete(&db, false, port)
|
|
.await
|
|
.json_result()
|
|
.unwrap();
|
|
|
|
let flow_data = cache::flow::fetch_version_lite(&db, 1443253234253454)
|
|
.await
|
|
.unwrap();
|
|
let flow_value = flow_data.value();
|
|
let forloop_module =
|
|
serde_json::from_str::<FlowModuleValue>(flow_value.modules[0].value.get()).unwrap();
|
|
let FlowModuleValue::ForloopFlow { modules_node: Some(id), .. } = forloop_module else {
|
|
panic!("Expected a forloop module with a flow node");
|
|
};
|
|
|
|
let test = || async {
|
|
let result = RunJob::from(JobPayload::FlowNode {
|
|
id,
|
|
path: "f/system/hello_with_nodes_flow/forloop-0".into(),
|
|
})
|
|
.arg("iter", json!({ "value": "tests", "index": 0 }))
|
|
.run_until_complete(&db, false, port)
|
|
.await
|
|
.json_result()
|
|
.unwrap();
|
|
|
|
assert_eq!(result, json!("Did you just say \"Hello tests!\"??!"));
|
|
};
|
|
test_for_versions(VERSION_FLAGS.iter().copied(), test).await;
|
|
Ok(())
|
|
}
|
|
|
|
async fn test_dependencies_payload(db: Pool<Postgres>) -> anyhow::Result<()> {
|
|
initialize_tracing().await;
|
|
let server = ApiServer::start(db.clone()).await?;
|
|
let port = server.addr.port();
|
|
|
|
let result = RunJob::from(JobPayload::Dependencies {
|
|
path: "f/system/hello".to_string(),
|
|
hash: ScriptHash(123412),
|
|
language: ScriptLang::Deno,
|
|
debouncing_settings: Default::default(),
|
|
dedicated_worker: None,
|
|
})
|
|
.run_until_complete(&db, false, port)
|
|
.await
|
|
.json_result()
|
|
.unwrap();
|
|
|
|
assert_eq!(
|
|
result.get("status").unwrap(),
|
|
&json!("Successful lock file generation")
|
|
);
|
|
Ok(())
|
|
}
|
|
|
|
#[sqlx::test(fixtures("base", "hello"))]
|
|
async fn test_dependencies_payload_min_1_427(db: Pool<Postgres>) -> anyhow::Result<()> {
|
|
*MIN_VERSION.write().await = MIN_VERSION_IS_AT_LEAST_1_427.version().clone();
|
|
test_dependencies_payload(db).await?;
|
|
Ok(())
|
|
}
|
|
#[sqlx::test(fixtures("base", "hello"))]
|
|
async fn test_dependencies_payload_min_1_432(db: Pool<Postgres>) -> anyhow::Result<()> {
|
|
*MIN_VERSION.write().await = MIN_VERSION_IS_AT_LEAST_1_432.version().clone();
|
|
test_dependencies_payload(db).await?;
|
|
Ok(())
|
|
}
|
|
#[sqlx::test(fixtures("base", "hello"))]
|
|
async fn test_dependencies_payload_min_1_440(db: Pool<Postgres>) -> anyhow::Result<()> {
|
|
*MIN_VERSION.write().await = MIN_VERSION_IS_AT_LEAST_1_440.version().clone();
|
|
test_dependencies_payload(db).await?;
|
|
Ok(())
|
|
}
|
|
|
|
// Just test that deploying a flow work as expected.
|
|
#[sqlx::test(fixtures("base", "hello"))]
|
|
async fn test_flow_dependencies_payload(db: Pool<Postgres>) -> anyhow::Result<()> {
|
|
initialize_tracing().await;
|
|
let server = ApiServer::start(db.clone()).await?;
|
|
let port = server.addr.port();
|
|
|
|
let test = || async {
|
|
let result = RunJob::from(JobPayload::FlowDependencies {
|
|
path: "f/system/hello_with_nodes_flow".to_string(),
|
|
dedicated_worker: None,
|
|
version: 1443253234253454,
|
|
debouncing_settings: Default::default(),
|
|
})
|
|
.run_until_complete(&db, false, port)
|
|
.await
|
|
.json_result()
|
|
.unwrap();
|
|
|
|
assert_eq!(
|
|
result.get("status").unwrap(),
|
|
&json!("Successful lock file generation")
|
|
);
|
|
};
|
|
test_for_versions(VERSION_FLAGS.iter().copied(), test).await;
|
|
Ok(())
|
|
}
|
|
|
|
#[sqlx::test(fixtures("base", "hello"))]
|
|
async fn test_raw_flow_dependencies_payload(db: Pool<Postgres>) -> anyhow::Result<()> {
|
|
initialize_tracing().await;
|
|
let server = ApiServer::start(db.clone()).await?;
|
|
let port = server.addr.port();
|
|
|
|
let test = || async {
|
|
let result = RunJob::from(JobPayload::RawFlowDependencies {
|
|
path: "none".to_string(),
|
|
flow_value: serde_json::from_value(json!({
|
|
"modules": [{
|
|
"id": "a",
|
|
"value": {
|
|
"type": "rawscript",
|
|
"content": r#"export function main(world: string) {
|
|
const greet = `Hello ${world}!`;
|
|
console.log(greet)
|
|
return greet
|
|
}"#,
|
|
"language": "deno",
|
|
"input_transforms": {
|
|
"world": { "type": "javascript", "expr": "flow_input.world" }
|
|
}
|
|
}
|
|
}],
|
|
"schema": {
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"properties": { "world": { "type": "string" } },
|
|
"type": "object",
|
|
"order": [ "world" ]
|
|
}
|
|
}))
|
|
.unwrap(),
|
|
})
|
|
.arg("skip_flow_update", json!(true))
|
|
.run_until_complete(&db, false, port)
|
|
.await
|
|
.json_result()
|
|
.unwrap();
|
|
|
|
let result = RunJob::from(JobPayload::RawFlow {
|
|
value: serde_json::from_value::<FlowValue>(
|
|
result.get("updated_flow_value").unwrap().clone(),
|
|
)
|
|
.unwrap(),
|
|
path: None,
|
|
restarted_from: None,
|
|
})
|
|
.arg("world", json!("Jean Neige"))
|
|
.run_until_complete(&db, false, port)
|
|
.await
|
|
.json_result()
|
|
.unwrap();
|
|
|
|
assert_eq!(result, json!("Hello Jean Neige!"));
|
|
};
|
|
test_for_versions(VERSION_FLAGS.iter().copied(), test).await;
|
|
Ok(())
|
|
}
|
|
|
|
#[sqlx::test(fixtures("base", "hello"))]
|
|
async fn test_raw_script_dependencies_payload(db: Pool<Postgres>) -> anyhow::Result<()> {
|
|
initialize_tracing().await;
|
|
let server = ApiServer::start(db.clone()).await?;
|
|
let port = server.addr.port();
|
|
|
|
let test = || async {
|
|
let result = RunJob::from(JobPayload::RawScriptDependencies {
|
|
script_path: "none".into(),
|
|
content: r#"export function main(world: string) {
|
|
const greet = `Hello ${world}!`;
|
|
console.log(greet)
|
|
return greet
|
|
}"#
|
|
.into(),
|
|
language: ScriptLang::Deno,
|
|
})
|
|
.run_until_complete(&db, false, port)
|
|
.await
|
|
.json_result()
|
|
.unwrap();
|
|
|
|
assert_eq!(
|
|
result,
|
|
json!({ "lock": "", "status": "Successful lock file generation" })
|
|
);
|
|
};
|
|
test_for_versions(VERSION_FLAGS.iter().copied(), test).await;
|
|
Ok(())
|
|
}
|
|
|
|
#[cfg(feature = "deno_core")]
|
|
#[sqlx::test(fixtures("base", "hello"))]
|
|
async fn test_flow_payload(db: Pool<Postgres>) -> anyhow::Result<()> {
|
|
initialize_tracing().await;
|
|
let server = ApiServer::start(db.clone()).await?;
|
|
let port = server.addr.port();
|
|
|
|
let test = || async {
|
|
let result = RunJob::from(JobPayload::Flow {
|
|
path: "f/system/hello_with_nodes_flow".to_string(),
|
|
dedicated_worker: None,
|
|
apply_preprocessor: false,
|
|
version: 1443253234253454, labels: None,
|
|
})
|
|
.run_until_complete(&db, false, port)
|
|
.await
|
|
.json_result()
|
|
.unwrap();
|
|
|
|
assert_eq!(
|
|
result,
|
|
json!([
|
|
"Did you just say \"Hello foo!\"??!",
|
|
"Did you just say \"Hello bar!\"??!",
|
|
"Did you just say \"Hello baz!\"??!",
|
|
])
|
|
);
|
|
};
|
|
// Test the not "lite" flow.
|
|
test_for_versions(VERSION_FLAGS.iter().copied(), test).await;
|
|
// Deploy the flow to produce the "lite" version.
|
|
let _ = RunJob::from(JobPayload::FlowDependencies {
|
|
path: "f/system/hello_with_nodes_flow".to_string(),
|
|
dedicated_worker: None,
|
|
version: 1443253234253454,
|
|
debouncing_settings: Default::default(),
|
|
})
|
|
.run_until_complete(&db, false, port)
|
|
.await
|
|
.json_result()
|
|
.unwrap();
|
|
// Test the "lite" flow.
|
|
test_for_versions(VERSION_FLAGS.iter().copied(), test).await;
|
|
Ok(())
|
|
}
|
|
|
|
#[cfg(feature = "deno_core")]
|
|
#[sqlx::test(fixtures("base", "hello"))]
|
|
async fn test_flow_payload_with_preprocessor(db: Pool<Postgres>) -> anyhow::Result<()> {
|
|
initialize_tracing().await;
|
|
let server = ApiServer::start(db.clone()).await?;
|
|
let port = server.addr.port();
|
|
|
|
let db = &db;
|
|
let test = || async {
|
|
use windmill_common::flow_status::{FlowStatus, FlowStatusModule};
|
|
|
|
let job = RunJob::from(JobPayload::Flow {
|
|
path: "f/system/hello_with_preprocessor".to_string(),
|
|
dedicated_worker: None,
|
|
apply_preprocessor: true,
|
|
version: 1443253234253456, labels: None,
|
|
})
|
|
.run_until_complete_with(db, false, port, |id| async move {
|
|
let job = sqlx::query!("SELECT preprocessed FROM v2_job WHERE id = $1", id)
|
|
.fetch_one(db)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(job.preprocessed, Some(false));
|
|
})
|
|
.await;
|
|
|
|
let args = job.args.as_ref().unwrap();
|
|
let flow_status = job.flow_status.as_ref().unwrap();
|
|
assert_eq!(args.get("foo"), Some(&json!("bar")));
|
|
assert_eq!(args.get("bar"), Some(&json!("baz")));
|
|
assert_eq!(job.json_result().unwrap(), json!("Hello bar-baz"));
|
|
let job = sqlx::query!("SELECT preprocessed FROM v2_job WHERE id = $1", job.id)
|
|
.fetch_one(db)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(job.preprocessed, Some(true));
|
|
let flow_status = serde_json::from_value::<FlowStatus>(flow_status.clone()).unwrap();
|
|
let FlowStatusModule::Success { job, .. } = flow_status.preprocessor_module.unwrap()
|
|
else {
|
|
panic!("Expected a success preprocessor module");
|
|
};
|
|
let pp_id = job;
|
|
let job = sqlx::query!(
|
|
"SELECT preprocessed, script_entrypoint_override FROM v2_job WHERE id = $1",
|
|
pp_id
|
|
)
|
|
.fetch_one(db)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(job.preprocessed, Some(true));
|
|
assert_eq!(
|
|
job.script_entrypoint_override.as_deref(),
|
|
Some("preprocessor")
|
|
);
|
|
};
|
|
// Test the not "lite" flow.
|
|
test_for_versions(VERSION_FLAGS.iter().copied(), test).await;
|
|
// Deploy the flow to produce the "lite" version.
|
|
let _ = RunJob::from(JobPayload::FlowDependencies {
|
|
path: "f/system/hello_with_preprocessor".to_string(),
|
|
dedicated_worker: None,
|
|
version: 1443253234253456,
|
|
debouncing_settings: Default::default(),
|
|
})
|
|
.run_until_complete(db, false, port)
|
|
.await
|
|
.json_result()
|
|
.unwrap();
|
|
// Test the "lite" flow.
|
|
test_for_versions(VERSION_FLAGS.iter().copied(), test).await;
|
|
Ok(())
|
|
}
|
|
|
|
#[cfg(feature = "deno_core")]
|
|
#[sqlx::test(fixtures("base", "hello"))]
|
|
async fn test_restarted_flow_payload(db: Pool<Postgres>) -> anyhow::Result<()> {
|
|
initialize_tracing().await;
|
|
let server = ApiServer::start(db.clone()).await?;
|
|
let port = server.addr.port();
|
|
|
|
let test = || async {
|
|
let completed_job_id = RunJob::from(JobPayload::Flow {
|
|
path: "f/system/hello_with_nodes_flow".to_string(),
|
|
dedicated_worker: None,
|
|
apply_preprocessor: true,
|
|
version: 1443253234253454, labels: None,
|
|
})
|
|
.run_until_complete(&db, false, port)
|
|
.await
|
|
.id;
|
|
|
|
let result = RunJob::from(JobPayload::RestartedFlow {
|
|
completed_job_id,
|
|
step_id: "a".into(),
|
|
branch_or_iteration_n: None,
|
|
flow_version: None,
|
|
})
|
|
.arg("iter", json!({ "value": "tests", "index": 0 }))
|
|
.run_until_complete(&db, false, port)
|
|
.await
|
|
.json_result()
|
|
.unwrap();
|
|
|
|
assert_eq!(
|
|
result,
|
|
json!([
|
|
"Did you just say \"Hello foo!\"??!",
|
|
"Did you just say \"Hello bar!\"??!",
|
|
"Did you just say \"Hello baz!\"??!",
|
|
])
|
|
);
|
|
};
|
|
// Test the not "lite" flow.
|
|
test_for_versions(VERSION_FLAGS.iter().copied(), test).await;
|
|
// Deploy the flow to produce the "lite" version.
|
|
let _ = RunJob::from(JobPayload::FlowDependencies {
|
|
path: "f/system/hello_with_nodes_flow".to_string(),
|
|
dedicated_worker: None,
|
|
version: 1443253234253454,
|
|
debouncing_settings: Default::default(),
|
|
})
|
|
.run_until_complete(&db, false, port)
|
|
.await
|
|
.json_result()
|
|
.unwrap();
|
|
// Test the "lite" flow.
|
|
test_for_versions(VERSION_FLAGS.iter().copied(), test).await;
|
|
Ok(())
|
|
}
|
|
|
|
#[cfg(feature = "deno_core")]
|
|
#[sqlx::test(fixtures("base", "hello"))]
|
|
async fn test_raw_flow_payload(db: Pool<Postgres>) -> anyhow::Result<()> {
|
|
initialize_tracing().await;
|
|
let server = ApiServer::start(db.clone()).await?;
|
|
let port = server.addr.port();
|
|
|
|
let test = || async {
|
|
let result = RunJob::from(JobPayload::RawFlow {
|
|
value: serde_json::from_value(json!({
|
|
"modules": [{
|
|
"id": "a",
|
|
"value": {
|
|
"type": "rawscript",
|
|
"content": r#"export function main(world: string) {
|
|
const greet = `Hello ${world}!`;
|
|
console.log(greet)
|
|
return greet
|
|
}"#,
|
|
"language": "deno",
|
|
"input_transforms": {
|
|
"world": { "type": "javascript", "expr": "flow_input.world" }
|
|
}
|
|
}
|
|
}],
|
|
"schema": {
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"properties": { "world": { "type": "string" } },
|
|
"type": "object",
|
|
"order": [ "world" ]
|
|
}
|
|
}))
|
|
.unwrap(),
|
|
path: None,
|
|
restarted_from: None,
|
|
})
|
|
.arg("world", json!("Jean Neige"))
|
|
.run_until_complete(&db, false, port)
|
|
.await
|
|
.json_result()
|
|
.unwrap();
|
|
|
|
assert_eq!(result, json!("Hello Jean Neige!"));
|
|
};
|
|
test_for_versions(VERSION_FLAGS.iter().copied(), test).await;
|
|
Ok(())
|
|
}
|
|
|
|
#[cfg(feature = "deno_core")]
|
|
#[sqlx::test(fixtures("base", "hello"))]
|
|
async fn test_raw_flow_payload_with_restarted_from(db: Pool<Postgres>) -> anyhow::Result<()> {
|
|
initialize_tracing().await;
|
|
let server = ApiServer::start(db.clone()).await?;
|
|
let port = server.addr.port();
|
|
|
|
let db = &db;
|
|
let test = |restarted_from, arg, result| async move {
|
|
let job = RunJob::from(JobPayload::RawFlow {
|
|
value: serde_json::from_value(json!({
|
|
"modules": [{
|
|
"id": "a",
|
|
"value": {
|
|
"type": "rawscript",
|
|
"content": r#"export function main(world: string) {
|
|
return `Hello ${world}!`;
|
|
}"#,
|
|
"language": "deno",
|
|
"input_transforms": {
|
|
"world": { "type": "javascript", "expr": "flow_input.world" }
|
|
}
|
|
}
|
|
}, {
|
|
"id": "b",
|
|
"value": {
|
|
"type": "rawscript",
|
|
"content": r#"export function main(world: string, a: string) {
|
|
return `${a} ${world}!`;
|
|
}"#,
|
|
"language": "deno",
|
|
"input_transforms": {
|
|
"world": { "type": "javascript", "expr": "flow_input.world" },
|
|
"a": { "type": "javascript", "expr": "results.a" }
|
|
}
|
|
}
|
|
}, {
|
|
"id": "c",
|
|
"value": {
|
|
"type": "forloopflow",
|
|
"iterator": { "type": "javascript", "expr": "['a', 'b', 'c']" },
|
|
"modules": [{
|
|
"value": {
|
|
"input_transforms": {
|
|
"world": { "type": "javascript", "expr": "flow_input.world" },
|
|
"b": { "type": "javascript", "expr": "results.b" },
|
|
"x": { "type": "javascript", "expr": "flow_input.iter.value" }
|
|
},
|
|
"type": "rawscript",
|
|
"language": "deno",
|
|
"content": r#"export function main(world: string, b: string, x: string) {
|
|
return `${x}: ${b} ${world}!`;
|
|
}"#,
|
|
},
|
|
}],
|
|
}
|
|
}],
|
|
"schema": {
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"properties": { "world": { "type": "string" } },
|
|
"type": "object",
|
|
"order": [ "world" ]
|
|
}
|
|
}))
|
|
.unwrap(),
|
|
path: None,
|
|
restarted_from,
|
|
})
|
|
.arg("world", arg)
|
|
.run_until_complete(db, false, port)
|
|
.await;
|
|
|
|
assert_eq!(job.json_result().unwrap(), result);
|
|
job.id
|
|
};
|
|
let flow_job_id = test(
|
|
None,
|
|
json!("foo"),
|
|
json!([
|
|
"a: Hello foo! foo! foo!",
|
|
"b: Hello foo! foo! foo!",
|
|
"c: Hello foo! foo! foo!"
|
|
]),
|
|
)
|
|
.await;
|
|
let flow_job_id = test(
|
|
Some(RestartedFrom {
|
|
flow_job_id,
|
|
step_id: "a".into(),
|
|
branch_or_iteration_n: None,
|
|
flow_version: None,
|
|
}),
|
|
json!("foo"),
|
|
json!([
|
|
"a: Hello foo! foo! foo!",
|
|
"b: Hello foo! foo! foo!",
|
|
"c: Hello foo! foo! foo!"
|
|
]),
|
|
)
|
|
.await;
|
|
let flow_job_id = test(
|
|
Some(RestartedFrom {
|
|
flow_job_id,
|
|
step_id: "b".into(),
|
|
branch_or_iteration_n: None,
|
|
flow_version: None,
|
|
}),
|
|
json!("bar"),
|
|
json!([
|
|
"a: Hello foo! bar! bar!",
|
|
"b: Hello foo! bar! bar!",
|
|
"c: Hello foo! bar! bar!"
|
|
]),
|
|
)
|
|
.await;
|
|
let _ = test(
|
|
Some(RestartedFrom {
|
|
flow_job_id,
|
|
step_id: "c".into(),
|
|
branch_or_iteration_n: Some(1),
|
|
flow_version: None,
|
|
}),
|
|
json!("yolo"),
|
|
json!([
|
|
"a: Hello foo! bar! bar!",
|
|
"b: Hello foo! bar! yolo!",
|
|
"c: Hello foo! bar! yolo!"
|
|
]),
|
|
)
|
|
.await;
|
|
Ok(())
|
|
}
|
|
|
|
#[sqlx::test(fixtures("base", "hello"))]
|
|
async fn test_dedicated_worker_preprocessor_bun(db: Pool<Postgres>) -> anyhow::Result<()> {
|
|
initialize_tracing().await;
|
|
let server = ApiServer::start(db.clone()).await?;
|
|
let port = server.addr.port();
|
|
|
|
let test = || async {
|
|
let db = &db;
|
|
let job = RunJob::from(JobPayload::ScriptHash {
|
|
hash: ScriptHash(123414),
|
|
path: "f/system/hello_preprocessor_dedicated_bun".to_string(),
|
|
cache_ttl: None,
|
|
cache_ignore_s3_path: None,
|
|
dedicated_worker: None,
|
|
language: ScriptLang::Bun,
|
|
priority: None,
|
|
apply_preprocessor: true,
|
|
concurrency_settings:
|
|
windmill_common::runnable_settings::ConcurrencySettings::default(),
|
|
debouncing_settings:
|
|
windmill_common::runnable_settings::DebouncingSettings::default(), labels: None,
|
|
})
|
|
.arg("foo", json!("hello"))
|
|
.arg("bar", json!("world"))
|
|
.run_until_complete_with(db, false, port, |id| async move {
|
|
let job = sqlx::query!("SELECT preprocessed FROM v2_job WHERE id = $1", id)
|
|
.fetch_one(db)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(job.preprocessed, Some(false));
|
|
})
|
|
.await;
|
|
|
|
let args = job.args.as_ref().unwrap();
|
|
assert_eq!(args.get("foo"), Some(&json!("hello_preprocessed")));
|
|
assert_eq!(args.get("bar"), Some(&json!("world_preprocessed")));
|
|
assert_eq!(
|
|
job.json_result().unwrap(),
|
|
json!("Hello hello_preprocessed world_preprocessed")
|
|
);
|
|
let job = sqlx::query!("SELECT preprocessed FROM v2_job WHERE id = $1", job.id)
|
|
.fetch_one(db)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(job.preprocessed, Some(true));
|
|
};
|
|
test_for_versions(VERSION_FLAGS.iter().copied(), test).await;
|
|
Ok(())
|
|
}
|
|
|
|
#[sqlx::test(fixtures("base", "hello"))]
|
|
async fn test_dedicated_worker_preprocessor_python(db: Pool<Postgres>) -> anyhow::Result<()> {
|
|
initialize_tracing().await;
|
|
let server = ApiServer::start(db.clone()).await?;
|
|
let port = server.addr.port();
|
|
|
|
let test = || async {
|
|
let db = &db;
|
|
let job = RunJob::from(JobPayload::ScriptHash {
|
|
hash: ScriptHash(123415),
|
|
path: "f/system/hello_preprocessor_dedicated_python".to_string(),
|
|
cache_ttl: None,
|
|
cache_ignore_s3_path: None,
|
|
dedicated_worker: None,
|
|
language: ScriptLang::Python3,
|
|
priority: None,
|
|
apply_preprocessor: true,
|
|
concurrency_settings:
|
|
windmill_common::runnable_settings::ConcurrencySettings::default(),
|
|
debouncing_settings:
|
|
windmill_common::runnable_settings::DebouncingSettings::default(), labels: None,
|
|
})
|
|
.arg("foo", json!("hello"))
|
|
.arg("bar", json!("world"))
|
|
.run_until_complete_with(db, false, port, |id| async move {
|
|
let job = sqlx::query!("SELECT preprocessed FROM v2_job WHERE id = $1", id)
|
|
.fetch_one(db)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(job.preprocessed, Some(false));
|
|
})
|
|
.await;
|
|
|
|
let args = job.args.as_ref().unwrap();
|
|
assert_eq!(args.get("foo"), Some(&json!("hello_preprocessed")));
|
|
assert_eq!(args.get("bar"), Some(&json!("world_preprocessed")));
|
|
assert_eq!(
|
|
job.json_result().unwrap(),
|
|
json!("Hello hello_preprocessed world_preprocessed")
|
|
);
|
|
let job = sqlx::query!("SELECT preprocessed FROM v2_job WHERE id = $1", job.id)
|
|
.fetch_one(db)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(job.preprocessed, Some(true));
|
|
};
|
|
test_for_versions(VERSION_FLAGS.iter().copied(), test).await;
|
|
Ok(())
|
|
}
|
|
|
|
#[sqlx::test(fixtures("base", "hello"))]
|
|
async fn test_dedicated_worker_preprocessor_deno(db: Pool<Postgres>) -> anyhow::Result<()> {
|
|
initialize_tracing().await;
|
|
let server = ApiServer::start(db.clone()).await?;
|
|
let port = server.addr.port();
|
|
|
|
let test = || async {
|
|
let db = &db;
|
|
let job = RunJob::from(JobPayload::ScriptHash {
|
|
hash: ScriptHash(123416),
|
|
path: "f/system/hello_preprocessor_dedicated_deno".to_string(),
|
|
cache_ttl: None,
|
|
cache_ignore_s3_path: None,
|
|
dedicated_worker: None,
|
|
language: ScriptLang::Deno,
|
|
priority: None,
|
|
apply_preprocessor: true,
|
|
concurrency_settings:
|
|
windmill_common::runnable_settings::ConcurrencySettings::default(),
|
|
debouncing_settings:
|
|
windmill_common::runnable_settings::DebouncingSettings::default(), labels: None,
|
|
})
|
|
.arg("foo", json!("hello"))
|
|
.arg("bar", json!("world"))
|
|
.run_until_complete_with(db, false, port, |id| async move {
|
|
let job = sqlx::query!("SELECT preprocessed FROM v2_job WHERE id = $1", id)
|
|
.fetch_one(db)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(job.preprocessed, Some(false));
|
|
})
|
|
.await;
|
|
|
|
let args = job.args.as_ref().unwrap();
|
|
assert_eq!(args.get("foo"), Some(&json!("hello_preprocessed")));
|
|
assert_eq!(args.get("bar"), Some(&json!("world_preprocessed")));
|
|
assert_eq!(
|
|
job.json_result().unwrap(),
|
|
json!("Hello hello_preprocessed world_preprocessed")
|
|
);
|
|
let job = sqlx::query!("SELECT preprocessed FROM v2_job WHERE id = $1", job.id)
|
|
.fetch_one(db)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(job.preprocessed, Some(true));
|
|
};
|
|
test_for_versions(VERSION_FLAGS.iter().copied(), test).await;
|
|
Ok(())
|
|
}
|
|
|
|
#[sqlx::test(fixtures("base", "hello"))]
|
|
async fn test_bunnative_preprocessor(db: Pool<Postgres>) -> anyhow::Result<()> {
|
|
initialize_tracing().await;
|
|
let server = ApiServer::start(db.clone()).await?;
|
|
let port = server.addr.port();
|
|
|
|
let test = || async {
|
|
let db = &db;
|
|
let job = RunJob::from(JobPayload::ScriptHash {
|
|
hash: ScriptHash(123417),
|
|
path: "f/system/hello_preprocessor_bunnative".to_string(),
|
|
cache_ttl: None,
|
|
cache_ignore_s3_path: None,
|
|
dedicated_worker: None,
|
|
language: ScriptLang::Bunnative,
|
|
priority: None,
|
|
apply_preprocessor: true,
|
|
concurrency_settings:
|
|
windmill_common::runnable_settings::ConcurrencySettings::default(),
|
|
debouncing_settings:
|
|
windmill_common::runnable_settings::DebouncingSettings::default(), labels: None,
|
|
})
|
|
.arg("foo", json!("hello"))
|
|
.arg("bar", json!("world"))
|
|
.run_until_complete_with(db, false, port, |id| async move {
|
|
let job = sqlx::query!("SELECT preprocessed FROM v2_job WHERE id = $1", id)
|
|
.fetch_one(db)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(job.preprocessed, Some(false));
|
|
})
|
|
.await;
|
|
|
|
let args = job.args.as_ref().unwrap();
|
|
assert_eq!(args.get("foo"), Some(&json!("hello_preprocessed")));
|
|
assert_eq!(args.get("bar"), Some(&json!("world_preprocessed")));
|
|
assert_eq!(
|
|
job.json_result().unwrap(),
|
|
json!("Hello hello_preprocessed world_preprocessed")
|
|
);
|
|
let job = sqlx::query!("SELECT preprocessed FROM v2_job WHERE id = $1", job.id)
|
|
.fetch_one(db)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(job.preprocessed, Some(true));
|
|
};
|
|
test_for_versions(VERSION_FLAGS.iter().copied(), test).await;
|
|
Ok(())
|
|
}
|
|
|
|
#[sqlx::test(fixtures("base", "hello"))]
|
|
async fn test_dedicated_worker_preprocessor_bunnative(
|
|
db: Pool<Postgres>,
|
|
) -> anyhow::Result<()> {
|
|
initialize_tracing().await;
|
|
let server = ApiServer::start(db.clone()).await?;
|
|
let port = server.addr.port();
|
|
|
|
let test = || async {
|
|
let db = &db;
|
|
let job = RunJob::from(JobPayload::ScriptHash {
|
|
hash: ScriptHash(123418),
|
|
path: "f/system/hello_preprocessor_dedicated_bunnative".to_string(),
|
|
cache_ttl: None,
|
|
cache_ignore_s3_path: None,
|
|
dedicated_worker: None,
|
|
language: ScriptLang::Bunnative,
|
|
priority: None,
|
|
apply_preprocessor: true,
|
|
concurrency_settings:
|
|
windmill_common::runnable_settings::ConcurrencySettings::default(),
|
|
debouncing_settings:
|
|
windmill_common::runnable_settings::DebouncingSettings::default(), labels: None,
|
|
})
|
|
.arg("foo", json!("hello"))
|
|
.arg("bar", json!("world"))
|
|
.run_until_complete_with(db, false, port, |id| async move {
|
|
let job = sqlx::query!("SELECT preprocessed FROM v2_job WHERE id = $1", id)
|
|
.fetch_one(db)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(job.preprocessed, Some(false));
|
|
})
|
|
.await;
|
|
|
|
let args = job.args.as_ref().unwrap();
|
|
assert_eq!(args.get("foo"), Some(&json!("hello_preprocessed")));
|
|
assert_eq!(args.get("bar"), Some(&json!("world_preprocessed")));
|
|
assert_eq!(
|
|
job.json_result().unwrap(),
|
|
json!("Hello hello_preprocessed world_preprocessed")
|
|
);
|
|
let job = sqlx::query!("SELECT preprocessed FROM v2_job WHERE id = $1", job.id)
|
|
.fetch_one(db)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(job.preprocessed, Some(true));
|
|
};
|
|
test_for_versions(VERSION_FLAGS.iter().copied(), test).await;
|
|
Ok(())
|
|
}
|
|
}
|