SessionManagerTests.swift 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
  1. //
  2. // SessionManagerTests.swift
  3. //
  4. // Copyright (c) 2014-2016 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 shouldApplyAuthorizationHeader = false
  47. var throwsErrorOnSecondAdapt = false
  48. func adapt(_ urlRequest: URLRequest) throws -> URLRequest {
  49. if throwsErrorOnSecondAdapt && adaptedCount == 1 {
  50. throwsErrorOnSecondAdapt = false
  51. throw AFError.invalidURL(url: "")
  52. }
  53. var urlRequest = urlRequest
  54. adaptedCount += 1
  55. if shouldApplyAuthorizationHeader && adaptedCount > 1 {
  56. if let header = Request.authorizationHeader(user: "user", password: "password") {
  57. urlRequest.setValue(header.value, forHTTPHeaderField: header.key)
  58. }
  59. }
  60. return urlRequest
  61. }
  62. func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion) {
  63. retryCount += 1
  64. if retryCount < 2 {
  65. completion(true, 0.0)
  66. } else {
  67. completion(false, 0.0)
  68. }
  69. }
  70. }
  71. private class UploadHandler: RequestAdapter, RequestRetrier {
  72. var adaptedCount = 0
  73. var retryCount = 0
  74. func adapt(_ urlRequest: URLRequest) throws -> URLRequest {
  75. adaptedCount += 1
  76. if adaptedCount == 1 { throw AFError.invalidURL(url: "") }
  77. return urlRequest
  78. }
  79. func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion) {
  80. retryCount += 1
  81. completion(true, 0.0)
  82. }
  83. }
  84. // MARK: Tests - Initialization
  85. func testInitializerWithDefaultArguments() {
  86. // Given, When
  87. let manager = SessionManager()
  88. // Then
  89. XCTAssertNotNil(manager.session.delegate, "session delegate should not be nil")
  90. XCTAssertTrue(manager.delegate === manager.session.delegate, "manager delegate should equal session delegate")
  91. XCTAssertNil(manager.session.serverTrustPolicyManager, "session server trust policy manager should be nil")
  92. }
  93. func testInitializerWithSpecifiedArguments() {
  94. // Given
  95. let configuration = URLSessionConfiguration.default
  96. let delegate = SessionDelegate()
  97. let serverTrustPolicyManager = ServerTrustPolicyManager(policies: [:])
  98. // When
  99. let manager = SessionManager(
  100. configuration: configuration,
  101. delegate: delegate,
  102. serverTrustPolicyManager: serverTrustPolicyManager
  103. )
  104. // Then
  105. XCTAssertNotNil(manager.session.delegate, "session delegate should not be nil")
  106. XCTAssertTrue(manager.delegate === manager.session.delegate, "manager delegate should equal session delegate")
  107. XCTAssertNotNil(manager.session.serverTrustPolicyManager, "session server trust policy manager should not be nil")
  108. }
  109. func testThatFailableInitializerSucceedsWithDefaultArguments() {
  110. // Given
  111. let delegate = SessionDelegate()
  112. let session: URLSession = {
  113. let configuration = URLSessionConfiguration.default
  114. return URLSession(configuration: configuration, delegate: delegate, delegateQueue: nil)
  115. }()
  116. // When
  117. let manager = SessionManager(session: session, delegate: delegate)
  118. // Then
  119. if let manager = manager {
  120. XCTAssertTrue(manager.delegate === manager.session.delegate, "manager delegate should equal session delegate")
  121. XCTAssertNil(manager.session.serverTrustPolicyManager, "session server trust policy manager should be nil")
  122. } else {
  123. XCTFail("manager should not be nil")
  124. }
  125. }
  126. func testThatFailableInitializerSucceedsWithSpecifiedArguments() {
  127. // Given
  128. let delegate = SessionDelegate()
  129. let session: URLSession = {
  130. let configuration = URLSessionConfiguration.default
  131. return URLSession(configuration: configuration, delegate: delegate, delegateQueue: nil)
  132. }()
  133. let serverTrustPolicyManager = ServerTrustPolicyManager(policies: [:])
  134. // When
  135. let manager = SessionManager(session: session, delegate: delegate, serverTrustPolicyManager: serverTrustPolicyManager)
  136. // Then
  137. if let manager = manager {
  138. XCTAssertTrue(manager.delegate === manager.session.delegate, "manager delegate should equal session delegate")
  139. XCTAssertNotNil(manager.session.serverTrustPolicyManager, "session server trust policy manager should not be nil")
  140. } else {
  141. XCTFail("manager should not be nil")
  142. }
  143. }
  144. func testThatFailableInitializerFailsWithWhenDelegateDoesNotEqualSessionDelegate() {
  145. // Given
  146. let delegate = SessionDelegate()
  147. let session: URLSession = {
  148. let configuration = URLSessionConfiguration.default
  149. return URLSession(configuration: configuration, delegate: SessionDelegate(), delegateQueue: nil)
  150. }()
  151. // When
  152. let manager = SessionManager(session: session, delegate: delegate)
  153. // Then
  154. XCTAssertNil(manager, "manager should be nil")
  155. }
  156. func testThatFailableInitializerFailsWhenSessionDelegateIsNil() {
  157. // Given
  158. let delegate = SessionDelegate()
  159. let session: URLSession = {
  160. let configuration = URLSessionConfiguration.default
  161. return URLSession(configuration: configuration, delegate: nil, delegateQueue: nil)
  162. }()
  163. // When
  164. let manager = SessionManager(session: session, delegate: delegate)
  165. // Then
  166. XCTAssertNil(manager, "manager should be nil")
  167. }
  168. // MARK: Tests - Default HTTP Headers
  169. func testDefaultUserAgentHeader() {
  170. // Given, When
  171. let userAgent = SessionManager.defaultHTTPHeaders["User-Agent"]
  172. // Then
  173. let osNameVersion: String = {
  174. let version = ProcessInfo.processInfo.operatingSystemVersion
  175. let versionString = "\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)"
  176. let osName: String = {
  177. #if os(iOS)
  178. return "iOS"
  179. #elseif os(watchOS)
  180. return "watchOS"
  181. #elseif os(tvOS)
  182. return "tvOS"
  183. #elseif os(macOS)
  184. return "OS X"
  185. #elseif os(Linux)
  186. return "Linux"
  187. #else
  188. return "Unknown"
  189. #endif
  190. }()
  191. return "\(osName) \(versionString)"
  192. }()
  193. let alamofireVersion: String = {
  194. guard
  195. let afInfo = Bundle(for: SessionManager.self).infoDictionary,
  196. let build = afInfo["CFBundleShortVersionString"]
  197. else { return "Unknown" }
  198. return "Alamofire/\(build)"
  199. }()
  200. let expectedUserAgent = "Unknown/Unknown (Unknown; build:Unknown; \(osNameVersion)) \(alamofireVersion)"
  201. XCTAssertEqual(userAgent, expectedUserAgent)
  202. }
  203. // MARK: Tests - Start Requests Immediately
  204. func testSetStartRequestsImmediatelyToFalseAndResumeRequest() {
  205. // Given
  206. let manager = SessionManager()
  207. manager.startRequestsImmediately = false
  208. let url = URL(string: "https://httpbin.org/get")!
  209. let urlRequest = URLRequest(url: url)
  210. let expectation = self.expectation(description: "\(url)")
  211. var response: HTTPURLResponse?
  212. // When
  213. manager.request(urlRequest)
  214. .response { resp in
  215. response = resp.response
  216. expectation.fulfill()
  217. }
  218. .resume()
  219. waitForExpectations(timeout: timeout, handler: nil)
  220. // Then
  221. XCTAssertNotNil(response, "response should not be nil")
  222. XCTAssertTrue(response?.statusCode == 200, "response status code should be 200")
  223. }
  224. // MARK: Tests - Deinitialization
  225. func testReleasingManagerWithPendingRequestDeinitializesSuccessfully() {
  226. // Given
  227. var manager: SessionManager? = SessionManager()
  228. manager?.startRequestsImmediately = false
  229. let url = URL(string: "https://httpbin.org/get")!
  230. let urlRequest = URLRequest(url: url)
  231. // When
  232. let request = manager?.request(urlRequest)
  233. manager = nil
  234. // Then
  235. XCTAssertTrue(request?.task?.state == .suspended, "request task state should be '.Suspended'")
  236. XCTAssertNil(manager, "manager should be nil")
  237. }
  238. func testReleasingManagerWithPendingCanceledRequestDeinitializesSuccessfully() {
  239. // Given
  240. var manager: SessionManager? = SessionManager()
  241. manager!.startRequestsImmediately = false
  242. let url = URL(string: "https://httpbin.org/get")!
  243. let urlRequest = URLRequest(url: url)
  244. // When
  245. let request = manager!.request(urlRequest)
  246. request.cancel()
  247. manager = nil
  248. // Then
  249. let state = request.task?.state
  250. XCTAssertTrue(state == .canceling || state == .completed, "state should be .Canceling or .Completed")
  251. XCTAssertNil(manager, "manager should be nil")
  252. }
  253. // MARK: Tests - Bad Requests
  254. func testThatDataRequestWithInvalidURLStringThrowsResponseHandlerError() {
  255. // Given
  256. let sessionManager = SessionManager()
  257. let expectation = self.expectation(description: "Request should fail with error")
  258. var response: DefaultDataResponse?
  259. // When
  260. sessionManager.request("https://httpbin.org/get/äëïöü").response { resp in
  261. response = resp
  262. expectation.fulfill()
  263. }
  264. waitForExpectations(timeout: timeout, handler: nil)
  265. // Then
  266. XCTAssertNil(response?.request)
  267. XCTAssertNil(response?.response)
  268. XCTAssertNotNil(response?.data)
  269. XCTAssertEqual(response?.data?.count, 0)
  270. XCTAssertNotNil(response?.error)
  271. if let error = response?.error as? AFError {
  272. XCTAssertTrue(error.isInvalidURLError)
  273. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  274. } else {
  275. XCTFail("error should not be nil")
  276. }
  277. }
  278. func testThatDownloadRequestWithInvalidURLStringThrowsResponseHandlerError() {
  279. // Given
  280. let sessionManager = SessionManager()
  281. let expectation = self.expectation(description: "Download should fail with error")
  282. var response: DefaultDownloadResponse?
  283. // When
  284. sessionManager.download("https://httpbin.org/get/äëïöü").response { resp in
  285. response = resp
  286. expectation.fulfill()
  287. }
  288. waitForExpectations(timeout: timeout, handler: nil)
  289. // Then
  290. XCTAssertNil(response?.request)
  291. XCTAssertNil(response?.response)
  292. XCTAssertNil(response?.temporaryURL)
  293. XCTAssertNil(response?.destinationURL)
  294. XCTAssertNil(response?.resumeData)
  295. XCTAssertNotNil(response?.error)
  296. if let error = response?.error as? AFError {
  297. XCTAssertTrue(error.isInvalidURLError)
  298. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  299. } else {
  300. XCTFail("error should not be nil")
  301. }
  302. }
  303. func testThatUploadDataRequestWithInvalidURLStringThrowsResponseHandlerError() {
  304. // Given
  305. let sessionManager = SessionManager()
  306. let expectation = self.expectation(description: "Upload should fail with error")
  307. var response: DefaultDataResponse?
  308. // When
  309. sessionManager.upload(Data(), to: "https://httpbin.org/get/äëïöü").response { resp in
  310. response = resp
  311. expectation.fulfill()
  312. }
  313. waitForExpectations(timeout: timeout, handler: nil)
  314. // Then
  315. XCTAssertNil(response?.request)
  316. XCTAssertNil(response?.response)
  317. XCTAssertNotNil(response?.data)
  318. XCTAssertEqual(response?.data?.count, 0)
  319. XCTAssertNotNil(response?.error)
  320. if let error = response?.error as? AFError {
  321. XCTAssertTrue(error.isInvalidURLError)
  322. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  323. } else {
  324. XCTFail("error should not be nil")
  325. }
  326. }
  327. func testThatUploadFileRequestWithInvalidURLStringThrowsResponseHandlerError() {
  328. // Given
  329. let sessionManager = SessionManager()
  330. let expectation = self.expectation(description: "Upload should fail with error")
  331. var response: DefaultDataResponse?
  332. // When
  333. sessionManager.upload(URL(fileURLWithPath: "/invalid"), to: "https://httpbin.org/get/äëïöü").response { resp in
  334. response = resp
  335. expectation.fulfill()
  336. }
  337. waitForExpectations(timeout: timeout, handler: nil)
  338. // Then
  339. XCTAssertNil(response?.request)
  340. XCTAssertNil(response?.response)
  341. XCTAssertNotNil(response?.data)
  342. XCTAssertEqual(response?.data?.count, 0)
  343. XCTAssertNotNil(response?.error)
  344. if let error = response?.error as? AFError {
  345. XCTAssertTrue(error.isInvalidURLError)
  346. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  347. } else {
  348. XCTFail("error should not be nil")
  349. }
  350. }
  351. func testThatUploadStreamRequestWithInvalidURLStringThrowsResponseHandlerError() {
  352. // Given
  353. let sessionManager = SessionManager()
  354. let expectation = self.expectation(description: "Upload should fail with error")
  355. var response: DefaultDataResponse?
  356. // When
  357. sessionManager.upload(InputStream(data: Data()), to: "https://httpbin.org/get/äëïöü").response { resp in
  358. response = resp
  359. expectation.fulfill()
  360. }
  361. waitForExpectations(timeout: timeout, handler: nil)
  362. // Then
  363. XCTAssertNil(response?.request)
  364. XCTAssertNil(response?.response)
  365. XCTAssertNotNil(response?.data)
  366. XCTAssertEqual(response?.data?.count, 0)
  367. XCTAssertNotNil(response?.error)
  368. if let error = response?.error as? AFError {
  369. XCTAssertTrue(error.isInvalidURLError)
  370. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  371. } else {
  372. XCTFail("error should not be nil")
  373. }
  374. }
  375. // MARK: Tests - Request Adapter
  376. func testThatSessionManagerCallsRequestAdapterWhenCreatingDataRequest() {
  377. // Given
  378. let adapter = HTTPMethodAdapter(method: .post)
  379. let sessionManager = SessionManager()
  380. sessionManager.adapter = adapter
  381. sessionManager.startRequestsImmediately = false
  382. // When
  383. let request = sessionManager.request("https://httpbin.org/get")
  384. // Then
  385. XCTAssertEqual(request.task?.originalRequest?.httpMethod, adapter.method.rawValue)
  386. }
  387. func testThatSessionManagerCallsRequestAdapterWhenCreatingDownloadRequest() {
  388. // Given
  389. let adapter = HTTPMethodAdapter(method: .post)
  390. let sessionManager = SessionManager()
  391. sessionManager.adapter = adapter
  392. sessionManager.startRequestsImmediately = false
  393. // When
  394. let destination = DownloadRequest.suggestedDownloadDestination()
  395. let request = sessionManager.download("https://httpbin.org/get", to: destination)
  396. // Then
  397. XCTAssertEqual(request.task?.originalRequest?.httpMethod, adapter.method.rawValue)
  398. }
  399. func testThatSessionManagerCallsRequestAdapterWhenCreatingUploadRequestWithData() {
  400. // Given
  401. let adapter = HTTPMethodAdapter(method: .get)
  402. let sessionManager = SessionManager()
  403. sessionManager.adapter = adapter
  404. sessionManager.startRequestsImmediately = false
  405. // When
  406. let request = sessionManager.upload("data".data(using: .utf8)!, to: "https://httpbin.org/post")
  407. // Then
  408. XCTAssertEqual(request.task?.originalRequest?.httpMethod, adapter.method.rawValue)
  409. }
  410. func testThatSessionManagerCallsRequestAdapterWhenCreatingUploadRequestWithFile() {
  411. // Given
  412. let adapter = HTTPMethodAdapter(method: .get)
  413. let sessionManager = SessionManager()
  414. sessionManager.adapter = adapter
  415. sessionManager.startRequestsImmediately = false
  416. // When
  417. let fileURL = URL(fileURLWithPath: "/path/to/some/file.txt")
  418. let request = sessionManager.upload(fileURL, to: "https://httpbin.org/post")
  419. // Then
  420. XCTAssertEqual(request.task?.originalRequest?.httpMethod, adapter.method.rawValue)
  421. }
  422. func testThatSessionManagerCallsRequestAdapterWhenCreatingUploadRequestWithInputStream() {
  423. // Given
  424. let adapter = HTTPMethodAdapter(method: .get)
  425. let sessionManager = SessionManager()
  426. sessionManager.adapter = adapter
  427. sessionManager.startRequestsImmediately = false
  428. // When
  429. let inputStream = InputStream(data: "data".data(using: .utf8)!)
  430. let request = sessionManager.upload(inputStream, to: "https://httpbin.org/post")
  431. // Then
  432. XCTAssertEqual(request.task?.originalRequest?.httpMethod, adapter.method.rawValue)
  433. }
  434. func testThatRequestAdapterErrorThrowsResponseHandlerError() {
  435. // Given
  436. let adapter = HTTPMethodAdapter(method: .post, throwsError: true)
  437. let sessionManager = SessionManager()
  438. sessionManager.adapter = adapter
  439. sessionManager.startRequestsImmediately = false
  440. // When
  441. let request = sessionManager.request("https://httpbin.org/get")
  442. // Then
  443. if let error = request.delegate.error as? AFError {
  444. XCTAssertTrue(error.isInvalidURLError)
  445. XCTAssertEqual(error.urlConvertible as? String, "")
  446. } else {
  447. XCTFail("error should not be nil")
  448. }
  449. }
  450. // MARK: Tests - Request Retrier
  451. func testThatSessionManagerCallsRequestRetrierWhenRequestEncountersError() {
  452. // Given
  453. let handler = RequestHandler()
  454. let sessionManager = SessionManager()
  455. sessionManager.adapter = handler
  456. sessionManager.retrier = handler
  457. let expectation = self.expectation(description: "request should eventually fail")
  458. var response: DataResponse<Any>?
  459. // When
  460. let request = sessionManager.request("https://httpbin.org/basic-auth/user/password")
  461. .validate()
  462. .responseJSON { jsonResponse in
  463. response = jsonResponse
  464. expectation.fulfill()
  465. }
  466. waitForExpectations(timeout: timeout, handler: nil)
  467. // Then
  468. XCTAssertEqual(handler.adaptedCount, 2)
  469. XCTAssertEqual(handler.retryCount, 2)
  470. XCTAssertEqual(request.retryCount, 1)
  471. XCTAssertEqual(response?.result.isSuccess, false)
  472. }
  473. func testThatSessionManagerCallsRequestRetrierWhenRequestInitiallyEncountersAdaptError() {
  474. // Given
  475. let handler = RequestHandler()
  476. handler.adaptedCount = 1
  477. handler.throwsErrorOnSecondAdapt = true
  478. handler.shouldApplyAuthorizationHeader = true
  479. let sessionManager = SessionManager()
  480. sessionManager.adapter = handler
  481. sessionManager.retrier = handler
  482. let expectation = self.expectation(description: "request should eventually fail")
  483. var response: DataResponse<Any>?
  484. // When
  485. sessionManager.request("https://httpbin.org/basic-auth/user/password")
  486. .validate()
  487. .responseJSON { jsonResponse in
  488. response = jsonResponse
  489. expectation.fulfill()
  490. }
  491. waitForExpectations(timeout: timeout, handler: nil)
  492. // Then
  493. XCTAssertEqual(handler.adaptedCount, 2)
  494. XCTAssertEqual(handler.retryCount, 1)
  495. XCTAssertEqual(response?.result.isSuccess, true)
  496. }
  497. func testThatSessionManagerCallsRequestRetrierWhenDownloadInitiallyEncountersAdaptError() {
  498. // Given
  499. let handler = RequestHandler()
  500. handler.adaptedCount = 1
  501. handler.throwsErrorOnSecondAdapt = true
  502. handler.shouldApplyAuthorizationHeader = true
  503. let sessionManager = SessionManager()
  504. sessionManager.adapter = handler
  505. sessionManager.retrier = handler
  506. let expectation = self.expectation(description: "request should eventually fail")
  507. var response: DownloadResponse<Any>?
  508. let destination: DownloadRequest.DownloadFileDestination = { _, _ in
  509. let fileURL = self.testDirectoryURL.appendingPathComponent("test-output.json")
  510. return (fileURL, [.removePreviousFile])
  511. }
  512. // When
  513. sessionManager.download("https://httpbin.org/basic-auth/user/password", to: destination)
  514. .validate()
  515. .responseJSON { jsonResponse in
  516. response = jsonResponse
  517. expectation.fulfill()
  518. }
  519. waitForExpectations(timeout: timeout, handler: nil)
  520. // Then
  521. XCTAssertEqual(handler.adaptedCount, 2)
  522. XCTAssertEqual(handler.retryCount, 1)
  523. XCTAssertEqual(response?.result.isSuccess, true)
  524. }
  525. func testThatSessionManagerCallsRequestRetrierWhenUploadInitiallyEncountersAdaptError() {
  526. // Given
  527. let handler = UploadHandler()
  528. let sessionManager = SessionManager()
  529. sessionManager.adapter = handler
  530. sessionManager.retrier = handler
  531. let expectation = self.expectation(description: "request should eventually fail")
  532. var response: DataResponse<Any>?
  533. let uploadData = "upload data".data(using: .utf8, allowLossyConversion: false)!
  534. // When
  535. sessionManager.upload(uploadData, to: "https://httpbin.org/post")
  536. .validate()
  537. .responseJSON { jsonResponse in
  538. response = jsonResponse
  539. expectation.fulfill()
  540. }
  541. waitForExpectations(timeout: timeout, handler: nil)
  542. // Then
  543. XCTAssertEqual(handler.adaptedCount, 2)
  544. XCTAssertEqual(handler.retryCount, 1)
  545. XCTAssertEqual(response?.result.isSuccess, true)
  546. }
  547. func testThatSessionManagerCallsAdapterWhenRequestIsRetried() {
  548. // Given
  549. let handler = RequestHandler()
  550. handler.shouldApplyAuthorizationHeader = true
  551. let sessionManager = SessionManager()
  552. sessionManager.adapter = handler
  553. sessionManager.retrier = handler
  554. let expectation = self.expectation(description: "request should eventually fail")
  555. var response: DataResponse<Any>?
  556. // When
  557. let request = sessionManager.request("https://httpbin.org/basic-auth/user/password")
  558. .validate()
  559. .responseJSON { jsonResponse in
  560. response = jsonResponse
  561. expectation.fulfill()
  562. }
  563. waitForExpectations(timeout: timeout, handler: nil)
  564. // Then
  565. XCTAssertEqual(handler.adaptedCount, 2)
  566. XCTAssertEqual(handler.retryCount, 1)
  567. XCTAssertEqual(request.retryCount, 1)
  568. XCTAssertEqual(response?.result.isSuccess, true)
  569. }
  570. func testThatRequestAdapterErrorThrowsResponseHandlerErrorWhenRequestIsRetried() {
  571. // Given
  572. let handler = RequestHandler()
  573. handler.throwsErrorOnSecondAdapt = true
  574. let sessionManager = SessionManager()
  575. sessionManager.adapter = handler
  576. sessionManager.retrier = handler
  577. let expectation = self.expectation(description: "request should eventually fail")
  578. var response: DataResponse<Any>?
  579. // When
  580. let request = sessionManager.request("https://httpbin.org/basic-auth/user/password")
  581. .validate()
  582. .responseJSON { jsonResponse in
  583. response = jsonResponse
  584. expectation.fulfill()
  585. }
  586. waitForExpectations(timeout: timeout, handler: nil)
  587. // Then
  588. XCTAssertEqual(handler.adaptedCount, 1)
  589. XCTAssertEqual(handler.retryCount, 1)
  590. XCTAssertEqual(request.retryCount, 0)
  591. XCTAssertEqual(response?.result.isSuccess, false)
  592. if let error = response?.result.error as? AFError {
  593. XCTAssertTrue(error.isInvalidURLError)
  594. XCTAssertEqual(error.urlConvertible as? String, "")
  595. } else {
  596. XCTFail("error should not be nil")
  597. }
  598. }
  599. }
  600. // MARK: -
  601. class SessionManagerConfigurationHeadersTestCase: BaseTestCase {
  602. enum ConfigurationType {
  603. case `default`, ephemeral, background
  604. }
  605. func testThatDefaultConfigurationHeadersAreSentWithRequest() {
  606. // Given, When, Then
  607. executeAuthorizationHeaderTest(for: .default)
  608. }
  609. func testThatEphemeralConfigurationHeadersAreSentWithRequest() {
  610. // Given, When, Then
  611. executeAuthorizationHeaderTest(for: .ephemeral)
  612. }
  613. // ⚠️ This test has been removed as a result of rdar://26870455 in Xcode 8 Seed 1
  614. // func testThatBackgroundConfigurationHeadersAreSentWithRequest() {
  615. // // Given, When, Then
  616. // executeAuthorizationHeaderTest(for: .background)
  617. // }
  618. private func executeAuthorizationHeaderTest(for type: ConfigurationType) {
  619. // Given
  620. let manager: SessionManager = {
  621. let configuration: URLSessionConfiguration = {
  622. let configuration: URLSessionConfiguration
  623. switch type {
  624. case .default:
  625. configuration = .default
  626. case .ephemeral:
  627. configuration = .ephemeral
  628. case .background:
  629. let identifier = "org.alamofire.test.manager-configuration-tests"
  630. configuration = .background(withIdentifier: identifier)
  631. }
  632. var headers = SessionManager.defaultHTTPHeaders
  633. headers["Authorization"] = "Bearer 123456"
  634. configuration.httpAdditionalHeaders = headers
  635. return configuration
  636. }()
  637. return SessionManager(configuration: configuration)
  638. }()
  639. let expectation = self.expectation(description: "request should complete successfully")
  640. var response: DataResponse<Any>?
  641. // When
  642. manager.request("https://httpbin.org/headers")
  643. .responseJSON { closureResponse in
  644. response = closureResponse
  645. expectation.fulfill()
  646. }
  647. waitForExpectations(timeout: timeout, handler: nil)
  648. // Then
  649. if let response = response {
  650. XCTAssertNotNil(response.request, "request should not be nil")
  651. XCTAssertNotNil(response.response, "response should not be nil")
  652. XCTAssertNotNil(response.data, "data should not be nil")
  653. XCTAssertTrue(response.result.isSuccess, "result should be a success")
  654. // The `as NSString` cast is necessary due to a compiler bug. See the following rdar for more info.
  655. // - https://openradar.appspot.com/radar?id=5517037090635776
  656. if
  657. let headers = (response.result.value as AnyObject?)?["headers" as NSString] as? [String: String],
  658. let authorization = headers["Authorization"]
  659. {
  660. XCTAssertEqual(authorization, "Bearer 123456", "authorization header value does not match")
  661. } else {
  662. XCTFail("failed to extract authorization header value")
  663. }
  664. } else {
  665. XCTFail("response should not be nil")
  666. }
  667. }
  668. }