agscheduler_cli/
http.rs

1use std::default::Default;
2use std::time::Duration;
3
4use reqwest::Method;
5use serde_json::Value;
6
7use crate::utils;
8
9pub static mut PASSWORD_SHA2: String = String::new();
10
11pub struct Options {
12    pub method: Method,
13    pub body: String,
14    pub timeout: Duration,
15}
16
17impl Default for Options {
18    fn default() -> Self {
19        Options {
20            method: Method::GET,
21            body: String::new(),
22            timeout: Duration::from_secs(6),
23        }
24    }
25}
26
27pub async fn fetch(url: String, options: Options) -> anyhow::Result<Value> {
28    let client = reqwest::Client::new();
29
30    let password_sha2;
31    unsafe { password_sha2 = PASSWORD_SHA2.as_str().to_string() }
32
33    let response = client
34        .request(options.method, url)
35        .header("Auth-Password-SHA2", password_sha2)
36        .body(options.body)
37        .timeout(options.timeout)
38        .send()
39        .await?;
40    if !response.status().is_success() {
41        let err = response.text().await?;
42        return Err(anyhow::anyhow!(err));
43    }
44
45    let body = response.text().await?;
46    let v: Value = serde_json::from_str(&body)?;
47    if v["error"] != "" {
48        return Err(anyhow::anyhow!(v["error"].as_str().unwrap().to_string()));
49    }
50
51    Ok(v["data"].to_owned())
52}
53
54pub async fn fetch_show_json(url: String, options: Options) {
55    match fetch(url, options).await {
56        Ok(result) => {
57            utils::show_json(result);
58        }
59        Err(err) => {
60            println!("Error: {}", err)
61        }
62    }
63}
64
65pub async fn fetch_show_ok(url: String, options: Options) {
66    match fetch(url, options).await {
67        Ok(_) => {
68            println!("Ok")
69        }
70        Err(err) => {
71            println!("Error: {}", err)
72        }
73    }
74}
75
76#[cfg(test)]
77mod tests {
78    use super::*;
79    use serde_json::json;
80
81    #[tokio::test]
82    async fn it_fetch_ok() {
83        let mut server = mockito::Server::new_async().await;
84        let url = server.url();
85
86        let body = json!({"data": {"hello":"world"}, "error": ""}).to_string();
87
88        server
89            .mock("GET", "/hello")
90            .with_status(200)
91            .with_body(body)
92            .create_async()
93            .await;
94
95        let result = fetch(format!("{}{}", url, "/hello"), Options::default())
96            .await
97            .unwrap();
98
99        assert_eq!("{\"hello\":\"world\"}", result.to_string());
100    }
101
102    #[tokio::test]
103    async fn it_fetch_status_failed() {
104        let mut server = mockito::Server::new_async().await;
105        let url = server.url();
106
107        let body = "404 page not found";
108
109        server
110            .mock("GET", "/")
111            .with_status(404)
112            .with_body(body)
113            .create_async()
114            .await;
115
116        let result = fetch(format!("{}{}", url, "/"), Options::default())
117            .await
118            .unwrap_err();
119
120        assert_eq!(body, result.to_string());
121    }
122
123    #[tokio::test]
124    async fn it_fetch_error() {
125        let mut server = mockito::Server::new_async().await;
126        let url = server.url();
127
128        let body = json!({"data": null, "error": "`id` not found!"}).to_string();
129
130        server
131            .mock("POST", "/job")
132            .with_status(200)
133            .with_body(body)
134            .create_async()
135            .await;
136
137        let result = fetch(
138            format!("{}{}", url, "/job"),
139            Options {
140                method: Method::POST,
141                ..Default::default()
142            },
143        )
144        .await
145        .unwrap_err();
146
147        assert_eq!("`id` not found!", result.to_string());
148    }
149}