diff --git a/src/relations/tests.rs b/src/relations/tests.rs index a174475..18cc2d4 100644 --- a/src/relations/tests.rs +++ b/src/relations/tests.rs @@ -457,20 +457,23 @@ mod live { .expect_err("deleting c's last route to the root should be refused"); assert_eq!( refused.get_status().as_u16(), - 400, - "a stranding delete is a client error, not a server fault: {refused:?}" + 409, + "a stranding delete conflicts with the graph as it stands: {refused:?}" + ); + assert_eq!( + refused.problem_slug().as_deref(), + Some("would-strand"), + "the refusal should say what it is refusing: {refused:?}" ); // With `a` declared root, the victim is unambiguous: `c` is the node that loses its last // route. Without a declared root this named a different node between runs, because the // projection picked the anchor itself. - let message = refused.get_message(); + let blocked_by = refused.problem().map(|p| p.blocked_by()).unwrap_or_default(); assert!( - message.contains("disconnect"), - "the refusal should say what it is refusing: {message}" - ); - assert!( - message.contains(c), - "the refusal should name {c} as the stranded resource: {message}" + blocked_by + .iter() + .any(|b| b.get("externalId").and_then(serde_json::Value::as_str) == Some(c)), + "the refusal should name {c} as the stranded resource: {blocked_by:?}" ); // Tear down in one request. Deleting these nodes individually is perfectly legal — diff --git a/src/timeseries/test.rs b/src/timeseries/test.rs index 4512a75..b0072d5 100644 --- a/src/timeseries/test.rs +++ b/src/timeseries/test.rs @@ -1531,18 +1531,24 @@ mod tests { Ok(_) => panic!("Expected 404 Not Found for non-existent timeseries"), Err(e) => { assert_eq!(e.get_status(), StatusCode::NOT_FOUND); - let msg = e.get_message(); - assert!( - msg.contains("Could not find following timeseries"), - "unexpected error body: {msg}" - ); + let problem = e.problem().unwrap_or_else(|| panic!("not a problem document: {}", e.get_message())); + assert_eq!(problem.slug(), Some("not-found"), "{problem:?}"); + // `missing` names each series whose data-points were skipped. + let named = problem + .extensions + .get("missing") + .and_then(serde_json::Value::as_array) + .is_some_and(|missing| { + missing.iter().any(|m| m.get("externalId").and_then(serde_json::Value::as_str) == Some(missing_ext_id.as_str())) + }); + assert!(named, "the refusal should name {missing_ext_id}: {problem:?}"); } } Ok(()) } /// The binary path resolves every series before it builds a frame, so a missing one is - /// refused here, with the JSON path's wording, and no frame is ever sent. + /// refused here, by the SDK itself, and no frame is ever sent. #[tokio::test] async fn test_insert_datapoints_binary_missing_timeseries_returns_not_found() -> Result<(), Box> { let api_service = create_api_service();