ResponseTests.swift 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. // ResponseTests.swift
  2. //
  3. // Copyright (c) 2014–2015 Alamofire Software Foundation (http://alamofire.org/)
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. import Alamofire
  23. import Foundation
  24. import XCTest
  25. class ResponseDataTestCase: BaseTestCase {
  26. func testThatResponseDataReturnsSuccessResultWithValidData() {
  27. // Given
  28. let URLString = "https://httpbin.org/get"
  29. let expectation = expectationWithDescription("request should succeed")
  30. var response: Response<NSData, NSError>?
  31. // When
  32. Alamofire.request(.GET, URLString, parameters: ["foo": "bar"])
  33. .responseData { closureResponse in
  34. response = closureResponse
  35. expectation.fulfill()
  36. }
  37. waitForExpectationsWithTimeout(defaultTimeout, handler: nil)
  38. // Then
  39. if let response = response {
  40. XCTAssertNotNil(response.request, "request should not be nil")
  41. XCTAssertNotNil(response.response, "response should not be nil")
  42. XCTAssertNotNil(response.data, "data should not be nil")
  43. XCTAssertTrue(response.result.isSuccess, "result should be success")
  44. } else {
  45. XCTFail("response should not be nil")
  46. }
  47. }
  48. func testThatResponseDataReturnsFailureResultWithOptionalDataAndError() {
  49. // Given
  50. let URLString = "https://invalid-url-here.org/this/does/not/exist"
  51. let expectation = expectationWithDescription("request should fail with 404")
  52. var response: Response<NSData, NSError>?
  53. // When
  54. Alamofire.request(.GET, URLString, parameters: ["foo": "bar"])
  55. .responseData { closureResponse in
  56. response = closureResponse
  57. expectation.fulfill()
  58. }
  59. waitForExpectationsWithTimeout(defaultTimeout, handler: nil)
  60. // Then
  61. if let response = response {
  62. XCTAssertNotNil(response.request, "request should not be nil")
  63. XCTAssertNil(response.response, "response should be nil")
  64. XCTAssertNotNil(response.data, "data should not be nil")
  65. XCTAssertTrue(response.result.isFailure, "result should be failure")
  66. } else {
  67. XCTFail("response should not be nil")
  68. }
  69. }
  70. }
  71. // MARK: -
  72. class ResponseStringTestCase: BaseTestCase {
  73. func testThatResponseStringReturnsSuccessResultWithValidString() {
  74. // Given
  75. let URLString = "https://httpbin.org/get"
  76. let expectation = expectationWithDescription("request should succeed")
  77. var response: Response<String, NSError>?
  78. // When
  79. Alamofire.request(.GET, URLString, parameters: ["foo": "bar"])
  80. .responseString { closureResponse in
  81. response = closureResponse
  82. expectation.fulfill()
  83. }
  84. waitForExpectationsWithTimeout(defaultTimeout, handler: nil)
  85. // Then
  86. if let response = response {
  87. XCTAssertNotNil(response.request, "request should not be nil")
  88. XCTAssertNotNil(response.response, "response should not be nil")
  89. XCTAssertNotNil(response.data, "data should not be nil")
  90. XCTAssertTrue(response.result.isSuccess, "result should be success")
  91. } else {
  92. XCTFail("response should not be nil")
  93. }
  94. }
  95. func testThatResponseStringReturnsFailureResultWithOptionalDataAndError() {
  96. // Given
  97. let URLString = "https://invalid-url-here.org/this/does/not/exist"
  98. let expectation = expectationWithDescription("request should fail with 404")
  99. var response: Response<String, NSError>?
  100. // When
  101. Alamofire.request(.GET, URLString, parameters: ["foo": "bar"])
  102. .responseString { closureResponse in
  103. response = closureResponse
  104. expectation.fulfill()
  105. }
  106. waitForExpectationsWithTimeout(defaultTimeout, handler: nil)
  107. // Then
  108. if let response = response {
  109. XCTAssertNotNil(response.request, "request should not be nil")
  110. XCTAssertNil(response.response, "response should be nil")
  111. XCTAssertNotNil(response.data, "data should not be nil")
  112. XCTAssertTrue(response.result.isFailure, "result should be failure")
  113. } else {
  114. XCTFail("response should not be nil")
  115. }
  116. }
  117. }
  118. // MARK: -
  119. class ResponseJSONTestCase: BaseTestCase {
  120. func testThatResponseJSONReturnsSuccessResultWithValidJSON() {
  121. // Given
  122. let URLString = "https://httpbin.org/get"
  123. let expectation = expectationWithDescription("request should succeed")
  124. var response: Response<AnyObject, NSError>?
  125. // When
  126. Alamofire.request(.GET, URLString, parameters: ["foo": "bar"])
  127. .responseJSON { closureResponse in
  128. response = closureResponse
  129. expectation.fulfill()
  130. }
  131. waitForExpectationsWithTimeout(defaultTimeout, handler: nil)
  132. // Then
  133. if let response = response {
  134. XCTAssertNotNil(response.request, "request should not be nil")
  135. XCTAssertNotNil(response.response, "response should not be nil")
  136. XCTAssertNotNil(response.data, "data should not be nil")
  137. XCTAssertTrue(response.result.isSuccess, "result should be success")
  138. } else {
  139. XCTFail("response should not be nil")
  140. }
  141. }
  142. func testThatResponseStringReturnsFailureResultWithOptionalDataAndError() {
  143. // Given
  144. let URLString = "https://invalid-url-here.org/this/does/not/exist"
  145. let expectation = expectationWithDescription("request should fail with 404")
  146. var response: Response<AnyObject, NSError>?
  147. // When
  148. Alamofire.request(.GET, URLString, parameters: ["foo": "bar"])
  149. .responseJSON { closureResponse in
  150. response = closureResponse
  151. expectation.fulfill()
  152. }
  153. waitForExpectationsWithTimeout(defaultTimeout, handler: nil)
  154. // Then
  155. if let response = response {
  156. XCTAssertNotNil(response.request, "request should not be nil")
  157. XCTAssertNil(response.response, "response should be nil")
  158. XCTAssertNotNil(response.data, "data should not be nil")
  159. XCTAssertTrue(response.result.isFailure, "result should be failure")
  160. } else {
  161. XCTFail("response should not be nil")
  162. }
  163. }
  164. func testThatResponseJSONReturnsSuccessResultForGETRequest() {
  165. // Given
  166. let URLString = "https://httpbin.org/get"
  167. let expectation = expectationWithDescription("request should succeed")
  168. var response: Response<AnyObject, NSError>?
  169. // When
  170. Alamofire.request(.GET, URLString, parameters: ["foo": "bar"])
  171. .responseJSON { closureResponse in
  172. response = closureResponse
  173. expectation.fulfill()
  174. }
  175. waitForExpectationsWithTimeout(defaultTimeout, handler: nil)
  176. // Then
  177. if let response = response {
  178. XCTAssertNotNil(response.request, "request should not be nil")
  179. XCTAssertNotNil(response.response, "response should not be nil")
  180. XCTAssertNotNil(response.data, "data should not be nil")
  181. XCTAssertTrue(response.result.isSuccess, "result should be success")
  182. // The `as NSString` cast is necessary due to a compiler bug. See the following rdar for more info.
  183. // - https://openradar.appspot.com/radar?id=5517037090635776
  184. if let args = response.result.value?["args" as NSString] as? [String: String] {
  185. XCTAssertEqual(args, ["foo": "bar"], "args should match parameters")
  186. } else {
  187. XCTFail("args should not be nil")
  188. }
  189. } else {
  190. XCTFail("response should not be nil")
  191. }
  192. }
  193. func testThatResponseJSONReturnsSuccessResultForPOSTRequest() {
  194. // Given
  195. let URLString = "https://httpbin.org/post"
  196. let expectation = expectationWithDescription("request should succeed")
  197. var response: Response<AnyObject, NSError>?
  198. // When
  199. Alamofire.request(.POST, URLString, parameters: ["foo": "bar"])
  200. .responseJSON { closureResponse in
  201. response = closureResponse
  202. expectation.fulfill()
  203. }
  204. waitForExpectationsWithTimeout(defaultTimeout, handler: nil)
  205. // Then
  206. if let response = response {
  207. XCTAssertNotNil(response.request, "request should not be nil")
  208. XCTAssertNotNil(response.response, "response should not be nil")
  209. XCTAssertNotNil(response.data, "data should not be nil")
  210. XCTAssertTrue(response.result.isSuccess, "result should be success")
  211. // The `as NSString` cast is necessary due to a compiler bug. See the following rdar for more info.
  212. // - https://openradar.appspot.com/radar?id=5517037090635776
  213. if let form = response.result.value?["form" as NSString] as? [String: String] {
  214. XCTAssertEqual(form, ["foo": "bar"], "form should match parameters")
  215. } else {
  216. XCTFail("form should not be nil")
  217. }
  218. } else {
  219. XCTFail("response should not be nil")
  220. }
  221. }
  222. }
  223. // MARK: -
  224. class RedirectResponseTestCase: BaseTestCase {
  225. // MARK: Setup and Teardown
  226. override func tearDown() {
  227. super.tearDown()
  228. Alamofire.Manager.sharedInstance.delegate.taskWillPerformHTTPRedirection = nil
  229. }
  230. // MARK: Tests
  231. func testThatRequestWillPerformHTTPRedirectionByDefault() {
  232. // Given
  233. let redirectURLString = "https://www.apple.com"
  234. let URLString = "https://httpbin.org/redirect-to?url=\(redirectURLString)"
  235. let expectation = expectationWithDescription("Request should redirect to \(redirectURLString)")
  236. var request: NSURLRequest?
  237. var response: NSHTTPURLResponse?
  238. var data: NSData?
  239. var error: NSError?
  240. // When
  241. Alamofire.request(.GET, URLString)
  242. .response { responseRequest, responseResponse, responseData, responseError in
  243. request = responseRequest
  244. response = responseResponse
  245. data = responseData
  246. error = responseError
  247. expectation.fulfill()
  248. }
  249. waitForExpectationsWithTimeout(defaultTimeout, handler: nil)
  250. // Then
  251. XCTAssertNotNil(request, "request should not be nil")
  252. XCTAssertNotNil(response, "response should not be nil")
  253. XCTAssertNotNil(data, "data should not be nil")
  254. XCTAssertNil(error, "error should be nil")
  255. XCTAssertEqual(response?.URL?.URLString ?? "", redirectURLString, "response URL should match the redirect URL")
  256. XCTAssertEqual(response?.statusCode ?? -1, 200, "response should have a 200 status code")
  257. }
  258. func testThatRequestWillPerformRedirectionMultipleTimesByDefault() {
  259. // Given
  260. let redirectURLString = "https://httpbin.org/get"
  261. let URLString = "https://httpbin.org/redirect/5"
  262. let expectation = expectationWithDescription("Request should redirect to \(redirectURLString)")
  263. var request: NSURLRequest?
  264. var response: NSHTTPURLResponse?
  265. var data: NSData?
  266. var error: NSError?
  267. // When
  268. Alamofire.request(.GET, URLString)
  269. .response { responseRequest, responseResponse, responseData, responseError in
  270. request = responseRequest
  271. response = responseResponse
  272. data = responseData
  273. error = responseError
  274. expectation.fulfill()
  275. }
  276. waitForExpectationsWithTimeout(defaultTimeout, handler: nil)
  277. // Then
  278. XCTAssertNotNil(request, "request should not be nil")
  279. XCTAssertNotNil(response, "response should not be nil")
  280. XCTAssertNotNil(data, "data should not be nil")
  281. XCTAssertNil(error, "error should be nil")
  282. XCTAssertEqual(response?.URL?.URLString ?? "", redirectURLString, "response URL should match the redirect URL")
  283. XCTAssertEqual(response?.statusCode ?? -1, 200, "response should have a 200 status code")
  284. }
  285. func testThatTaskOverrideClosureCanPerformHTTPRedirection() {
  286. // Given
  287. let redirectURLString = "https://www.apple.com"
  288. let URLString = "https://httpbin.org/redirect-to?url=\(redirectURLString)"
  289. let expectation = expectationWithDescription("Request should redirect to \(redirectURLString)")
  290. let delegate: Alamofire.Manager.SessionDelegate = Alamofire.Manager.sharedInstance.delegate
  291. delegate.taskWillPerformHTTPRedirection = { _, _, _, request in
  292. return request
  293. }
  294. var request: NSURLRequest?
  295. var response: NSHTTPURLResponse?
  296. var data: NSData?
  297. var error: NSError?
  298. // When
  299. Alamofire.request(.GET, URLString)
  300. .response { responseRequest, responseResponse, responseData, responseError in
  301. request = responseRequest
  302. response = responseResponse
  303. data = responseData
  304. error = responseError
  305. expectation.fulfill()
  306. }
  307. waitForExpectationsWithTimeout(defaultTimeout, handler: nil)
  308. // Then
  309. XCTAssertNotNil(request, "request should not be nil")
  310. XCTAssertNotNil(response, "response should not be nil")
  311. XCTAssertNotNil(data, "data should not be nil")
  312. XCTAssertNil(error, "error should be nil")
  313. XCTAssertEqual(response?.URL?.URLString ?? "", redirectURLString, "response URL should match the redirect URL")
  314. XCTAssertEqual(response?.statusCode ?? -1, 200, "response should have a 200 status code")
  315. }
  316. func testThatTaskOverrideClosureCanCancelHTTPRedirection() {
  317. // Given
  318. let redirectURLString = "https://www.apple.com"
  319. let URLString = "https://httpbin.org/redirect-to?url=\(redirectURLString)"
  320. let expectation = expectationWithDescription("Request should not redirect to \(redirectURLString)")
  321. let delegate: Alamofire.Manager.SessionDelegate = Alamofire.Manager.sharedInstance.delegate
  322. delegate.taskWillPerformHTTPRedirection = { _, _, _, _ in
  323. return nil
  324. }
  325. var request: NSURLRequest?
  326. var response: NSHTTPURLResponse?
  327. var data: NSData?
  328. var error: NSError?
  329. // When
  330. Alamofire.request(.GET, URLString)
  331. .response { responseRequest, responseResponse, responseData, responseError in
  332. request = responseRequest
  333. response = responseResponse
  334. data = responseData
  335. error = responseError
  336. expectation.fulfill()
  337. }
  338. waitForExpectationsWithTimeout(defaultTimeout, handler: nil)
  339. // Then
  340. XCTAssertNotNil(request, "request should not be nil")
  341. XCTAssertNotNil(response, "response should not be nil")
  342. XCTAssertNotNil(data, "data should not be nil")
  343. XCTAssertNil(error, "error should be nil")
  344. XCTAssertEqual(response?.URL?.URLString ?? "", URLString, "response URL should match the origin URL")
  345. XCTAssertEqual(response?.statusCode ?? -1, 302, "response should have a 302 status code")
  346. }
  347. func testThatTaskOverrideClosureIsCalledMultipleTimesForMultipleHTTPRedirects() {
  348. // Given
  349. let redirectURLString = "https://httpbin.org/get"
  350. let URLString = "https://httpbin.org/redirect/5"
  351. let expectation = expectationWithDescription("Request should redirect to \(redirectURLString)")
  352. let delegate: Alamofire.Manager.SessionDelegate = Alamofire.Manager.sharedInstance.delegate
  353. var totalRedirectCount = 0
  354. delegate.taskWillPerformHTTPRedirection = { _, _, _, request in
  355. ++totalRedirectCount
  356. return request
  357. }
  358. var request: NSURLRequest?
  359. var response: NSHTTPURLResponse?
  360. var data: NSData?
  361. var error: NSError?
  362. // When
  363. Alamofire.request(.GET, URLString)
  364. .response { responseRequest, responseResponse, responseData, responseError in
  365. request = responseRequest
  366. response = responseResponse
  367. data = responseData
  368. error = responseError
  369. expectation.fulfill()
  370. }
  371. waitForExpectationsWithTimeout(defaultTimeout, handler: nil)
  372. // Then
  373. XCTAssertNotNil(request, "request should not be nil")
  374. XCTAssertNotNil(response, "response should not be nil")
  375. XCTAssertNotNil(data, "data should not be nil")
  376. XCTAssertNil(error, "error should be nil")
  377. XCTAssertEqual(response?.URL?.URLString ?? "", redirectURLString, "response URL should match the redirect URL")
  378. XCTAssertEqual(response?.statusCode ?? -1, 200, "response should have a 200 status code")
  379. XCTAssertEqual(totalRedirectCount, 5, "total redirect count should be 5")
  380. }
  381. func testThatRedirectedRequestContainsAllHeadersFromOriginalRequest() {
  382. // Given
  383. let redirectURLString = "https://httpbin.org/get"
  384. let URLString = "https://httpbin.org/redirect-to?url=\(redirectURLString)"
  385. let headers = [
  386. "Authorization": "1234",
  387. "Custom-Header": "foobar",
  388. ]
  389. // NOTE: It appears that most headers are maintained during a redirect with the exception of the `Authorization`
  390. // header. It appears that Apple's strips the `Authorization` header from the redirected URL request. If you
  391. // need to maintain the `Authorization` header, you need to manually append it to the redirected request.
  392. let manager = Manager(configuration: NSURLSessionConfiguration.ephemeralSessionConfiguration())
  393. manager.delegate.taskWillPerformHTTPRedirection = { session, task, response, request in
  394. var redirectedRequest = request
  395. if let
  396. originalRequest = task.originalRequest,
  397. headers = originalRequest.allHTTPHeaderFields,
  398. authorizationHeaderValue = headers["Authorization"]
  399. {
  400. let mutableRequest = request.mutableCopy() as! NSMutableURLRequest
  401. mutableRequest.setValue(authorizationHeaderValue, forHTTPHeaderField: "Authorization")
  402. redirectedRequest = mutableRequest
  403. }
  404. return redirectedRequest
  405. }
  406. let expectation = expectationWithDescription("Request should redirect to \(redirectURLString)")
  407. var response: Response<AnyObject, NSError>?
  408. // When
  409. manager.request(.GET, URLString, headers: headers)
  410. .responseJSON { closureResponse in
  411. response = closureResponse
  412. expectation.fulfill()
  413. }
  414. waitForExpectationsWithTimeout(defaultTimeout, handler: nil)
  415. // Then
  416. XCTAssertNotNil(response?.request, "request should not be nil")
  417. XCTAssertNotNil(response?.response, "response should not be nil")
  418. XCTAssertNotNil(response?.data, "data should not be nil")
  419. XCTAssertTrue(response?.result.isSuccess ?? false, "response result should be a success")
  420. if let
  421. JSON = response?.result.value as? [String: AnyObject],
  422. headers = JSON["headers"] as? [String: String]
  423. {
  424. XCTAssertEqual(headers["Custom-Header"], "foobar", "Custom-Header should be equal to foobar")
  425. XCTAssertEqual(headers["Authorization"], "1234", "Authorization header should be equal to 1234")
  426. }
  427. }
  428. }