ResponseTests.swift 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. //
  2. // ResponseTests.swift
  3. //
  4. // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/)
  5. //
  6. // Permission is hereby granted, free of charge, to any person obtaining a copy
  7. // of this software and associated documentation files (the "Software"), to deal
  8. // in the Software without restriction, including without limitation the rights
  9. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. // copies of the Software, and to permit persons to whom the Software is
  11. // furnished to do so, subject to the following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be included in
  14. // all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. // THE SOFTWARE.
  23. //
  24. import Alamofire
  25. import Foundation
  26. import XCTest
  27. class ResponseTestCase: BaseTestCase {
  28. func testThatResponseReturnsSuccessResultWithValidData() {
  29. // Given
  30. let urlString = "https://httpbin.org/get"
  31. let expectation = self.expectation(description: "request should succeed")
  32. var response: DataResponse<Data?>?
  33. // When
  34. Alamofire.request(urlString, parameters: ["foo": "bar"]).response { resp in
  35. response = resp
  36. expectation.fulfill()
  37. }
  38. waitForExpectations(timeout: timeout, handler: nil)
  39. // Then
  40. XCTAssertNotNil(response?.request)
  41. XCTAssertNotNil(response?.response)
  42. XCTAssertNotNil(response?.data)
  43. XCTAssertNil(response?.error)
  44. XCTAssertNotNil(response?.metrics)
  45. }
  46. func testThatResponseReturnsFailureResultWithOptionalDataAndError() {
  47. // Given
  48. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  49. let expectation = self.expectation(description: "request should fail with 404")
  50. var response: DataResponse<Data?>?
  51. // When
  52. Alamofire.request(urlString, parameters: ["foo": "bar"]).response { resp in
  53. response = resp
  54. expectation.fulfill()
  55. }
  56. waitForExpectations(timeout: timeout, handler: nil)
  57. // Then
  58. XCTAssertNotNil(response?.request)
  59. XCTAssertNil(response?.response)
  60. XCTAssertNil(response?.data)
  61. XCTAssertNotNil(response?.error)
  62. XCTAssertNotNil(response?.metrics)
  63. }
  64. }
  65. // MARK: -
  66. class ResponseDataTestCase: BaseTestCase {
  67. func testThatResponseDataReturnsSuccessResultWithValidData() {
  68. // Given
  69. let urlString = "https://httpbin.org/get"
  70. let expectation = self.expectation(description: "request should succeed")
  71. var response: DataResponse<Data>?
  72. // When
  73. Alamofire.request(urlString, parameters: ["foo": "bar"]).responseData { resp in
  74. response = resp
  75. expectation.fulfill()
  76. }
  77. waitForExpectations(timeout: timeout, handler: nil)
  78. // Then
  79. XCTAssertNotNil(response?.request)
  80. XCTAssertNotNil(response?.response)
  81. XCTAssertNotNil(response?.data)
  82. XCTAssertNotNil(response?.data)
  83. XCTAssertEqual(response?.result.isSuccess, true)
  84. XCTAssertNotNil(response?.metrics)
  85. }
  86. func testThatResponseDataReturnsFailureResultWithOptionalDataAndError() {
  87. // Given
  88. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  89. let expectation = self.expectation(description: "request should fail with 404")
  90. var response: DataResponse<Data>?
  91. // When
  92. Alamofire.request(urlString, parameters: ["foo": "bar"]).responseData { resp in
  93. response = resp
  94. expectation.fulfill()
  95. }
  96. waitForExpectations(timeout: timeout, handler: nil)
  97. // Then
  98. XCTAssertNotNil(response?.request)
  99. XCTAssertNil(response?.response)
  100. XCTAssertNil(response?.data)
  101. XCTAssertEqual(response?.result.isFailure, true)
  102. XCTAssertNotNil(response?.metrics)
  103. }
  104. }
  105. // MARK: -
  106. class ResponseStringTestCase: BaseTestCase {
  107. func testThatResponseStringReturnsSuccessResultWithValidString() {
  108. // Given
  109. let urlString = "https://httpbin.org/get"
  110. let expectation = self.expectation(description: "request should succeed")
  111. var response: DataResponse<String>?
  112. // When
  113. Alamofire.request(urlString, parameters: ["foo": "bar"]).responseString { resp in
  114. response = resp
  115. expectation.fulfill()
  116. }
  117. waitForExpectations(timeout: timeout, handler: nil)
  118. // Then
  119. XCTAssertNotNil(response?.request)
  120. XCTAssertNotNil(response?.response)
  121. XCTAssertNotNil(response?.data)
  122. XCTAssertNotNil(response?.data)
  123. XCTAssertEqual(response?.result.isSuccess, true)
  124. XCTAssertNotNil(response?.metrics)
  125. }
  126. func testThatResponseStringReturnsFailureResultWithOptionalDataAndError() {
  127. // Given
  128. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  129. let expectation = self.expectation(description: "request should fail with 404")
  130. var response: DataResponse<String>?
  131. // When
  132. Alamofire.request(urlString, parameters: ["foo": "bar"]).responseString { resp in
  133. response = resp
  134. expectation.fulfill()
  135. }
  136. waitForExpectations(timeout: timeout, handler: nil)
  137. // Then
  138. XCTAssertNotNil(response?.request)
  139. XCTAssertNil(response?.response)
  140. XCTAssertNil(response?.data)
  141. XCTAssertEqual(response?.result.isFailure, true)
  142. XCTAssertNotNil(response?.metrics)
  143. }
  144. }
  145. // MARK: -
  146. class ResponseJSONTestCase: BaseTestCase {
  147. func testThatResponseJSONReturnsSuccessResultWithValidJSON() {
  148. // Given
  149. let urlString = "https://httpbin.org/get"
  150. let expectation = self.expectation(description: "request should succeed")
  151. var response: DataResponse<Any>?
  152. // When
  153. Alamofire.request(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  154. response = resp
  155. expectation.fulfill()
  156. }
  157. waitForExpectations(timeout: timeout, handler: nil)
  158. // Then
  159. XCTAssertNotNil(response?.request)
  160. XCTAssertNotNil(response?.response)
  161. XCTAssertNotNil(response?.data)
  162. XCTAssertNotNil(response?.data)
  163. XCTAssertEqual(response?.result.isSuccess, true)
  164. XCTAssertNotNil(response?.metrics)
  165. }
  166. func testThatResponseStringReturnsFailureResultWithOptionalDataAndError() {
  167. // Given
  168. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  169. let expectation = self.expectation(description: "request should fail")
  170. var response: DataResponse<Any>?
  171. // When
  172. Alamofire.request(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  173. response = resp
  174. expectation.fulfill()
  175. }
  176. waitForExpectations(timeout: timeout, handler: nil)
  177. // Then
  178. XCTAssertNotNil(response?.request)
  179. XCTAssertNil(response?.response)
  180. XCTAssertNil(response?.data)
  181. XCTAssertEqual(response?.result.isFailure, true)
  182. XCTAssertNotNil(response?.metrics)
  183. }
  184. func testThatResponseJSONReturnsSuccessResultForGETRequest() {
  185. // Given
  186. let urlString = "https://httpbin.org/get"
  187. let expectation = self.expectation(description: "request should succeed")
  188. var response: DataResponse<Any>?
  189. // When
  190. Alamofire.request(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  191. response = resp
  192. expectation.fulfill()
  193. }
  194. waitForExpectations(timeout: timeout, handler: nil)
  195. // Then
  196. XCTAssertNotNil(response?.request)
  197. XCTAssertNotNil(response?.response)
  198. XCTAssertNotNil(response?.data)
  199. XCTAssertNotNil(response?.data)
  200. XCTAssertEqual(response?.result.isSuccess, true)
  201. XCTAssertNotNil(response?.metrics)
  202. if
  203. let responseDictionary = response?.result.value as? [String: Any],
  204. let args = responseDictionary["args"] as? [String: String]
  205. {
  206. XCTAssertEqual(args, ["foo": "bar"], "args should match parameters")
  207. } else {
  208. XCTFail("args should not be nil")
  209. }
  210. }
  211. func testThatResponseJSONReturnsSuccessResultForPOSTRequest() {
  212. // Given
  213. let urlString = "https://httpbin.org/post"
  214. let expectation = self.expectation(description: "request should succeed")
  215. var response: DataResponse<Any>?
  216. // When
  217. Alamofire.request(urlString, method: .post, parameters: ["foo": "bar"]).responseJSON { resp in
  218. response = resp
  219. expectation.fulfill()
  220. }
  221. waitForExpectations(timeout: timeout, handler: nil)
  222. // Then
  223. XCTAssertNotNil(response?.request)
  224. XCTAssertNotNil(response?.response)
  225. XCTAssertNotNil(response?.data)
  226. XCTAssertNotNil(response?.data)
  227. XCTAssertEqual(response?.result.isSuccess, true)
  228. XCTAssertNotNil(response?.metrics)
  229. if
  230. let responseDictionary = response?.result.value as? [String: Any],
  231. let form = responseDictionary["form"] as? [String: String]
  232. {
  233. XCTAssertEqual(form, ["foo": "bar"], "form should match parameters")
  234. } else {
  235. XCTFail("form should not be nil")
  236. }
  237. }
  238. }
  239. class ResponseJSONDecodableTestCase: BaseTestCase {
  240. struct HTTPBinResponse: Decodable {
  241. let headers: [String: String]
  242. let origin: String
  243. let url: String
  244. }
  245. func testThatResponseJSONReturnsSuccessResultWithValidJSON() {
  246. // Given
  247. let urlString = "https://httpbin.org/get"
  248. let expectation = self.expectation(description: "request should succeed")
  249. var response: DataResponse<HTTPBinResponse>?
  250. // When
  251. Alamofire.request(urlString, parameters: [:]).responseJSONDecodable { (resp: DataResponse<HTTPBinResponse>) in
  252. response = resp
  253. expectation.fulfill()
  254. }
  255. waitForExpectations(timeout: timeout, handler: nil)
  256. // Then
  257. XCTAssertNotNil(response?.request)
  258. XCTAssertNotNil(response?.response)
  259. XCTAssertNotNil(response?.data)
  260. XCTAssertEqual(response?.result.isSuccess, true)
  261. XCTAssertEqual(response?.result.value?.url, "https://httpbin.org/get")
  262. XCTAssertNotNil(response?.metrics)
  263. }
  264. func testThatResponseStringReturnsFailureResultWithOptionalDataAndError() {
  265. // Given
  266. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  267. let expectation = self.expectation(description: "request should fail")
  268. var response: DataResponse<HTTPBinResponse>?
  269. // When
  270. Alamofire.request(urlString, parameters: [:]).responseJSONDecodable { (resp: DataResponse<HTTPBinResponse>) in
  271. response = resp
  272. expectation.fulfill()
  273. }
  274. waitForExpectations(timeout: timeout, handler: nil)
  275. // Then
  276. XCTAssertNotNil(response?.request)
  277. XCTAssertNil(response?.response)
  278. XCTAssertNil(response?.data)
  279. XCTAssertEqual(response?.result.isFailure, true)
  280. XCTAssertNotNil(response?.metrics)
  281. }
  282. }
  283. // MARK: -
  284. class ResponseMapTestCase: BaseTestCase {
  285. func testThatMapTransformsSuccessValue() {
  286. // Given
  287. let urlString = "https://httpbin.org/get"
  288. let expectation = self.expectation(description: "request should succeed")
  289. var response: DataResponse<String>?
  290. // When
  291. Alamofire.request(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  292. response = resp.map { json in
  293. // json["args"]["foo"] is "bar": use this invariant to test the map function
  294. return ((json as? [String: Any])?["args"] as? [String: Any])?["foo"] as? String ?? "invalid"
  295. }
  296. expectation.fulfill()
  297. }
  298. waitForExpectations(timeout: timeout, handler: nil)
  299. // Then
  300. XCTAssertNotNil(response?.request)
  301. XCTAssertNotNil(response?.response)
  302. XCTAssertNotNil(response?.data)
  303. XCTAssertEqual(response?.result.isSuccess, true)
  304. XCTAssertEqual(response?.result.value, "bar")
  305. XCTAssertNotNil(response?.metrics)
  306. }
  307. func testThatMapPreservesFailureError() {
  308. // Given
  309. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  310. let expectation = self.expectation(description: "request should fail with 404")
  311. var response: DataResponse<String>?
  312. // When
  313. Alamofire.request(urlString, parameters: ["foo": "bar"]).responseData { resp in
  314. response = resp.map { _ in "ignored" }
  315. expectation.fulfill()
  316. }
  317. waitForExpectations(timeout: timeout, handler: nil)
  318. // Then
  319. XCTAssertNotNil(response?.request)
  320. XCTAssertNil(response?.response)
  321. XCTAssertNil(response?.data)
  322. XCTAssertEqual(response?.result.isFailure, true)
  323. XCTAssertNotNil(response?.metrics)
  324. }
  325. }
  326. // MARK: -
  327. class ResponseFlatMapTestCase: BaseTestCase {
  328. func testThatFlatMapTransformsSuccessValue() {
  329. // Given
  330. let urlString = "https://httpbin.org/get"
  331. let expectation = self.expectation(description: "request should succeed")
  332. var response: DataResponse<String>?
  333. // When
  334. Alamofire.request(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  335. response = resp.flatMap { json in
  336. // json["args"]["foo"] is "bar": use this invariant to test the flatMap function
  337. return ((json as? [String: Any])?["args"] as? [String: Any])?["foo"] as? String ?? "invalid"
  338. }
  339. expectation.fulfill()
  340. }
  341. waitForExpectations(timeout: timeout, handler: nil)
  342. // Then
  343. XCTAssertNotNil(response?.request)
  344. XCTAssertNotNil(response?.response)
  345. XCTAssertNotNil(response?.data)
  346. XCTAssertEqual(response?.result.isSuccess, true)
  347. XCTAssertEqual(response?.result.value, "bar")
  348. XCTAssertNotNil(response?.metrics)
  349. }
  350. func testThatFlatMapCatchesTransformationError() {
  351. // Given
  352. struct TransformError: Error {}
  353. let urlString = "https://httpbin.org/get"
  354. let expectation = self.expectation(description: "request should succeed")
  355. var response: DataResponse<String>?
  356. // When
  357. Alamofire.request(urlString, parameters: ["foo": "bar"]).responseData { resp in
  358. response = resp.flatMap { json in
  359. throw TransformError()
  360. }
  361. expectation.fulfill()
  362. }
  363. waitForExpectations(timeout: timeout, handler: nil)
  364. // Then
  365. XCTAssertNotNil(response?.request)
  366. XCTAssertNotNil(response?.response)
  367. XCTAssertNotNil(response?.data)
  368. XCTAssertEqual(response?.result.isFailure, true)
  369. if let error = response?.result.error {
  370. XCTAssertTrue(error is TransformError)
  371. } else {
  372. XCTFail("flatMap should catch the transformation error")
  373. }
  374. XCTAssertNotNil(response?.metrics)
  375. }
  376. func testThatFlatMapPreservesFailureError() {
  377. // Given
  378. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  379. let expectation = self.expectation(description: "request should fail with 404")
  380. var response: DataResponse<String>?
  381. // When
  382. Alamofire.request(urlString, parameters: ["foo": "bar"]).responseData { resp in
  383. response = resp.flatMap { _ in "ignored" }
  384. expectation.fulfill()
  385. }
  386. waitForExpectations(timeout: timeout, handler: nil)
  387. // Then
  388. XCTAssertNotNil(response?.request)
  389. XCTAssertNil(response?.response)
  390. XCTAssertNil(response?.data)
  391. XCTAssertEqual(response?.result.isFailure, true)
  392. XCTAssertNotNil(response?.metrics)
  393. }
  394. }
  395. // MARK: -
  396. enum TestError: Error {
  397. case error(error: Error)
  398. }
  399. enum TransformationError: Error {
  400. case error
  401. func alwaysFails() throws -> TestError {
  402. throw TransformationError.error
  403. }
  404. }
  405. class ResponseMapErrorTestCase: BaseTestCase {
  406. func testThatMapErrorTransformsFailureValue() {
  407. // Given
  408. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  409. let expectation = self.expectation(description: "request should not succeed")
  410. var response: DataResponse<Any>?
  411. // When
  412. Alamofire.request(urlString).responseJSON { resp in
  413. response = resp.mapError { error in
  414. return TestError.error(error: error)
  415. }
  416. expectation.fulfill()
  417. }
  418. waitForExpectations(timeout: timeout, handler: nil)
  419. // Then
  420. XCTAssertNotNil(response?.request)
  421. XCTAssertNil(response?.response)
  422. XCTAssertNil(response?.data)
  423. XCTAssertEqual(response?.result.isFailure, true)
  424. guard let error = response?.error as? TestError, case .error = error else { XCTFail(); return }
  425. XCTAssertNotNil(response?.metrics)
  426. }
  427. func testThatMapErrorPreservesSuccessValue() {
  428. // Given
  429. let urlString = "https://httpbin.org/get"
  430. let expectation = self.expectation(description: "request should succeed")
  431. var response: DataResponse<Data>?
  432. // When
  433. Alamofire.request(urlString).responseData { resp in
  434. response = resp.mapError { TestError.error(error: $0) }
  435. expectation.fulfill()
  436. }
  437. waitForExpectations(timeout: timeout, handler: nil)
  438. // Then
  439. XCTAssertNotNil(response?.request)
  440. XCTAssertNotNil(response?.response)
  441. XCTAssertNotNil(response?.data)
  442. XCTAssertEqual(response?.result.isSuccess, true)
  443. XCTAssertNotNil(response?.metrics)
  444. }
  445. }
  446. // MARK: -
  447. class ResponseFlatMapErrorTestCase: BaseTestCase {
  448. func testThatFlatMapErrorPreservesSuccessValue() {
  449. // Given
  450. let urlString = "https://httpbin.org/get"
  451. let expectation = self.expectation(description: "request should succeed")
  452. var response: DataResponse<Data>?
  453. // When
  454. Alamofire.request(urlString).responseData { resp in
  455. response = resp.flatMapError { TestError.error(error: $0) }
  456. expectation.fulfill()
  457. }
  458. waitForExpectations(timeout: timeout, handler: nil)
  459. // Then
  460. XCTAssertNotNil(response?.request)
  461. XCTAssertNotNil(response?.response)
  462. XCTAssertNotNil(response?.data)
  463. XCTAssertEqual(response?.result.isSuccess, true)
  464. XCTAssertNotNil(response?.metrics)
  465. }
  466. func testThatFlatMapErrorCatchesTransformationError() {
  467. // Given
  468. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  469. let expectation = self.expectation(description: "request should fail")
  470. var response: DataResponse<Data>?
  471. // When
  472. Alamofire.request(urlString).responseData { resp in
  473. response = resp.flatMapError { _ in try TransformationError.error.alwaysFails() }
  474. expectation.fulfill()
  475. }
  476. waitForExpectations(timeout: timeout, handler: nil)
  477. // Then
  478. XCTAssertNotNil(response?.request)
  479. XCTAssertNil(response?.response)
  480. XCTAssertNil(response?.data)
  481. XCTAssertEqual(response?.result.isFailure, true)
  482. if let error = response?.result.error {
  483. XCTAssertTrue(error is TransformationError)
  484. } else {
  485. XCTFail("flatMapError should catch the transformation error")
  486. }
  487. XCTAssertNotNil(response?.metrics)
  488. }
  489. func testThatFlatMapErrorTransformsError() {
  490. // Given
  491. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  492. let expectation = self.expectation(description: "request should fail")
  493. var response: DataResponse<Data>?
  494. // When
  495. Alamofire.request(urlString).responseData { resp in
  496. response = resp.flatMapError { TestError.error(error: $0) }
  497. expectation.fulfill()
  498. }
  499. waitForExpectations(timeout: timeout, handler: nil)
  500. // Then
  501. XCTAssertNotNil(response?.request)
  502. XCTAssertNil(response?.response)
  503. XCTAssertNil(response?.data)
  504. XCTAssertEqual(response?.result.isFailure, true)
  505. guard let error = response?.error as? TestError, case .error = error else { XCTFail(); return }
  506. XCTAssertNotNil(response?.metrics)
  507. }
  508. }