SessionManagerTests.swift 28 KB

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