diff --git a/crates/executor-core/tests/sdk_docs.rs b/crates/executor-core/tests/sdk_docs.rs index 69f7a42..a376a8f 100644 --- a/crates/executor-core/tests/sdk_docs.rs +++ b/crates/executor-core/tests/sdk_docs.rs @@ -501,8 +501,27 @@ async fn docs_bridge_preserves_cross_app_isolation() { v == () "# ); - let body = run_script(engine, &reader_src, baseline_request(app_b)).await; - assert_eq!(body, json!(true)); + let body = run_script(engine.clone(), &reader_src, baseline_request(app_b)).await; + assert_eq!(body, json!(true), "app B must not see app A's document"); + + // Positive control — without it this test has no teeth (an execution_id-keyed + // bridge would pass the negative above). `baseline_request` mints a fresh + // execution_id/script_id per call, so this re-read under app_a is a different + // execution than the writer; it must still find A's own doc. + let reader_a = format!( + r#" + let c = docs::collection("shared"); + let v = c.get("{id_a_str}"); + if v == () {{ "MISSING" }} else {{ v.data.from }} + "# + ); + let body = run_script(engine, &reader_a, baseline_request(app_a)).await; + assert_eq!( + body, + json!("a"), + "app A must read back its own document in a later execution — storage is \ + keyed by app_id, not execution_id/script_id" + ); } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] diff --git a/crates/executor-core/tests/sdk_kv.rs b/crates/executor-core/tests/sdk_kv.rs index 775ac1d..a0f8cd9 100644 --- a/crates/executor-core/tests/sdk_kv.rs +++ b/crates/executor-core/tests/sdk_kv.rs @@ -311,6 +311,21 @@ async fn kv_bridge_preserves_cross_app_isolation() { let c = kv::collection("shared"); c.get("k") "#; - let body = run_script(engine, reader, baseline_request(app_b)).await; - assert_eq!(body, Value::Null); + let body = run_script(engine.clone(), reader, baseline_request(app_b)).await; + assert_eq!(body, Value::Null, "app B must not see app A's value"); + + // Positive control — WITHOUT it this test has no teeth. `baseline_request` + // mints a fresh execution_id AND script_id each call, so this second run under + // app_a is a DIFFERENT execution/script than the writer. A bridge that keyed + // storage by execution_id or script_id (instead of app_id) would pass the + // negative above AND every single-execution round-trip, while app-scoped + // persistence was completely gone. This catches that: app A must still read + // back its own value across executions. + let body = run_script(engine, reader, baseline_request(app_a)).await; + assert_eq!( + body, + Value::from("from-a"), + "app A must read back its own value in a later execution — storage is keyed \ + by app_id, not execution_id/script_id" + ); } diff --git a/crates/executor-core/tests/sdk_retry.rs b/crates/executor-core/tests/sdk_retry.rs index 9cf950c..288fceb 100644 --- a/crates/executor-core/tests/sdk_retry.rs +++ b/crates/executor-core/tests/sdk_retry.rs @@ -140,12 +140,40 @@ async fn retry_policy_clamps_visible_at_script_layer() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn retry_policy_rejects_bogus_backoff() { let engine = build_engine(); + + // Pin the REASON. A bare `is_err()` would pass if `retry::policy` were not + // registered at all (ErrorFunctionNotFound), or on a typo in the script + // source, or if EVERY policy were rejected — none of which is "an invalid + // backoff is rejected". The message must name `backoff`. let src = r#"retry::policy(#{ backoff: "bogus" });"#.to_string(); let req = baseline_request(AppId::new()); - let res = tokio::task::spawn_blocking(move || engine.execute(&src, req)) + let err = tokio::task::spawn_blocking({ + let engine = engine.clone(); + move || engine.execute(&src, req) + }) + .await + .unwrap() + .unwrap_err() + .to_string(); + assert!( + err.to_lowercase().contains("backoff"), + "the rejection must be about the backoff value specifically, got: {err}" + ); + + // Control: the SAME call with a VALID backoff succeeds — proving `retry::policy` + // is registered and does not reject everything, so the failure above is + // specific to the bad value. + let ok_src = r#" + let p = retry::policy(#{ backoff: "constant", max_attempts: 2, base_ms: 1 }); + retry::run(p, || 7) + "# + .to_string(); + let req = baseline_request(AppId::new()); + let resp = tokio::task::spawn_blocking(move || engine.execute(&ok_src, req)) .await - .unwrap(); - assert!(res.is_err()); + .unwrap() + .expect("a valid backoff must be accepted"); + assert_eq!(resp.body, serde_json::json!(7)); } #[tokio::test(flavor = "multi_thread", worker_threads = 2)]