Skip to main content

api_testing_core/rest/
cleanup.rs

1use anyhow::Context;
2
3use crate::Result;
4use crate::rest::schema::RestCleanup;
5
6pub fn render_cleanup_path(cleanup: &RestCleanup, main_response_body: &[u8]) -> Result<String> {
7    let response_json: Option<serde_json::Value> = serde_json::from_slice(main_response_body).ok();
8
9    let mut path = cleanup.path_template.clone();
10    for (key, expr) in &cleanup.vars {
11        let lines = response_json
12            .as_ref()
13            .and_then(|json| crate::jq::query_raw(json, expr).ok())
14            .unwrap_or_default();
15        let value = lines.first().cloned().unwrap_or_default();
16        let value = value.trim().to_string();
17        if value.is_empty() || value == "null" {
18            anyhow::bail!("cleanup var '{key}' is empty");
19        }
20        path = path.replace(&format!("{{{{{key}}}}}"), &value);
21    }
22
23    if !path.starts_with('/') {
24        anyhow::bail!("cleanup.pathTemplate must resolve to an absolute path (starts with /)");
25    }
26
27    Ok(path)
28}
29
30pub fn execute_cleanup(
31    cleanup: &RestCleanup,
32    base_url: &str,
33    bearer_token: Option<&str>,
34    main_response_body: &[u8],
35) -> Result<()> {
36    let cleanup_path = render_cleanup_path(cleanup, main_response_body)?;
37    let base = base_url.trim_end_matches('/');
38    let cleanup_url = format!("{base}{cleanup_path}");
39
40    let method = reqwest::Method::from_bytes(cleanup.method.as_bytes())
41        .with_context(|| format!("invalid cleanup HTTP method: {}", cleanup.method))?;
42
43    let client = reqwest::blocking::Client::new();
44    let mut builder = client.request(method, &cleanup_url);
45    if let Some(token) = bearer_token {
46        let value = format!("Bearer {token}");
47        builder = builder.header(reqwest::header::AUTHORIZATION, value);
48    }
49
50    let response = builder
51        .send()
52        .with_context(|| format!("cleanup request failed: {} {}", cleanup.method, cleanup_url))?;
53
54    let got = response.status().as_u16();
55    let expected = cleanup.expect_status;
56    if got != expected {
57        anyhow::bail!(
58            "cleanup failed: expected {expected} but got {got} ({} {cleanup_url})",
59            cleanup.method
60        );
61    }
62
63    Ok(())
64}
65
66#[cfg(test)]
67mod tests {
68    use super::*;
69    use pretty_assertions::assert_eq;
70
71    #[test]
72    fn rest_cleanup_renders_path_and_substitutes_vars() {
73        let cleanup = crate::rest::schema::parse_rest_request_json(serde_json::json!({
74            "method": "GET",
75            "path": "/x",
76            "cleanup": {
77                "pathTemplate": "/files/{{key}}",
78                "vars": { "key": ".key" }
79            }
80        }))
81        .unwrap()
82        .cleanup
83        .unwrap();
84
85        let body = serde_json::to_vec(&serde_json::json!({"key": "abc"})).unwrap();
86        let path = render_cleanup_path(&cleanup, &body).unwrap();
87        assert_eq!(path, "/files/abc");
88    }
89
90    #[test]
91    fn rest_cleanup_var_null_is_error() {
92        let cleanup = crate::rest::schema::parse_rest_request_json(serde_json::json!({
93            "method": "GET",
94            "path": "/x",
95            "cleanup": {
96                "pathTemplate": "/files/{{key}}",
97                "vars": { "key": ".missing" }
98            }
99        }))
100        .unwrap()
101        .cleanup
102        .unwrap();
103
104        let body = serde_json::to_vec(&serde_json::json!({"key": "abc"})).unwrap();
105        let err = render_cleanup_path(&cleanup, &body).unwrap_err();
106        assert!(err.to_string().contains("cleanup var 'key' is empty"));
107    }
108
109    #[test]
110    fn rest_cleanup_requires_absolute_path() {
111        let cleanup = crate::rest::schema::parse_rest_request_json(serde_json::json!({
112            "method": "GET",
113            "path": "/x",
114            "cleanup": {
115                "pathTemplate": "{{key}}",
116                "vars": { "key": ".key" }
117            }
118        }))
119        .unwrap()
120        .cleanup
121        .unwrap();
122
123        let body = serde_json::to_vec(&serde_json::json!({"key": "abc"})).unwrap();
124        let err = render_cleanup_path(&cleanup, &body).unwrap_err();
125        assert!(err.to_string().contains("absolute path"));
126    }
127}