SessionManagerTests.swift 31 KB

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