1use serde::{Deserialize, Serialize};
7use serde_json::{json, Value};
8use std::collections::HashMap;
9
10#[derive(Debug, Deserialize)]
12pub struct HarLog {
13 pub version: String,
15 pub creator: HarCreator,
17 #[serde(default)]
19 pub browser: Option<HarBrowser>,
20 #[serde(default)]
22 pub pages: Vec<HarPage>,
23 pub entries: Vec<HarEntry>,
25}
26
27#[derive(Debug, Deserialize)]
29pub struct HarCreator {
30 pub name: String,
32 pub version: String,
34}
35
36#[derive(Debug, Deserialize)]
38pub struct HarBrowser {
39 pub name: String,
41 pub version: String,
43}
44
45#[derive(Debug, Deserialize)]
47pub struct HarPage {
48 pub started_date_time: String,
50 pub id: String,
52 pub title: String,
54 pub page_timings: HarPageTimings,
56}
57
58#[derive(Debug, Deserialize)]
60pub struct HarPageTimings {
61 pub on_content_load: Option<f64>,
63 pub on_load: Option<f64>,
65}
66
67#[derive(Debug, Deserialize)]
69pub struct HarEntry {
70 pub pageref: Option<String>,
72 #[serde(rename = "startedDateTime")]
74 pub started_date_time: String,
75 pub time: f64,
77 pub request: HarRequest,
79 pub response: HarResponse,
81 pub cache: HarCache,
83 pub timings: HarTimings,
85}
86
87#[derive(Debug, Deserialize)]
89pub struct HarRequest {
90 pub method: String,
92 pub url: String,
94 #[serde(rename = "httpVersion")]
96 pub http_version: String,
97 pub cookies: Vec<HarCookie>,
99 pub headers: Vec<HarHeader>,
101 #[serde(default, rename = "queryString")]
103 pub query_string: Vec<HarQueryParam>,
104 #[serde(rename = "postData")]
106 pub post_data: Option<HarPostData>,
107 #[serde(rename = "headersSize")]
109 pub headers_size: i64,
110 #[serde(rename = "bodySize")]
112 pub body_size: i64,
113}
114
115#[derive(Debug, Deserialize)]
117pub struct HarResponse {
118 pub status: u16,
120 #[serde(rename = "statusText")]
122 pub status_text: String,
123 #[serde(rename = "httpVersion")]
125 pub http_version: String,
126 pub cookies: Vec<HarCookie>,
128 pub headers: Vec<HarHeader>,
130 pub content: HarContent,
132 #[serde(rename = "redirectURL")]
134 pub redirect_url: String,
135 #[serde(rename = "headersSize")]
137 pub headers_size: i64,
138 #[serde(rename = "bodySize")]
140 pub body_size: i64,
141}
142
143#[derive(Debug, Deserialize)]
145pub struct HarCookie {
146 pub name: String,
148 pub value: String,
150 #[serde(default)]
152 pub path: Option<String>,
153 #[serde(default)]
155 pub domain: Option<String>,
156 #[serde(default)]
158 pub expires: Option<String>,
159 #[serde(default)]
161 pub http_only: Option<bool>,
162 #[serde(default)]
164 pub secure: Option<bool>,
165}
166
167#[derive(Debug, Deserialize)]
169pub struct HarHeader {
170 pub name: String,
172 pub value: String,
174}
175
176#[derive(Debug, Deserialize)]
178pub struct HarQueryParam {
179 pub name: String,
181 pub value: String,
183}
184
185#[derive(Debug, Deserialize)]
187pub struct HarPostData {
188 #[serde(rename = "mimeType")]
190 pub mime_type: String,
191 #[serde(default)]
193 pub params: Vec<HarParam>,
194 #[serde(default)]
196 pub text: Option<String>,
197}
198
199#[derive(Debug, Deserialize)]
201pub struct HarParam {
202 pub name: String,
204 pub value: Option<String>,
206 #[serde(default, rename = "fileName")]
208 pub file_name: Option<String>,
209 #[serde(default, rename = "contentType")]
211 pub content_type: Option<String>,
212}
213
214#[derive(Debug, Deserialize)]
216pub struct HarContent {
217 pub size: i64,
219 #[serde(default)]
221 pub compression: Option<i64>,
222 #[serde(rename = "mimeType")]
224 pub mime_type: String,
225 #[serde(default)]
227 pub text: Option<String>,
228 #[serde(default)]
230 pub encoding: Option<String>,
231}
232
233#[derive(Debug, Deserialize)]
235pub struct HarCache {}
236
237#[derive(Debug, Deserialize)]
239pub struct HarTimings {
240 #[serde(default)]
242 pub send: Option<f64>,
243 #[serde(default)]
245 pub wait: Option<f64>,
246 #[serde(default)]
248 pub receive: Option<f64>,
249}
250
251#[derive(Debug, Deserialize)]
253pub struct HarArchive {
254 pub log: HarLog,
256}
257
258#[derive(Debug, Serialize)]
260pub struct MockForgeRoute {
261 pub method: String,
263 pub path: String,
265 pub headers: HashMap<String, String>,
267 pub body: Option<String>,
269 pub response: MockForgeResponse,
271}
272
273#[derive(Debug, Serialize)]
275pub struct MockForgeResponse {
276 pub status: u16,
278 pub headers: HashMap<String, String>,
280 pub body: Value,
282}
283
284pub struct HarImportResult {
286 pub routes: Vec<MockForgeRoute>,
288 pub warnings: Vec<String>,
290}
291
292pub fn import_har_archive(
294 content: &str,
295 base_url: Option<&str>,
296) -> Result<HarImportResult, String> {
297 let archive: HarArchive =
298 serde_json::from_str(content).map_err(|e| format!("Failed to parse HAR archive: {}", e))?;
299
300 let mut routes = Vec::new();
301 let mut warnings = Vec::new();
302
303 for entry in &archive.log.entries {
305 match convert_entry_to_route(entry, base_url) {
306 Ok(route) => routes.push(route),
307 Err(e) => warnings.push(format!("Failed to convert HAR entry: {}", e)),
308 }
309 }
310
311 Ok(HarImportResult { routes, warnings })
312}
313
314fn convert_entry_to_route(
316 entry: &HarEntry,
317 base_url: Option<&str>,
318) -> Result<MockForgeRoute, String> {
319 let request = &entry.request;
320 let response = &entry.response;
321
322 let path = extract_path_from_url(&request.url, base_url)?;
324
325 let mut request_headers = HashMap::new();
327 for header in &request.headers {
328 if !header.name.is_empty() {
329 request_headers.insert(header.name.clone(), header.value.clone());
330 }
331 }
332
333 let body = extract_request_body(request);
335
336 let mut response_headers = HashMap::new();
338 for header in &response.headers {
339 if !header.name.is_empty() {
340 response_headers.insert(header.name.clone(), header.value.clone());
341 }
342 }
343
344 let response_body = extract_response_body(response);
346
347 let mock_response = MockForgeResponse {
348 status: response.status,
349 headers: response_headers,
350 body: response_body,
351 };
352
353 Ok(MockForgeRoute {
354 method: request.method.clone(),
355 path,
356 headers: request_headers,
357 body,
358 response: mock_response,
359 })
360}
361
362fn extract_path_from_url(url: &str, base_url: Option<&str>) -> Result<String, String> {
364 if let Ok(parsed_url) = url::Url::parse(url) {
365 let path = parsed_url.path();
366 let query = parsed_url.query();
367
368 let full_path = if let Some(q) = query {
369 format!("{}?{}", path, q)
370 } else {
371 path.to_string()
372 };
373
374 if let Some(base) = base_url {
376 if let Ok(base_parsed) = url::Url::parse(base) {
377 if parsed_url.host() == base_parsed.host() {
378 return Ok(full_path);
379 }
380 }
381 }
382
383 Ok(full_path)
385 } else {
386 Ok(url.to_string())
388 }
389}
390
391fn extract_request_body(request: &HarRequest) -> Option<String> {
393 if let Some(post_data) = &request.post_data {
394 if let Some(text) = &post_data.text {
395 if !text.is_empty() {
396 return Some(text.clone());
397 }
398 }
399
400 if !post_data.params.is_empty() {
402 let mut form_data = Vec::new();
403 for param in &post_data.params {
404 if let Some(value) = ¶m.value {
405 form_data.push(format!("{}={}", param.name, value));
406 }
407 }
408 if !form_data.is_empty() {
409 return Some(form_data.join("&"));
410 }
411 }
412 }
413 None
414}
415
416fn extract_response_body(response: &HarResponse) -> Value {
418 if let Some(text) = &response.content.text {
419 if !text.is_empty() {
420 if let Ok(json_value) = serde_json::from_str::<Value>(text) {
422 return json_value;
423 }
424
425 return Value::String(text.clone());
427 }
428 }
429
430 json!({"message": "Mock response from HAR import"})
432}
433
434#[cfg(test)]
435mod tests {
436 use super::*;
437
438 #[test]
439 fn test_parse_har_archive() {
440 let har_json = r#"{
441 "log": {
442 "version": "1.2",
443 "creator": {
444 "name": "Test Creator",
445 "version": "1.0"
446 },
447 "entries": [
448 {
449 "startedDateTime": "2024-01-15T10:30:00Z",
450 "time": 123.45,
451 "request": {
452 "method": "GET",
453 "url": "https://api.example.com/users",
454 "httpVersion": "HTTP/1.1",
455 "cookies": [],
456 "headers": [
457 {"name": "Authorization", "value": "Bearer token123"},
458 {"name": "Content-Type", "value": "application/json"}
459 ],
460 "queryString": [],
461 "headersSize": 150,
462 "bodySize": 0
463 },
464 "response": {
465 "status": 200,
466 "statusText": "OK",
467 "httpVersion": "HTTP/1.1",
468 "cookies": [],
469 "headers": [
470 {"name": "Content-Type", "value": "application/json"}
471 ],
472 "content": {
473 "size": 45,
474 "mimeType": "application/json",
475 "text": "{\"users\": [{\"id\": 1, \"name\": \"John\"}]}"
476 },
477 "redirectURL": "",
478 "headersSize": 100,
479 "bodySize": 45
480 },
481 "cache": {},
482 "timings": {
483 "send": 10.0,
484 "wait": 100.0,
485 "receive": 13.45
486 }
487 }
488 ]
489 }
490 }"#;
491
492 let result = import_har_archive(har_json, Some("https://api.example.com")).unwrap();
493
494 assert_eq!(result.routes.len(), 1);
495 assert_eq!(result.routes[0].method, "GET");
496 assert_eq!(result.routes[0].path, "/users");
497 assert!(result.routes[0].headers.contains_key("Authorization"));
498 assert_eq!(result.routes[0].response.status, 200);
499 }
500
501 #[test]
502 fn test_extract_path_from_url() {
503 assert_eq!(
505 extract_path_from_url(
506 "https://api.example.com/users/123",
507 Some("https://api.example.com")
508 )
509 .unwrap(),
510 "/users/123"
511 );
512
513 assert_eq!(
515 extract_path_from_url(
516 "https://api.example.com/search?q=test&page=1",
517 Some("https://api.example.com")
518 )
519 .unwrap(),
520 "/search?q=test&page=1"
521 );
522
523 assert_eq!(extract_path_from_url("https://api.example.com/users", None).unwrap(), "/users");
525 }
526
527 #[test]
528 fn test_extract_request_body() {
529 let request_with_text = HarRequest {
530 method: "POST".to_string(),
531 url: "https://api.example.com/users".to_string(),
532 http_version: "HTTP/1.1".to_string(),
533 cookies: vec![],
534 headers: vec![],
535 query_string: vec![],
536 post_data: Some(HarPostData {
537 mime_type: "application/json".to_string(),
538 params: vec![],
539 text: Some(r#"{"name": "John"}"#.to_string()),
540 }),
541 headers_size: 100,
542 body_size: 16,
543 };
544
545 assert_eq!(
546 extract_request_body(&request_with_text),
547 Some(r#"{"name": "John"}"#.to_string())
548 );
549 }
550
551 #[test]
552 fn test_extract_response_body() {
553 let response_with_json = HarResponse {
554 status: 200,
555 status_text: "OK".to_string(),
556 http_version: "HTTP/1.1".to_string(),
557 cookies: vec![],
558 headers: vec![],
559 content: HarContent {
560 size: 25,
561 compression: None,
562 mime_type: "application/json".to_string(),
563 text: Some(r#"{"message": "success"}"#.to_string()),
564 encoding: None,
565 },
566 redirect_url: "".to_string(),
567 headers_size: 100,
568 body_size: 25,
569 };
570
571 let body = extract_response_body(&response_with_json);
572 assert_eq!(body, json!({"message": "success"}));
573 }
574
575 #[test]
576 fn test_parse_har_with_multiple_entries() {
577 let har_json = r#"{
578 "log": {
579 "version": "1.2",
580 "creator": {
581 "name": "Test Creator",
582 "version": "1.0"
583 },
584 "entries": [
585 {
586 "startedDateTime": "2024-01-15T10:30:00Z",
587 "time": 123.45,
588 "request": {
589 "method": "GET",
590 "url": "https://api.example.com/users",
591 "httpVersion": "HTTP/1.1",
592 "cookies": [],
593 "headers": [],
594 "queryString": [],
595 "headersSize": 100,
596 "bodySize": 0
597 },
598 "response": {
599 "status": 200,
600 "statusText": "OK",
601 "httpVersion": "HTTP/1.1",
602 "cookies": [],
603 "headers": [],
604 "content": {
605 "size": 25,
606 "mimeType": "application/json",
607 "text": "{\"users\": []}"
608 },
609 "redirectURL": "",
610 "headersSize": 100,
611 "bodySize": 25
612 },
613 "cache": {},
614 "timings": {}
615 },
616 {
617 "startedDateTime": "2024-01-15T10:31:00Z",
618 "time": 234.56,
619 "request": {
620 "method": "POST",
621 "url": "https://api.example.com/users",
622 "httpVersion": "HTTP/1.1",
623 "cookies": [],
624 "headers": [],
625 "queryString": [],
626 "headersSize": 100,
627 "bodySize": 16
628 },
629 "response": {
630 "status": 201,
631 "statusText": "Created",
632 "httpVersion": "HTTP/1.1",
633 "cookies": [],
634 "headers": [],
635 "content": {
636 "size": 25,
637 "mimeType": "application/json",
638 "text": "{\"id\": 123}"
639 },
640 "redirectURL": "",
641 "headersSize": 100,
642 "bodySize": 25
643 },
644 "cache": {},
645 "timings": {}
646 }
647 ]
648 }
649 }"#;
650
651 let result = import_har_archive(har_json, Some("https://api.example.com")).unwrap();
652
653 assert_eq!(result.routes.len(), 2);
654
655 assert_eq!(result.routes[0].method, "GET");
657 assert_eq!(result.routes[0].path, "/users");
658 assert_eq!(result.routes[0].response.status, 200);
659
660 assert_eq!(result.routes[1].method, "POST");
662 assert_eq!(result.routes[1].path, "/users");
663 assert_eq!(result.routes[1].response.status, 201);
664 }
665
666 #[test]
667 fn test_parse_har_with_query_parameters() {
668 let har_json = r#"{
669 "log": {
670 "version": "1.2",
671 "creator": {"name": "Test", "version": "1.0"},
672 "entries": [{
673 "startedDateTime": "2024-01-15T10:30:00Z",
674 "time": 123.45,
675 "request": {
676 "method": "GET",
677 "url": "https://api.example.com/search?q=test&page=1&limit=10",
678 "httpVersion": "HTTP/1.1",
679 "cookies": [],
680 "headers": [],
681 "queryString": [
682 {"name": "q", "value": "test"},
683 {"name": "page", "value": "1"},
684 {"name": "limit", "value": "10"}
685 ],
686 "headersSize": 100,
687 "bodySize": 0
688 },
689 "response": {
690 "status": 200,
691 "statusText": "OK",
692 "httpVersion": "HTTP/1.1",
693 "cookies": [],
694 "headers": [],
695 "content": {"size": 25, "mimeType": "application/json", "text": "{}"},
696 "redirectURL": "",
697 "headersSize": 100,
698 "bodySize": 25
699 },
700 "cache": {},
701 "timings": {}
702 }]
703 }
704 }"#;
705
706 let result = import_har_archive(har_json, Some("https://api.example.com")).unwrap();
707
708 assert_eq!(result.routes.len(), 1);
709 assert_eq!(result.routes[0].method, "GET");
710 assert_eq!(result.routes[0].path, "/search?q=test&page=1&limit=10");
711 }
712
713 #[test]
714 fn test_parse_har_with_post_data() {
715 let har_json = r#"{
716 "log": {
717 "version": "1.2",
718 "creator": {"name": "Test", "version": "1.0"},
719 "entries": [{
720 "startedDateTime": "2024-01-15T10:30:00Z",
721 "time": 123.45,
722 "request": {
723 "method": "POST",
724 "url": "https://api.example.com/users",
725 "httpVersion": "HTTP/1.1",
726 "cookies": [],
727 "headers": [],
728 "queryString": [],
729 "postData": {
730 "mimeType": "application/json",
731 "params": [],
732 "text": "{\"name\": \"John\", \"age\": 30}"
733 },
734 "headersSize": 100,
735 "bodySize": 30
736 },
737 "response": {
738 "status": 201,
739 "statusText": "Created",
740 "httpVersion": "HTTP/1.1",
741 "cookies": [],
742 "headers": [],
743 "content": {"size": 25, "mimeType": "application/json", "text": "{}"},
744 "redirectURL": "",
745 "headersSize": 100,
746 "bodySize": 25
747 },
748 "cache": {},
749 "timings": {}
750 }]
751 }
752 }"#;
753
754 let result = import_har_archive(har_json, Some("https://api.example.com")).unwrap();
755
756 assert_eq!(result.routes.len(), 1);
757 assert_eq!(result.routes[0].method, "POST");
758 assert_eq!(result.routes[0].path, "/users");
759 assert_eq!(result.routes[0].body, Some("{\"name\": \"John\", \"age\": 30}".to_string()));
760 }
761
762 #[test]
763 fn test_parse_har_with_form_data() {
764 let har_json = r#"{
765 "log": {
766 "version": "1.2",
767 "creator": {"name": "Test", "version": "1.0"},
768 "entries": [{
769 "startedDateTime": "2024-01-15T10:30:00Z",
770 "time": 123.45,
771 "request": {
772 "method": "POST",
773 "url": "https://api.example.com/form",
774 "httpVersion": "HTTP/1.1",
775 "cookies": [],
776 "headers": [],
777 "queryString": [],
778 "postData": {
779 "mimeType": "application/x-www-form-urlencoded",
780 "params": [
781 {"name": "username", "value": "john_doe"},
782 {"name": "password", "value": "secret123"},
783 {"name": "remember", "value": "true"}
784 ],
785 "text": null
786 },
787 "headersSize": 100,
788 "bodySize": 50
789 },
790 "response": {
791 "status": 200,
792 "statusText": "OK",
793 "httpVersion": "HTTP/1.1",
794 "cookies": [],
795 "headers": [],
796 "content": {"size": 25, "mimeType": "application/json", "text": "{}"},
797 "redirectURL": "",
798 "headersSize": 100,
799 "bodySize": 25
800 },
801 "cache": {},
802 "timings": {}
803 }]
804 }
805 }"#;
806
807 let result = import_har_archive(har_json, Some("https://api.example.com")).unwrap();
808
809 assert_eq!(result.routes.len(), 1);
810 assert_eq!(result.routes[0].method, "POST");
811 assert_eq!(result.routes[0].path, "/form");
812 assert_eq!(
813 result.routes[0].body,
814 Some("username=john_doe&password=secret123&remember=true".to_string())
815 );
816 }
817
818 #[test]
819 fn test_extract_path_from_url_edge_cases() {
820 let test_cases = vec![
822 (
823 "https://api.example.com/users/123",
824 Some("https://api.example.com"),
825 "/users/123",
826 ),
827 (
828 "https://api.example.com/users/123/details",
829 Some("https://api.example.com"),
830 "/users/123/details",
831 ),
832 (
833 "https://api.example.com/search?q=test",
834 Some("https://api.example.com"),
835 "/search?q=test",
836 ),
837 (
838 "https://api.example.com/search?q=test&page=1",
839 Some("https://api.example.com"),
840 "/search?q=test&page=1",
841 ),
842 ("https://api.example.com/", Some("https://api.example.com"), "/"),
843 ("https://api.example.com", Some("https://api.example.com"), "/"),
844 ("https://api.example.com/users", None, "/users"),
845 ("https://api.example.com/users/", None, "/users/"),
846 ("http://localhost:9080/api/test", Some("http://localhost:9080"), "/api/test"),
847 (
848 "https://subdomain.example.com/api/v1/test",
849 Some("https://subdomain.example.com"),
850 "/api/v1/test",
851 ),
852 ];
853
854 for (url, base_url, expected) in test_cases {
855 let result = extract_path_from_url(url, base_url);
856 assert_eq!(result.unwrap(), expected, "Failed for URL: {}, base: {:?}", url, base_url);
857 }
858 }
859
860 #[test]
861 fn test_extract_request_body_comprehensive() {
862 let request_with_json = HarRequest {
864 method: "POST".to_string(),
865 url: "https://api.example.com/users".to_string(),
866 http_version: "HTTP/1.1".to_string(),
867 cookies: vec![],
868 headers: vec![],
869 query_string: vec![],
870 post_data: Some(HarPostData {
871 mime_type: "application/json".to_string(),
872 params: vec![],
873 text: Some(r#"{"name": "John", "age": 30}"#.to_string()),
874 }),
875 headers_size: 100,
876 body_size: 30,
877 };
878 assert_eq!(
879 extract_request_body(&request_with_json),
880 Some(r#"{"name": "John", "age": 30}"#.to_string())
881 );
882
883 let request_with_form = HarRequest {
885 method: "POST".to_string(),
886 url: "https://api.example.com/form".to_string(),
887 http_version: "HTTP/1.1".to_string(),
888 cookies: vec![],
889 headers: vec![],
890 query_string: vec![],
891 post_data: Some(HarPostData {
892 mime_type: "application/x-www-form-urlencoded".to_string(),
893 params: vec![
894 HarParam {
895 name: "username".to_string(),
896 value: Some("john_doe".to_string()),
897 file_name: None,
898 content_type: None,
899 },
900 HarParam {
901 name: "password".to_string(),
902 value: Some("secret123".to_string()),
903 file_name: None,
904 content_type: None,
905 },
906 HarParam {
907 name: "remember".to_string(),
908 value: Some("true".to_string()),
909 file_name: None,
910 content_type: None,
911 },
912 ],
913 text: None,
914 }),
915 headers_size: 100,
916 body_size: 50,
917 };
918 assert_eq!(
919 extract_request_body(&request_with_form),
920 Some("username=john_doe&password=secret123&remember=true".to_string())
921 );
922
923 let request_with_empty_params = HarRequest {
925 method: "POST".to_string(),
926 url: "https://api.example.com/form".to_string(),
927 http_version: "HTTP/1.1".to_string(),
928 cookies: vec![],
929 headers: vec![],
930 query_string: vec![],
931 post_data: Some(HarPostData {
932 mime_type: "application/x-www-form-urlencoded".to_string(),
933 params: vec![],
934 text: Some("".to_string()),
935 }),
936 headers_size: 100,
937 body_size: 0,
938 };
939 assert_eq!(extract_request_body(&request_with_empty_params), None);
940
941 let request_no_body = HarRequest {
943 method: "GET".to_string(),
944 url: "https://api.example.com/users".to_string(),
945 http_version: "HTTP/1.1".to_string(),
946 cookies: vec![],
947 headers: vec![],
948 query_string: vec![],
949 post_data: None,
950 headers_size: 100,
951 body_size: 0,
952 };
953 assert_eq!(extract_request_body(&request_no_body), None);
954 }
955
956 #[test]
957 fn test_extract_response_body_comprehensive() {
958 let response_with_json = HarResponse {
960 status: 200,
961 status_text: "OK".to_string(),
962 http_version: "HTTP/1.1".to_string(),
963 cookies: vec![],
964 headers: vec![],
965 content: HarContent {
966 size: 25,
967 compression: None,
968 mime_type: "application/json".to_string(),
969 text: Some(r#"{"message": "success"}"#.to_string()),
970 encoding: None,
971 },
972 redirect_url: "".to_string(),
973 headers_size: 100,
974 body_size: 25,
975 };
976 assert_eq!(extract_response_body(&response_with_json), json!({"message": "success"}));
977
978 let response_with_invalid_json = HarResponse {
980 status: 200,
981 status_text: "OK".to_string(),
982 http_version: "HTTP/1.1".to_string(),
983 cookies: vec![],
984 headers: vec![],
985 content: HarContent {
986 size: 15,
987 compression: None,
988 mime_type: "text/plain".to_string(),
989 text: Some("not json".to_string()),
990 encoding: None,
991 },
992 redirect_url: "".to_string(),
993 headers_size: 100,
994 body_size: 15,
995 };
996 assert_eq!(extract_response_body(&response_with_invalid_json), json!("not json"));
997
998 let response_with_empty_text = HarResponse {
1000 status: 204,
1001 status_text: "No Content".to_string(),
1002 http_version: "HTTP/1.1".to_string(),
1003 cookies: vec![],
1004 headers: vec![],
1005 content: HarContent {
1006 size: 0,
1007 compression: None,
1008 mime_type: "application/json".to_string(),
1009 text: Some("".to_string()),
1010 encoding: None,
1011 },
1012 redirect_url: "".to_string(),
1013 headers_size: 100,
1014 body_size: 0,
1015 };
1016 assert_eq!(
1017 extract_response_body(&response_with_empty_text),
1018 json!({"message": "Mock response from HAR import"})
1019 );
1020
1021 let response_with_no_text = HarResponse {
1023 status: 500,
1024 status_text: "Internal Server Error".to_string(),
1025 http_version: "HTTP/1.1".to_string(),
1026 cookies: vec![],
1027 headers: vec![],
1028 content: HarContent {
1029 size: 0,
1030 compression: None,
1031 mime_type: "application/json".to_string(),
1032 text: None,
1033 encoding: None,
1034 },
1035 redirect_url: "".to_string(),
1036 headers_size: 100,
1037 body_size: 0,
1038 };
1039 assert_eq!(
1040 extract_response_body(&response_with_no_text),
1041 json!({"message": "Mock response from HAR import"})
1042 );
1043
1044 let response_with_complex_json = HarResponse {
1046 status: 200,
1047 status_text: "OK".to_string(),
1048 http_version: "HTTP/1.1".to_string(),
1049 cookies: vec![],
1050 headers: vec![],
1051 content: HarContent {
1052 size: 100,
1053 compression: None,
1054 mime_type: "application/json".to_string(),
1055 text: Some(r#"{"users": [{"id": 1, "name": "John"}, {"id": 2, "name": "Jane"}], "total": 2}"#.to_string()),
1056 encoding: None,
1057 },
1058 redirect_url: "".to_string(),
1059 headers_size: 100,
1060 body_size: 100,
1061 };
1062 let expected =
1063 json!({"users": [{"id": 1, "name": "John"}, {"id": 2, "name": "Jane"}], "total": 2});
1064 assert_eq!(extract_response_body(&response_with_complex_json), expected);
1065 }
1066
1067 #[test]
1068 fn test_parse_har_with_different_status_codes() {
1069 let har_json = r#"{
1070 "log": {
1071 "version": "1.2",
1072 "creator": {"name": "Test", "version": "1.0"},
1073 "entries": [
1074 {
1075 "startedDateTime": "2024-01-15T10:30:00Z",
1076 "time": 123.45,
1077 "request": {"method": "GET", "url": "https://api.example.com/test", "httpVersion": "HTTP/1.1", "cookies": [], "headers": [], "queryString": [], "headersSize": 100, "bodySize": 0},
1078 "response": {"status": 404, "statusText": "Not Found", "httpVersion": "HTTP/1.1", "cookies": [], "headers": [], "content": {"size": 0, "mimeType": "application/json", "text": null}, "redirectURL": "", "headersSize": 100, "bodySize": 0},
1079 "cache": {}, "timings": {}
1080 },
1081 {
1082 "startedDateTime": "2024-01-15T10:31:00Z",
1083 "time": 234.56,
1084 "request": {"method": "POST", "url": "https://api.example.com/test", "httpVersion": "HTTP/1.1", "cookies": [], "headers": [], "queryString": [], "headersSize": 100, "bodySize": 0},
1085 "response": {"status": 500, "statusText": "Internal Server Error", "httpVersion": "HTTP/1.1", "cookies": [], "headers": [], "content": {"size": 0, "mimeType": "application/json", "text": null}, "redirectURL": "", "headersSize": 100, "bodySize": 0},
1086 "cache": {}, "timings": {}
1087 }
1088 ]
1089 }
1090 }"#;
1091
1092 let result = import_har_archive(har_json, Some("https://api.example.com")).unwrap();
1093
1094 assert_eq!(result.routes.len(), 2);
1095 assert_eq!(result.routes[0].response.status, 404);
1096 assert_eq!(result.routes[1].response.status, 500);
1097 }
1098
1099 #[test]
1100 fn test_parse_har_with_invalid_json() {
1101 let invalid_har_json = r#"{
1102 "log": {
1103 "version": "1.2",
1104 "creator": {"name": "Test", "version": "1.0"},
1105 "entries": [
1106 {
1107 "startedDateTime": "2024-01-15T10:30:00Z",
1108 "time": "invalid_number",
1109 "request": {"method": "GET", "url": "https://api.example.com/test", "httpVersion": "HTTP/1.1"},
1110 "response": {"status": 200, "statusText": "OK", "httpVersion": "HTTP/1.1"},
1111 "cache": {},
1112 "timings": {}
1113 }
1114 ]
1115 }
1116 }"#;
1117
1118 let result = import_har_archive(invalid_har_json, Some("https://api.example.com"));
1119 assert!(result.is_err());
1120 }
1121}