RequestTests.swift 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115
  1. //
  2. // RequestTests.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. final class RequestResponseTestCase: BaseTestCase {
  28. func testRequestResponse() {
  29. // Given
  30. let urlString = "https://httpbin.org/get"
  31. let expectation = self.expectation(description: "GET request should succeed: \(urlString)")
  32. var response: DataResponse<Data?>?
  33. // When
  34. AF.request(urlString, parameters: ["foo": "bar"])
  35. .response { resp in
  36. response = resp
  37. expectation.fulfill()
  38. }
  39. waitForExpectations(timeout: timeout, handler: nil)
  40. // Then
  41. XCTAssertNotNil(response?.request)
  42. XCTAssertNotNil(response?.response)
  43. XCTAssertNotNil(response?.data)
  44. XCTAssertNil(response?.error)
  45. }
  46. func testRequestResponseWithProgress() {
  47. // Given
  48. let randomBytes = 1 * 1024 * 1024
  49. let urlString = "https://httpbin.org/bytes/\(randomBytes)"
  50. let expectation = self.expectation(description: "Bytes download progress should be reported: \(urlString)")
  51. var progressValues: [Double] = []
  52. var response: DataResponse<Data?>?
  53. // When
  54. AF.request(urlString)
  55. .downloadProgress { progress in
  56. progressValues.append(progress.fractionCompleted)
  57. }
  58. .response { resp in
  59. response = resp
  60. expectation.fulfill()
  61. }
  62. waitForExpectations(timeout: timeout, handler: nil)
  63. // Then
  64. XCTAssertNotNil(response?.request)
  65. XCTAssertNotNil(response?.response)
  66. XCTAssertNotNil(response?.data)
  67. XCTAssertNil(response?.error)
  68. var previousProgress: Double = progressValues.first ?? 0.0
  69. for progress in progressValues {
  70. XCTAssertGreaterThanOrEqual(progress, previousProgress)
  71. previousProgress = progress
  72. }
  73. if let lastProgressValue = progressValues.last {
  74. XCTAssertEqual(lastProgressValue, 1.0)
  75. } else {
  76. XCTFail("last item in progressValues should not be nil")
  77. }
  78. }
  79. func testPOSTRequestWithUnicodeParameters() {
  80. // Given
  81. let urlString = "https://httpbin.org/post"
  82. let parameters = [
  83. "french": "français",
  84. "japanese": "日本語",
  85. "arabic": "العربية",
  86. "emoji": "😃"
  87. ]
  88. let expectation = self.expectation(description: "request should succeed")
  89. var response: DataResponse<Any>?
  90. // When
  91. AF.request(urlString, method: .post, parameters: parameters)
  92. .responseJSON { closureResponse in
  93. response = closureResponse
  94. expectation.fulfill()
  95. }
  96. waitForExpectations(timeout: timeout, handler: nil)
  97. // Then
  98. XCTAssertNotNil(response?.request)
  99. XCTAssertNotNil(response?.response)
  100. XCTAssertNotNil(response?.data)
  101. if let json = response?.result.value as? [String: Any], let form = json["form"] as? [String: String] {
  102. XCTAssertEqual(form["french"], parameters["french"])
  103. XCTAssertEqual(form["japanese"], parameters["japanese"])
  104. XCTAssertEqual(form["arabic"], parameters["arabic"])
  105. XCTAssertEqual(form["emoji"], parameters["emoji"])
  106. } else {
  107. XCTFail("form parameter in JSON should not be nil")
  108. }
  109. }
  110. func testPOSTRequestWithBase64EncodedImages() {
  111. // Given
  112. let urlString = "https://httpbin.org/post"
  113. let pngBase64EncodedString: String = {
  114. let URL = url(forResource: "unicorn", withExtension: "png")
  115. let data = try! Data(contentsOf: URL)
  116. return data.base64EncodedString(options: .lineLength64Characters)
  117. }()
  118. let jpegBase64EncodedString: String = {
  119. let URL = url(forResource: "rainbow", withExtension: "jpg")
  120. let data = try! Data(contentsOf: URL)
  121. return data.base64EncodedString(options: .lineLength64Characters)
  122. }()
  123. let parameters = [
  124. "email": "user@alamofire.org",
  125. "png_image": pngBase64EncodedString,
  126. "jpeg_image": jpegBase64EncodedString
  127. ]
  128. let expectation = self.expectation(description: "request should succeed")
  129. var response: DataResponse<Any>?
  130. // When
  131. AF.request(urlString, method: .post, parameters: parameters)
  132. .responseJSON { closureResponse in
  133. response = closureResponse
  134. expectation.fulfill()
  135. }
  136. waitForExpectations(timeout: timeout, handler: nil)
  137. // Then
  138. XCTAssertNotNil(response?.request)
  139. XCTAssertNotNil(response?.response)
  140. XCTAssertNotNil(response?.data)
  141. XCTAssertEqual(response?.result.isSuccess, true)
  142. if let json = response?.result.value as? [String: Any], let form = json["form"] as? [String: String] {
  143. XCTAssertEqual(form["email"], parameters["email"])
  144. XCTAssertEqual(form["png_image"], parameters["png_image"])
  145. XCTAssertEqual(form["jpeg_image"], parameters["jpeg_image"])
  146. } else {
  147. XCTFail("form parameter in JSON should not be nil")
  148. }
  149. }
  150. // MARK: Queues
  151. func testThatResponseSerializationWorksWithSerializationQueue() {
  152. // Given
  153. let queue = DispatchQueue(label: "org.alamofire.testSerializationQueue")
  154. let manager = Session(serializationQueue: queue)
  155. let expectation = self.expectation(description: "request should complete")
  156. var response: DataResponse<Any>?
  157. // When
  158. manager.request("https://httpbin.org/get").responseJSON { (resp) in
  159. response = resp
  160. expectation.fulfill()
  161. }
  162. waitForExpectations(timeout: timeout, handler: nil)
  163. // Then
  164. XCTAssertEqual(response?.result.isSuccess, true)
  165. }
  166. func testThatRequestsWorksWithRequestAndSerializationQueue() {
  167. // Given
  168. let requestQueue = DispatchQueue(label: "org.alamofire.testRequestQueue")
  169. let serializationQueue = DispatchQueue(label: "org.alamofire.testSerializationQueue")
  170. let manager = Session(requestQueue: requestQueue, serializationQueue: serializationQueue)
  171. let expectation = self.expectation(description: "request should complete")
  172. var response: DataResponse<Any>?
  173. // When
  174. manager.request("https://httpbin.org/get").responseJSON { (resp) in
  175. response = resp
  176. expectation.fulfill()
  177. }
  178. waitForExpectations(timeout: timeout, handler: nil)
  179. // Then
  180. XCTAssertEqual(response?.result.isSuccess, true)
  181. }
  182. // MARK: Encodable Parameters
  183. func testThatRequestsCanPassEncodableParametersAsJSONBodyData() {
  184. // Given
  185. let parameters = HTTPBinParameters(property: "one")
  186. let expect = expectation(description: "request should complete")
  187. var receivedResponse: DataResponse<HTTPBinResponse>?
  188. // When
  189. AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: JSONParameterEncoder.default)
  190. .responseDecodable { (response: DataResponse<HTTPBinResponse>) in
  191. receivedResponse = response
  192. expect.fulfill()
  193. }
  194. waitForExpectations(timeout: timeout, handler: nil)
  195. // Then
  196. XCTAssertEqual(receivedResponse?.result.value?.data, "{\"property\":\"one\"}")
  197. }
  198. func testThatRequestsCanPassEncodableParametersAsAURLQuery() {
  199. // Given
  200. let parameters = HTTPBinParameters(property: "one")
  201. let expect = expectation(description: "request should complete")
  202. var receivedResponse: DataResponse<HTTPBinResponse>?
  203. // When
  204. AF.request("https://httpbin.org/get", method: .get, parameters: parameters)
  205. .responseDecodable { (response: DataResponse<HTTPBinResponse>) in
  206. receivedResponse = response
  207. expect.fulfill()
  208. }
  209. waitForExpectations(timeout: timeout, handler: nil)
  210. // Then
  211. XCTAssertEqual(receivedResponse?.result.value?.args, ["property": "one"])
  212. }
  213. func testThatRequestsCanPassEncodableParametersAsURLEncodedBodyData() {
  214. // Given
  215. let parameters = HTTPBinParameters(property: "one")
  216. let expect = expectation(description: "request should complete")
  217. var receivedResponse: DataResponse<HTTPBinResponse>?
  218. // When
  219. AF.request("https://httpbin.org/post", method: .post, parameters: parameters)
  220. .responseDecodable { (response: DataResponse<HTTPBinResponse>) in
  221. receivedResponse = response
  222. expect.fulfill()
  223. }
  224. waitForExpectations(timeout: timeout, handler: nil)
  225. // Then
  226. XCTAssertEqual(receivedResponse?.result.value?.form, ["property": "one"])
  227. }
  228. // MARK: Lifetime Events
  229. func testThatAutomaticallyResumedRequestReceivesAppropriateLifetimeEvents() {
  230. // Given
  231. let eventMonitor = ClosureEventMonitor()
  232. let session = Session(eventMonitors: [eventMonitor])
  233. let expect = expectation(description: "request should receive appropriate lifetime events")
  234. expect.expectedFulfillmentCount = 3
  235. eventMonitor.requestDidResumeTask = { (_, _) in expect.fulfill() }
  236. eventMonitor.requestDidResume = { _ in expect.fulfill() }
  237. eventMonitor.requestDidFinish = { _ in expect.fulfill() }
  238. // Fulfill other events that would exceed the expected count. Inverted expectations require the full timeout.
  239. eventMonitor.requestDidSuspend = { _ in expect.fulfill() }
  240. eventMonitor.requestDidSuspendTask = { (_, _) in expect.fulfill() }
  241. eventMonitor.requestDidCancel = { _ in expect.fulfill() }
  242. eventMonitor.requestDidCancelTask = { (_, _) in expect.fulfill() }
  243. // When
  244. let request = session.request(URLRequest.makeHTTPBinRequest())
  245. waitForExpectations(timeout: timeout, handler: nil)
  246. // Then
  247. XCTAssertEqual(request.state, .finished)
  248. }
  249. func testThatAutomaticallyAndManuallyResumedRequestReceivesAppropriateLifetimeEvents() {
  250. // Given
  251. let eventMonitor = ClosureEventMonitor()
  252. let session = Session(eventMonitors: [eventMonitor])
  253. let expect = expectation(description: "request should receive appropriate lifetime events")
  254. expect.expectedFulfillmentCount = 3
  255. eventMonitor.requestDidResumeTask = { (_, _) in expect.fulfill() }
  256. eventMonitor.requestDidResume = { _ in expect.fulfill() }
  257. eventMonitor.requestDidFinish = { _ in expect.fulfill() }
  258. // Fulfill other events that would exceed the expected count. Inverted expectations require the full timeout.
  259. eventMonitor.requestDidSuspend = { _ in expect.fulfill() }
  260. eventMonitor.requestDidSuspendTask = { (_, _) in expect.fulfill() }
  261. eventMonitor.requestDidCancel = { _ in expect.fulfill() }
  262. eventMonitor.requestDidCancelTask = { (_, _) in expect.fulfill() }
  263. // When
  264. let request = session.request(URLRequest.makeHTTPBinRequest())
  265. for _ in 0..<100 {
  266. request.resume()
  267. }
  268. waitForExpectations(timeout: timeout, handler: nil)
  269. // Then
  270. XCTAssertEqual(request.state, .finished)
  271. }
  272. func testThatManuallyResumedRequestReceivesAppropriateLifetimeEvents() {
  273. // Given
  274. let eventMonitor = ClosureEventMonitor()
  275. let session = Session(startRequestsImmediately: false, eventMonitors: [eventMonitor])
  276. let expect = expectation(description: "request should receive appropriate lifetime events")
  277. expect.expectedFulfillmentCount = 3
  278. eventMonitor.requestDidResumeTask = { (_, _) in expect.fulfill() }
  279. eventMonitor.requestDidResume = { _ in expect.fulfill() }
  280. eventMonitor.requestDidFinish = { _ in expect.fulfill() }
  281. // Fulfill other events that would exceed the expected count. Inverted expectations require the full timeout.
  282. eventMonitor.requestDidSuspend = { _ in expect.fulfill() }
  283. eventMonitor.requestDidSuspendTask = { (_, _) in expect.fulfill() }
  284. eventMonitor.requestDidCancel = { _ in expect.fulfill() }
  285. eventMonitor.requestDidCancelTask = { (_, _) in expect.fulfill() }
  286. // When
  287. let request = session.request(URLRequest.makeHTTPBinRequest())
  288. for _ in 0..<100 {
  289. request.resume()
  290. }
  291. waitForExpectations(timeout: timeout, handler: nil)
  292. // Then
  293. XCTAssertEqual(request.state, .finished)
  294. }
  295. func testThatRequestManuallyResumedManyTimesOnlyReceivesAppropriateLifetimeEvents() {
  296. // Given
  297. let eventMonitor = ClosureEventMonitor()
  298. let session = Session(startRequestsImmediately: false, eventMonitors: [eventMonitor])
  299. let expect = expectation(description: "request should receive appropriate lifetime events")
  300. expect.expectedFulfillmentCount = 3
  301. eventMonitor.requestDidResumeTask = { (_, _) in expect.fulfill() }
  302. eventMonitor.requestDidResume = { _ in expect.fulfill() }
  303. eventMonitor.requestDidFinish = { _ in expect.fulfill() }
  304. // Fulfill other events that would exceed the expected count. Inverted expectations require the full timeout.
  305. eventMonitor.requestDidSuspend = { _ in expect.fulfill() }
  306. eventMonitor.requestDidSuspendTask = { (_, _) in expect.fulfill() }
  307. eventMonitor.requestDidCancel = { _ in expect.fulfill() }
  308. eventMonitor.requestDidCancelTask = { (_, _) in expect.fulfill() }
  309. // When
  310. let request = session.request(URLRequest.makeHTTPBinRequest())
  311. for _ in 0..<100 {
  312. request.resume()
  313. }
  314. waitForExpectations(timeout: timeout, handler: nil)
  315. // Then
  316. XCTAssertEqual(request.state, .finished)
  317. }
  318. func testThatRequestManuallySuspendedManyTimesAfterAutomaticResumeOnlyReceivesAppropriateLifetimeEvents() {
  319. // Given
  320. let eventMonitor = ClosureEventMonitor()
  321. let session = Session(startRequestsImmediately: false, eventMonitors: [eventMonitor])
  322. let expect = expectation(description: "request should receive appropriate lifetime events")
  323. expect.expectedFulfillmentCount = 2
  324. eventMonitor.requestDidSuspendTask = { (_, _) in expect.fulfill() }
  325. eventMonitor.requestDidSuspend = { _ in expect.fulfill() }
  326. // Fulfill other events that would exceed the expected count. Inverted expectations require the full timeout.
  327. eventMonitor.requestDidCancel = { _ in expect.fulfill() }
  328. eventMonitor.requestDidCancelTask = { (_, _) in expect.fulfill() }
  329. // When
  330. let request = session.request(URLRequest.makeHTTPBinRequest())
  331. for _ in 0..<100 {
  332. request.suspend()
  333. }
  334. waitForExpectations(timeout: timeout, handler: nil)
  335. // Then
  336. XCTAssertEqual(request.state, .suspended)
  337. }
  338. func testThatRequestManuallySuspendedManyTimesOnlyReceivesAppropriateLifetimeEvents() {
  339. // Given
  340. let eventMonitor = ClosureEventMonitor()
  341. let session = Session(startRequestsImmediately: false, eventMonitors: [eventMonitor])
  342. let expect = expectation(description: "request should receive appropriate lifetime events")
  343. expect.expectedFulfillmentCount = 2
  344. eventMonitor.requestDidSuspendTask = { (_, _) in expect.fulfill() }
  345. eventMonitor.requestDidSuspend = { _ in expect.fulfill() }
  346. // Fulfill other events that would exceed the expected count. Inverted expectations require the full timeout.
  347. eventMonitor.requestDidResume = { _ in expect.fulfill() }
  348. eventMonitor.requestDidResumeTask = { (_, _) in expect.fulfill() }
  349. eventMonitor.requestDidCancel = { _ in expect.fulfill() }
  350. eventMonitor.requestDidCancelTask = { (_, _) in expect.fulfill() }
  351. // When
  352. let request = session.request(URLRequest.makeHTTPBinRequest())
  353. for _ in 0..<100 {
  354. request.suspend()
  355. }
  356. waitForExpectations(timeout: timeout, handler: nil)
  357. // Then
  358. XCTAssertEqual(request.state, .suspended)
  359. }
  360. func testThatRequestManuallyCancelledManyTimesAfterAutomaticResumeOnlyReceivesAppropriateLifetimeEvents() {
  361. // Given
  362. let eventMonitor = ClosureEventMonitor()
  363. let session = Session(eventMonitors: [eventMonitor])
  364. let expect = expectation(description: "request should receive appropriate lifetime events")
  365. expect.expectedFulfillmentCount = 2
  366. eventMonitor.requestDidCancelTask = { (_, _) in expect.fulfill() }
  367. eventMonitor.requestDidCancel = { _ in expect.fulfill() }
  368. // Fulfill other events that would exceed the expected count. Inverted expectations require the full timeout.
  369. eventMonitor.requestDidSuspend = { _ in expect.fulfill() }
  370. eventMonitor.requestDidSuspendTask = { (_, _) in expect.fulfill() }
  371. // When
  372. let request = session.request(URLRequest.makeHTTPBinRequest())
  373. // Cancellation stops task creation, so don't cancel the request until the task has been created.
  374. eventMonitor.requestDidCreateTask = { (_, _) in
  375. for _ in 0..<100 {
  376. request.cancel()
  377. }
  378. }
  379. waitForExpectations(timeout: timeout, handler: nil)
  380. // Then
  381. XCTAssertEqual(request.state, .cancelled)
  382. }
  383. func testThatRequestManuallyCancelledManyTimesOnlyReceivesAppropriateLifetimeEvents() {
  384. // Given
  385. let eventMonitor = ClosureEventMonitor()
  386. let session = Session(startRequestsImmediately: false, eventMonitors: [eventMonitor])
  387. let expect = expectation(description: "request should receive appropriate lifetime events")
  388. expect.expectedFulfillmentCount = 2
  389. eventMonitor.requestDidCancelTask = { (_, _) in expect.fulfill() }
  390. eventMonitor.requestDidCancel = { _ in expect.fulfill() }
  391. // Fulfill other events that would exceed the expected count. Inverted expectations require the full timeout.
  392. eventMonitor.requestDidResume = { _ in expect.fulfill() }
  393. eventMonitor.requestDidResumeTask = { (_, _) in expect.fulfill() }
  394. eventMonitor.requestDidSuspend = { _ in expect.fulfill() }
  395. eventMonitor.requestDidSuspendTask = { (_, _) in expect.fulfill() }
  396. // When
  397. let request = session.request(URLRequest.makeHTTPBinRequest())
  398. // Cancellation stops task creation, so don't cancel the request until the task has been created.
  399. eventMonitor.requestDidCreateTask = { (_, _) in
  400. for _ in 0..<100 {
  401. request.cancel()
  402. }
  403. }
  404. waitForExpectations(timeout: timeout, handler: nil)
  405. // Then
  406. XCTAssertEqual(request.state, .cancelled)
  407. }
  408. func testThatRequestManuallyCancelledManyTimesOnManyQueuesOnlyReceivesAppropriateLifetimeEvents() {
  409. // Given
  410. let eventMonitor = ClosureEventMonitor()
  411. let session = Session(eventMonitors: [eventMonitor])
  412. let expect = expectation(description: "request should receive appropriate lifetime events")
  413. expect.expectedFulfillmentCount = 5
  414. eventMonitor.requestDidCancelTask = { (_, _) in expect.fulfill() }
  415. eventMonitor.requestDidCancel = { _ in expect.fulfill() }
  416. eventMonitor.requestDidResume = { _ in expect.fulfill() }
  417. eventMonitor.requestDidResumeTask = { (_, _) in expect.fulfill() }
  418. // Fulfill other events that would exceed the expected count. Inverted expectations require the full timeout.
  419. eventMonitor.requestDidSuspend = { _ in expect.fulfill() }
  420. eventMonitor.requestDidSuspendTask = { (_, _) in expect.fulfill() }
  421. // When
  422. let request = session.request(URLRequest.makeHTTPBinRequest())
  423. // Cancellation stops task creation, so don't cancel the request until the task has been created.
  424. eventMonitor.requestDidCreateTask = { (_, _) in
  425. DispatchQueue.concurrentPerform(iterations: 100) { i in
  426. request.cancel()
  427. if i == 99 { expect.fulfill() }
  428. }
  429. }
  430. waitForExpectations(timeout: timeout, handler: nil)
  431. // Then
  432. XCTAssertEqual(request.state, .cancelled)
  433. }
  434. func testThatRequestTriggersAllAppropriateLifetimeEvents() {
  435. // Given
  436. let eventMonitor = ClosureEventMonitor()
  437. let session = Session(eventMonitors: [eventMonitor])
  438. let didReceiveChallenge = expectation(description: "didReceiveChallenge should fire")
  439. let taskDidFinishCollecting = expectation(description: "taskDidFinishCollecting should fire")
  440. let didReceiveData = expectation(description: "didReceiveData should fire")
  441. let willCacheResponse = expectation(description: "willCacheResponse should fire")
  442. let didCreateURLRequest = expectation(description: "didCreateInitialURLRequest should fire")
  443. let didCreateTask = expectation(description: "didCreateTask should fire")
  444. let didGatherMetrics = expectation(description: "didGatherMetrics should fire")
  445. let didComplete = expectation(description: "didComplete should fire")
  446. let didFinish = expectation(description: "didFinish should fire")
  447. let didResume = expectation(description: "didResume should fire")
  448. let didResumeTask = expectation(description: "didResumeTask should fire")
  449. let didParseResponse = expectation(description: "didParseResponse should fire")
  450. let responseHandler = expectation(description: "responseHandler should fire")
  451. var dataReceived = false
  452. eventMonitor.taskDidReceiveChallenge = { (_, _, _) in didReceiveChallenge.fulfill() }
  453. eventMonitor.taskDidFinishCollectingMetrics = { (_, _, _) in taskDidFinishCollecting.fulfill() }
  454. eventMonitor.dataTaskDidReceiveData = { (_, _, _) in
  455. guard !dataReceived else { return }
  456. // Data may be received many times, fulfill only once.
  457. dataReceived = true
  458. didReceiveData.fulfill()
  459. }
  460. eventMonitor.dataTaskWillCacheResponse = { (_, _, _) in willCacheResponse.fulfill() }
  461. eventMonitor.requestDidCreateInitialURLRequest = { (_, _) in didCreateURLRequest.fulfill() }
  462. eventMonitor.requestDidCreateTask = { (_, _) in didCreateTask.fulfill() }
  463. eventMonitor.requestDidGatherMetrics = { (_, _) in didGatherMetrics.fulfill() }
  464. eventMonitor.requestDidCompleteTaskWithError = { (_, _, _) in didComplete.fulfill() }
  465. eventMonitor.requestDidFinish = { (_) in didFinish.fulfill() }
  466. eventMonitor.requestDidResume = { (_) in didResume.fulfill() }
  467. eventMonitor.requestDidResumeTask = { (_, _) in didResumeTask.fulfill() }
  468. eventMonitor.requestDidParseResponse = { (_, _) in didParseResponse.fulfill() }
  469. // When
  470. let request = session.request(URLRequest.makeHTTPBinRequest()).response { _ in
  471. responseHandler.fulfill()
  472. }
  473. waitForExpectations(timeout: timeout, handler: nil)
  474. // Then
  475. XCTAssertEqual(request.state, .finished)
  476. }
  477. func testThatCancelledRequestTriggersAllAppropriateLifetimeEvents() {
  478. // Given
  479. let eventMonitor = ClosureEventMonitor()
  480. let session = Session(startRequestsImmediately: false, eventMonitors: [eventMonitor])
  481. let taskDidFinishCollecting = expectation(description: "taskDidFinishCollecting should fire")
  482. let didCreateURLRequest = expectation(description: "didCreateInitialURLRequest should fire")
  483. let didCreateTask = expectation(description: "didCreateTask should fire")
  484. let didGatherMetrics = expectation(description: "didGatherMetrics should fire")
  485. let didComplete = expectation(description: "didComplete should fire")
  486. let didFinish = expectation(description: "didFinish should fire")
  487. let didResume = expectation(description: "didResume should fire")
  488. let didResumeTask = expectation(description: "didResumeTask should fire")
  489. let didParseResponse = expectation(description: "didParseResponse should fire")
  490. let didCancel = expectation(description: "didCancel should fire")
  491. let didCancelTask = expectation(description: "didCancelTask should fire")
  492. let responseHandler = expectation(description: "responseHandler should fire")
  493. eventMonitor.taskDidFinishCollectingMetrics = { (_, _, _) in taskDidFinishCollecting.fulfill() }
  494. eventMonitor.requestDidCreateInitialURLRequest = { (_, _) in didCreateURLRequest.fulfill() }
  495. eventMonitor.requestDidCreateTask = { (_, _) in didCreateTask.fulfill() }
  496. eventMonitor.requestDidGatherMetrics = { (_, _) in didGatherMetrics.fulfill() }
  497. eventMonitor.requestDidCompleteTaskWithError = { (_, _, _) in didComplete.fulfill() }
  498. eventMonitor.requestDidFinish = { (_) in didFinish.fulfill() }
  499. eventMonitor.requestDidResume = { (_) in didResume.fulfill() }
  500. eventMonitor.requestDidParseResponse = { (_, _) in didParseResponse.fulfill() }
  501. eventMonitor.requestDidCancel = { (_) in didCancel.fulfill() }
  502. eventMonitor.requestDidCancelTask = { (_, _) in didCancelTask.fulfill() }
  503. // When
  504. let request = session.request(URLRequest.makeHTTPBinRequest()).response { _ in
  505. responseHandler.fulfill()
  506. }
  507. eventMonitor.requestDidResumeTask = { (_, _) in
  508. request.cancel()
  509. didResumeTask.fulfill()
  510. }
  511. request.resume()
  512. waitForExpectations(timeout: timeout, handler: nil)
  513. // Then
  514. XCTAssertEqual(request.state, .cancelled)
  515. }
  516. func testThatAppendingResponseSerializerToCancelledRequestCallsCompletion() {
  517. // Given
  518. let session = Session()
  519. var response1: DataResponse<Any>?
  520. var response2: DataResponse<Any>?
  521. let expect = expectation(description: "both response serializer completions should be called")
  522. expect.expectedFulfillmentCount = 2
  523. // When
  524. let request = session.request(URLRequest.makeHTTPBinRequest())
  525. request.responseJSON { resp in
  526. response1 = resp
  527. expect.fulfill()
  528. request.responseJSON { resp in
  529. response2 = resp
  530. expect.fulfill()
  531. }
  532. }
  533. request.cancel()
  534. waitForExpectations(timeout: timeout, handler: nil)
  535. // Then
  536. XCTAssertEqual(response1?.error?.asAFError?.isExplicitlyCancelledError, true)
  537. XCTAssertEqual(response2?.error?.asAFError?.isExplicitlyCancelledError, true)
  538. }
  539. func testThatAppendingResponseSerializerToCompletedRequestInsideCompletionResumesRequest() {
  540. // Given
  541. let session = Session()
  542. var response1: DataResponse<Any>?
  543. var response2: DataResponse<Any>?
  544. var response3: DataResponse<Any>?
  545. let expect = expectation(description: "both response serializer completions should be called")
  546. expect.expectedFulfillmentCount = 3
  547. // When
  548. let request = session.request(URLRequest.makeHTTPBinRequest())
  549. request.responseJSON { resp in
  550. response1 = resp
  551. expect.fulfill()
  552. request.responseJSON { resp in
  553. response2 = resp
  554. expect.fulfill()
  555. request.responseJSON { resp in
  556. response3 = resp
  557. expect.fulfill()
  558. }
  559. }
  560. }
  561. waitForExpectations(timeout: timeout, handler: nil)
  562. // Then
  563. XCTAssertNotNil(response1?.value)
  564. XCTAssertNotNil(response2?.value)
  565. XCTAssertNotNil(response3?.value)
  566. }
  567. func testThatAppendingResponseSerializerToCompletedRequestOutsideCompletionResumesRequest() {
  568. // Given
  569. let session = Session()
  570. let request = session.request(URLRequest.makeHTTPBinRequest())
  571. var response1: DataResponse<Any>?
  572. var response2: DataResponse<Any>?
  573. var response3: DataResponse<Any>?
  574. // When
  575. let expect1 = expectation(description: "response serializer 1 completion should be called")
  576. request.responseJSON { response1 = $0; expect1.fulfill() }
  577. waitForExpectations(timeout: timeout, handler: nil)
  578. let expect2 = expectation(description: "response serializer 2 completion should be called")
  579. request.responseJSON { response2 = $0; expect2.fulfill() }
  580. waitForExpectations(timeout: timeout, handler: nil)
  581. let expect3 = expectation(description: "response serializer 3 completion should be called")
  582. request.responseJSON { response3 = $0; expect3.fulfill() }
  583. waitForExpectations(timeout: timeout, handler: nil)
  584. // Then
  585. XCTAssertNotNil(response1?.value)
  586. XCTAssertNotNil(response2?.value)
  587. XCTAssertNotNil(response3?.value)
  588. }
  589. }
  590. // MARK: -
  591. class RequestDescriptionTestCase: BaseTestCase {
  592. func testRequestDescription() {
  593. // Given
  594. let urlString = "https://httpbin.org/get"
  595. let manager = Session(startRequestsImmediately: false)
  596. let request = manager.request(urlString)
  597. let expectation = self.expectation(description: "Request description should update: \(urlString)")
  598. var response: HTTPURLResponse?
  599. // When
  600. request.response { resp in
  601. response = resp.response
  602. expectation.fulfill()
  603. }.resume()
  604. waitForExpectations(timeout: timeout, handler: nil)
  605. // Then
  606. XCTAssertEqual(request.description, "GET https://httpbin.org/get (\(response?.statusCode ?? -1))")
  607. }
  608. }
  609. // MARK: -
  610. final class RequestCURLDescriptionTestCase: BaseTestCase {
  611. // MARK: Properties
  612. let manager: Session = {
  613. let manager = Session()
  614. return manager
  615. }()
  616. let managerWithAcceptLanguageHeader: Session = {
  617. var headers = HTTPHeaders.default
  618. headers["Accept-Language"] = "en-US"
  619. let configuration = URLSessionConfiguration.af.default
  620. configuration.headers = headers
  621. let manager = Session(configuration: configuration)
  622. return manager
  623. }()
  624. let managerWithContentTypeHeader: Session = {
  625. var headers = HTTPHeaders.default
  626. headers["Content-Type"] = "application/json"
  627. let configuration = URLSessionConfiguration.af.default
  628. configuration.headers = headers
  629. let manager = Session(configuration: configuration)
  630. return manager
  631. }()
  632. func managerWithCookie(_ cookie: HTTPCookie) -> Session {
  633. let configuration = URLSessionConfiguration.af.default
  634. configuration.httpCookieStorage?.setCookie(cookie)
  635. return Session(configuration: configuration)
  636. }
  637. let managerDisallowingCookies: Session = {
  638. let configuration = URLSessionConfiguration.af.default
  639. configuration.httpShouldSetCookies = false
  640. let manager = Session(configuration: configuration)
  641. return manager
  642. }()
  643. // MARK: Tests
  644. func testGETRequestCURLDescription() {
  645. // Given
  646. let urlString = "https://httpbin.org/get"
  647. let expectation = self.expectation(description: "request should complete")
  648. var components: [String]?
  649. // When
  650. manager.request(urlString).cURLDescription {
  651. components = self.cURLCommandComponents(from: $0)
  652. expectation.fulfill()
  653. }
  654. waitForExpectations(timeout: timeout, handler: nil)
  655. // Then
  656. XCTAssertEqual(components?[0..<3], ["$", "curl", "-v"])
  657. XCTAssertTrue(components?.contains("-X") == true)
  658. XCTAssertEqual(components?.last, "\"\(urlString)\"")
  659. }
  660. func testGETRequestCURLDescriptionSynchronous() {
  661. // Given
  662. let urlString = "https://httpbin.org/get"
  663. let expectation = self.expectation(description: "request should complete")
  664. var components: [String]?
  665. var syncComponents: [String]?
  666. // When
  667. let request = manager.request(urlString)
  668. request.cURLDescription {
  669. components = self.cURLCommandComponents(from: $0)
  670. syncComponents = self.cURLCommandComponents(from: request.cURLDescription())
  671. expectation.fulfill()
  672. }
  673. waitForExpectations(timeout: timeout, handler: nil)
  674. // Then
  675. XCTAssertEqual(components?[0..<3], ["$", "curl", "-v"])
  676. XCTAssertTrue(components?.contains("-X") == true)
  677. XCTAssertEqual(components?.last, "\"\(urlString)\"")
  678. XCTAssertEqual(components, syncComponents)
  679. }
  680. func testGETRequestCURLDescriptionCanBeRequestedManyTimes() {
  681. // Given
  682. let urlString = "https://httpbin.org/get"
  683. let expectation = self.expectation(description: "request should complete")
  684. var components: [String]?
  685. var secondComponents: [String]?
  686. // When
  687. let request = manager.request(urlString)
  688. request.cURLDescription {
  689. components = self.cURLCommandComponents(from: $0)
  690. request.cURLDescription {
  691. secondComponents = self.cURLCommandComponents(from: $0)
  692. expectation.fulfill()
  693. }
  694. }
  695. // Trigger the overwrite behavior.
  696. request.cURLDescription {
  697. components = self.cURLCommandComponents(from: $0)
  698. request.cURLDescription {
  699. secondComponents = self.cURLCommandComponents(from: $0)
  700. expectation.fulfill()
  701. }
  702. }
  703. waitForExpectations(timeout: timeout, handler: nil)
  704. // Then
  705. XCTAssertEqual(components?[0..<3], ["$", "curl", "-v"])
  706. XCTAssertTrue(components?.contains("-X") == true)
  707. XCTAssertEqual(components?.last, "\"\(urlString)\"")
  708. XCTAssertEqual(components, secondComponents)
  709. }
  710. func testGETRequestWithCustomHeaderCURLDescription() {
  711. // Given
  712. let urlString = "https://httpbin.org/get"
  713. let expectation = self.expectation(description: "request should complete")
  714. var cURLDescription: String?
  715. // When
  716. let headers: HTTPHeaders = ["X-Custom-Header": "{\"key\": \"value\"}"]
  717. manager.request(urlString, headers: headers).cURLDescription {
  718. cURLDescription = $0
  719. expectation.fulfill()
  720. }
  721. waitForExpectations(timeout: timeout, handler: nil)
  722. // Then
  723. XCTAssertNotNil(cURLDescription?.range(of: "-H \"X-Custom-Header: {\\\"key\\\": \\\"value\\\"}\""))
  724. }
  725. func testGETRequestWithDuplicateHeadersDebugDescription() {
  726. // Given
  727. let urlString = "https://httpbin.org/get"
  728. let expectation = self.expectation(description: "request should complete")
  729. var cURLDescription: String?
  730. var components: [String]?
  731. // When
  732. let headers: HTTPHeaders = ["Accept-Language": "en-GB"]
  733. managerWithAcceptLanguageHeader.request(urlString, headers: headers).cURLDescription {
  734. components = self.cURLCommandComponents(from: $0)
  735. cURLDescription = $0
  736. expectation.fulfill()
  737. }
  738. waitForExpectations(timeout: timeout, handler: nil)
  739. // Then
  740. XCTAssertEqual(components?[0..<3], ["$", "curl", "-v"])
  741. XCTAssertTrue(components?.contains("-X") == true)
  742. XCTAssertEqual(components?.last, "\"\(urlString)\"")
  743. let acceptLanguageCount = components?.filter { $0.contains("Accept-Language") }.count
  744. XCTAssertEqual(acceptLanguageCount, 1, "command should contain a single Accept-Language header")
  745. XCTAssertNotNil(cURLDescription?.range(of: "-H \"Accept-Language: en-GB\""))
  746. }
  747. func testPOSTRequestCURLDescription() {
  748. // Given
  749. let urlString = "https://httpbin.org/post"
  750. let expectation = self.expectation(description: "request should complete")
  751. var components: [String]?
  752. // When
  753. manager.request(urlString, method: .post).cURLDescription {
  754. components = self.cURLCommandComponents(from: $0)
  755. expectation.fulfill()
  756. }
  757. waitForExpectations(timeout: timeout, handler: nil)
  758. // Then
  759. XCTAssertEqual(components?[0..<3], ["$", "curl", "-v"])
  760. XCTAssertEqual(components?[3..<5], ["-X", "POST"])
  761. XCTAssertEqual(components?.last, "\"\(urlString)\"")
  762. }
  763. func testPOSTRequestWithJSONParametersCURLDescription() {
  764. // Given
  765. let urlString = "https://httpbin.org/post"
  766. let expectation = self.expectation(description: "request should complete")
  767. var cURLDescription: String?
  768. var components: [String]?
  769. let parameters = [
  770. "foo": "bar",
  771. "fo\"o": "b\"ar",
  772. "f'oo": "ba'r"
  773. ]
  774. // When
  775. manager.request(urlString, method: .post, parameters: parameters, encoding: JSONEncoding.default).cURLDescription {
  776. components = self.cURLCommandComponents(from: $0)
  777. cURLDescription = $0
  778. expectation.fulfill()
  779. }
  780. waitForExpectations(timeout: timeout, handler: nil)
  781. // Then
  782. XCTAssertEqual(components?[0..<3], ["$", "curl", "-v"])
  783. XCTAssertEqual(components?[3..<5], ["-X", "POST"])
  784. XCTAssertNotNil(cURLDescription?.range(of: "-H \"Content-Type: application/json\""))
  785. XCTAssertNotNil(cURLDescription?.range(of: "-d \"{"))
  786. XCTAssertNotNil(cURLDescription?.range(of: "\\\"f'oo\\\":\\\"ba'r\\\""))
  787. XCTAssertNotNil(cURLDescription?.range(of: "\\\"fo\\\\\\\"o\\\":\\\"b\\\\\\\"ar\\\""))
  788. XCTAssertNotNil(cURLDescription?.range(of: "\\\"foo\\\":\\\"bar\\"))
  789. XCTAssertEqual(components?.last, "\"\(urlString)\"")
  790. }
  791. func testPOSTRequestWithCookieCURLDescription() {
  792. // Given
  793. let urlString = "https://httpbin.org/post"
  794. let properties = [
  795. HTTPCookiePropertyKey.domain: "httpbin.org",
  796. HTTPCookiePropertyKey.path: "/post",
  797. HTTPCookiePropertyKey.name: "foo",
  798. HTTPCookiePropertyKey.value: "bar",
  799. ]
  800. let cookie = HTTPCookie(properties: properties)!
  801. let cookieManager = managerWithCookie(cookie)
  802. let expectation = self.expectation(description: "request should complete")
  803. var components: [String]?
  804. // When
  805. cookieManager.request(urlString, method: .post).cURLDescription {
  806. components = self.cURLCommandComponents(from: $0)
  807. expectation.fulfill()
  808. }
  809. waitForExpectations(timeout: timeout, handler: nil)
  810. // Then
  811. XCTAssertEqual(components?[0..<3], ["$", "curl", "-v"])
  812. XCTAssertEqual(components?[3..<5], ["-X", "POST"])
  813. XCTAssertEqual(components?.last, "\"\(urlString)\"")
  814. XCTAssertEqual(components?[5..<6], ["-b"])
  815. }
  816. func testPOSTRequestWithCookiesDisabledCURLDescriptionHasNoCookies() {
  817. // Given
  818. let urlString = "https://httpbin.org/post"
  819. let properties = [
  820. HTTPCookiePropertyKey.domain: "httpbin.org",
  821. HTTPCookiePropertyKey.path: "/post",
  822. HTTPCookiePropertyKey.name: "foo",
  823. HTTPCookiePropertyKey.value: "bar",
  824. ]
  825. let cookie = HTTPCookie(properties: properties)!
  826. managerDisallowingCookies.session.configuration.httpCookieStorage?.setCookie(cookie)
  827. let expectation = self.expectation(description: "request should complete")
  828. var components: [String]?
  829. // When
  830. managerDisallowingCookies.request(urlString, method: .post).cURLDescription {
  831. components = self.cURLCommandComponents(from: $0)
  832. expectation.fulfill()
  833. }
  834. waitForExpectations(timeout: timeout, handler: nil)
  835. // Then
  836. let cookieComponents = components?.filter { $0 == "-b" }
  837. XCTAssertTrue(cookieComponents?.isEmpty == true)
  838. }
  839. func testMultipartFormDataRequestWithDuplicateHeadersCURLDescriptionHasOneContentTypeHeader() {
  840. // Given
  841. let urlString = "https://httpbin.org/post"
  842. let japaneseData = Data("日本語".utf8)
  843. let expectation = self.expectation(description: "multipart form data encoding should succeed")
  844. var cURLDescription: String?
  845. var components: [String]?
  846. // When
  847. managerWithContentTypeHeader.upload(multipartFormData: { (data) in
  848. data.append(japaneseData, withName: "japanese")
  849. }, to: urlString).cURLDescription {
  850. components = self.cURLCommandComponents(from: $0)
  851. cURLDescription = $0
  852. expectation.fulfill()
  853. }
  854. waitForExpectations(timeout: timeout, handler: nil)
  855. // Then
  856. XCTAssertEqual(components?[0..<3], ["$", "curl", "-v"])
  857. XCTAssertTrue(components?.contains("-X") == true)
  858. XCTAssertEqual(components?.last, "\"\(urlString)\"")
  859. let contentTypeCount = components?.filter { $0.contains("Content-Type") }.count
  860. XCTAssertEqual(contentTypeCount, 1, "command should contain a single Content-Type header")
  861. XCTAssertNotNil(cURLDescription?.range(of: "-H \"Content-Type: multipart/form-data;"))
  862. }
  863. func testThatRequestWithInvalidURLDebugDescription() {
  864. // Given
  865. let urlString = "invalid_url"
  866. let expectation = self.expectation(description: "request should complete")
  867. var cURLDescription: String?
  868. // When
  869. manager.request(urlString).cURLDescription {
  870. cURLDescription = $0
  871. expectation.fulfill()
  872. }
  873. waitForExpectations(timeout: timeout, handler: nil)
  874. // Then
  875. XCTAssertNotNil(cURLDescription, "debugDescription should not crash")
  876. }
  877. // MARK: Test Helper Methods
  878. private func cURLCommandComponents(from cURLString: String) -> [String] {
  879. return cURLString.components(separatedBy: .whitespacesAndNewlines)
  880. .filter { $0 != "" && $0 != "\\" }
  881. }
  882. }