SessionManagerTests.swift 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003
  1. //
  2. // SessionManagerTests.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. @testable import Alamofire
  25. import Foundation
  26. import XCTest
  27. class SessionManagerTestCase: BaseTestCase {
  28. // MARK: Helper Types
  29. private class HTTPMethodAdapter: RequestAdapter {
  30. let method: HTTPMethod
  31. let throwsError: Bool
  32. init(method: HTTPMethod, throwsError: Bool = false) {
  33. self.method = method
  34. self.throwsError = throwsError
  35. }
  36. func adapt(_ urlRequest: URLRequest) throws -> URLRequest {
  37. guard !throwsError else { throw AFError.invalidURL(url: "") }
  38. var urlRequest = urlRequest
  39. urlRequest.httpMethod = method.rawValue
  40. return urlRequest
  41. }
  42. }
  43. private class RequestHandler: RequestAdapter, RequestRetrier {
  44. var adaptedCount = 0
  45. var retryCount = 0
  46. var retryErrors: [Error] = []
  47. var shouldApplyAuthorizationHeader = false
  48. var throwsErrorOnSecondAdapt = false
  49. func adapt(_ urlRequest: URLRequest) throws -> URLRequest {
  50. if throwsErrorOnSecondAdapt && adaptedCount == 1 {
  51. throwsErrorOnSecondAdapt = false
  52. throw AFError.invalidURL(url: "")
  53. }
  54. var urlRequest = urlRequest
  55. adaptedCount += 1
  56. if shouldApplyAuthorizationHeader && adaptedCount > 1 {
  57. if let header = HTTPHeaders.authorization(withUsername: "user", password: "password").first {
  58. urlRequest.setValue(header.value, forHTTPHeaderField: header.key)
  59. }
  60. }
  61. return urlRequest
  62. }
  63. func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion) {
  64. retryCount += 1
  65. retryErrors.append(error)
  66. if retryCount < 2 {
  67. completion(true, 0.0)
  68. } else {
  69. completion(false, 0.0)
  70. }
  71. }
  72. }
  73. private class UploadHandler: RequestAdapter, RequestRetrier {
  74. var adaptedCount = 0
  75. var retryCount = 0
  76. var retryErrors: [Error] = []
  77. func adapt(_ urlRequest: URLRequest) throws -> URLRequest {
  78. adaptedCount += 1
  79. if adaptedCount == 1 { throw AFError.invalidURL(url: "") }
  80. return urlRequest
  81. }
  82. func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion) {
  83. retryCount += 1
  84. retryErrors.append(error)
  85. completion(true, 0.0)
  86. }
  87. }
  88. // MARK: Tests - Initialization
  89. func testInitializerWithDefaultArguments() {
  90. // Given, When
  91. let manager = SessionManager()
  92. // Then
  93. XCTAssertNotNil(manager.session.delegate, "session delegate should not be nil")
  94. XCTAssertTrue(manager.delegate === manager.session.delegate, "manager delegate should equal session delegate")
  95. XCTAssertNil(manager.trustManager, "session server trust policy manager should be nil")
  96. }
  97. func testInitializerWithSpecifiedArguments() {
  98. // Given
  99. let configuration = URLSessionConfiguration.default
  100. let delegate = SessionDelegate()
  101. let serverTrustManager = ServerTrustManager(evaluators: [:])
  102. // When
  103. let manager = SessionManager(configuration: configuration,
  104. delegate: delegate,
  105. trustManager: serverTrustManager)
  106. // Then
  107. XCTAssertNotNil(manager.session.delegate, "session delegate should not be nil")
  108. XCTAssertTrue(manager.delegate === manager.session.delegate, "manager delegate should equal session delegate")
  109. XCTAssertNotNil(manager.trustManager, "session server trust policy manager should not be nil")
  110. }
  111. // TODO: If we allow intialization with a URLSession, we can't control the queues, so do we want this API?
  112. // func testThatFailableInitializerSucceedsWithDefaultArguments() {
  113. // // Given
  114. // let delegate = SessionDelegate()
  115. // let session: URLSession = {
  116. // let configuration = URLSessionConfiguration.default
  117. // return URLSession(configuration: configuration, delegate: delegate, delegateQueue: nil)
  118. // }()
  119. //
  120. // // When
  121. // let manager = SessionManager(session: session, delegate: delegate)
  122. //
  123. // // Then
  124. // if let manager = manager {
  125. // XCTAssertTrue(manager.delegate === manager.session.delegate, "manager delegate should equal session delegate")
  126. // XCTAssertNil(manager.session.serverTrustManager, "session server trust policy manager should be nil")
  127. // } else {
  128. // XCTFail("manager should not be nil")
  129. // }
  130. // }
  131. //
  132. // func testThatFailableInitializerSucceedsWithSpecifiedArguments() {
  133. // // Given
  134. // let delegate = SessionDelegate()
  135. // let session: URLSession = {
  136. // let configuration = URLSessionConfiguration.default
  137. // return URLSession(configuration: configuration, delegate: delegate, delegateQueue: nil)
  138. // }()
  139. //
  140. // let serverTrustManager = ServerTrustManager(evaluators: [:])
  141. //
  142. // // When
  143. // let manager = SessionManager(session: session, delegate: delegate, serverTrustManager: serverTrustManager)
  144. //
  145. // // Then
  146. // if let manager = manager {
  147. // XCTAssertTrue(manager.delegate === manager.session.delegate, "manager delegate should equal session delegate")
  148. // XCTAssertNotNil(manager.session.serverTrustManager, "session server trust policy manager should not be nil")
  149. // } else {
  150. // XCTFail("manager should not be nil")
  151. // }
  152. // }
  153. //
  154. // func testThatFailableInitializerFailsWithWhenDelegateDoesNotEqualSessionDelegate() {
  155. // // Given
  156. // let delegate = SessionDelegate()
  157. // let session: URLSession = {
  158. // let configuration = URLSessionConfiguration.default
  159. // return URLSession(configuration: configuration, delegate: SessionDelegate(), delegateQueue: nil)
  160. // }()
  161. //
  162. // // When
  163. // let manager = SessionManager(session: session, delegate: delegate)
  164. //
  165. // // Then
  166. // XCTAssertNil(manager, "manager should be nil")
  167. // }
  168. //
  169. // func testThatFailableInitializerFailsWhenSessionDelegateIsNil() {
  170. // // Given
  171. // let delegate = SessionDelegate()
  172. // let session: URLSession = {
  173. // let configuration = URLSessionConfiguration.default
  174. // return URLSession(configuration: configuration, delegate: nil, delegateQueue: nil)
  175. // }()
  176. //
  177. // // When
  178. // let manager = SessionManager(session: session, delegate: delegate)
  179. //
  180. // // Then
  181. // XCTAssertNil(manager, "manager should be nil")
  182. // }
  183. // MARK: Tests - Default HTTP Headers
  184. func testDefaultUserAgentHeader() {
  185. // Given, When
  186. let userAgent = SessionManager.defaultHTTPHeaders["User-Agent"]
  187. // Then
  188. let osNameVersion: String = {
  189. let version = ProcessInfo.processInfo.operatingSystemVersion
  190. let versionString = "\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)"
  191. let osName: String = {
  192. #if os(iOS)
  193. return "iOS"
  194. #elseif os(watchOS)
  195. return "watchOS"
  196. #elseif os(tvOS)
  197. return "tvOS"
  198. #elseif os(macOS)
  199. return "macOS"
  200. #elseif os(Linux)
  201. return "Linux"
  202. #else
  203. return "Unknown"
  204. #endif
  205. }()
  206. return "\(osName) \(versionString)"
  207. }()
  208. let alamofireVersion: String = {
  209. guard
  210. let afInfo = Bundle(for: SessionManager.self).infoDictionary,
  211. let build = afInfo["CFBundleShortVersionString"]
  212. else { return "Unknown" }
  213. return "Alamofire/\(build)"
  214. }()
  215. let expectedUserAgent = "Unknown/Unknown (Unknown; build:Unknown; \(osNameVersion)) \(alamofireVersion)"
  216. XCTAssertEqual(userAgent, expectedUserAgent)
  217. }
  218. // MARK: Tests - Supported Accept-Encodings
  219. func testDefaultAcceptEncodingSupportsAppropriateEncodingsOnAppropriateSystems() {
  220. // Given
  221. let brotliURL = URL(string: "https://httpbin.org/brotli")!
  222. let gzipURL = URL(string: "https://httpbin.org/gzip")!
  223. let deflateURL = URL(string: "https://httpbin.org/deflate")!
  224. let brotliExpectation = expectation(description: "brotli request should complete")
  225. let gzipExpectation = expectation(description: "gzip request should complete")
  226. let deflateExpectation = expectation(description: "deflate request should complete")
  227. var brotliResponse: DataResponse<Any>?
  228. var gzipResponse: DataResponse<Any>?
  229. var deflateResponse: DataResponse<Any>?
  230. // When
  231. Alamofire.request(brotliURL).responseJSON { (response) in
  232. brotliResponse = response
  233. brotliExpectation.fulfill()
  234. }
  235. Alamofire.request(gzipURL).responseJSON { (response) in
  236. gzipResponse = response
  237. gzipExpectation.fulfill()
  238. }
  239. Alamofire.request(deflateURL).responseJSON { (response) in
  240. deflateResponse = response
  241. deflateExpectation.fulfill()
  242. }
  243. waitForExpectations(timeout: timeout, handler: nil)
  244. // Then
  245. if #available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, *) {
  246. XCTAssertTrue(brotliResponse?.result.isSuccess == true)
  247. } else {
  248. XCTAssertTrue(brotliResponse?.result.isFailure == true)
  249. }
  250. XCTAssertTrue(gzipResponse?.result.isSuccess == true)
  251. XCTAssertTrue(deflateResponse?.result.isSuccess == true)
  252. }
  253. // MARK: Tests - Start Requests Immediately
  254. func testSetStartRequestsImmediatelyToFalseAndResumeRequest() {
  255. // Given
  256. let delegate = SessionDelegate(startRequestsImmediately: false)
  257. let manager = SessionManager(delegate: delegate)
  258. let url = URL(string: "https://httpbin.org/get")!
  259. let urlRequest = URLRequest(url: url)
  260. let expectation = self.expectation(description: "\(url)")
  261. var response: HTTPURLResponse?
  262. // When
  263. manager.request(urlRequest)
  264. .response { resp in
  265. response = resp.response
  266. expectation.fulfill()
  267. }
  268. .resume()
  269. waitForExpectations(timeout: timeout, handler: nil)
  270. // Then
  271. XCTAssertNotNil(response, "response should not be nil")
  272. XCTAssertTrue(response?.statusCode == 200, "response status code should be 200")
  273. }
  274. func testSetStartRequestsImmediatelyToFalseAndCancelledCallsResponseHandlers() {
  275. // Given
  276. let delegate = SessionDelegate(startRequestsImmediately: false)
  277. let manager = SessionManager(delegate: delegate)
  278. let url = URL(string: "https://httpbin.org/get")!
  279. let urlRequest = URLRequest(url: url)
  280. let expectation = self.expectation(description: "\(url)")
  281. var response: DataResponse<Data?>?
  282. // When
  283. let request = manager.request(urlRequest)
  284. .cancel()
  285. .response { resp in
  286. response = resp
  287. expectation.fulfill()
  288. }
  289. waitForExpectations(timeout: timeout, handler: nil)
  290. // Then
  291. XCTAssertNotNil(response, "response should not be nil")
  292. XCTAssertTrue(request.isCancelled)
  293. XCTAssertNil(request.task)
  294. guard let error = request.error as? AFError, case .explicitlyCancelled = error else { XCTFail(); return }
  295. }
  296. func testSetStartRequestsImmediatelyToFalseAndResumeThenCancelRequestHasCorrectOutput() {
  297. // Given
  298. let delegate = SessionDelegate(startRequestsImmediately: false)
  299. let manager = SessionManager(delegate: delegate)
  300. let url = URL(string: "https://httpbin.org/get")!
  301. let urlRequest = URLRequest(url: url)
  302. let expectation = self.expectation(description: "\(url)")
  303. var response: DataResponse<Data?>?
  304. // When
  305. let request = manager.request(urlRequest)
  306. .resume()
  307. .cancel()
  308. .response { resp in
  309. response = resp
  310. expectation.fulfill()
  311. }
  312. waitForExpectations(timeout: timeout, handler: nil)
  313. // Then
  314. XCTAssertNotNil(response, "response should not be nil")
  315. XCTAssertTrue(request.isCancelled)
  316. XCTAssertNil(request.task)
  317. guard let error = request.error as? AFError, case .explicitlyCancelled = error else { XCTFail(); return }
  318. }
  319. func testSetStartRequestsImmediatelyToFalseAndCancelThenResumeRequestDoesntCreateTaskAndStaysCancelled() {
  320. // Given
  321. let delegate = SessionDelegate(startRequestsImmediately: false)
  322. let manager = SessionManager(delegate: delegate)
  323. let url = URL(string: "https://httpbin.org/get")!
  324. let urlRequest = URLRequest(url: url)
  325. let expectation = self.expectation(description: "\(url)")
  326. var response: DataResponse<Data?>?
  327. // When
  328. let request = manager.request(urlRequest)
  329. .cancel()
  330. .resume()
  331. .response { resp in
  332. response = resp
  333. expectation.fulfill()
  334. }
  335. waitForExpectations(timeout: timeout, handler: nil)
  336. // Then
  337. XCTAssertNotNil(response, "response should not be nil")
  338. XCTAssertTrue(request.isCancelled)
  339. XCTAssertNil(request.task)
  340. guard let error = request.error as? AFError, case .explicitlyCancelled = error else { XCTFail(); return }
  341. }
  342. // MARK: Tests - Deinitialization
  343. func testReleasingManagerWithPendingRequestDeinitializesSuccessfully() {
  344. // Given
  345. let delegate = SessionDelegate(startRequestsImmediately: false)
  346. let monitor = ClosureEventMonitor()
  347. let expectation = self.expectation(description: "Request created")
  348. monitor.requestDidCreateTask = { (_, _) in expectation.fulfill() }
  349. var manager: SessionManager? = SessionManager(delegate: delegate, eventMonitors: [monitor])
  350. let url = URL(string: "https://httpbin.org/get")!
  351. let urlRequest = URLRequest(url: url)
  352. // When
  353. let request = manager?.request(urlRequest)
  354. manager = nil
  355. waitForExpectations(timeout: timeout, handler: nil)
  356. // Then
  357. XCTAssertEqual(request?.task?.state, .suspended)
  358. XCTAssertNil(manager, "manager should be nil")
  359. }
  360. // TODO: Make this test wait less with proper internal async work.
  361. // TODO: Reevaluate this test with new async structure vs. deinit
  362. func testReleasingManagerWithPendingCanceledRequestDeinitializesSuccessfully() {
  363. // Given
  364. let delegate = SessionDelegate(startRequestsImmediately: false)
  365. var manager: SessionManager? = SessionManager(delegate: delegate)
  366. let url = URL(string: "https://httpbin.org/get")!
  367. let urlRequest = URLRequest(url: url)
  368. // When
  369. let request = manager?.request(urlRequest)
  370. request?.cancel()
  371. manager = nil
  372. // Then
  373. let state = request?.state
  374. XCTAssertTrue(state == .cancelled, "state should be .canceling or .completed")
  375. XCTAssertNil(manager, "manager should be nil")
  376. }
  377. // MARK: Tests - Bad Requests
  378. func testThatDataRequestWithInvalidURLStringThrowsResponseHandlerError() {
  379. // Given
  380. let sessionManager = SessionManager()
  381. let expectation = self.expectation(description: "Request should fail with error")
  382. var response: DataResponse<Data?>?
  383. // When
  384. sessionManager.request("https://httpbin.org/get/äëïöü").response { resp in
  385. response = resp
  386. expectation.fulfill()
  387. }
  388. waitForExpectations(timeout: timeout, handler: nil)
  389. // Then
  390. XCTAssertNil(response?.request)
  391. XCTAssertNil(response?.response)
  392. XCTAssertNil(response?.data)
  393. XCTAssertNotNil(response?.error)
  394. if let error = response?.error as? AFError {
  395. XCTAssertTrue(error.isInvalidURLError)
  396. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  397. } else {
  398. XCTFail("error should not be nil")
  399. }
  400. }
  401. // func testThatDownloadRequestWithInvalidURLStringThrowsResponseHandlerError() {
  402. // // Given
  403. // let sessionManager = SessionManager()
  404. // let expectation = self.expectation(description: "Download should fail with error")
  405. //
  406. // var response: DefaultDownloadResponse?
  407. //
  408. // // When
  409. // sessionManager.download("https://httpbin.org/get/äëïöü").response { resp in
  410. // response = resp
  411. // expectation.fulfill()
  412. // }
  413. //
  414. // waitForExpectations(timeout: timeout, handler: nil)
  415. //
  416. // // Then
  417. // XCTAssertNil(response?.request)
  418. // XCTAssertNil(response?.response)
  419. // XCTAssertNil(response?.temporaryURL)
  420. // XCTAssertNil(response?.destinationURL)
  421. // XCTAssertNil(response?.resumeData)
  422. // XCTAssertNotNil(response?.error)
  423. //
  424. // if let error = response?.error as? AFError {
  425. // XCTAssertTrue(error.isInvalidURLError)
  426. // XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  427. // } else {
  428. // XCTFail("error should not be nil")
  429. // }
  430. // }
  431. //
  432. func testThatUploadDataRequestWithInvalidURLStringThrowsResponseHandlerError() {
  433. // Given
  434. let sessionManager = SessionManager()
  435. let expectation = self.expectation(description: "Upload should fail with error")
  436. var response: DataResponse<Data?>?
  437. // When
  438. sessionManager.upload(Data(), to: "https://httpbin.org/get/äëïöü").response { resp in
  439. response = resp
  440. expectation.fulfill()
  441. }
  442. waitForExpectations(timeout: timeout, handler: nil)
  443. // Then
  444. XCTAssertNil(response?.request)
  445. XCTAssertNil(response?.response)
  446. XCTAssertNil(response?.data)
  447. XCTAssertNotNil(response?.error)
  448. if let error = response?.error as? AFError {
  449. XCTAssertTrue(error.isInvalidURLError)
  450. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  451. } else {
  452. XCTFail("error should not be nil")
  453. }
  454. }
  455. func testThatUploadFileRequestWithInvalidURLStringThrowsResponseHandlerError() {
  456. // Given
  457. let sessionManager = SessionManager()
  458. let expectation = self.expectation(description: "Upload should fail with error")
  459. var response: DataResponse<Data?>?
  460. // When
  461. sessionManager.upload(URL(fileURLWithPath: "/invalid"), to: "https://httpbin.org/get/äëïöü").response { resp in
  462. response = resp
  463. expectation.fulfill()
  464. }
  465. waitForExpectations(timeout: timeout, handler: nil)
  466. // Then
  467. XCTAssertNil(response?.request)
  468. XCTAssertNil(response?.response)
  469. XCTAssertNil(response?.data)
  470. XCTAssertNotNil(response?.error)
  471. if let error = response?.error as? AFError {
  472. XCTAssertTrue(error.isInvalidURLError)
  473. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  474. } else {
  475. XCTFail("error should not be nil")
  476. }
  477. }
  478. func testThatUploadStreamRequestWithInvalidURLStringThrowsResponseHandlerError() {
  479. // Given
  480. let sessionManager = SessionManager()
  481. let expectation = self.expectation(description: "Upload should fail with error")
  482. var response: DataResponse<Data?>?
  483. // When
  484. sessionManager.upload(InputStream(data: Data()), to: "https://httpbin.org/get/äëïöü").response { resp in
  485. response = resp
  486. expectation.fulfill()
  487. }
  488. waitForExpectations(timeout: timeout, handler: nil)
  489. // Then
  490. XCTAssertNil(response?.request)
  491. XCTAssertNil(response?.response)
  492. XCTAssertNil(response?.data)
  493. XCTAssertNotNil(response?.error)
  494. if let error = response?.error as? AFError {
  495. XCTAssertTrue(error.isInvalidURLError)
  496. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  497. } else {
  498. XCTFail("error should not be nil")
  499. }
  500. }
  501. // MARK: Tests - Request Adapter
  502. func testThatSessionManagerCallsRequestAdapterWhenCreatingDataRequest() {
  503. // Given
  504. let adapter = HTTPMethodAdapter(method: .post)
  505. let delegate = SessionDelegate(startRequestsImmediately: false)
  506. let monitor = ClosureEventMonitor()
  507. let expectation = self.expectation(description: "Request created")
  508. monitor.requestDidCreateTask = { (_, _) in expectation.fulfill() }
  509. let sessionManager = SessionManager(delegate: delegate, adapter: adapter, eventMonitors: [monitor])
  510. // When
  511. let request = sessionManager.request("https://httpbin.org/get")
  512. waitForExpectations(timeout: timeout, handler: nil)
  513. // Then
  514. XCTAssertEqual(request.task?.originalRequest?.httpMethod, adapter.method.rawValue)
  515. }
  516. func testThatSessionManagerCallsRequestAdapterWhenCreatingDownloadRequest() {
  517. // Given
  518. let adapter = HTTPMethodAdapter(method: .post)
  519. let delegate = SessionDelegate(startRequestsImmediately: false)
  520. let monitor = ClosureEventMonitor()
  521. let expectation = self.expectation(description: "Request created")
  522. monitor.requestDidCreateTask = { (_, _) in expectation.fulfill() }
  523. let sessionManager = SessionManager(delegate: delegate, adapter: adapter, eventMonitors: [monitor])
  524. // When
  525. let request = sessionManager.download("https://httpbin.org/get")
  526. waitForExpectations(timeout: timeout, handler: nil)
  527. // Then
  528. XCTAssertEqual(request.task?.originalRequest?.httpMethod, adapter.method.rawValue)
  529. }
  530. func testThatSessionManagerCallsRequestAdapterWhenCreatingUploadRequestWithData() {
  531. // Given
  532. let adapter = HTTPMethodAdapter(method: .get)
  533. let delegate = SessionDelegate(startRequestsImmediately: false)
  534. let monitor = ClosureEventMonitor()
  535. let expectation = self.expectation(description: "Request created")
  536. monitor.requestDidCreateTask = { (_, _) in expectation.fulfill() }
  537. let sessionManager = SessionManager(delegate: delegate, adapter: adapter, eventMonitors: [monitor])
  538. // When
  539. let request = sessionManager.upload("data".data(using: .utf8)!, to: "https://httpbin.org/post")
  540. waitForExpectations(timeout: timeout, handler: nil)
  541. // Then
  542. XCTAssertEqual(request.task?.originalRequest?.httpMethod, adapter.method.rawValue)
  543. }
  544. func testThatSessionManagerCallsRequestAdapterWhenCreatingUploadRequestWithFile() {
  545. // Given
  546. let adapter = HTTPMethodAdapter(method: .get)
  547. let delegate = SessionDelegate(startRequestsImmediately: false)
  548. let monitor = ClosureEventMonitor()
  549. let expectation = self.expectation(description: "Request created")
  550. monitor.requestDidCreateTask = { (_, _) in expectation.fulfill() }
  551. let sessionManager = SessionManager(delegate: delegate, adapter: adapter, eventMonitors: [monitor])
  552. // When
  553. let fileURL = URL(fileURLWithPath: "/path/to/some/file.txt")
  554. let request = sessionManager.upload(fileURL, to: "https://httpbin.org/post")
  555. waitForExpectations(timeout: timeout, handler: nil)
  556. // Then
  557. XCTAssertEqual(request.task?.originalRequest?.httpMethod, adapter.method.rawValue)
  558. }
  559. func testThatSessionManagerCallsRequestAdapterWhenCreatingUploadRequestWithInputStream() {
  560. // Given
  561. let adapter = HTTPMethodAdapter(method: .get)
  562. let delegate = SessionDelegate(startRequestsImmediately: false)
  563. let monitor = ClosureEventMonitor()
  564. let expectation = self.expectation(description: "Request created")
  565. monitor.requestDidCreateTask = { (_, _) in expectation.fulfill() }
  566. let sessionManager = SessionManager(delegate: delegate, adapter: adapter, eventMonitors: [monitor])
  567. // When
  568. let inputStream = InputStream(data: "data".data(using: .utf8)!)
  569. let request = sessionManager.upload(inputStream, to: "https://httpbin.org/post")
  570. waitForExpectations(timeout: timeout, handler: nil)
  571. // Then
  572. XCTAssertEqual(request.task?.originalRequest?.httpMethod, adapter.method.rawValue)
  573. }
  574. func testThatRequestAdapterErrorThrowsResponseHandlerError() {
  575. // Given
  576. let adapter = HTTPMethodAdapter(method: .post, throwsError: true)
  577. let delegate = SessionDelegate(startRequestsImmediately: false)
  578. let monitor = ClosureEventMonitor()
  579. let expectation = self.expectation(description: "Request created")
  580. monitor.requestDidFailToAdaptURLRequestWithError = { (_, _, _) in expectation.fulfill() }
  581. let sessionManager = SessionManager(delegate: delegate, adapter: adapter, eventMonitors: [monitor])
  582. // When
  583. let request = sessionManager.request("https://httpbin.org/get")
  584. waitForExpectations(timeout: timeout, handler: nil)
  585. // Then
  586. if let error = request.error as? AFError {
  587. XCTAssertTrue(error.isInvalidURLError)
  588. XCTAssertEqual(error.urlConvertible as? String, "")
  589. } else {
  590. XCTFail("error should not be nil")
  591. }
  592. }
  593. // MARK: Tests - Request Retrier
  594. func testThatSessionManagerCallsRequestRetrierWhenRequestEncountersError() {
  595. // Given
  596. let handler = RequestHandler()
  597. let sessionManager = SessionManager(adapter: handler, retrier: handler)
  598. let expectation = self.expectation(description: "request should eventually fail")
  599. var response: DataResponse<Any>?
  600. // When
  601. let request = sessionManager.request("https://httpbin.org/basic-auth/user/password")
  602. .validate()
  603. .responseJSON { jsonResponse in
  604. response = jsonResponse
  605. expectation.fulfill()
  606. }
  607. waitForExpectations(timeout: timeout, handler: nil)
  608. // Then
  609. XCTAssertEqual(handler.adaptedCount, 2)
  610. XCTAssertEqual(handler.retryCount, 2)
  611. XCTAssertEqual(request.retryCount, 1)
  612. XCTAssertEqual(response?.result.isSuccess, false)
  613. XCTAssertTrue(sessionManager.delegate.requestTaskMap.isEmpty)
  614. }
  615. func testThatSessionManagerCallsRequestRetrierWhenRequestInitiallyEncountersAdaptError() {
  616. // Given
  617. let handler = RequestHandler()
  618. handler.adaptedCount = 1
  619. handler.throwsErrorOnSecondAdapt = true
  620. handler.shouldApplyAuthorizationHeader = true
  621. let sessionManager = SessionManager(adapter: handler, retrier: handler)
  622. let expectation = self.expectation(description: "request should eventually fail")
  623. var response: DataResponse<Any>?
  624. // When
  625. sessionManager.request("https://httpbin.org/basic-auth/user/password")
  626. .validate()
  627. .responseJSON { jsonResponse in
  628. response = jsonResponse
  629. expectation.fulfill()
  630. }
  631. waitForExpectations(timeout: timeout, handler: nil)
  632. // Then
  633. XCTAssertEqual(handler.adaptedCount, 2)
  634. XCTAssertEqual(handler.retryCount, 1)
  635. XCTAssertEqual(response?.result.isSuccess, true)
  636. XCTAssertTrue(sessionManager.delegate.requestTaskMap.isEmpty)
  637. }
  638. //
  639. // func testThatSessionManagerCallsRequestRetrierWhenDownloadInitiallyEncountersAdaptError() {
  640. // // Given
  641. // let handler = RequestHandler()
  642. // handler.adaptedCount = 1
  643. // handler.throwsErrorOnSecondAdapt = true
  644. // handler.shouldApplyAuthorizationHeader = true
  645. //
  646. // let sessionManager = SessionManager()
  647. // sessionManager.adapter = handler
  648. // sessionManager.retrier = handler
  649. //
  650. // let expectation = self.expectation(description: "request should eventually fail")
  651. // var response: DownloadResponse<Any>?
  652. //
  653. // let destination: DownloadRequest.DownloadFileDestination = { _, _ in
  654. // let fileURL = self.testDirectoryURL.appendingPathComponent("test-output.json")
  655. // return (fileURL, [.removePreviousFile])
  656. // }
  657. //
  658. // // When
  659. // sessionManager.download("https://httpbin.org/basic-auth/user/password", to: destination)
  660. // .validate()
  661. // .responseJSON { jsonResponse in
  662. // response = jsonResponse
  663. // expectation.fulfill()
  664. // }
  665. //
  666. // waitForExpectations(timeout: timeout, handler: nil)
  667. //
  668. // // Then
  669. // XCTAssertEqual(handler.adaptedCount, 2)
  670. // XCTAssertEqual(handler.retryCount, 1)
  671. // XCTAssertEqual(response?.result.isSuccess, true)
  672. // XCTAssertTrue(sessionManager.delegate.protectedRequests.directValue.isEmpty)
  673. //
  674. // handler.retryErrors.forEach { XCTAssertFalse($0 is AdaptError) }
  675. // }
  676. //
  677. func testThatSessionManagerCallsRequestRetrierWhenUploadInitiallyEncountersAdaptError() {
  678. // Given
  679. let handler = UploadHandler()
  680. let sessionManager = SessionManager(adapter: handler, retrier: handler)
  681. let expectation = self.expectation(description: "request should eventually fail")
  682. var response: DataResponse<Any>?
  683. let uploadData = Data("upload data".utf8)
  684. // When
  685. sessionManager.upload(uploadData, to: "https://httpbin.org/post")
  686. .validate()
  687. .responseJSON { jsonResponse in
  688. response = jsonResponse
  689. expectation.fulfill()
  690. }
  691. waitForExpectations(timeout: timeout, handler: nil)
  692. // Then
  693. XCTAssertEqual(handler.adaptedCount, 2)
  694. XCTAssertEqual(handler.retryCount, 1)
  695. XCTAssertEqual(response?.result.isSuccess, true)
  696. XCTAssertTrue(sessionManager.delegate.requestTaskMap.isEmpty)
  697. }
  698. func testThatSessionManagerCallsAdapterWhenRequestIsRetried() {
  699. // Given
  700. let handler = RequestHandler()
  701. handler.shouldApplyAuthorizationHeader = true
  702. let sessionManager = SessionManager(adapter: handler, retrier: handler)
  703. let expectation = self.expectation(description: "request should eventually succeed")
  704. var response: DataResponse<Any>?
  705. // When
  706. let request = sessionManager.request("https://httpbin.org/basic-auth/user/password")
  707. .validate()
  708. .responseJSON { jsonResponse in
  709. response = jsonResponse
  710. expectation.fulfill()
  711. }
  712. waitForExpectations(timeout: timeout, handler: nil)
  713. // Then
  714. XCTAssertEqual(handler.adaptedCount, 2)
  715. XCTAssertEqual(handler.retryCount, 1)
  716. XCTAssertEqual(request.retryCount, 1)
  717. XCTAssertEqual(response?.result.isSuccess, true)
  718. XCTAssertTrue(sessionManager.delegate.requestTaskMap.isEmpty)
  719. }
  720. // func testThatRequestAdapterErrorThrowsResponseHandlerErrorWhenRequestIsRetried() {
  721. // // Given
  722. // let handler = RequestHandler()
  723. // handler.throwsErrorOnSecondAdapt = true
  724. //
  725. // let sessionManager = SessionManager(adapter: handler, retrier: handler)
  726. //
  727. // let expectation = self.expectation(description: "request should eventually fail")
  728. // var response: DataResponse<Any>?
  729. //
  730. // // When
  731. // let request = sessionManager.request("https://httpbin.org/basic-auth/user/password")
  732. // .validate()
  733. // .responseJSON { jsonResponse in
  734. // response = jsonResponse
  735. // expectation.fulfill()
  736. // }
  737. //
  738. // waitForExpectations(timeout: timeout, handler: nil)
  739. //
  740. // // Then
  741. // XCTAssertEqual(handler.adaptedCount, 1)
  742. // XCTAssertEqual(handler.retryCount, 1)
  743. // XCTAssertEqual(request.retryCount, 0)
  744. // XCTAssertEqual(response?.result.isSuccess, false)
  745. // XCTAssertTrue(sessionManager.delegate.requestTaskMap.isEmpty)
  746. //
  747. // if let error = response?.result.error as? AFError {
  748. // XCTAssertTrue(error.isInvalidURLError)
  749. // XCTAssertEqual(error.urlConvertible as? String, "")
  750. // } else {
  751. // XCTFail("error should not be nil")
  752. // }
  753. // }
  754. }
  755. // MARK: -
  756. class SessionManagerConfigurationHeadersTestCase: BaseTestCase {
  757. enum ConfigurationType {
  758. case `default`, ephemeral, background
  759. }
  760. func testThatDefaultConfigurationHeadersAreSentWithRequest() {
  761. // Given, When, Then
  762. executeAuthorizationHeaderTest(for: .default)
  763. }
  764. func testThatEphemeralConfigurationHeadersAreSentWithRequest() {
  765. // Given, When, Then
  766. executeAuthorizationHeaderTest(for: .ephemeral)
  767. }
  768. #if os(macOS)
  769. func testThatBackgroundConfigurationHeadersAreSentWithRequest() {
  770. // Given, When, Then
  771. executeAuthorizationHeaderTest(for: .background)
  772. }
  773. #endif
  774. private func executeAuthorizationHeaderTest(for type: ConfigurationType) {
  775. // Given
  776. let manager: SessionManager = {
  777. let configuration: URLSessionConfiguration = {
  778. let configuration: URLSessionConfiguration
  779. switch type {
  780. case .default:
  781. configuration = .default
  782. case .ephemeral:
  783. configuration = .ephemeral
  784. case .background:
  785. let identifier = "org.alamofire.test.manager-configuration-tests"
  786. configuration = .background(withIdentifier: identifier)
  787. }
  788. var headers = SessionManager.defaultHTTPHeaders
  789. headers["Authorization"] = "Bearer 123456"
  790. configuration.httpAdditionalHeaders = headers
  791. return configuration
  792. }()
  793. return SessionManager(configuration: configuration)
  794. }()
  795. let expectation = self.expectation(description: "request should complete successfully")
  796. var response: DataResponse<Any>?
  797. // When
  798. manager.request("https://httpbin.org/headers")
  799. .responseJSON { closureResponse in
  800. response = closureResponse
  801. expectation.fulfill()
  802. }
  803. waitForExpectations(timeout: timeout, handler: nil)
  804. // Then
  805. if let response = response {
  806. XCTAssertNotNil(response.request, "request should not be nil")
  807. XCTAssertNotNil(response.response, "response should not be nil")
  808. XCTAssertNotNil(response.data, "data should not be nil")
  809. XCTAssertTrue(response.result.isSuccess, "result should be a success")
  810. if
  811. let response = response.result.value as? [String: Any],
  812. let headers = response["headers"] as? [String: String],
  813. let authorization = headers["Authorization"]
  814. {
  815. XCTAssertEqual(authorization, "Bearer 123456", "authorization header value does not match")
  816. } else {
  817. XCTFail("failed to extract authorization header value")
  818. }
  819. } else {
  820. XCTFail("response should not be nil")
  821. }
  822. }
  823. }