1use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
27#[serde(rename_all = "camelCase")]
28pub struct HttpRequest {
29 #[serde(skip_serializing_if = "Option::is_none")]
30 pub method: Option<String>,
31
32 #[serde(skip_serializing_if = "Option::is_none")]
33 pub path: Option<String>,
34
35 #[serde(skip_serializing_if = "Option::is_none")]
36 pub query_string_parameters: Option<HashMap<String, Vec<String>>>,
37
38 #[serde(skip_serializing_if = "Option::is_none")]
39 pub headers: Option<HashMap<String, Vec<String>>>,
40
41 #[serde(skip_serializing_if = "Option::is_none")]
42 pub body: Option<Body>,
43}
44
45impl HttpRequest {
46 pub fn new() -> Self {
48 Self::default()
49 }
50
51 pub fn method(mut self, method: impl Into<String>) -> Self {
53 self.method = Some(method.into());
54 self
55 }
56
57 pub fn path(mut self, path: impl Into<String>) -> Self {
59 self.path = Some(path.into());
60 self
61 }
62
63 pub fn query_param(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
65 let params = self.query_string_parameters.get_or_insert_with(HashMap::new);
66 params
67 .entry(key.into())
68 .or_default()
69 .push(value.into());
70 self
71 }
72
73 pub fn header(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
75 let headers = self.headers.get_or_insert_with(HashMap::new);
76 headers
77 .entry(key.into())
78 .or_default()
79 .push(value.into());
80 self
81 }
82
83 pub fn body(mut self, body: impl Into<String>) -> Self {
85 self.body = Some(Body::Plain(body.into()));
86 self
87 }
88
89 pub fn json_body(mut self, json: serde_json::Value) -> Self {
91 self.body = Some(Body::Typed {
92 body_type: "JSON".to_string(),
93 json: json.to_string(),
94 });
95 self
96 }
97}
98
99#[derive(Debug, Clone, PartialEq)]
105pub enum Body {
106 Plain(String),
108 Typed { body_type: String, json: String },
110}
111
112impl Serialize for Body {
113 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
114 where
115 S: serde::Serializer,
116 {
117 match self {
118 Body::Plain(s) => serializer.serialize_str(s),
119 Body::Typed { body_type, json } => {
120 use serde::ser::SerializeMap;
121 let mut map = serializer.serialize_map(Some(2))?;
122 map.serialize_entry("type", body_type)?;
123 map.serialize_entry("json", json)?;
124 map.end()
125 }
126 }
127 }
128}
129
130impl<'de> Deserialize<'de> for Body {
131 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
132 where
133 D: serde::Deserializer<'de>,
134 {
135 use serde_json::Value;
136 let v = Value::deserialize(deserializer)?;
137 match v {
138 Value::String(s) => Ok(Body::Plain(s)),
139 Value::Object(map) => {
140 let body_type = map
141 .get("type")
142 .and_then(|v| v.as_str())
143 .unwrap_or("JSON")
144 .to_string();
145 let json = map
146 .get("json")
147 .and_then(|v| v.as_str())
148 .unwrap_or("")
149 .to_string();
150 Ok(Body::Typed { body_type, json })
151 }
152 _ => Ok(Body::Plain(v.to_string())),
153 }
154 }
155}
156
157#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
173#[serde(rename_all = "camelCase")]
174pub struct HttpResponse {
175 #[serde(skip_serializing_if = "Option::is_none")]
176 pub status_code: Option<u16>,
177
178 #[serde(skip_serializing_if = "Option::is_none")]
179 pub headers: Option<HashMap<String, Vec<String>>>,
180
181 #[serde(skip_serializing_if = "Option::is_none")]
182 pub body: Option<String>,
183
184 #[serde(skip_serializing_if = "Option::is_none")]
185 pub delay: Option<Delay>,
186}
187
188impl HttpResponse {
189 pub fn new() -> Self {
191 Self::default()
192 }
193
194 pub fn status_code(mut self, code: u16) -> Self {
196 self.status_code = Some(code);
197 self
198 }
199
200 pub fn header(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
202 let headers = self.headers.get_or_insert_with(HashMap::new);
203 headers
204 .entry(key.into())
205 .or_default()
206 .push(value.into());
207 self
208 }
209
210 pub fn body(mut self, body: impl Into<String>) -> Self {
212 self.body = Some(body.into());
213 self
214 }
215
216 pub fn delay(mut self, delay: Delay) -> Self {
218 self.delay = Some(delay);
219 self
220 }
221}
222
223#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
236#[serde(rename_all = "camelCase")]
237pub struct HttpForward {
238 pub host: String,
239
240 #[serde(skip_serializing_if = "Option::is_none")]
241 pub port: Option<u16>,
242
243 #[serde(skip_serializing_if = "Option::is_none")]
244 pub scheme: Option<String>,
245}
246
247impl HttpForward {
248 pub fn new(host: impl Into<String>, port: u16) -> Self {
250 Self {
251 host: host.into(),
252 port: Some(port),
253 scheme: None,
254 }
255 }
256
257 pub fn scheme(mut self, scheme: impl Into<String>) -> Self {
259 self.scheme = Some(scheme.into());
260 self
261 }
262}
263
264#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
270#[serde(rename_all = "camelCase")]
271pub struct HttpError {
272 #[serde(skip_serializing_if = "Option::is_none")]
273 pub drop_connection: Option<bool>,
274
275 #[serde(skip_serializing_if = "Option::is_none")]
276 pub response_bytes: Option<String>,
277}
278
279impl HttpError {
280 pub fn new() -> Self {
282 Self::default()
283 }
284
285 pub fn drop_connection(mut self, drop: bool) -> Self {
287 self.drop_connection = Some(drop);
288 self
289 }
290
291 pub fn response_bytes(mut self, bytes: impl Into<String>) -> Self {
293 self.response_bytes = Some(bytes.into());
294 self
295 }
296}
297
298#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
304#[serde(rename_all = "camelCase")]
305pub struct Delay {
306 pub time_unit: String,
307 pub value: u64,
308}
309
310impl Delay {
311 pub fn milliseconds(value: u64) -> Self {
313 Self {
314 time_unit: "MILLISECONDS".to_string(),
315 value,
316 }
317 }
318
319 pub fn seconds(value: u64) -> Self {
321 Self {
322 time_unit: "SECONDS".to_string(),
323 value,
324 }
325 }
326}
327
328#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
334#[serde(rename_all = "camelCase")]
335pub struct Times {
336 #[serde(skip_serializing_if = "Option::is_none")]
337 pub remaining_times: Option<u32>,
338
339 pub unlimited: bool,
340}
341
342impl Times {
343 pub fn unlimited() -> Self {
345 Self {
346 remaining_times: None,
347 unlimited: true,
348 }
349 }
350
351 pub fn exactly(n: u32) -> Self {
353 Self {
354 remaining_times: Some(n),
355 unlimited: false,
356 }
357 }
358
359 pub fn once() -> Self {
361 Self::exactly(1)
362 }
363}
364
365#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
371#[serde(rename_all = "camelCase")]
372pub struct TimeToLive {
373 #[serde(skip_serializing_if = "Option::is_none")]
374 pub time_unit: Option<String>,
375
376 #[serde(skip_serializing_if = "Option::is_none")]
377 pub time_to_live: Option<u64>,
378
379 pub unlimited: bool,
380}
381
382impl TimeToLive {
383 pub fn unlimited() -> Self {
385 Self {
386 time_unit: None,
387 time_to_live: None,
388 unlimited: true,
389 }
390 }
391
392 pub fn seconds(seconds: u64) -> Self {
394 Self {
395 time_unit: Some("SECONDS".to_string()),
396 time_to_live: Some(seconds),
397 unlimited: false,
398 }
399 }
400
401 pub fn milliseconds(millis: u64) -> Self {
403 Self {
404 time_unit: Some("MILLISECONDS".to_string()),
405 time_to_live: Some(millis),
406 unlimited: false,
407 }
408 }
409}
410
411#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
417#[serde(rename_all = "camelCase")]
418pub struct VerificationTimes {
419 #[serde(skip_serializing_if = "Option::is_none")]
420 pub at_least: Option<u32>,
421
422 #[serde(skip_serializing_if = "Option::is_none")]
423 pub at_most: Option<u32>,
424}
425
426impl VerificationTimes {
427 pub fn at_least(n: u32) -> Self {
429 Self {
430 at_least: Some(n),
431 at_most: None,
432 }
433 }
434
435 pub fn at_most(n: u32) -> Self {
437 Self {
438 at_least: None,
439 at_most: Some(n),
440 }
441 }
442
443 pub fn exactly(n: u32) -> Self {
445 Self {
446 at_least: Some(n),
447 at_most: Some(n),
448 }
449 }
450
451 pub fn between(min: u32, max: u32) -> Self {
453 Self {
454 at_least: Some(min),
455 at_most: Some(max),
456 }
457 }
458}
459
460#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
466#[serde(rename_all = "camelCase")]
467pub struct Expectation {
468 #[serde(skip_serializing_if = "Option::is_none")]
469 pub id: Option<String>,
470
471 #[serde(skip_serializing_if = "Option::is_none")]
472 pub priority: Option<i32>,
473
474 pub http_request: HttpRequest,
475
476 #[serde(skip_serializing_if = "Option::is_none")]
477 pub http_response: Option<HttpResponse>,
478
479 #[serde(skip_serializing_if = "Option::is_none")]
480 pub http_forward: Option<HttpForward>,
481
482 #[serde(skip_serializing_if = "Option::is_none")]
483 pub http_error: Option<HttpError>,
484
485 #[serde(skip_serializing_if = "Option::is_none")]
486 pub times: Option<Times>,
487
488 #[serde(skip_serializing_if = "Option::is_none")]
489 pub time_to_live: Option<TimeToLive>,
490}
491
492impl Expectation {
493 pub fn new(request: HttpRequest) -> Self {
495 Self {
496 http_request: request,
497 ..Default::default()
498 }
499 }
500
501 pub fn id(mut self, id: impl Into<String>) -> Self {
503 self.id = Some(id.into());
504 self
505 }
506
507 pub fn priority(mut self, priority: i32) -> Self {
509 self.priority = Some(priority);
510 self
511 }
512
513 pub fn respond(mut self, response: HttpResponse) -> Self {
515 self.http_response = Some(response);
516 self
517 }
518
519 pub fn forward(mut self, forward: HttpForward) -> Self {
521 self.http_forward = Some(forward);
522 self
523 }
524
525 pub fn error(mut self, error: HttpError) -> Self {
527 self.http_error = Some(error);
528 self
529 }
530
531 pub fn times(mut self, times: Times) -> Self {
533 self.times = Some(times);
534 self
535 }
536
537 pub fn time_to_live(mut self, ttl: TimeToLive) -> Self {
539 self.time_to_live = Some(ttl);
540 self
541 }
542}
543
544#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
550#[serde(rename_all = "camelCase")]
551pub struct Verification {
552 pub http_request: HttpRequest,
553
554 #[serde(skip_serializing_if = "Option::is_none")]
555 pub times: Option<VerificationTimes>,
556}
557
558#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
560#[serde(rename_all = "camelCase")]
561pub struct VerificationSequence {
562 pub http_requests: Vec<HttpRequest>,
563}
564
565#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
571pub struct Ports {
572 pub ports: Vec<u16>,
573}
574
575#[derive(Debug, Clone, Copy, PartialEq, Eq)]
581pub enum RetrieveType {
582 Requests,
584 ActiveExpectations,
586 RecordedExpectations,
588 Logs,
590 RequestResponses,
592}
593
594impl RetrieveType {
595 pub fn as_str(&self) -> &'static str {
597 match self {
598 RetrieveType::Requests => "REQUESTS",
599 RetrieveType::ActiveExpectations => "ACTIVE_EXPECTATIONS",
600 RetrieveType::RecordedExpectations => "RECORDED_EXPECTATIONS",
601 RetrieveType::Logs => "LOGS",
602 RetrieveType::RequestResponses => "REQUEST_RESPONSES",
603 }
604 }
605}
606
607#[derive(Debug, Clone, Copy, PartialEq, Eq)]
609pub enum RetrieveFormat {
610 Json,
611 LogEntries,
612}
613
614impl RetrieveFormat {
615 pub fn as_str(&self) -> &'static str {
617 match self {
618 RetrieveFormat::Json => "JSON",
619 RetrieveFormat::LogEntries => "LOG_ENTRIES",
620 }
621 }
622}
623
624#[derive(Debug, Clone, Copy, PartialEq, Eq)]
626pub enum ClearType {
627 All,
628 Log,
629 Expectations,
630}
631
632impl ClearType {
633 pub fn as_str(&self) -> &'static str {
635 match self {
636 ClearType::All => "ALL",
637 ClearType::Log => "LOG",
638 ClearType::Expectations => "EXPECTATIONS",
639 }
640 }
641}