integration.rs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. //! Integration tests for cdk-http-client using mockito
  2. use cdk_http_client::{HttpClient, HttpError};
  3. use serde::{Deserialize, Serialize};
  4. #[derive(Debug, Serialize, Deserialize, PartialEq)]
  5. struct TestPayload {
  6. name: String,
  7. value: i32,
  8. }
  9. #[derive(Debug, Serialize, Deserialize, PartialEq)]
  10. struct TestResponse {
  11. success: bool,
  12. data: String,
  13. }
  14. // === HttpClient::fetch tests ===
  15. #[tokio::test]
  16. async fn test_fetch_success() {
  17. let mut server = mockito::Server::new_async().await;
  18. let mock = server
  19. .mock("GET", "/api/data")
  20. .with_status(200)
  21. .with_header("content-type", "application/json")
  22. .with_body(r#"{"success": true, "data": "hello"}"#)
  23. .create_async()
  24. .await;
  25. let client = HttpClient::new();
  26. let url = format!("{}/api/data", server.url());
  27. let result: Result<TestResponse, _> = client.fetch(&url).await;
  28. assert!(result.is_ok());
  29. let response = result.expect("Fetch should succeed");
  30. assert!(response.success);
  31. assert_eq!(response.data, "hello");
  32. mock.assert_async().await;
  33. }
  34. #[tokio::test]
  35. async fn test_fetch_error_status() {
  36. let mut server = mockito::Server::new_async().await;
  37. let mock = server
  38. .mock("GET", "/api/error")
  39. .with_status(404)
  40. .with_body("Not Found")
  41. .create_async()
  42. .await;
  43. let client = HttpClient::new();
  44. let url = format!("{}/api/error", server.url());
  45. let result: Result<TestResponse, _> = client.fetch(&url).await;
  46. assert!(result.is_err());
  47. if let Err(HttpError::Status { status, message }) = result {
  48. assert_eq!(status, 404);
  49. assert_eq!(message, "Not Found");
  50. } else {
  51. panic!("Expected HttpError::Status");
  52. }
  53. mock.assert_async().await;
  54. }
  55. #[tokio::test]
  56. async fn test_fetch_server_error() {
  57. let mut server = mockito::Server::new_async().await;
  58. let mock = server
  59. .mock("GET", "/api/server-error")
  60. .with_status(500)
  61. .with_body("Internal Server Error")
  62. .create_async()
  63. .await;
  64. let client = HttpClient::new();
  65. let url = format!("{}/api/server-error", server.url());
  66. let result: Result<TestResponse, _> = client.fetch(&url).await;
  67. assert!(result.is_err());
  68. if let Err(HttpError::Status { status, .. }) = result {
  69. assert_eq!(status, 500);
  70. } else {
  71. panic!("Expected HttpError::Status");
  72. }
  73. mock.assert_async().await;
  74. }
  75. // === HttpClient::post_json tests ===
  76. #[tokio::test]
  77. async fn test_post_json_success() {
  78. let mut server = mockito::Server::new_async().await;
  79. let mock = server
  80. .mock("POST", "/api/submit")
  81. .match_header("content-type", "application/json")
  82. .match_body(mockito::Matcher::Json(serde_json::json!({
  83. "name": "test",
  84. "value": 42
  85. })))
  86. .with_status(200)
  87. .with_header("content-type", "application/json")
  88. .with_body(r#"{"success": true, "data": "received"}"#)
  89. .create_async()
  90. .await;
  91. let client = HttpClient::new();
  92. let url = format!("{}/api/submit", server.url());
  93. let payload = TestPayload {
  94. name: "test".to_string(),
  95. value: 42,
  96. };
  97. let result: Result<TestResponse, _> = client.post_json(&url, &payload).await;
  98. assert!(result.is_ok());
  99. let response = result.expect("POST JSON should succeed");
  100. assert!(response.success);
  101. assert_eq!(response.data, "received");
  102. mock.assert_async().await;
  103. }
  104. #[tokio::test]
  105. async fn test_post_json_error_status() {
  106. let mut server = mockito::Server::new_async().await;
  107. let mock = server
  108. .mock("POST", "/api/submit")
  109. .with_status(400)
  110. .with_body("Bad Request")
  111. .create_async()
  112. .await;
  113. let client = HttpClient::new();
  114. let url = format!("{}/api/submit", server.url());
  115. let payload = TestPayload {
  116. name: "test".to_string(),
  117. value: 42,
  118. };
  119. let result: Result<TestResponse, _> = client.post_json(&url, &payload).await;
  120. assert!(result.is_err());
  121. if let Err(HttpError::Status { status, message }) = result {
  122. assert_eq!(status, 400);
  123. assert_eq!(message, "Bad Request");
  124. } else {
  125. panic!("Expected HttpError::Status");
  126. }
  127. mock.assert_async().await;
  128. }
  129. // === HttpClient::get_raw tests ===
  130. #[tokio::test]
  131. async fn test_get_raw_success() {
  132. let mut server = mockito::Server::new_async().await;
  133. let mock = server
  134. .mock("GET", "/api/raw")
  135. .with_status(200)
  136. .with_body("raw content")
  137. .create_async()
  138. .await;
  139. let client = HttpClient::new();
  140. let url = format!("{}/api/raw", server.url());
  141. let result = client.get_raw(&url).await;
  142. assert!(result.is_ok());
  143. let response = result.expect("GET raw should succeed");
  144. assert_eq!(response.status(), 200);
  145. assert!(response.is_success());
  146. mock.assert_async().await;
  147. }
  148. // === RawResponse tests ===
  149. #[tokio::test]
  150. async fn test_raw_response_is_success_with_200() {
  151. let mut server = mockito::Server::new_async().await;
  152. let mock = server
  153. .mock("GET", "/")
  154. .with_status(200)
  155. .create_async()
  156. .await;
  157. let client = HttpClient::new();
  158. let response = client
  159. .get_raw(&server.url())
  160. .await
  161. .expect("Request should succeed");
  162. assert!(response.is_success());
  163. assert!(!response.is_client_error());
  164. assert!(!response.is_server_error());
  165. assert_eq!(response.status(), 200);
  166. mock.assert_async().await;
  167. }
  168. #[tokio::test]
  169. async fn test_raw_response_is_success_with_201() {
  170. let mut server = mockito::Server::new_async().await;
  171. let mock = server
  172. .mock("GET", "/")
  173. .with_status(201)
  174. .create_async()
  175. .await;
  176. let client = HttpClient::new();
  177. let response = client
  178. .get_raw(&server.url())
  179. .await
  180. .expect("Request should succeed");
  181. assert!(response.is_success());
  182. assert_eq!(response.status(), 201);
  183. mock.assert_async().await;
  184. }
  185. #[tokio::test]
  186. async fn test_raw_response_is_success_with_299() {
  187. let mut server = mockito::Server::new_async().await;
  188. let mock = server
  189. .mock("GET", "/")
  190. .with_status(299)
  191. .create_async()
  192. .await;
  193. let client = HttpClient::new();
  194. let response = client
  195. .get_raw(&server.url())
  196. .await
  197. .expect("Request should succeed");
  198. assert!(response.is_success());
  199. assert_eq!(response.status(), 299);
  200. mock.assert_async().await;
  201. }
  202. #[tokio::test]
  203. async fn test_raw_response_is_not_success_with_100() {
  204. // Note: HTTP 1xx informational responses are special and may not be
  205. // fully supported by all HTTP libraries. We test with 100 Continue.
  206. // mockito may convert some 1xx codes to 500, so we just verify the
  207. // logic works with the boundary check (200..300).
  208. let mut server = mockito::Server::new_async().await;
  209. // Use 301 redirect as a more reliable "not success" boundary test
  210. let mock = server
  211. .mock("GET", "/")
  212. .with_status(301)
  213. .create_async()
  214. .await;
  215. let client = HttpClient::new();
  216. let response = client
  217. .get_raw(&server.url())
  218. .await
  219. .expect("Request should succeed");
  220. // 301 is a redirect, not success
  221. assert!(!response.is_success());
  222. assert_eq!(response.status(), 301);
  223. mock.assert_async().await;
  224. }
  225. #[tokio::test]
  226. async fn test_raw_response_is_not_success_with_300() {
  227. let mut server = mockito::Server::new_async().await;
  228. let mock = server
  229. .mock("GET", "/")
  230. .with_status(300)
  231. .create_async()
  232. .await;
  233. let client = HttpClient::new();
  234. let response = client
  235. .get_raw(&server.url())
  236. .await
  237. .expect("Request should succeed");
  238. assert!(!response.is_success());
  239. assert_eq!(response.status(), 300);
  240. mock.assert_async().await;
  241. }
  242. #[tokio::test]
  243. async fn test_raw_response_is_client_error_with_400() {
  244. let mut server = mockito::Server::new_async().await;
  245. let mock = server
  246. .mock("GET", "/")
  247. .with_status(400)
  248. .create_async()
  249. .await;
  250. let client = HttpClient::new();
  251. let response = client
  252. .get_raw(&server.url())
  253. .await
  254. .expect("Request should succeed");
  255. assert!(response.is_client_error());
  256. assert!(!response.is_success());
  257. assert!(!response.is_server_error());
  258. assert_eq!(response.status(), 400);
  259. mock.assert_async().await;
  260. }
  261. #[tokio::test]
  262. async fn test_raw_response_is_client_error_with_499() {
  263. let mut server = mockito::Server::new_async().await;
  264. let mock = server
  265. .mock("GET", "/")
  266. .with_status(499)
  267. .create_async()
  268. .await;
  269. let client = HttpClient::new();
  270. let response = client
  271. .get_raw(&server.url())
  272. .await
  273. .expect("Request should succeed");
  274. assert!(response.is_client_error());
  275. assert_eq!(response.status(), 499);
  276. mock.assert_async().await;
  277. }
  278. #[tokio::test]
  279. async fn test_raw_response_is_not_client_error_with_399() {
  280. let mut server = mockito::Server::new_async().await;
  281. let mock = server
  282. .mock("GET", "/")
  283. .with_status(399)
  284. .create_async()
  285. .await;
  286. let client = HttpClient::new();
  287. let response = client
  288. .get_raw(&server.url())
  289. .await
  290. .expect("Request should succeed");
  291. assert!(!response.is_client_error());
  292. assert_eq!(response.status(), 399);
  293. mock.assert_async().await;
  294. }
  295. #[tokio::test]
  296. async fn test_raw_response_is_server_error_with_500() {
  297. let mut server = mockito::Server::new_async().await;
  298. let mock = server
  299. .mock("GET", "/")
  300. .with_status(500)
  301. .create_async()
  302. .await;
  303. let client = HttpClient::new();
  304. let response = client
  305. .get_raw(&server.url())
  306. .await
  307. .expect("Request should succeed");
  308. assert!(response.is_server_error());
  309. assert!(!response.is_success());
  310. assert!(!response.is_client_error());
  311. assert_eq!(response.status(), 500);
  312. mock.assert_async().await;
  313. }
  314. #[tokio::test]
  315. async fn test_raw_response_is_server_error_with_599() {
  316. let mut server = mockito::Server::new_async().await;
  317. let mock = server
  318. .mock("GET", "/")
  319. .with_status(599)
  320. .create_async()
  321. .await;
  322. let client = HttpClient::new();
  323. let response = client
  324. .get_raw(&server.url())
  325. .await
  326. .expect("Request should succeed");
  327. assert!(response.is_server_error());
  328. assert_eq!(response.status(), 599);
  329. mock.assert_async().await;
  330. }
  331. #[tokio::test]
  332. async fn test_raw_response_is_not_server_error_with_499() {
  333. let mut server = mockito::Server::new_async().await;
  334. let mock = server
  335. .mock("GET", "/")
  336. .with_status(499)
  337. .create_async()
  338. .await;
  339. let client = HttpClient::new();
  340. let response = client
  341. .get_raw(&server.url())
  342. .await
  343. .expect("Request should succeed");
  344. assert!(!response.is_server_error());
  345. assert_eq!(response.status(), 499);
  346. mock.assert_async().await;
  347. }
  348. #[tokio::test]
  349. async fn test_raw_response_text() {
  350. let mut server = mockito::Server::new_async().await;
  351. let mock = server
  352. .mock("GET", "/")
  353. .with_status(200)
  354. .with_body("Hello, World!")
  355. .create_async()
  356. .await;
  357. let client = HttpClient::new();
  358. let response = client
  359. .get_raw(&server.url())
  360. .await
  361. .expect("Request should succeed");
  362. let text = response
  363. .text()
  364. .await
  365. .expect("Text extraction should succeed");
  366. assert_eq!(text, "Hello, World!");
  367. mock.assert_async().await;
  368. }
  369. #[tokio::test]
  370. async fn test_raw_response_json() {
  371. let mut server = mockito::Server::new_async().await;
  372. let mock = server
  373. .mock("GET", "/")
  374. .with_status(200)
  375. .with_header("content-type", "application/json")
  376. .with_body(r#"{"success": true, "data": "json_test"}"#)
  377. .create_async()
  378. .await;
  379. let client = HttpClient::new();
  380. let response = client
  381. .get_raw(&server.url())
  382. .await
  383. .expect("Request should succeed");
  384. let json: TestResponse = response.json().await.expect("JSON parsing should succeed");
  385. assert!(json.success);
  386. assert_eq!(json.data, "json_test");
  387. mock.assert_async().await;
  388. }
  389. #[tokio::test]
  390. async fn test_raw_response_bytes() {
  391. let mut server = mockito::Server::new_async().await;
  392. let mock = server
  393. .mock("GET", "/")
  394. .with_status(200)
  395. .with_body(vec![0x01, 0x02, 0x03, 0x04])
  396. .create_async()
  397. .await;
  398. let client = HttpClient::new();
  399. let response = client
  400. .get_raw(&server.url())
  401. .await
  402. .expect("Request should succeed");
  403. let bytes = response
  404. .bytes()
  405. .await
  406. .expect("Bytes extraction should succeed");
  407. assert_eq!(bytes, vec![0x01, 0x02, 0x03, 0x04]);
  408. mock.assert_async().await;
  409. }
  410. // === RequestBuilder tests ===
  411. #[tokio::test]
  412. async fn test_request_builder_send() {
  413. let mut server = mockito::Server::new_async().await;
  414. let mock = server
  415. .mock("GET", "/api/builder")
  416. .with_status(200)
  417. .with_body("builder response")
  418. .create_async()
  419. .await;
  420. let client = HttpClient::new();
  421. let url = format!("{}/api/builder", server.url());
  422. let response = client
  423. .get(&url)
  424. .send()
  425. .await
  426. .expect("Request should succeed");
  427. assert_eq!(response.status(), 200);
  428. assert_eq!(
  429. response
  430. .text()
  431. .await
  432. .expect("Text extraction should succeed"),
  433. "builder response"
  434. );
  435. mock.assert_async().await;
  436. }
  437. #[tokio::test]
  438. async fn test_request_builder_send_json() {
  439. let mut server = mockito::Server::new_async().await;
  440. let mock = server
  441. .mock("POST", "/api/json")
  442. .with_status(200)
  443. .with_header("content-type", "application/json")
  444. .with_body(r#"{"success": true, "data": "builder_json"}"#)
  445. .create_async()
  446. .await;
  447. let client = HttpClient::new();
  448. let url = format!("{}/api/json", server.url());
  449. let payload = TestPayload {
  450. name: "builder".to_string(),
  451. value: 100,
  452. };
  453. let result: TestResponse = client
  454. .post(&url)
  455. .json(&payload)
  456. .send_json()
  457. .await
  458. .expect("Request should succeed");
  459. assert!(result.success);
  460. assert_eq!(result.data, "builder_json");
  461. mock.assert_async().await;
  462. }
  463. #[tokio::test]
  464. async fn test_request_builder_with_headers() {
  465. let mut server = mockito::Server::new_async().await;
  466. let mock = server
  467. .mock("GET", "/api/headers")
  468. .match_header("X-Custom-Header", "custom-value")
  469. .match_header("Authorization", "Bearer token123")
  470. .with_status(200)
  471. .with_body("headers received")
  472. .create_async()
  473. .await;
  474. let client = HttpClient::new();
  475. let url = format!("{}/api/headers", server.url());
  476. let response = client
  477. .get(&url)
  478. .header("X-Custom-Header", "custom-value")
  479. .header("Authorization", "Bearer token123")
  480. .send()
  481. .await
  482. .expect("Request should succeed");
  483. assert_eq!(response.status(), 200);
  484. assert_eq!(
  485. response
  486. .text()
  487. .await
  488. .expect("Text extraction should succeed"),
  489. "headers received"
  490. );
  491. mock.assert_async().await;
  492. }
  493. #[tokio::test]
  494. async fn test_request_builder_post_with_form() {
  495. let mut server = mockito::Server::new_async().await;
  496. let mock = server
  497. .mock("POST", "/api/form")
  498. .match_header(
  499. "content-type",
  500. mockito::Matcher::Regex("application/x-www-form-urlencoded.*".to_string()),
  501. )
  502. .with_status(200)
  503. .with_header("content-type", "application/json")
  504. .with_body(r#"{"success": true, "data": "form_received"}"#)
  505. .create_async()
  506. .await;
  507. let client = HttpClient::new();
  508. let url = format!("{}/api/form", server.url());
  509. let form_data = [("field1", "value1"), ("field2", "value2")];
  510. let response: TestResponse = client
  511. .post(&url)
  512. .form(&form_data)
  513. .send_json()
  514. .await
  515. .expect("Request should succeed");
  516. assert!(response.success);
  517. assert_eq!(response.data, "form_received");
  518. mock.assert_async().await;
  519. }
  520. #[tokio::test]
  521. async fn test_request_builder_patch() {
  522. let mut server = mockito::Server::new_async().await;
  523. let mock = server
  524. .mock("PATCH", "/api/resource")
  525. .with_status(200)
  526. .with_header("content-type", "application/json")
  527. .with_body(r#"{"success": true, "data": "patched"}"#)
  528. .create_async()
  529. .await;
  530. let client = HttpClient::new();
  531. let url = format!("{}/api/resource", server.url());
  532. let payload = TestPayload {
  533. name: "update".to_string(),
  534. value: 99,
  535. };
  536. let result: TestResponse = client
  537. .patch(&url)
  538. .json(&payload)
  539. .send_json()
  540. .await
  541. .expect("Request should succeed");
  542. assert!(result.success);
  543. assert_eq!(result.data, "patched");
  544. mock.assert_async().await;
  545. }
  546. // === Convenience function test ===
  547. #[tokio::test]
  548. async fn test_fetch_convenience_function() {
  549. let mut server = mockito::Server::new_async().await;
  550. let mock = server
  551. .mock("GET", "/api/convenience")
  552. .with_status(200)
  553. .with_header("content-type", "application/json")
  554. .with_body(r#"{"success": true, "data": "convenience"}"#)
  555. .create_async()
  556. .await;
  557. let url = format!("{}/api/convenience", server.url());
  558. let result: Result<TestResponse, _> = cdk_http_client::fetch(&url).await;
  559. assert!(result.is_ok());
  560. let response = result.expect("Fetch should succeed");
  561. assert!(response.success);
  562. assert_eq!(response.data, "convenience");
  563. mock.assert_async().await;
  564. }
  565. // === Error handling tests ===
  566. #[tokio::test]
  567. async fn test_json_deserialization_error() {
  568. let mut server = mockito::Server::new_async().await;
  569. let mock = server
  570. .mock("GET", "/api/invalid-json")
  571. .with_status(200)
  572. .with_header("content-type", "application/json")
  573. .with_body("not valid json")
  574. .create_async()
  575. .await;
  576. let client = HttpClient::new();
  577. let url = format!("{}/api/invalid-json", server.url());
  578. let result: Result<TestResponse, _> = client.fetch(&url).await;
  579. assert!(result.is_err());
  580. // The error should be about JSON parsing, which becomes HttpError::Other from reqwest
  581. let err = result.expect_err("Should be a deserialization error");
  582. let err_str = format!("{}", err);
  583. assert!(
  584. err_str.contains("expected") || err_str.contains("JSON") || err_str.contains("error"),
  585. "Error should mention parsing issue: {}",
  586. err_str
  587. );
  588. mock.assert_async().await;
  589. }
  590. #[tokio::test]
  591. async fn test_raw_response_json_deserialization_error() {
  592. let mut server = mockito::Server::new_async().await;
  593. let mock = server
  594. .mock("GET", "/")
  595. .with_status(200)
  596. .with_body("invalid json")
  597. .create_async()
  598. .await;
  599. let client = HttpClient::new();
  600. let response = client
  601. .get_raw(&server.url())
  602. .await
  603. .expect("Request should succeed");
  604. let result: Result<TestResponse, _> = response.json().await;
  605. assert!(result.is_err());
  606. mock.assert_async().await;
  607. }