RequestTests.swift 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900
  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. // MARK: -
  28. class RequestResponseTestCase: BaseTestCase {
  29. func testRequestResponse() {
  30. // Given
  31. let urlString = "https://httpbin.org/get"
  32. let expectation = self.expectation(description: "GET request should succeed: \(urlString)")
  33. var response: DataResponse<Data?>?
  34. // When
  35. AF.request(urlString, parameters: ["foo": "bar"])
  36. .response { resp in
  37. response = resp
  38. expectation.fulfill()
  39. }
  40. waitForExpectations(timeout: timeout, handler: nil)
  41. // Then
  42. XCTAssertNotNil(response?.request)
  43. XCTAssertNotNil(response?.response)
  44. XCTAssertNotNil(response?.data)
  45. XCTAssertNil(response?.error)
  46. }
  47. func testRequestResponseWithProgress() {
  48. // Given
  49. let randomBytes = 1 * 1024 * 1024
  50. let urlString = "https://httpbin.org/bytes/\(randomBytes)"
  51. let expectation = self.expectation(description: "Bytes download progress should be reported: \(urlString)")
  52. var progressValues: [Double] = []
  53. var response: DataResponse<Data?>?
  54. // When
  55. AF.request(urlString)
  56. .downloadProgress { progress in
  57. progressValues.append(progress.fractionCompleted)
  58. }
  59. .response { resp in
  60. response = resp
  61. expectation.fulfill()
  62. }
  63. waitForExpectations(timeout: timeout, handler: nil)
  64. // Then
  65. XCTAssertNotNil(response?.request)
  66. XCTAssertNotNil(response?.response)
  67. XCTAssertNotNil(response?.data)
  68. XCTAssertNil(response?.error)
  69. var previousProgress: Double = progressValues.first ?? 0.0
  70. for progress in progressValues {
  71. XCTAssertGreaterThanOrEqual(progress, previousProgress)
  72. previousProgress = progress
  73. }
  74. if let lastProgressValue = progressValues.last {
  75. XCTAssertEqual(lastProgressValue, 1.0)
  76. } else {
  77. XCTFail("last item in progressValues should not be nil")
  78. }
  79. }
  80. func testPOSTRequestWithUnicodeParameters() {
  81. // Given
  82. let urlString = "https://httpbin.org/post"
  83. let parameters = [
  84. "french": "français",
  85. "japanese": "日本語",
  86. "arabic": "العربية",
  87. "emoji": "😃"
  88. ]
  89. let expectation = self.expectation(description: "request should succeed")
  90. var response: DataResponse<Any>?
  91. // When
  92. AF.request(urlString, method: .post, parameters: parameters)
  93. .responseJSON { closureResponse in
  94. response = closureResponse
  95. expectation.fulfill()
  96. }
  97. waitForExpectations(timeout: timeout, handler: nil)
  98. // Then
  99. XCTAssertNotNil(response?.request)
  100. XCTAssertNotNil(response?.response)
  101. XCTAssertNotNil(response?.data)
  102. if let json = response?.result.value as? [String: Any], let form = json["form"] as? [String: String] {
  103. XCTAssertEqual(form["french"], parameters["french"])
  104. XCTAssertEqual(form["japanese"], parameters["japanese"])
  105. XCTAssertEqual(form["arabic"], parameters["arabic"])
  106. XCTAssertEqual(form["emoji"], parameters["emoji"])
  107. } else {
  108. XCTFail("form parameter in JSON should not be nil")
  109. }
  110. }
  111. func testPOSTRequestWithBase64EncodedImages() {
  112. // Given
  113. let urlString = "https://httpbin.org/post"
  114. let pngBase64EncodedString: String = {
  115. let URL = url(forResource: "unicorn", withExtension: "png")
  116. let data = try! Data(contentsOf: URL)
  117. return data.base64EncodedString(options: .lineLength64Characters)
  118. }()
  119. let jpegBase64EncodedString: String = {
  120. let URL = url(forResource: "rainbow", withExtension: "jpg")
  121. let data = try! Data(contentsOf: URL)
  122. return data.base64EncodedString(options: .lineLength64Characters)
  123. }()
  124. let parameters = [
  125. "email": "user@alamofire.org",
  126. "png_image": pngBase64EncodedString,
  127. "jpeg_image": jpegBase64EncodedString
  128. ]
  129. let expectation = self.expectation(description: "request should succeed")
  130. var response: DataResponse<Any>?
  131. // When
  132. AF.request(urlString, method: .post, parameters: parameters)
  133. .responseJSON { closureResponse in
  134. response = closureResponse
  135. expectation.fulfill()
  136. }
  137. waitForExpectations(timeout: timeout, handler: nil)
  138. // Then
  139. XCTAssertNotNil(response?.request)
  140. XCTAssertNotNil(response?.response)
  141. XCTAssertNotNil(response?.data)
  142. XCTAssertEqual(response?.result.isSuccess, true)
  143. if let json = response?.result.value as? [String: Any], let form = json["form"] as? [String: String] {
  144. XCTAssertEqual(form["email"], parameters["email"])
  145. XCTAssertEqual(form["png_image"], parameters["png_image"])
  146. XCTAssertEqual(form["jpeg_image"], parameters["jpeg_image"])
  147. } else {
  148. XCTFail("form parameter in JSON should not be nil")
  149. }
  150. }
  151. // MARK: Serialization Queue
  152. func testThatResponseSerializationWorksWithSerializationQueue() {
  153. // Given
  154. let queue = DispatchQueue(label: "org.alamofire.serializationQueue")
  155. let manager = Session(serializationQueue: queue)
  156. let expectation = self.expectation(description: "request should complete")
  157. var response: DataResponse<Any>?
  158. // When
  159. manager.request("https://httpbin.org/get").responseJSON { (resp) in
  160. response = resp
  161. expectation.fulfill()
  162. }
  163. waitForExpectations(timeout: timeout, handler: nil)
  164. // Then
  165. XCTAssertEqual(response?.result.isSuccess, true)
  166. }
  167. // MARK: Encodable Parameters
  168. func testThatRequestsCanPassEncodableParametersAsJSONBodyData() {
  169. // Given
  170. let parameters = HTTPBinParameters(property: "one")
  171. let expect = expectation(description: "request should complete")
  172. var receivedResponse: DataResponse<HTTPBinResponse>?
  173. // When
  174. AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: JSONParameterEncoder.default)
  175. .responseDecodable { (response: DataResponse<HTTPBinResponse>) in
  176. receivedResponse = response
  177. expect.fulfill()
  178. }
  179. waitForExpectations(timeout: timeout, handler: nil)
  180. // Then
  181. XCTAssertEqual(receivedResponse?.result.value?.data, "{\"property\":\"one\"}")
  182. }
  183. func testThatRequestsCanPassEncodableParametersAsAURLQuery() {
  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/get", method: .get, parameters: parameters)
  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?.args, ["property": "one"])
  197. }
  198. func testThatRequestsCanPassEncodableParametersAsURLEncodedBodyData() {
  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/post", method: .post, 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?.form, ["property": "one"])
  212. }
  213. // MARK: - Lifetime Events
  214. func testThatAutomaticallyResumedRequestReceivesAppropriateLifetimeEvents() {
  215. // Given
  216. let eventMonitor = ClosureEventMonitor()
  217. let session = Session(eventMonitors: [eventMonitor])
  218. let expect = expectation(description: "request should receive appropriate lifetime events")
  219. expect.expectedFulfillmentCount = 3
  220. eventMonitor.requestDidResumeTask = { (_, _) in expect.fulfill() }
  221. eventMonitor.requestDidResume = { _ in expect.fulfill() }
  222. eventMonitor.requestDidFinish = { _ in expect.fulfill() }
  223. // Fulfill other events that would exceed the expected count. Inverted expectations require the full timeout.
  224. eventMonitor.requestDidSuspend = { _ in expect.fulfill() }
  225. eventMonitor.requestDidSuspendTask = { (_, _) in expect.fulfill() }
  226. eventMonitor.requestDidCancel = { _ in expect.fulfill() }
  227. eventMonitor.requestDidCancelTask = { (_, _) in expect.fulfill() }
  228. // When
  229. let request = session.request(URLRequest.makeHTTPBinRequest())
  230. waitForExpectations(timeout: timeout, handler: nil)
  231. // Then
  232. XCTAssertEqual(request.state, .resumed)
  233. }
  234. func testThatAutomaticallyAndManuallyResumedRequestReceivesAppropriateLifetimeEvents() {
  235. // Given
  236. let eventMonitor = ClosureEventMonitor()
  237. let session = Session(eventMonitors: [eventMonitor])
  238. let expect = expectation(description: "request should receive appropriate lifetime events")
  239. expect.expectedFulfillmentCount = 3
  240. eventMonitor.requestDidResumeTask = { (_, _) in expect.fulfill() }
  241. eventMonitor.requestDidResume = { _ in expect.fulfill() }
  242. eventMonitor.requestDidFinish = { _ in expect.fulfill() }
  243. // Fulfill other events that would exceed the expected count. Inverted expectations require the full timeout.
  244. eventMonitor.requestDidSuspend = { _ in expect.fulfill() }
  245. eventMonitor.requestDidSuspendTask = { (_, _) in expect.fulfill() }
  246. eventMonitor.requestDidCancel = { _ in expect.fulfill() }
  247. eventMonitor.requestDidCancelTask = { (_, _) in expect.fulfill() }
  248. // When
  249. let request = session.request(URLRequest.makeHTTPBinRequest())
  250. for _ in 0..<100 {
  251. request.resume()
  252. }
  253. waitForExpectations(timeout: timeout, handler: nil)
  254. // Then
  255. XCTAssertEqual(request.state, .resumed)
  256. }
  257. func testThatManuallyResumedRequestReceivesAppropriateLifetimeEvents() {
  258. // Given
  259. let eventMonitor = ClosureEventMonitor()
  260. let session = Session(startRequestsImmediately: false, eventMonitors: [eventMonitor])
  261. let expect = expectation(description: "request should receive appropriate lifetime events")
  262. expect.expectedFulfillmentCount = 3
  263. eventMonitor.requestDidResumeTask = { (_, _) in expect.fulfill() }
  264. eventMonitor.requestDidResume = { _ in expect.fulfill() }
  265. eventMonitor.requestDidFinish = { _ in expect.fulfill() }
  266. // Fulfill other events that would exceed the expected count. Inverted expectations require the full timeout.
  267. eventMonitor.requestDidSuspend = { _ in expect.fulfill() }
  268. eventMonitor.requestDidSuspendTask = { (_, _) in expect.fulfill() }
  269. eventMonitor.requestDidCancel = { _ in expect.fulfill() }
  270. eventMonitor.requestDidCancelTask = { (_, _) in expect.fulfill() }
  271. // When
  272. let request = session.request(URLRequest.makeHTTPBinRequest())
  273. for _ in 0..<100 {
  274. request.resume()
  275. }
  276. waitForExpectations(timeout: timeout, handler: nil)
  277. // Then
  278. XCTAssertEqual(request.state, .resumed)
  279. }
  280. func testThatRequestManuallyResumedManyTimesOnlyReceivesAppropriateLifetimeEvents() {
  281. // Given
  282. let eventMonitor = ClosureEventMonitor()
  283. let session = Session(startRequestsImmediately: false, eventMonitors: [eventMonitor])
  284. let expect = expectation(description: "request should receive appropriate lifetime events")
  285. expect.expectedFulfillmentCount = 3
  286. eventMonitor.requestDidResumeTask = { (_, _) in expect.fulfill() }
  287. eventMonitor.requestDidResume = { _ in expect.fulfill() }
  288. eventMonitor.requestDidFinish = { _ in expect.fulfill() }
  289. // Fulfill other events that would exceed the expected count. Inverted expectations require the full timeout.
  290. eventMonitor.requestDidSuspend = { _ in expect.fulfill() }
  291. eventMonitor.requestDidSuspendTask = { (_, _) in expect.fulfill() }
  292. eventMonitor.requestDidCancel = { _ in expect.fulfill() }
  293. eventMonitor.requestDidCancelTask = { (_, _) in expect.fulfill() }
  294. // When
  295. let request = session.request(URLRequest.makeHTTPBinRequest())
  296. for _ in 0..<100 {
  297. request.resume()
  298. }
  299. waitForExpectations(timeout: timeout, handler: nil)
  300. // Then
  301. XCTAssertEqual(request.state, .resumed)
  302. }
  303. func testThatRequestManuallySuspendedManyTimesAfterAutomaticResumeOnlyReceivesAppropriateLifetimeEvents() {
  304. // Given
  305. let eventMonitor = ClosureEventMonitor()
  306. let session = Session(startRequestsImmediately: false, eventMonitors: [eventMonitor])
  307. let expect = expectation(description: "request should receive appropriate lifetime events")
  308. expect.expectedFulfillmentCount = 2
  309. eventMonitor.requestDidSuspendTask = { (_, _) in expect.fulfill() }
  310. eventMonitor.requestDidSuspend = { _ in expect.fulfill() }
  311. // Fulfill other events that would exceed the expected count. Inverted expectations require the full timeout.
  312. eventMonitor.requestDidCancel = { _ in expect.fulfill() }
  313. eventMonitor.requestDidCancelTask = { (_, _) in expect.fulfill() }
  314. // When
  315. let request = session.request(URLRequest.makeHTTPBinRequest())
  316. for _ in 0..<100 {
  317. request.suspend()
  318. }
  319. waitForExpectations(timeout: timeout, handler: nil)
  320. // Then
  321. XCTAssertEqual(request.state, .suspended)
  322. }
  323. func testThatRequestManuallySuspendedManyTimesOnlyReceivesAppropriateLifetimeEvents() {
  324. // Given
  325. let eventMonitor = ClosureEventMonitor()
  326. let session = Session(startRequestsImmediately: false, eventMonitors: [eventMonitor])
  327. let expect = expectation(description: "request should receive appropriate lifetime events")
  328. expect.expectedFulfillmentCount = 2
  329. eventMonitor.requestDidSuspendTask = { (_, _) in expect.fulfill() }
  330. eventMonitor.requestDidSuspend = { _ in expect.fulfill() }
  331. // Fulfill other events that would exceed the expected count. Inverted expectations require the full timeout.
  332. eventMonitor.requestDidResume = { _ in expect.fulfill() }
  333. eventMonitor.requestDidResumeTask = { (_, _) in expect.fulfill() }
  334. eventMonitor.requestDidCancel = { _ in expect.fulfill() }
  335. eventMonitor.requestDidCancelTask = { (_, _) in expect.fulfill() }
  336. // When
  337. let request = session.request(URLRequest.makeHTTPBinRequest())
  338. for _ in 0..<100 {
  339. request.suspend()
  340. }
  341. waitForExpectations(timeout: timeout, handler: nil)
  342. // Then
  343. XCTAssertEqual(request.state, .suspended)
  344. }
  345. func testThatRequestManuallyCancelledManyTimesAfterAutomaticResumeOnlyReceivesAppropriateLifetimeEvents() {
  346. // Given
  347. let eventMonitor = ClosureEventMonitor()
  348. let session = Session(eventMonitors: [eventMonitor])
  349. let expect = expectation(description: "request should receive appropriate lifetime events")
  350. expect.expectedFulfillmentCount = 2
  351. eventMonitor.requestDidCancelTask = { (_, _) in expect.fulfill() }
  352. eventMonitor.requestDidCancel = { _ in expect.fulfill() }
  353. // Fulfill other events that would exceed the expected count. Inverted expectations require the full timeout.
  354. eventMonitor.requestDidSuspend = { _ in expect.fulfill() }
  355. eventMonitor.requestDidSuspendTask = { (_, _) in expect.fulfill() }
  356. // When
  357. let request = session.request(URLRequest.makeHTTPBinRequest())
  358. // Cancellation stops task creation, so don't cancel the request until the task has been created.
  359. eventMonitor.requestDidCreateTask = { (_, _) in
  360. for _ in 0..<100 {
  361. request.cancel()
  362. }
  363. }
  364. waitForExpectations(timeout: timeout, handler: nil)
  365. // Then
  366. XCTAssertEqual(request.state, .cancelled)
  367. }
  368. func testThatRequestManuallyCancelledManyTimesOnlyReceivesAppropriateLifetimeEvents() {
  369. // Given
  370. let eventMonitor = ClosureEventMonitor()
  371. let session = Session(startRequestsImmediately: false, eventMonitors: [eventMonitor])
  372. let expect = expectation(description: "request should receive appropriate lifetime events")
  373. expect.expectedFulfillmentCount = 2
  374. eventMonitor.requestDidCancelTask = { (_, _) in expect.fulfill() }
  375. eventMonitor.requestDidCancel = { _ in expect.fulfill() }
  376. // Fulfill other events that would exceed the expected count. Inverted expectations require the full timeout.
  377. eventMonitor.requestDidResume = { _ in expect.fulfill() }
  378. eventMonitor.requestDidResumeTask = { (_, _) in expect.fulfill() }
  379. eventMonitor.requestDidSuspend = { _ in expect.fulfill() }
  380. eventMonitor.requestDidSuspendTask = { (_, _) in expect.fulfill() }
  381. // When
  382. let request = session.request(URLRequest.makeHTTPBinRequest())
  383. // Cancellation stops task creation, so don't cancel the request until the task has been created.
  384. eventMonitor.requestDidCreateTask = { (_, _) in
  385. for _ in 0..<100 {
  386. request.cancel()
  387. }
  388. }
  389. waitForExpectations(timeout: timeout, handler: nil)
  390. // Then
  391. XCTAssertEqual(request.state, .cancelled)
  392. }
  393. func testThatRequestManuallyCancelledManyTimesOnManyQueuesOnlyReceivesAppropriateLifetimeEvents() {
  394. // Given
  395. let eventMonitor = ClosureEventMonitor()
  396. let session = Session(eventMonitors: [eventMonitor])
  397. let expect = expectation(description: "request should receive appropriate lifetime events")
  398. expect.expectedFulfillmentCount = 5
  399. eventMonitor.requestDidCancelTask = { (_, _) in expect.fulfill() }
  400. eventMonitor.requestDidCancel = { _ in expect.fulfill() }
  401. eventMonitor.requestDidResume = { _ in expect.fulfill() }
  402. eventMonitor.requestDidResumeTask = { (_, _) in expect.fulfill() }
  403. // Fulfill other events that would exceed the expected count. Inverted expectations require the full timeout.
  404. eventMonitor.requestDidSuspend = { _ in expect.fulfill() }
  405. eventMonitor.requestDidSuspendTask = { (_, _) in expect.fulfill() }
  406. // When
  407. let request = session.request(URLRequest.makeHTTPBinRequest())
  408. // Cancellation stops task creation, so don't cancel the request until the task has been created.
  409. eventMonitor.requestDidCreateTask = { (_, _) in
  410. DispatchQueue.concurrentPerform(iterations: 100) { i in
  411. request.cancel()
  412. if i == 99 { expect.fulfill() }
  413. }
  414. }
  415. waitForExpectations(timeout: timeout, handler: nil)
  416. // Then
  417. XCTAssertEqual(request.state, .cancelled)
  418. }
  419. func testThatRequestTriggersAllAppropriateLifetimeEvents() {
  420. // Given
  421. let eventMonitor = ClosureEventMonitor()
  422. let session = Session(eventMonitors: [eventMonitor])
  423. let expect = expectation(description: "request should receive appropriate lifetime events")
  424. expect.expectedFulfillmentCount = 13
  425. var dataReceived = false
  426. eventMonitor.taskDidReceiveChallenge = { (_, _, _) in expect.fulfill() }
  427. eventMonitor.taskDidFinishCollectingMetrics = { (_, _, _) in expect.fulfill() }
  428. eventMonitor.dataTaskDidReceiveData = { (_, _, _) in
  429. guard !dataReceived else { return }
  430. // Data may be received many times, fulfill only once.
  431. dataReceived = true
  432. expect.fulfill()
  433. }
  434. eventMonitor.dataTaskWillCacheResponse = { (_, _, _) in expect.fulfill() }
  435. eventMonitor.requestDidCreateURLRequest = { (_, _) in expect.fulfill() }
  436. eventMonitor.requestDidCreateTask = { (_, _) in expect.fulfill() }
  437. eventMonitor.requestDidGatherMetrics = { (_, _) in expect.fulfill() }
  438. eventMonitor.requestDidCompleteTaskWithError = { (_, _, _) in expect.fulfill() }
  439. eventMonitor.requestDidFinish = { (_) in expect.fulfill() }
  440. eventMonitor.requestDidResume = { (_) in expect.fulfill() }
  441. eventMonitor.requestDidResumeTask = { (_, _) in expect.fulfill() }
  442. eventMonitor.requestDidParseResponse = { (_, _) in expect.fulfill() }
  443. // When
  444. let request = session.request(URLRequest.makeHTTPBinRequest()).response { _ in
  445. expect.fulfill()
  446. }
  447. waitForExpectations(timeout: timeout, handler: nil)
  448. // Then
  449. XCTAssertEqual(request.state, .resumed)
  450. }
  451. func testThatCancelledRequestTriggersAllAppropriateLifetimeEvents() {
  452. // Given
  453. let eventMonitor = ClosureEventMonitor()
  454. let session = Session(startRequestsImmediately: false, eventMonitors: [eventMonitor])
  455. let expect = expectation(description: "request should receive appropriate lifetime events")
  456. expect.expectedFulfillmentCount = 12
  457. eventMonitor.taskDidFinishCollectingMetrics = { (_, _, _) in expect.fulfill() }
  458. eventMonitor.requestDidCreateURLRequest = { (_, _) in expect.fulfill() }
  459. eventMonitor.requestDidCreateTask = { (_, _) in expect.fulfill() }
  460. eventMonitor.requestDidGatherMetrics = { (_, _) in expect.fulfill() }
  461. eventMonitor.requestDidCompleteTaskWithError = { (_, _, _) in expect.fulfill() }
  462. eventMonitor.requestDidFinish = { (_) in expect.fulfill() }
  463. eventMonitor.requestDidResume = { (_) in expect.fulfill() }
  464. eventMonitor.requestDidCancel = { _ in expect.fulfill() }
  465. eventMonitor.requestDidCancelTask = { _, _ in expect.fulfill() }
  466. eventMonitor.requestDidParseResponse = { (_, _) in expect.fulfill() }
  467. // When
  468. let request = session.request(URLRequest.makeHTTPBinRequest()).response { _ in
  469. expect.fulfill()
  470. }
  471. eventMonitor.requestDidResumeTask = { (_, _) in
  472. request.cancel()
  473. expect.fulfill()
  474. }
  475. request.resume()
  476. waitForExpectations(timeout: timeout, handler: nil)
  477. // Then
  478. XCTAssertEqual(request.state, .cancelled)
  479. }
  480. }
  481. // MARK: -
  482. class RequestDescriptionTestCase: BaseTestCase {
  483. func testRequestDescription() {
  484. // Given
  485. let urlString = "https://httpbin.org/get"
  486. let manager = Session(startRequestsImmediately: false)
  487. let request = manager.request(urlString)
  488. let expectation = self.expectation(description: "Request description should update: \(urlString)")
  489. var response: HTTPURLResponse?
  490. // When
  491. request.response { resp in
  492. response = resp.response
  493. expectation.fulfill()
  494. }.resume()
  495. waitForExpectations(timeout: timeout, handler: nil)
  496. // Then
  497. XCTAssertEqual(request.description, "GET https://httpbin.org/get (\(response?.statusCode ?? -1))")
  498. }
  499. }
  500. // MARK: -
  501. class RequestDebugDescriptionTestCase: BaseTestCase {
  502. // MARK: Properties
  503. let manager: Session = {
  504. let manager = Session()
  505. return manager
  506. }()
  507. let managerWithAcceptLanguageHeader: Session = {
  508. var headers = HTTPHeaders.default
  509. headers["Accept-Language"] = "en-US"
  510. let configuration = URLSessionConfiguration.af.default
  511. configuration.headers = headers
  512. let manager = Session(configuration: configuration)
  513. return manager
  514. }()
  515. let managerWithContentTypeHeader: Session = {
  516. var headers = HTTPHeaders.default
  517. headers["Content-Type"] = "application/json"
  518. let configuration = URLSessionConfiguration.af.default
  519. configuration.headers = headers
  520. let manager = Session(configuration: configuration)
  521. return manager
  522. }()
  523. func managerWithCookie(_ cookie: HTTPCookie) -> Session {
  524. let configuration = URLSessionConfiguration.af.default
  525. configuration.httpCookieStorage?.setCookie(cookie)
  526. return Session(configuration: configuration)
  527. }
  528. let managerDisallowingCookies: Session = {
  529. let configuration = URLSessionConfiguration.af.default
  530. configuration.httpShouldSetCookies = false
  531. let manager = Session(configuration: configuration)
  532. return manager
  533. }()
  534. // MARK: Tests
  535. func testGETRequestDebugDescription() {
  536. // Given
  537. let urlString = "https://httpbin.org/get"
  538. let expectation = self.expectation(description: "request should complete")
  539. // When
  540. let request = manager.request(urlString).response { _ in expectation.fulfill() }
  541. waitForExpectations(timeout: timeout, handler: nil)
  542. let components = cURLCommandComponents(for: request)
  543. // Then
  544. XCTAssertEqual(components[0..<3], ["$", "curl", "-v"])
  545. XCTAssertTrue(components.contains("-X"))
  546. XCTAssertEqual(components.last, "\"\(urlString)\"")
  547. }
  548. func testGETRequestWithJSONHeaderDebugDescription() {
  549. // Given
  550. let urlString = "https://httpbin.org/get"
  551. let expectation = self.expectation(description: "request should complete")
  552. // When
  553. let headers: HTTPHeaders = [ "X-Custom-Header": "{\"key\": \"value\"}" ]
  554. let request = manager.request(urlString, headers: headers).response { _ in expectation.fulfill() }
  555. waitForExpectations(timeout: timeout, handler: nil)
  556. // Then
  557. XCTAssertNotNil(request.debugDescription.range(of: "-H \"X-Custom-Header: {\\\"key\\\": \\\"value\\\"}\""))
  558. }
  559. func testGETRequestWithDuplicateHeadersDebugDescription() {
  560. // Given
  561. let urlString = "https://httpbin.org/get"
  562. let expectation = self.expectation(description: "request should complete")
  563. // When
  564. let headers: HTTPHeaders = [ "Accept-Language": "en-GB" ]
  565. let request = managerWithAcceptLanguageHeader.request(urlString, headers: headers).response { _ in expectation.fulfill() }
  566. waitForExpectations(timeout: timeout, handler: nil)
  567. let components = cURLCommandComponents(for: request)
  568. // Then
  569. XCTAssertEqual(components[0..<3], ["$", "curl", "-v"])
  570. XCTAssertTrue(components.contains("-X"))
  571. XCTAssertEqual(components.last, "\"\(urlString)\"")
  572. let tokens = request.debugDescription.components(separatedBy: "Accept-Language:")
  573. XCTAssertTrue(tokens.count == 2, "command should contain a single Accept-Language header")
  574. XCTAssertNotNil(request.debugDescription.range(of: "-H \"Accept-Language: en-GB\""))
  575. }
  576. func testPOSTRequestDebugDescription() {
  577. // Given
  578. let urlString = "https://httpbin.org/post"
  579. let expectation = self.expectation(description: "request should complete")
  580. // When
  581. let request = manager.request(urlString, method: .post).response { _ in expectation.fulfill() }
  582. waitForExpectations(timeout: timeout, handler: nil)
  583. let components = cURLCommandComponents(for: request)
  584. // Then
  585. XCTAssertEqual(components[0..<3], ["$", "curl", "-v"])
  586. XCTAssertEqual(components[3..<5], ["-X", "POST"])
  587. XCTAssertEqual(components.last, "\"\(urlString)\"")
  588. }
  589. func testPOSTRequestWithJSONParametersDebugDescription() {
  590. // Given
  591. let urlString = "https://httpbin.org/post"
  592. let expectation = self.expectation(description: "request should complete")
  593. let parameters = [
  594. "foo": "bar",
  595. "fo\"o": "b\"ar",
  596. "f'oo": "ba'r"
  597. ]
  598. // When
  599. let request = manager.request(urlString, method: .post, parameters: parameters, encoding: JSONEncoding.default).response {
  600. _ in expectation.fulfill()
  601. }
  602. waitForExpectations(timeout: timeout, handler: nil)
  603. let components = cURLCommandComponents(for: request)
  604. // Then
  605. XCTAssertEqual(components[0..<3], ["$", "curl", "-v"])
  606. XCTAssertEqual(components[3..<5], ["-X", "POST"])
  607. XCTAssertNotNil(request.debugDescription.range(of: "-H \"Content-Type: application/json\""))
  608. XCTAssertNotNil(request.debugDescription.range(of: "-d \"{"))
  609. XCTAssertNotNil(request.debugDescription.range(of: "\\\"f'oo\\\":\\\"ba'r\\\""))
  610. XCTAssertNotNil(request.debugDescription.range(of: "\\\"fo\\\\\\\"o\\\":\\\"b\\\\\\\"ar\\\""))
  611. XCTAssertNotNil(request.debugDescription.range(of: "\\\"foo\\\":\\\"bar\\"))
  612. XCTAssertEqual(components.last, "\"\(urlString)\"")
  613. }
  614. func testPOSTRequestWithCookieDebugDescription() {
  615. // Given
  616. let urlString = "https://httpbin.org/post"
  617. let properties = [
  618. HTTPCookiePropertyKey.domain: "httpbin.org",
  619. HTTPCookiePropertyKey.path: "/post",
  620. HTTPCookiePropertyKey.name: "foo",
  621. HTTPCookiePropertyKey.value: "bar",
  622. ]
  623. let cookie = HTTPCookie(properties: properties)!
  624. let cookieManager = managerWithCookie(cookie)
  625. let expectation = self.expectation(description: "request should complete")
  626. // When
  627. let request = cookieManager.request(urlString, method: .post).response { _ in expectation.fulfill() }
  628. waitForExpectations(timeout: timeout, handler: nil)
  629. let components = cURLCommandComponents(for: request)
  630. // Then
  631. XCTAssertEqual(components[0..<3], ["$", "curl", "-v"])
  632. XCTAssertEqual(components[3..<5], ["-X", "POST"])
  633. XCTAssertEqual(components.last, "\"\(urlString)\"")
  634. XCTAssertEqual(components[5..<6], ["-b"])
  635. }
  636. func testPOSTRequestWithCookiesDisabledDebugDescription() {
  637. // Given
  638. let urlString = "https://httpbin.org/post"
  639. let properties = [
  640. HTTPCookiePropertyKey.domain: "httpbin.org",
  641. HTTPCookiePropertyKey.path: "/post",
  642. HTTPCookiePropertyKey.name: "foo",
  643. HTTPCookiePropertyKey.value: "bar",
  644. ]
  645. let cookie = HTTPCookie(properties: properties)!
  646. managerDisallowingCookies.session.configuration.httpCookieStorage?.setCookie(cookie)
  647. // When
  648. let request = managerDisallowingCookies.request(urlString, method: .post)
  649. let components = cURLCommandComponents(for: request)
  650. // Then
  651. let cookieComponents = components.filter { $0 == "-b" }
  652. XCTAssertTrue(cookieComponents.isEmpty)
  653. }
  654. func testMultipartFormDataRequestWithDuplicateHeadersDebugDescription() {
  655. // Given
  656. let urlString = "https://httpbin.org/post"
  657. let japaneseData = Data("日本語".utf8)
  658. let expectation = self.expectation(description: "multipart form data encoding should succeed")
  659. // When
  660. let request = managerWithContentTypeHeader.upload(multipartFormData: { (data) in
  661. data.append(japaneseData, withName: "japanese")
  662. }, to: urlString)
  663. .response { _ in
  664. expectation.fulfill()
  665. }
  666. waitForExpectations(timeout: timeout, handler: nil)
  667. let components = cURLCommandComponents(for: request)
  668. // Then
  669. XCTAssertEqual(components[0..<3], ["$", "curl", "-v"])
  670. XCTAssertTrue(components.contains("-X"))
  671. XCTAssertEqual(components.last, "\"\(urlString)\"")
  672. let tokens = request.debugDescription.components(separatedBy: "Content-Type:")
  673. XCTAssertTrue(tokens.count == 2, "command should contain a single Content-Type header")
  674. XCTAssertNotNil(request.debugDescription.range(of: "-H \"Content-Type: multipart/form-data;"))
  675. }
  676. func testThatRequestWithInvalidURLDebugDescription() {
  677. // Given
  678. let urlString = "invalid_url"
  679. let expectation = self.expectation(description: "request should complete")
  680. // When
  681. let request = manager.request(urlString).response { _ in expectation.fulfill() }
  682. waitForExpectations(timeout: timeout, handler: nil)
  683. let debugDescription = request.debugDescription
  684. // Then
  685. XCTAssertNotNil(debugDescription, "debugDescription should not crash")
  686. }
  687. // MARK: Test Helper Methods
  688. private func cURLCommandComponents(for request: Request) -> [String] {
  689. let whitespaceCharacterSet = CharacterSet.whitespacesAndNewlines
  690. return request.debugDescription
  691. .components(separatedBy: whitespaceCharacterSet)
  692. .filter { $0 != "" && $0 != "\\" }
  693. }
  694. }