-
-
Notifications
You must be signed in to change notification settings - Fork 11
/
lib.rs
126 lines (108 loc) Β· 3.7 KB
/
lib.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use anyhow::anyhow;
use csv::Writer;
use reqwest::Url;
struct CsvClient {
pub url: Url
}
impl CsvClient {
pub fn new<S>(url: S) -> CsvClient where S: Into<Url> {
CsvClient {
url: url.into()
}
}
pub async fn fetch(&self, report: &str) -> anyhow::Result<String> {
let client = reqwest::Client::new();
client.get(self.url.join("/reports/")?.join(report)?).send().await?.text().await
.map_err(|err| anyhow!("Request for report failed - {}", err))
}
pub async fn save(&self, report: &str, data: &Vec<Vec<String>>) -> anyhow::Result<bool> {
let mut wtr = Writer::from_writer(vec![]);
for row in data {
wtr.write_record(row)?;
}
let client = reqwest::Client::new();
let response = client.post(self.url.join("/reports/")?.join(report)?)
.header("content-type", "text/csv;charset=utf-8")
.body(wtr.into_inner()?)
.send()
.await?;
Ok(response.status().as_u16() == 201)
}
}
#[cfg(test)]
mod tests {
use expectest::prelude::*;
use fakeit::{datetime, name};
use pact_consumer::prelude::*;
use pact_models::prelude::*;
use rand::prelude::*;
use regex::Regex;
use serde_json::json;
use crate::CsvClient;
#[tokio::test]
async fn test_csv_client() {
let _ = env_logger::builder().is_test(true).try_init();
let csv_service = PactBuilder::new_v4("CsvClient", "CsvServer")
.using_plugin("csv", None).await
.interaction("request for a report", "core/interaction/http", |mut i| async move {
i.request.path("/reports/report001.csv");
i.response
.ok()
.contents(ContentType::from("text/csv"), json!({
"csvHeaders": false,
"column:1": "matching(type,'Name')",
"column:2": "matching(number,100)",
"column:3": "matching(datetime, 'yyyy-MM-dd','2000-01-01')"
})).await;
i.clone()
})
.await
.start_mock_server_async()
.await;
let client = CsvClient::new(csv_service.url().clone());
let data = client.fetch("report001.csv").await.unwrap();
let columns: Vec<&str> = data.trim().split(",").collect();
expect!(columns.get(0)).to(be_some().value(&"Name"));
expect!(columns.get(1)).to(be_some().value(&"100"));
let date = columns.get(2).unwrap();
let re = Regex::new("\\d{4}-\\d{2}-\\d{2}").unwrap();
expect!(re.is_match(date)).to(be_true());
}
#[tokio::test]
async fn test_post_csv() {
let _ = env_logger::builder().is_test(true).try_init();
let csv_service = PactBuilder::new_v4("CsvClient", "CsvServer")
.using_plugin("csv", None).await
.interaction("request for to store a report", "core/interaction/http", |mut i| async move {
i.request
.path("/reports/report001.csv")
.method("POST")
.contents(ContentType::from("text/csv"), json!({
"csvHeaders": false,
"column:1": "matching(type,'Name')",
"column:2": "matching(number,100)",
"column:3": "matching(datetime, 'yyyy-MM-dd','2000-01-01')"
})).await;
i.response.created();
i.clone()
})
.await
.start_mock_server_async()
.await;
let client = CsvClient::new(csv_service.url().clone());
let rows = random::<u8>();
let mut data = vec![];
for _ in 0..rows {
let num: u8 = random();
let month = datetime::month().parse::<u8>().unwrap_or_default();
let day = datetime::day().parse::<u8>().unwrap_or_default();
data.push(vec![
name::full(),
num.to_string(),
format!("{}-{:02}-{:02}", datetime::year(), month, day)
]);
}
let result = client.save("report001.csv", &data).await;
expect!(result).to(be_ok().value(true));
}
}