1mod protocol;
5
6use http::header::{CONTENT_TYPE, COOKIE};
7pub use protocol::{
8 FilterOption, Row, RowActions, SESSION_COOKIE, body_bytes, body_string, cookie_header,
9 field_error, filter_options, form_body, input_value, multipart_body, response_cookies,
10 row_actions, rows, session_cookie_value, set_cookie_header,
11};
12use topcoat::router::{Body, Router};
13
14#[derive(Clone)]
16pub struct TestClient<'a> {
17 router: &'a Router,
18 cookies: Vec<(String, String)>,
19 tenant: Option<uuid::Uuid>,
20}
21
22impl<'a> TestClient<'a> {
23 pub fn new(router: &'a Router) -> Self {
24 Self {
25 router,
26 cookies: Vec::new(),
27 tenant: None,
28 }
29 }
30
31 pub fn cookie(&self, name: &str, value: &str) -> Self {
34 let mut client = self.clone();
35 match client.cookies.iter_mut().find(|(kept, _)| kept == name) {
36 Some(existing) => existing.1 = value.to_string(),
37 None => client.cookies.push((name.to_string(), value.to_string())),
38 }
39 client
40 }
41
42 pub fn cookies(&self, cookies: &[(String, String)]) -> Self {
45 let mut client = self.clone();
46 for (name, value) in cookies {
47 match client.cookies.iter_mut().find(|(kept, _)| kept == name) {
48 Some(existing) => existing.1 = value.clone(),
49 None => client.cookies.push((name.clone(), value.clone())),
50 }
51 }
52 client
53 }
54
55 pub fn csrf(&self, token: &str) -> Self {
57 self.cookie(tablo_core::csrf::COOKIE_NAME, token)
58 }
59
60 pub fn tenant(&self, tenant: uuid::Uuid) -> Self {
63 let mut client = self.clone();
64 client.tenant = Some(tenant);
65 client
66 }
67
68 pub async fn get(&self, uri: &str) -> http::Response<Body> {
69 self.router
70 .handle(self.request(http::Method::GET, uri))
71 .await
72 }
73
74 pub async fn post_form(&self, uri: &str, body: String) -> http::Response<Body> {
75 let mut request = self.request(http::Method::POST, uri);
76 request.headers_mut().insert(
77 CONTENT_TYPE,
78 http::HeaderValue::from_static("application/x-www-form-urlencoded"),
79 );
80 *request.body_mut() = Body::from(body);
81 self.router.handle(request).await
82 }
83
84 pub async fn post_multipart(
85 &self,
86 uri: &str,
87 boundary: &str,
88 body: String,
89 ) -> http::Response<Body> {
90 let mut request = self.request(http::Method::POST, uri);
91 request.headers_mut().insert(
92 CONTENT_TYPE,
93 format!("multipart/form-data; boundary={boundary}")
94 .parse()
95 .expect("multipart content type"),
96 );
97 *request.body_mut() = Body::from(body);
98 self.router.handle(request).await
99 }
100
101 pub async fn post_json(&self, uri: &str, body: String, identity: &str) -> http::Response<Body> {
103 let mut request = self.request(http::Method::POST, uri);
104 request.headers_mut().insert(
105 CONTENT_TYPE,
106 http::HeaderValue::from_static("application/json"),
107 );
108 request.headers_mut().insert(
109 topcoat::router::request::IDENTITY_HEADER,
110 http::HeaderValue::from_str(identity).expect("identity header"),
111 );
112 *request.body_mut() = Body::from(body);
113 self.router.handle(request).await
114 }
115
116 fn request(&self, method: http::Method, uri: &str) -> http::Request<Body> {
117 let mut builder = http::Request::builder().method(method).uri(uri);
118 if let Some(jar) = cookie_header(
119 self.cookies
120 .iter()
121 .map(|(name, value)| (name.as_str(), value.as_str())),
122 ) {
123 builder = builder.header(COOKIE, jar);
124 }
125 let (mut parts, body) = builder.body(Body::empty()).unwrap().into_parts();
126 if let Some(tenant) = self.tenant {
127 parts.extensions.insert(tablo_core::Tenant(tenant));
128 }
129 http::Request::from_parts(parts, body)
130 }
131}