//! `pic triggers` smoke tests. Covers the create-cron / create-kv / //! create-dead-letter happy paths plus a generic create-from-json //! escape hatch. use predicates::prelude::*; use crate::common; use crate::common::cleanup::AppGuard; #[ignore = "needs DATABASE_URL pointing at a running Postgres"] #[test] fn create_kv_and_show_in_ls() { let Some(fx) = common::fixture_or_skip() else { return; }; let env = common::admin_env(fx); let (script_id, guard) = common::deploy_fixture(&env, "trg-kv", "hello.rhai"); let app = guard.slug().to_string(); let out = common::pic_as(&env) .args([ "triggers", "create-kv", "--app", &app, "--script", &script_id, "--collection", "users", "--op", "insert", "--op", "update", ]) .output() .expect("create-kv"); assert!( out.status.success(), "create-kv failed: {out:?}\n{}", String::from_utf8_lossy(&out.stderr) ); let stdout = String::from_utf8(out.stdout).unwrap(); assert!(stdout.contains("kind") && stdout.contains("kv")); let out = common::pic_as(&env) .args(["triggers", "ls", "--app", &app]) .output() .expect("triggers ls"); let stdout = String::from_utf8(out.stdout).unwrap(); let header = stdout.lines().next().expect("header"); assert_eq!( common::cells(header), vec![ "id", "kind", "script_id", "enabled", "dispatch", "retry_max", "materialized", "created_at" ] ); let row = stdout .lines() .skip(1) .map(common::cells) .find(|c| c.get(1).copied() == Some("kv")) .unwrap_or_else(|| panic!("kv trigger missing from ls: {stdout}")); assert_eq!(row[2], script_id); // D1: a hand-authored trigger is not materialized. assert_eq!( row[6], "false", "an app-authored trigger shows materialized = false" ); } #[ignore = "needs DATABASE_URL pointing at a running Postgres"] #[test] fn create_cron_persists_schedule() { let Some(fx) = common::fixture_or_skip() else { return; }; let env = common::admin_env(fx); let (script_id, guard) = common::deploy_fixture(&env, "trg-cron", "hello.rhai"); let app = guard.slug().to_string(); common::pic_as(&env) .args([ "triggers", "create-cron", "--app", &app, "--script", &script_id, "--schedule", "0 0 * * * *", ]) .assert() .success(); let out = common::pic_as(&env) .args(["triggers", "ls", "--app", &app]) .output() .expect("triggers ls"); let stdout = String::from_utf8(out.stdout).unwrap(); assert!( stdout.lines().skip(1).any(|l| l.contains("cron")), "cron trigger missing: {stdout}" ); } #[ignore = "needs DATABASE_URL pointing at a running Postgres"] #[test] fn create_dead_letter_with_filter() { let Some(fx) = common::fixture_or_skip() else { return; }; let env = common::admin_env(fx); let (script_id, guard) = common::deploy_fixture(&env, "trg-dl", "hello.rhai"); let app = guard.slug().to_string(); common::pic_as(&env) .args([ "triggers", "create-dead-letter", "--app", &app, "--script", &script_id, "--source-filter", "queue", ]) .assert() .success(); } #[ignore = "needs DATABASE_URL pointing at a running Postgres"] #[test] fn create_from_json_inline_body_succeeds() { let Some(fx) = common::fixture_or_skip() else { return; }; let env = common::admin_env(fx); let (script_id, guard) = common::deploy_fixture(&env, "trg-json", "hello.rhai"); let app = guard.slug().to_string(); let body = format!(r#"{{"script_id":"{script_id}","collection_glob":"*","dispatch_mode":"async"}}"#); common::pic_as(&env) .args([ "triggers", "create-from-json", "--app", &app, "--kind", "kv", "--body", &body, ]) .assert() .success(); } #[ignore = "needs DATABASE_URL pointing at a running Postgres"] #[test] fn rm_drops_trigger_from_ls() { let Some(fx) = common::fixture_or_skip() else { return; }; let env = common::admin_env(fx); let (script_id, guard) = common::deploy_fixture(&env, "trg-rm", "hello.rhai"); let app = guard.slug().to_string(); // Create + capture id from ls common::pic_as(&env) .args([ "triggers", "create-cron", "--app", &app, "--script", &script_id, "--schedule", "0 0 * * * *", ]) .assert() .success(); let out = common::pic_as(&env) .args(["triggers", "ls", "--app", &app]) .output() .expect("triggers ls"); let stdout = String::from_utf8(out.stdout).unwrap(); let row = stdout .lines() .skip(1) .map(common::cells) .find(|c| c.get(1).copied() == Some("cron")) .unwrap_or_else(|| panic!("cron trigger missing: {stdout}")); let id = row[0].to_string(); common::pic_as(&env) .args(["triggers", "rm", "--app", &app, &id]) .assert() .success() .stdout(predicate::str::contains(format!("Deleted trigger {id}"))); let out = common::pic_as(&env) .args(["triggers", "ls", "--app", &app]) .output() .expect("triggers ls after rm"); let stdout = String::from_utf8(out.stdout).unwrap(); assert!( !stdout.lines().any(|l| l.contains(&id)), "deleted trigger still in ls: {stdout}" ); // Belt-and-braces so guard ordering is explicit. drop(guard); } /// Belt-and-braces: explicit binding so AppGuard isn't unused-warned. #[allow(dead_code)] fn _force_guard_in_scope() { let _: Option = None; }