//! `pic routes` smoke + edge tests. Covers the create → ls → match → //! rm round trip and the validation surface (unknown script id, //! conflict on duplicate). use predicates::prelude::*; use crate::common; #[ignore = "needs DATABASE_URL pointing at a running Postgres"] #[test] fn create_ls_match_remove_round_trip() { let Some(fx) = common::fixture_or_skip() else { return; }; let env = common::admin_env(fx); let (script_id, guard) = common::deploy_fixture(&env, "routes-rt", "hello.rhai"); let app_slug = guard.slug().to_string(); // Create — exact path, any method, sync dispatch by default. common::pic_as(&env) .args([ "routes", "create", "--script", &script_id, "--path", "/hook", "--method", "POST", ]) .assert() .success() .stdout(predicate::str::contains("Created route")); // Ls — header columns and our row present. let out = common::pic_as(&env) .args(["routes", "ls", &script_id]) .output() .expect("routes ls"); assert!(out.status.success(), "routes ls failed: {out:?}"); let stdout = String::from_utf8(out.stdout).unwrap(); let mut lines = stdout.lines(); let header = lines.next().expect("header row"); assert_eq!( common::cells(header), vec![ "id", "method", "host", "path_kind", "path", "dispatch", "created_at" ] ); let row = lines .map(common::cells) .find(|c| c.get(4).copied() == Some("/hook")) .unwrap_or_else(|| panic!("/hook row not in routes ls output: {stdout}")); assert_eq!(row[1], "POST"); assert_eq!(row[5], "sync"); let route_id = row[0].to_string(); // Match — POST /hook on the app's any-host space resolves. let out = common::pic_as(&env) .args([ "routes", "match", "--app", &app_slug, "--method", "POST", "http://localhost/hook", ]) .output() .expect("routes match"); assert!(out.status.success(), "routes match failed: {out:?}"); let stdout = String::from_utf8(out.stdout).unwrap(); assert!( stdout.contains("matched") && stdout.contains("true"), "match should have hit: {stdout}" ); assert!( stdout.contains(&route_id), "match output should name the route id: {stdout}" ); // Rm — drops the row. common::pic_as(&env) .args(["routes", "rm", &route_id]) .assert() .success() .stdout(predicate::str::contains(format!( "Deleted route {route_id}" ))); let out = common::pic_as(&env) .args(["routes", "ls", &script_id]) .output() .expect("routes ls after rm"); assert!(out.status.success()); let stdout = String::from_utf8(out.stdout).unwrap(); assert!( !stdout.lines().skip(1).any(|l| l.contains(&route_id)), "deleted route still in ls: {stdout}" ); } #[ignore = "needs DATABASE_URL pointing at a running Postgres"] #[test] fn create_async_dispatch_is_persisted() { let Some(fx) = common::fixture_or_skip() else { return; }; let env = common::admin_env(fx); let (script_id, _guard) = common::deploy_fixture(&env, "routes-async", "hello.rhai"); common::pic_as(&env) .args([ "routes", "create", "--script", &script_id, "--path", "/bg", "--method", "POST", "--dispatch", "async", ]) .assert() .success(); let out = common::pic_as(&env) .args(["routes", "ls", &script_id]) .output() .expect("routes ls"); let stdout = String::from_utf8(out.stdout).unwrap(); let row = stdout .lines() .skip(1) .map(common::cells) .find(|c| c.get(4).copied() == Some("/bg")) .unwrap_or_else(|| panic!("/bg row missing: {stdout}")); assert_eq!(row[5], "async", "dispatch column should be async: {row:?}"); } #[ignore = "needs DATABASE_URL pointing at a running Postgres"] #[test] fn create_against_unknown_script_404s() { let Some(fx) = common::fixture_or_skip() else { return; }; let env = common::admin_env(fx); // Bogus UUID-shaped script id so the path matcher accepts it // but the script lookup 404s. common::pic_as(&env) .args([ "routes", "create", "--script", "00000000-0000-0000-0000-000000000000", "--path", "/x", ]) .assert() .failure() .stderr(predicate::str::contains("HTTP 404")); }