SessionTests.swift 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521
  1. //
  2. // SessionTests.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 SessionTestCase: BaseTestCase {
  28. // MARK: Helper Types
  29. private class HTTPMethodAdapter: RequestInterceptor {
  30. let method: HTTPMethod
  31. let throwsError: Bool
  32. var adaptedCount = 0
  33. init(method: HTTPMethod, throwsError: Bool = false) {
  34. self.method = method
  35. self.throwsError = throwsError
  36. }
  37. func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest>) -> Void) {
  38. adaptedCount += 1
  39. let result: Result<URLRequest> = Result {
  40. guard !throwsError else { throw AFError.invalidURL(url: "") }
  41. var urlRequest = urlRequest
  42. urlRequest.httpMethod = method.rawValue
  43. return urlRequest
  44. }
  45. completion(result)
  46. }
  47. }
  48. private class HeaderAdapter: RequestInterceptor {
  49. let headers: HTTPHeaders
  50. let throwsError: Bool
  51. var adaptedCount = 0
  52. init(headers: HTTPHeaders = ["field": "value"], throwsError: Bool = false) {
  53. self.headers = headers
  54. self.throwsError = throwsError
  55. }
  56. func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest>) -> Void) {
  57. adaptedCount += 1
  58. let result: Result<URLRequest> = Result {
  59. guard !throwsError else { throw AFError.invalidURL(url: "") }
  60. var urlRequest = urlRequest
  61. var finalHeaders = urlRequest.httpHeaders
  62. headers.forEach { finalHeaders.add($0) }
  63. urlRequest.httpHeaders = finalHeaders
  64. return urlRequest
  65. }
  66. completion(result)
  67. }
  68. }
  69. private class RequestHandler: RequestInterceptor {
  70. var adaptCalledCount = 0
  71. var adaptedCount = 0
  72. var retryCount = 0
  73. var retryCalledCount = 0
  74. var retryErrors: [Error] = []
  75. var shouldApplyAuthorizationHeader = false
  76. var throwsErrorOnFirstAdapt = false
  77. var throwsErrorOnSecondAdapt = false
  78. var throwsErrorOnRetry = false
  79. var shouldRetry = true
  80. var retryDelay: TimeInterval?
  81. func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest>) -> Void) {
  82. adaptCalledCount += 1
  83. let result: Result<URLRequest> = Result {
  84. if throwsErrorOnFirstAdapt {
  85. throwsErrorOnFirstAdapt = false
  86. throw AFError.invalidURL(url: "/adapt/error/1")
  87. }
  88. if throwsErrorOnSecondAdapt && adaptedCount == 1 {
  89. throwsErrorOnSecondAdapt = false
  90. throw AFError.invalidURL(url: "/adapt/error/2")
  91. }
  92. var urlRequest = urlRequest
  93. adaptedCount += 1
  94. if shouldApplyAuthorizationHeader && adaptedCount > 1 {
  95. urlRequest.httpHeaders.update(.authorization(username: "user", password: "password"))
  96. }
  97. return urlRequest
  98. }
  99. completion(result)
  100. }
  101. func retry(
  102. _ request: Request,
  103. for session: Session,
  104. dueTo error: Error,
  105. completion: @escaping (RetryResult) -> Void)
  106. {
  107. retryCalledCount += 1
  108. if throwsErrorOnRetry {
  109. let error = AFError.invalidURL(url: "/invalid/url/\(retryCalledCount)")
  110. completion(.doNotRetryWithError(error))
  111. return
  112. }
  113. guard shouldRetry else { completion(.doNotRetry); return }
  114. retryCount += 1
  115. retryErrors.append(error)
  116. if retryCount < 2 {
  117. if let retryDelay = retryDelay {
  118. completion(.retryWithDelay(retryDelay))
  119. } else {
  120. completion(.retry)
  121. }
  122. } else {
  123. completion(.doNotRetry)
  124. }
  125. }
  126. }
  127. private class UploadHandler: RequestInterceptor {
  128. var adaptCalledCount = 0
  129. var adaptedCount = 0
  130. var retryCalledCount = 0
  131. var retryCount = 0
  132. var retryErrors: [Error] = []
  133. func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest>) -> Void) {
  134. adaptCalledCount += 1
  135. let result: Result<URLRequest> = Result {
  136. adaptedCount += 1
  137. if adaptedCount == 1 { throw AFError.invalidURL(url: "") }
  138. return urlRequest
  139. }
  140. completion(result)
  141. }
  142. func retry(
  143. _ request: Request,
  144. for session: Session,
  145. dueTo error: Error,
  146. completion: @escaping (RetryResult) -> Void)
  147. {
  148. retryCalledCount += 1
  149. retryCount += 1
  150. retryErrors.append(error)
  151. completion(.retry)
  152. }
  153. }
  154. // MARK: Tests - Initialization
  155. func testInitializerWithDefaultArguments() {
  156. // Given, When
  157. let session = Session()
  158. // Then
  159. XCTAssertNotNil(session.session.delegate, "session delegate should not be nil")
  160. XCTAssertTrue(session.delegate === session.session.delegate, "manager delegate should equal session delegate")
  161. XCTAssertNil(session.serverTrustManager, "session server trust policy manager should be nil")
  162. }
  163. func testInitializerWithSpecifiedArguments() {
  164. // Given
  165. let configuration = URLSessionConfiguration.default
  166. let delegate = SessionDelegate()
  167. let serverTrustManager = ServerTrustManager(evaluators: [:])
  168. // When
  169. let session = Session(configuration: configuration,
  170. delegate: delegate,
  171. serverTrustManager: serverTrustManager)
  172. // Then
  173. XCTAssertNotNil(session.session.delegate, "session delegate should not be nil")
  174. XCTAssertTrue(session.delegate === session.session.delegate, "manager delegate should equal session delegate")
  175. XCTAssertNotNil(session.serverTrustManager, "session server trust policy manager should not be nil")
  176. }
  177. func testThatSessionInitializerSucceedsWithDefaultArguments() {
  178. // Given
  179. let delegate = SessionDelegate()
  180. let underlyingQueue = DispatchQueue(label: "underlyingQueue")
  181. let urlSession: URLSession = {
  182. let configuration = URLSessionConfiguration.default
  183. let queue = OperationQueue(underlyingQueue: underlyingQueue, name: "delegateQueue")
  184. return URLSession(configuration: configuration, delegate: delegate, delegateQueue: queue)
  185. }()
  186. // When
  187. let session = Session(session: urlSession, delegate: delegate, rootQueue: underlyingQueue)
  188. // Then
  189. XCTAssertTrue(session.delegate === session.session.delegate, "manager delegate should equal session delegate")
  190. XCTAssertNil(session.serverTrustManager, "session server trust policy manager should be nil")
  191. }
  192. func testThatSessionInitializerSucceedsWithSpecifiedArguments() {
  193. // Given
  194. let delegate = SessionDelegate()
  195. let underlyingQueue = DispatchQueue(label: "underlyingQueue")
  196. let urlSession: URLSession = {
  197. let configuration = URLSessionConfiguration.default
  198. let queue = OperationQueue(underlyingQueue: underlyingQueue, name: "delegateQueue")
  199. return URLSession(configuration: configuration, delegate: delegate, delegateQueue: queue)
  200. }()
  201. let serverTrustManager = ServerTrustManager(evaluators: [:])
  202. // When
  203. let session = Session(session: urlSession,
  204. delegate: delegate,
  205. rootQueue: underlyingQueue,
  206. serverTrustManager: serverTrustManager)
  207. // Then
  208. XCTAssertTrue(session.delegate === session.session.delegate, "manager delegate should equal session delegate")
  209. XCTAssertNotNil(session.serverTrustManager, "session server trust policy manager should not be nil")
  210. }
  211. // MARK: Tests - Default HTTP Headers
  212. func testDefaultUserAgentHeader() {
  213. // Given, When
  214. let userAgent = HTTPHeaders.default["User-Agent"]
  215. // Then
  216. let osNameVersion: String = {
  217. let version = ProcessInfo.processInfo.operatingSystemVersion
  218. let versionString = "\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)"
  219. let osName: String = {
  220. #if os(iOS)
  221. return "iOS"
  222. #elseif os(watchOS)
  223. return "watchOS"
  224. #elseif os(tvOS)
  225. return "tvOS"
  226. #elseif os(macOS)
  227. return "macOS"
  228. #elseif os(Linux)
  229. return "Linux"
  230. #else
  231. return "Unknown"
  232. #endif
  233. }()
  234. return "\(osName) \(versionString)"
  235. }()
  236. let alamofireVersion: String = {
  237. guard
  238. let afInfo = Bundle(for: Session.self).infoDictionary,
  239. let build = afInfo["CFBundleShortVersionString"]
  240. else { return "Unknown" }
  241. return "Alamofire/\(build)"
  242. }()
  243. let expectedUserAgent = "Unknown/Unknown (Unknown; build:Unknown; \(osNameVersion)) \(alamofireVersion)"
  244. XCTAssertEqual(userAgent, expectedUserAgent)
  245. }
  246. // MARK: Tests - Supported Accept-Encodings
  247. func testDefaultAcceptEncodingSupportsAppropriateEncodingsOnAppropriateSystems() {
  248. // Given
  249. let brotliURL = URL(string: "https://httpbin.org/brotli")!
  250. let gzipURL = URL(string: "https://httpbin.org/gzip")!
  251. let deflateURL = URL(string: "https://httpbin.org/deflate")!
  252. let brotliExpectation = expectation(description: "brotli request should complete")
  253. let gzipExpectation = expectation(description: "gzip request should complete")
  254. let deflateExpectation = expectation(description: "deflate request should complete")
  255. var brotliResponse: DataResponse<Any>?
  256. var gzipResponse: DataResponse<Any>?
  257. var deflateResponse: DataResponse<Any>?
  258. // When
  259. AF.request(brotliURL).responseJSON { response in
  260. brotliResponse = response
  261. brotliExpectation.fulfill()
  262. }
  263. AF.request(gzipURL).responseJSON { response in
  264. gzipResponse = response
  265. gzipExpectation.fulfill()
  266. }
  267. AF.request(deflateURL).responseJSON { response in
  268. deflateResponse = response
  269. deflateExpectation.fulfill()
  270. }
  271. waitForExpectations(timeout: timeout, handler: nil)
  272. // Then
  273. if #available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, *) {
  274. XCTAssertTrue(brotliResponse?.result.isSuccess == true)
  275. } else {
  276. XCTAssertTrue(brotliResponse?.result.isFailure == true)
  277. }
  278. XCTAssertTrue(gzipResponse?.result.isSuccess == true)
  279. XCTAssertTrue(deflateResponse?.result.isSuccess == true)
  280. }
  281. // MARK: Tests - Start Requests Immediately
  282. func testSetStartRequestsImmediatelyToFalseAndResumeRequest() {
  283. // Given
  284. let session = Session(startRequestsImmediately: false)
  285. let url = URL(string: "https://httpbin.org/get")!
  286. let urlRequest = URLRequest(url: url)
  287. let expectation = self.expectation(description: "\(url)")
  288. var response: HTTPURLResponse?
  289. // When
  290. session.request(urlRequest)
  291. .response { resp in
  292. response = resp.response
  293. expectation.fulfill()
  294. }
  295. .resume()
  296. waitForExpectations(timeout: timeout, handler: nil)
  297. // Then
  298. XCTAssertNotNil(response, "response should not be nil")
  299. XCTAssertTrue(response?.statusCode == 200, "response status code should be 200")
  300. }
  301. func testSetStartRequestsImmediatelyToFalseAndCancelledCallsResponseHandlers() {
  302. // Given
  303. let session = Session(startRequestsImmediately: false)
  304. let url = URL(string: "https://httpbin.org/get")!
  305. let urlRequest = URLRequest(url: url)
  306. let expectation = self.expectation(description: "\(url)")
  307. var response: DataResponse<Data?>?
  308. // When
  309. let request = session.request(urlRequest)
  310. .cancel()
  311. .response { resp in
  312. response = resp
  313. expectation.fulfill()
  314. }
  315. waitForExpectations(timeout: timeout, handler: nil)
  316. // Then
  317. XCTAssertNotNil(response, "response should not be nil")
  318. XCTAssertTrue(request.isCancelled)
  319. XCTAssertTrue((request.task == nil) || (request.task?.state == .canceling || request.task?.state == .completed))
  320. guard let error = request.error?.asAFError, case .explicitlyCancelled = error else {
  321. XCTFail("Request should have an .explicitlyCancelled error.")
  322. return
  323. }
  324. }
  325. func testSetStartRequestsImmediatelyToFalseAndResumeThenCancelRequestHasCorrectOutput() {
  326. // Given
  327. let session = Session(startRequestsImmediately: false)
  328. let url = URL(string: "https://httpbin.org/get")!
  329. let urlRequest = URLRequest(url: url)
  330. let expectation = self.expectation(description: "\(url)")
  331. var response: DataResponse<Data?>?
  332. // When
  333. let request = session.request(urlRequest)
  334. .resume()
  335. .cancel()
  336. .response { resp in
  337. response = resp
  338. expectation.fulfill()
  339. }
  340. waitForExpectations(timeout: timeout, handler: nil)
  341. // Then
  342. XCTAssertNotNil(response, "response should not be nil")
  343. XCTAssertTrue(request.isCancelled)
  344. XCTAssertTrue((request.task == nil) || (request.task?.state == .canceling || request.task?.state == .completed))
  345. guard let error = request.error?.asAFError, case .explicitlyCancelled = error else {
  346. XCTFail("Request should have an .explicitlyCancelled error.")
  347. return
  348. }
  349. }
  350. func testSetStartRequestsImmediatelyToFalseAndCancelThenResumeRequestDoesntCreateTaskAndStaysCancelled() {
  351. // Given
  352. let session = Session(startRequestsImmediately: false)
  353. let url = URL(string: "https://httpbin.org/get")!
  354. let urlRequest = URLRequest(url: url)
  355. let expectation = self.expectation(description: "\(url)")
  356. var response: DataResponse<Data?>?
  357. // When
  358. let request = session.request(urlRequest)
  359. .cancel()
  360. .resume()
  361. .response { resp in
  362. response = resp
  363. expectation.fulfill()
  364. }
  365. waitForExpectations(timeout: timeout, handler: nil)
  366. // Then
  367. XCTAssertNotNil(response, "response should not be nil")
  368. XCTAssertTrue(request.isCancelled)
  369. XCTAssertTrue((request.task == nil) || (request.task?.state == .canceling || request.task?.state == .completed))
  370. guard let error = request.error?.asAFError, case .explicitlyCancelled = error else {
  371. XCTFail("Request should have an .explicitlyCancelled error.")
  372. return
  373. }
  374. }
  375. // MARK: Tests - Deinitialization
  376. func testReleasingManagerWithPendingRequestDeinitializesSuccessfully() {
  377. // Given
  378. let monitor = ClosureEventMonitor()
  379. let expectation = self.expectation(description: "Request created")
  380. monitor.requestDidCreateTask = { _, _ in expectation.fulfill() }
  381. var session: Session? = Session(startRequestsImmediately: false, eventMonitors: [monitor])
  382. let url = URL(string: "https://httpbin.org/get")!
  383. let urlRequest = URLRequest(url: url)
  384. // When
  385. let request = session?.request(urlRequest)
  386. session = nil
  387. waitForExpectations(timeout: timeout, handler: nil)
  388. // Then
  389. XCTAssertEqual(request?.task?.state, .suspended)
  390. XCTAssertNil(session, "manager should be nil")
  391. }
  392. func testReleasingManagerWithPendingCanceledRequestDeinitializesSuccessfully() {
  393. // Given
  394. var session: Session? = Session(startRequestsImmediately: false)
  395. let url = URL(string: "https://httpbin.org/get")!
  396. let urlRequest = URLRequest(url: url)
  397. // When
  398. let request = session?.request(urlRequest)
  399. request?.cancel()
  400. session = nil
  401. let state = request?.state
  402. // Then
  403. XCTAssertTrue(state == .cancelled, "state should be .cancelled")
  404. XCTAssertNil(session, "manager should be nil")
  405. }
  406. // MARK: Tests - Bad Requests
  407. func testThatDataRequestWithInvalidURLStringThrowsResponseHandlerError() {
  408. // Given
  409. let session = Session()
  410. let expectation = self.expectation(description: "Request should fail with error")
  411. var response: DataResponse<Data?>?
  412. // When
  413. session.request("https://httpbin.org/get/äëïöü").response { resp in
  414. response = resp
  415. expectation.fulfill()
  416. }
  417. waitForExpectations(timeout: timeout, handler: nil)
  418. // Then
  419. XCTAssertNil(response?.request)
  420. XCTAssertNil(response?.response)
  421. XCTAssertNil(response?.data)
  422. XCTAssertNotNil(response?.error)
  423. if let error = response?.error?.asAFError {
  424. XCTAssertTrue(error.isInvalidURLError)
  425. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  426. } else {
  427. XCTFail("error should not be nil")
  428. }
  429. }
  430. func testThatDownloadRequestWithInvalidURLStringThrowsResponseHandlerError() {
  431. // Given
  432. let session = Session()
  433. let expectation = self.expectation(description: "Download should fail with error")
  434. var response: DownloadResponse<URL?>?
  435. // When
  436. session.download("https://httpbin.org/get/äëïöü").response { resp in
  437. response = resp
  438. expectation.fulfill()
  439. }
  440. waitForExpectations(timeout: timeout, handler: nil)
  441. // Then
  442. XCTAssertNil(response?.request)
  443. XCTAssertNil(response?.response)
  444. XCTAssertNil(response?.fileURL)
  445. XCTAssertNil(response?.resumeData)
  446. XCTAssertNotNil(response?.error)
  447. if let error = response?.error?.asAFError {
  448. XCTAssertTrue(error.isInvalidURLError)
  449. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  450. } else {
  451. XCTFail("error should not be nil")
  452. }
  453. }
  454. func testThatUploadDataRequestWithInvalidURLStringThrowsResponseHandlerError() {
  455. // Given
  456. let session = Session()
  457. let expectation = self.expectation(description: "Upload should fail with error")
  458. var response: DataResponse<Data?>?
  459. // When
  460. session.upload(Data(), to: "https://httpbin.org/get/äëïöü").response { resp in
  461. response = resp
  462. expectation.fulfill()
  463. }
  464. waitForExpectations(timeout: timeout, handler: nil)
  465. // Then
  466. XCTAssertNil(response?.request)
  467. XCTAssertNil(response?.response)
  468. XCTAssertNil(response?.data)
  469. XCTAssertNotNil(response?.error)
  470. if let error = response?.error?.asAFError {
  471. XCTAssertTrue(error.isInvalidURLError)
  472. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  473. } else {
  474. XCTFail("error should not be nil")
  475. }
  476. }
  477. func testThatUploadFileRequestWithInvalidURLStringThrowsResponseHandlerError() {
  478. // Given
  479. let session = Session()
  480. let expectation = self.expectation(description: "Upload should fail with error")
  481. var response: DataResponse<Data?>?
  482. // When
  483. session.upload(URL(fileURLWithPath: "/invalid"), to: "https://httpbin.org/get/äëïöü").response { resp in
  484. response = resp
  485. expectation.fulfill()
  486. }
  487. waitForExpectations(timeout: timeout, handler: nil)
  488. // Then
  489. XCTAssertNil(response?.request)
  490. XCTAssertNil(response?.response)
  491. XCTAssertNil(response?.data)
  492. XCTAssertNotNil(response?.error)
  493. if let error = response?.error?.asAFError {
  494. XCTAssertTrue(error.isInvalidURLError)
  495. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  496. } else {
  497. XCTFail("error should not be nil")
  498. }
  499. }
  500. func testThatUploadStreamRequestWithInvalidURLStringThrowsResponseHandlerError() {
  501. // Given
  502. let session = Session()
  503. let expectation = self.expectation(description: "Upload should fail with error")
  504. var response: DataResponse<Data?>?
  505. // When
  506. session.upload(InputStream(data: Data()), to: "https://httpbin.org/get/äëïöü").response { resp in
  507. response = resp
  508. expectation.fulfill()
  509. }
  510. waitForExpectations(timeout: timeout, handler: nil)
  511. // Then
  512. XCTAssertNil(response?.request)
  513. XCTAssertNil(response?.response)
  514. XCTAssertNil(response?.data)
  515. XCTAssertNotNil(response?.error)
  516. if let error = response?.error?.asAFError {
  517. XCTAssertTrue(error.isInvalidURLError)
  518. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  519. } else {
  520. XCTFail("error should not be nil")
  521. }
  522. }
  523. // MARK: Tests - Request Adapter
  524. func testThatSessionCallsRequestAdaptersWhenCreatingDataRequest() {
  525. // Given
  526. let urlString = "https://httpbin.org/get"
  527. let methodAdapter = HTTPMethodAdapter(method: .post)
  528. let headerAdapter = HeaderAdapter()
  529. let monitor = ClosureEventMonitor()
  530. let session = Session(startRequestsImmediately: false, interceptor: methodAdapter, eventMonitors: [monitor])
  531. // When
  532. let expectation1 = self.expectation(description: "Request 1 created")
  533. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  534. let request1 = session.request(urlString)
  535. waitForExpectations(timeout: timeout, handler: nil)
  536. let expectation2 = self.expectation(description: "Request 2 created")
  537. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  538. let request2 = session.request(urlString, interceptor: headerAdapter)
  539. waitForExpectations(timeout: timeout, handler: nil)
  540. // Then
  541. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  542. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  543. XCTAssertEqual(request2.task?.originalRequest?.allHTTPHeaderFields?.count, 1)
  544. XCTAssertEqual(methodAdapter.adaptedCount, 2)
  545. XCTAssertEqual(headerAdapter.adaptedCount, 1)
  546. }
  547. func testThatSessionCallsRequestAdaptersWhenCreatingDownloadRequest() {
  548. // Given
  549. let urlString = "https://httpbin.org/get"
  550. let methodAdapter = HTTPMethodAdapter(method: .post)
  551. let headerAdapter = HeaderAdapter()
  552. let monitor = ClosureEventMonitor()
  553. let session = Session(startRequestsImmediately: false, interceptor: methodAdapter, eventMonitors: [monitor])
  554. // When
  555. let expectation1 = self.expectation(description: "Request 1 created")
  556. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  557. let request1 = session.download(urlString)
  558. waitForExpectations(timeout: timeout, handler: nil)
  559. let expectation2 = self.expectation(description: "Request 2 created")
  560. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  561. let request2 = session.download(urlString, interceptor: headerAdapter)
  562. waitForExpectations(timeout: timeout, handler: nil)
  563. // Then
  564. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  565. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  566. XCTAssertEqual(request2.task?.originalRequest?.allHTTPHeaderFields?.count, 1)
  567. XCTAssertEqual(methodAdapter.adaptedCount, 2)
  568. XCTAssertEqual(headerAdapter.adaptedCount, 1)
  569. }
  570. func testThatSessionCallsRequestAdaptersWhenCreatingUploadRequestWithData() {
  571. // Given
  572. let data = Data("data".utf8)
  573. let urlString = "https://httpbin.org/post"
  574. let methodAdapter = HTTPMethodAdapter(method: .get)
  575. let headerAdapter = HeaderAdapter()
  576. let monitor = ClosureEventMonitor()
  577. let session = Session(startRequestsImmediately: false, interceptor: methodAdapter, eventMonitors: [monitor])
  578. // When
  579. let expectation1 = self.expectation(description: "Request 1 created")
  580. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  581. let request1 = session.upload(data, to: urlString)
  582. waitForExpectations(timeout: timeout, handler: nil)
  583. let expectation2 = self.expectation(description: "Request 2 created")
  584. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  585. let request2 = session.upload(data, to: urlString, interceptor: headerAdapter)
  586. waitForExpectations(timeout: timeout, handler: nil)
  587. // Then
  588. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  589. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  590. XCTAssertEqual(request2.task?.originalRequest?.allHTTPHeaderFields?.count, 1)
  591. XCTAssertEqual(methodAdapter.adaptedCount, 2)
  592. XCTAssertEqual(headerAdapter.adaptedCount, 1)
  593. }
  594. func testThatSessionCallsRequestAdaptersWhenCreatingUploadRequestWithFile() {
  595. // Given
  596. let fileURL = URL(fileURLWithPath: "/path/to/some/file.txt")
  597. let urlString = "https://httpbin.org/post"
  598. let methodAdapter = HTTPMethodAdapter(method: .get)
  599. let headerAdapter = HeaderAdapter()
  600. let monitor = ClosureEventMonitor()
  601. let session = Session(startRequestsImmediately: false, interceptor: methodAdapter, eventMonitors: [monitor])
  602. // When
  603. let expectation1 = self.expectation(description: "Request 1 created")
  604. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  605. let request1 = session.upload(fileURL, to: urlString)
  606. waitForExpectations(timeout: timeout, handler: nil)
  607. let expectation2 = self.expectation(description: "Request 2 created")
  608. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  609. let request2 = session.upload(fileURL, to: urlString, interceptor: headerAdapter)
  610. waitForExpectations(timeout: timeout, handler: nil)
  611. // Then
  612. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  613. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  614. XCTAssertEqual(request2.task?.originalRequest?.allHTTPHeaderFields?.count, 1)
  615. XCTAssertEqual(methodAdapter.adaptedCount, 2)
  616. XCTAssertEqual(headerAdapter.adaptedCount, 1)
  617. }
  618. func testThatSessionCallsRequestAdaptersWhenCreatingUploadRequestWithInputStream() {
  619. // Given
  620. let inputStream = InputStream(data: Data("data".utf8))
  621. let urlString = "https://httpbin.org/post"
  622. let methodAdapter = HTTPMethodAdapter(method: .get)
  623. let headerAdapter = HeaderAdapter()
  624. let monitor = ClosureEventMonitor()
  625. let session = Session(startRequestsImmediately: false, interceptor: methodAdapter, eventMonitors: [monitor])
  626. // When
  627. let expectation1 = self.expectation(description: "Request 1 created")
  628. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  629. let request1 = session.upload(inputStream, to: urlString)
  630. waitForExpectations(timeout: timeout, handler: nil)
  631. let expectation2 = self.expectation(description: "Request 2 created")
  632. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  633. let request2 = session.upload(inputStream, to: urlString, interceptor: headerAdapter)
  634. waitForExpectations(timeout: timeout, handler: nil)
  635. // Then
  636. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  637. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  638. XCTAssertEqual(request2.task?.originalRequest?.allHTTPHeaderFields?.count, 1)
  639. XCTAssertEqual(methodAdapter.adaptedCount, 2)
  640. XCTAssertEqual(headerAdapter.adaptedCount, 1)
  641. }
  642. func testThatSessionReturnsRequestAdaptationErrorWhenRequestAdapterThrowsError() {
  643. // Given
  644. let urlString = "https://httpbin.org/get"
  645. let methodAdapter = HTTPMethodAdapter(method: .post, throwsError: true)
  646. let headerAdapter = HeaderAdapter(throwsError: true)
  647. let monitor = ClosureEventMonitor()
  648. let session = Session(startRequestsImmediately: false, interceptor: methodAdapter, eventMonitors: [monitor])
  649. // When
  650. let expectation1 = self.expectation(description: "Request 1 created")
  651. monitor.requestDidFailToAdaptURLRequestWithError = { _, _, _ in expectation1.fulfill() }
  652. let request1 = session.request(urlString)
  653. waitForExpectations(timeout: timeout, handler: nil)
  654. let expectation2 = self.expectation(description: "Request 2 created")
  655. monitor.requestDidFailToAdaptURLRequestWithError = { _, _, _ in expectation2.fulfill() }
  656. let request2 = session.request(urlString, interceptor: headerAdapter)
  657. waitForExpectations(timeout: timeout, handler: nil)
  658. let requests = [request1, request2]
  659. // Then
  660. for request in requests {
  661. if let error = request.error?.asAFError {
  662. XCTAssertTrue(error.isRequestAdaptationError)
  663. XCTAssertEqual(error.underlyingError?.asAFError?.urlConvertible as? String, "")
  664. } else {
  665. XCTFail("error should not be nil")
  666. }
  667. }
  668. }
  669. // MARK: Tests - Request Retrier
  670. func testThatSessionCallsRequestRetrierWhenRequestEncountersError() {
  671. // Given
  672. let handler = RequestHandler()
  673. let session = Session()
  674. let expectation = self.expectation(description: "request should eventually fail")
  675. var response: DataResponse<Any>?
  676. // When
  677. let request = session.request("https://httpbin.org/basic-auth/user/password", interceptor: handler)
  678. .validate()
  679. .responseJSON { jsonResponse in
  680. response = jsonResponse
  681. expectation.fulfill()
  682. }
  683. waitForExpectations(timeout: timeout, handler: nil)
  684. // Then
  685. XCTAssertEqual(handler.adaptCalledCount, 2)
  686. XCTAssertEqual(handler.adaptedCount, 2)
  687. XCTAssertEqual(handler.retryCalledCount, 3)
  688. XCTAssertEqual(handler.retryCount, 3)
  689. XCTAssertEqual(request.retryCount, 1)
  690. XCTAssertEqual(response?.result.isSuccess, false)
  691. XCTAssertTrue(session.requestTaskMap.isEmpty)
  692. }
  693. func testThatSessionCallsRequestRetrierThenSessionRetrierWhenRequestEncountersError() {
  694. // Given
  695. let sessionHandler = RequestHandler()
  696. let requestHandler = RequestHandler()
  697. let session = Session(interceptor: sessionHandler)
  698. let expectation = self.expectation(description: "request should eventually fail")
  699. var response: DataResponse<Any>?
  700. // When
  701. let request = session.request("https://httpbin.org/basic-auth/user/password", interceptor: requestHandler)
  702. .validate()
  703. .responseJSON { jsonResponse in
  704. response = jsonResponse
  705. expectation.fulfill()
  706. }
  707. waitForExpectations(timeout: timeout, handler: nil)
  708. // Then
  709. XCTAssertEqual(sessionHandler.adaptCalledCount, 3)
  710. XCTAssertEqual(sessionHandler.adaptedCount, 3)
  711. XCTAssertEqual(sessionHandler.retryCalledCount, 3)
  712. XCTAssertEqual(sessionHandler.retryCount, 3)
  713. XCTAssertEqual(requestHandler.adaptCalledCount, 3)
  714. XCTAssertEqual(requestHandler.adaptedCount, 3)
  715. XCTAssertEqual(requestHandler.retryCalledCount, 4)
  716. XCTAssertEqual(requestHandler.retryCount, 4)
  717. XCTAssertEqual(request.retryCount, 2)
  718. XCTAssertEqual(response?.result.isSuccess, false)
  719. XCTAssertTrue(session.requestTaskMap.isEmpty)
  720. }
  721. func testThatSessionCallsRequestRetrierWhenRequestInitiallyEncountersAdaptError() {
  722. // Given
  723. let handler = RequestHandler()
  724. handler.adaptedCount = 1
  725. handler.throwsErrorOnSecondAdapt = true
  726. handler.shouldApplyAuthorizationHeader = true
  727. let session = Session()
  728. let expectation = self.expectation(description: "request should eventually fail")
  729. var response: DataResponse<Any>?
  730. // When
  731. session.request("https://httpbin.org/basic-auth/user/password", interceptor: handler)
  732. .validate()
  733. .responseJSON { jsonResponse in
  734. response = jsonResponse
  735. expectation.fulfill()
  736. }
  737. waitForExpectations(timeout: timeout, handler: nil)
  738. // Then
  739. XCTAssertEqual(handler.adaptCalledCount, 2)
  740. XCTAssertEqual(handler.adaptedCount, 2)
  741. XCTAssertEqual(handler.retryCalledCount, 1)
  742. XCTAssertEqual(handler.retryCount, 1)
  743. XCTAssertEqual(response?.result.isSuccess, true)
  744. XCTAssertTrue(session.requestTaskMap.isEmpty)
  745. }
  746. func testThatSessionCallsRequestRetrierWhenDownloadInitiallyEncountersAdaptError() {
  747. // Given
  748. let handler = RequestHandler()
  749. handler.adaptedCount = 1
  750. handler.throwsErrorOnSecondAdapt = true
  751. handler.shouldApplyAuthorizationHeader = true
  752. let session = Session()
  753. let expectation = self.expectation(description: "request should eventually fail")
  754. var response: DownloadResponse<Any>?
  755. let destination: DownloadRequest.Destination = { _, _ in
  756. let fileURL = self.testDirectoryURL.appendingPathComponent("test-output.json")
  757. return (fileURL, [.removePreviousFile])
  758. }
  759. // When
  760. session.download("https://httpbin.org/basic-auth/user/password", interceptor: handler, to: destination)
  761. .validate()
  762. .responseJSON { jsonResponse in
  763. response = jsonResponse
  764. expectation.fulfill()
  765. }
  766. waitForExpectations(timeout: timeout, handler: nil)
  767. // Then
  768. XCTAssertEqual(handler.adaptCalledCount, 2)
  769. XCTAssertEqual(handler.adaptedCount, 2)
  770. XCTAssertEqual(handler.retryCalledCount, 1)
  771. XCTAssertEqual(handler.retryCount, 1)
  772. XCTAssertEqual(response?.result.isSuccess, true)
  773. XCTAssertTrue(session.requestTaskMap.isEmpty)
  774. }
  775. func testThatSessionCallsRequestRetrierWhenUploadInitiallyEncountersAdaptError() {
  776. // Given
  777. let handler = UploadHandler()
  778. let session = Session(interceptor: handler)
  779. let expectation = self.expectation(description: "request should eventually fail")
  780. var response: DataResponse<Any>?
  781. let uploadData = Data("upload data".utf8)
  782. // When
  783. session.upload(uploadData, to: "https://httpbin.org/post")
  784. .validate()
  785. .responseJSON { jsonResponse in
  786. response = jsonResponse
  787. expectation.fulfill()
  788. }
  789. waitForExpectations(timeout: timeout, handler: nil)
  790. // Then
  791. XCTAssertEqual(handler.adaptCalledCount, 2)
  792. XCTAssertEqual(handler.adaptedCount, 2)
  793. XCTAssertEqual(handler.retryCalledCount, 1)
  794. XCTAssertEqual(handler.retryCount, 1)
  795. XCTAssertEqual(response?.result.isSuccess, true)
  796. XCTAssertTrue(session.requestTaskMap.isEmpty)
  797. }
  798. func testThatSessionCallsAdapterWhenRequestIsRetried() {
  799. // Given
  800. let handler = RequestHandler()
  801. handler.shouldApplyAuthorizationHeader = true
  802. let session = Session(interceptor: handler)
  803. let expectation = self.expectation(description: "request should eventually succeed")
  804. var response: DataResponse<Any>?
  805. // When
  806. let request = session.request("https://httpbin.org/basic-auth/user/password")
  807. .validate()
  808. .responseJSON { jsonResponse in
  809. response = jsonResponse
  810. expectation.fulfill()
  811. }
  812. waitForExpectations(timeout: timeout, handler: nil)
  813. // Then
  814. XCTAssertEqual(handler.adaptCalledCount, 2)
  815. XCTAssertEqual(handler.adaptedCount, 2)
  816. XCTAssertEqual(handler.retryCalledCount, 1)
  817. XCTAssertEqual(handler.retryCount, 1)
  818. XCTAssertEqual(request.retryCount, 1)
  819. XCTAssertEqual(response?.result.isSuccess, true)
  820. XCTAssertTrue(session.requestTaskMap.isEmpty)
  821. }
  822. func testThatSessionReturnsRequestAdaptationErrorWhenRequestIsRetried() {
  823. // Given
  824. let handler = RequestHandler()
  825. handler.throwsErrorOnSecondAdapt = true
  826. let session = Session(interceptor: handler)
  827. let expectation = self.expectation(description: "request should eventually fail")
  828. var response: DataResponse<Any>?
  829. // When
  830. let request = session.request("https://httpbin.org/basic-auth/user/password")
  831. .validate()
  832. .responseJSON { jsonResponse in
  833. response = jsonResponse
  834. expectation.fulfill()
  835. }
  836. waitForExpectations(timeout: timeout, handler: nil)
  837. // Then
  838. XCTAssertEqual(handler.adaptCalledCount, 2)
  839. XCTAssertEqual(handler.adaptedCount, 1)
  840. XCTAssertEqual(handler.retryCalledCount, 3)
  841. XCTAssertEqual(handler.retryCount, 3)
  842. XCTAssertEqual(request.retryCount, 1)
  843. XCTAssertEqual(response?.result.isSuccess, false)
  844. XCTAssertTrue(session.requestTaskMap.isEmpty)
  845. if let error = response?.result.error?.asAFError {
  846. XCTAssertTrue(error.isRequestAdaptationError)
  847. XCTAssertEqual(error.underlyingError?.asAFError?.urlConvertible as? String, "/adapt/error/2")
  848. } else {
  849. XCTFail("error should not be nil")
  850. }
  851. }
  852. func testThatSessionRetriesRequestWithDelayWhenRetryResultContainsDelay() {
  853. // Given
  854. let handler = RequestHandler()
  855. handler.retryDelay = 0.01
  856. handler.throwsErrorOnSecondAdapt = true
  857. let session = Session(interceptor: handler)
  858. let expectation = self.expectation(description: "request should eventually fail")
  859. var response: DataResponse<Any>?
  860. // When
  861. let request = session.request("https://httpbin.org/basic-auth/user/password")
  862. .validate()
  863. .responseJSON { jsonResponse in
  864. response = jsonResponse
  865. expectation.fulfill()
  866. }
  867. waitForExpectations(timeout: timeout, handler: nil)
  868. // Then
  869. XCTAssertEqual(handler.adaptCalledCount, 2)
  870. XCTAssertEqual(handler.adaptedCount, 1)
  871. XCTAssertEqual(handler.retryCalledCount, 3)
  872. XCTAssertEqual(handler.retryCount, 3)
  873. XCTAssertEqual(request.retryCount, 1)
  874. XCTAssertEqual(response?.result.isSuccess, false)
  875. XCTAssertTrue(session.requestTaskMap.isEmpty)
  876. if let error = response?.result.error?.asAFError {
  877. XCTAssertTrue(error.isRequestAdaptationError)
  878. XCTAssertEqual(error.underlyingError?.asAFError?.urlConvertible as? String, "/adapt/error/2")
  879. } else {
  880. XCTFail("error should not be nil")
  881. }
  882. }
  883. func testThatSessionReturnsRequestRetryErrorWhenRequestRetrierThrowsError() {
  884. // Given
  885. let handler = RequestHandler()
  886. handler.throwsErrorOnRetry = true
  887. let session = Session(interceptor: handler)
  888. let expectation = self.expectation(description: "request should eventually fail")
  889. var response: DataResponse<Any>?
  890. // When
  891. let request = session.request("https://httpbin.org/basic-auth/user/password")
  892. .validate()
  893. .responseJSON { jsonResponse in
  894. response = jsonResponse
  895. expectation.fulfill()
  896. }
  897. waitForExpectations(timeout: timeout, handler: nil)
  898. // Then
  899. XCTAssertEqual(handler.adaptCalledCount, 1)
  900. XCTAssertEqual(handler.adaptedCount, 1)
  901. XCTAssertEqual(handler.retryCalledCount, 2)
  902. XCTAssertEqual(handler.retryCount, 0)
  903. XCTAssertEqual(request.retryCount, 0)
  904. XCTAssertEqual(response?.result.isSuccess, false)
  905. XCTAssertTrue(session.requestTaskMap.isEmpty)
  906. if let error = response?.result.error?.asAFError {
  907. XCTAssertTrue(error.isRequestRetryError)
  908. XCTAssertEqual(error.underlyingError?.asAFError?.urlConvertible as? String, "/invalid/url/2")
  909. } else {
  910. XCTFail("error should not be nil")
  911. }
  912. }
  913. // MARK: Tests - Response Serializer Retry
  914. func testThatSessionCallsRequestRetrierWhenResponseSerializerThrowsError() {
  915. // Given
  916. let handler = RequestHandler()
  917. handler.shouldRetry = false
  918. let session = Session()
  919. let expectation = self.expectation(description: "request should eventually fail")
  920. var response: DataResponse<Any>?
  921. // When
  922. let request = session.request("https://httpbin.org/image/jpeg", interceptor: handler)
  923. .validate()
  924. .responseJSON { jsonResponse in
  925. response = jsonResponse
  926. expectation.fulfill()
  927. }
  928. waitForExpectations(timeout: timeout, handler: nil)
  929. // Then
  930. XCTAssertEqual(handler.adaptCalledCount, 1)
  931. XCTAssertEqual(handler.adaptedCount, 1)
  932. XCTAssertEqual(handler.retryCalledCount, 1)
  933. XCTAssertEqual(handler.retryCount, 0)
  934. XCTAssertEqual(request.retryCount, 0)
  935. XCTAssertEqual(response?.result.isSuccess, false)
  936. XCTAssertTrue(session.requestTaskMap.isEmpty)
  937. if let error = response?.error?.asAFError {
  938. XCTAssertTrue(error.isResponseSerializationError)
  939. XCTAssertTrue(error.localizedDescription.starts(with: "JSON could not be serialized"))
  940. } else {
  941. XCTFail("error should not be nil")
  942. }
  943. }
  944. func testThatSessionCallsRequestRetrierForAllResponseSerializersThatThrowError() throws {
  945. // Given
  946. let handler = RequestHandler()
  947. handler.throwsErrorOnRetry = true
  948. let session = Session()
  949. let json1Expectation = self.expectation(description: "request should eventually fail")
  950. var json1Response: DataResponse<Any>?
  951. let json2Expectation = self.expectation(description: "request should eventually fail")
  952. var json2Response: DataResponse<Any>?
  953. // When
  954. let request = session.request("https://httpbin.org/image/jpeg", interceptor: handler)
  955. .validate()
  956. .responseJSON { response in
  957. json1Response = response
  958. json1Expectation.fulfill()
  959. }
  960. .responseJSON { response in
  961. json2Response = response
  962. json2Expectation.fulfill()
  963. }
  964. waitForExpectations(timeout: timeout, handler: nil)
  965. // Then
  966. XCTAssertEqual(handler.adaptCalledCount, 1)
  967. XCTAssertEqual(handler.adaptedCount, 1)
  968. XCTAssertEqual(handler.retryCalledCount, 2)
  969. XCTAssertEqual(handler.retryCount, 0)
  970. XCTAssertEqual(request.retryCount, 0)
  971. XCTAssertEqual(json1Response?.result.isSuccess, false)
  972. XCTAssertEqual(json2Response?.result.isSuccess, false)
  973. XCTAssertTrue(session.requestTaskMap.isEmpty)
  974. let errors: [AFError] = [json1Response, json2Response].compactMap { $0?.error?.asAFError }
  975. XCTAssertEqual(errors.count, 2)
  976. for (index, error) in errors.enumerated() {
  977. XCTAssertTrue(error.isRequestRetryError)
  978. XCTAssertEqual(error.localizedDescription.starts(with: "Request retry failed with retry error"), true)
  979. if case let .requestRetryFailed(retryError, originalError) = error {
  980. XCTAssertEqual(try retryError.asAFError?.urlConvertible?.asURL().absoluteString, "/invalid/url/\(index + 1)")
  981. XCTAssertTrue(originalError.localizedDescription.starts(with: "JSON could not be serialized"))
  982. } else {
  983. XCTFail("Error failure reason should be response serialization failure")
  984. }
  985. }
  986. }
  987. func testThatSessionRetriesRequestImmediatelyWhenResponseSerializerRequestsRetry() throws {
  988. // Given
  989. let handler = RequestHandler()
  990. let session = Session()
  991. let json1Expectation = self.expectation(description: "request should eventually fail")
  992. var json1Response: DataResponse<Any>?
  993. let json2Expectation = self.expectation(description: "request should eventually fail")
  994. var json2Response: DataResponse<Any>?
  995. // When
  996. let request = session.request("https://httpbin.org/image/jpeg", interceptor: handler)
  997. .validate()
  998. .responseJSON { response in
  999. json1Response = response
  1000. json1Expectation.fulfill()
  1001. }
  1002. .responseJSON { response in
  1003. json2Response = response
  1004. json2Expectation.fulfill()
  1005. }
  1006. waitForExpectations(timeout: 10, handler: nil)
  1007. // Then
  1008. XCTAssertEqual(handler.adaptCalledCount, 2)
  1009. XCTAssertEqual(handler.adaptedCount, 2)
  1010. XCTAssertEqual(handler.retryCalledCount, 3)
  1011. XCTAssertEqual(handler.retryCount, 3)
  1012. XCTAssertEqual(request.retryCount, 1)
  1013. XCTAssertEqual(json1Response?.result.isSuccess, false)
  1014. XCTAssertEqual(json2Response?.result.isSuccess, false)
  1015. XCTAssertTrue(session.requestTaskMap.isEmpty)
  1016. let errors: [AFError] = [json1Response, json2Response].compactMap { $0?.error?.asAFError }
  1017. XCTAssertEqual(errors.count, 2)
  1018. for error in errors {
  1019. XCTAssertTrue(error.isResponseSerializationError)
  1020. XCTAssertTrue(error.localizedDescription.starts(with: "JSON could not be serialized"))
  1021. }
  1022. }
  1023. func testThatSessionCallsResponseSerializerCompletionsWhenAdapterThrowsErrorDuringRetry() {
  1024. // Four retries should occur given this scenario:
  1025. // 1) Retrier is called from first response serializer failure (trips retry)
  1026. // 2) Retrier is called by Session for adapt error thrown
  1027. // 3) Retrier is called again from first response serializer failure
  1028. // 4) Retrier is called from second response serializer failure
  1029. // Given
  1030. let handler = RequestHandler()
  1031. handler.throwsErrorOnSecondAdapt = true
  1032. let session = Session()
  1033. let json1Expectation = self.expectation(description: "request should eventually fail")
  1034. var json1Response: DataResponse<Any>?
  1035. let json2Expectation = self.expectation(description: "request should eventually fail")
  1036. var json2Response: DataResponse<Any>?
  1037. // When
  1038. let request = session.request("https://httpbin.org/image/jpeg", interceptor: handler)
  1039. .validate()
  1040. .responseJSON { response in
  1041. json1Response = response
  1042. json1Expectation.fulfill()
  1043. }
  1044. .responseJSON { response in
  1045. json2Response = response
  1046. json2Expectation.fulfill()
  1047. }
  1048. waitForExpectations(timeout: 10, handler: nil)
  1049. // Then
  1050. XCTAssertEqual(handler.adaptCalledCount, 2)
  1051. XCTAssertEqual(handler.adaptedCount, 1)
  1052. XCTAssertEqual(handler.retryCalledCount, 4)
  1053. XCTAssertEqual(handler.retryCount, 4)
  1054. XCTAssertEqual(request.retryCount, 1)
  1055. XCTAssertEqual(json1Response?.result.isSuccess, false)
  1056. XCTAssertEqual(json2Response?.result.isSuccess, false)
  1057. XCTAssertTrue(session.requestTaskMap.isEmpty)
  1058. let errors: [AFError] = [json1Response, json2Response].compactMap { $0?.error?.asAFError }
  1059. XCTAssertEqual(errors.count, 2)
  1060. for error in errors {
  1061. XCTAssertTrue(error.isRequestAdaptationError)
  1062. XCTAssertEqual(error.localizedDescription, "Request adaption failed with error: URL is not valid: /adapt/error/2")
  1063. }
  1064. }
  1065. func testThatSessionCallsResponseSerializerCompletionsWhenAdapterThrowsErrorDuringRetryForDownloads() {
  1066. // Four retries should occur given this scenario:
  1067. // 1) Retrier is called from first response serializer failure (trips retry)
  1068. // 2) Retrier is called by Session for adapt error thrown
  1069. // 3) Retrier is called again from first response serializer failure
  1070. // 4) Retrier is called from second response serializer failure
  1071. // Given
  1072. let handler = RequestHandler()
  1073. handler.throwsErrorOnSecondAdapt = true
  1074. let session = Session()
  1075. let json1Expectation = self.expectation(description: "request should eventually fail")
  1076. var json1Response: DownloadResponse<Any>?
  1077. let json2Expectation = self.expectation(description: "request should eventually fail")
  1078. var json2Response: DownloadResponse<Any>?
  1079. // When
  1080. let request = session.download("https://httpbin.org/image/jpeg", interceptor: handler)
  1081. .validate()
  1082. .responseJSON { response in
  1083. json1Response = response
  1084. json1Expectation.fulfill()
  1085. }
  1086. .responseJSON { response in
  1087. json2Response = response
  1088. json2Expectation.fulfill()
  1089. }
  1090. waitForExpectations(timeout: 10, handler: nil)
  1091. // Then
  1092. XCTAssertEqual(handler.adaptCalledCount, 2)
  1093. XCTAssertEqual(handler.adaptedCount, 1)
  1094. XCTAssertEqual(handler.retryCalledCount, 4)
  1095. XCTAssertEqual(handler.retryCount, 4)
  1096. XCTAssertEqual(request.retryCount, 1)
  1097. XCTAssertEqual(json1Response?.result.isSuccess, false)
  1098. XCTAssertEqual(json2Response?.result.isSuccess, false)
  1099. XCTAssertTrue(session.requestTaskMap.isEmpty)
  1100. let errors: [AFError] = [json1Response, json2Response].compactMap { $0?.error?.asAFError }
  1101. XCTAssertEqual(errors.count, 2)
  1102. for error in errors {
  1103. XCTAssertTrue(error.isRequestAdaptationError)
  1104. XCTAssertEqual(error.localizedDescription, "Request adaption failed with error: URL is not valid: /adapt/error/2")
  1105. }
  1106. }
  1107. // MARK: Tests - Session Invalidation
  1108. func testThatSessionIsInvalidatedAndAllRequestsCompleteWhenSessionIsDeinitialized() {
  1109. // Given
  1110. let invalidationExpectation = expectation(description: "sessionDidBecomeInvalidWithError should be called")
  1111. let events = ClosureEventMonitor()
  1112. events.sessionDidBecomeInvalidWithError = { (_, _) in
  1113. invalidationExpectation.fulfill()
  1114. }
  1115. var session: Session? = Session(startRequestsImmediately: false, eventMonitors: [events])
  1116. var error: Error?
  1117. let requestExpectation = expectation(description: "request should complete")
  1118. // When
  1119. session?.request(URLRequest.makeHTTPBinRequest()).response { (response) in
  1120. error = response.error
  1121. requestExpectation.fulfill()
  1122. }
  1123. session = nil
  1124. waitForExpectations(timeout: timeout, handler: nil)
  1125. // Then
  1126. assertErrorIsAFError(error) { XCTAssertTrue($0.isSessionDeinitializedError) }
  1127. }
  1128. }
  1129. // MARK: -
  1130. class SessionManagerConfigurationHeadersTestCase: BaseTestCase {
  1131. enum ConfigurationType {
  1132. case `default`, ephemeral, background
  1133. }
  1134. func testThatDefaultConfigurationHeadersAreSentWithRequest() {
  1135. // Given, When, Then
  1136. executeAuthorizationHeaderTest(for: .default)
  1137. }
  1138. func testThatEphemeralConfigurationHeadersAreSentWithRequest() {
  1139. // Given, When, Then
  1140. executeAuthorizationHeaderTest(for: .ephemeral)
  1141. }
  1142. #if os(macOS)
  1143. func testThatBackgroundConfigurationHeadersAreSentWithRequest() {
  1144. // Given, When, Then
  1145. executeAuthorizationHeaderTest(for: .background)
  1146. }
  1147. #endif
  1148. private func executeAuthorizationHeaderTest(for type: ConfigurationType) {
  1149. // Given
  1150. let session: Session = {
  1151. let configuration: URLSessionConfiguration = {
  1152. let configuration: URLSessionConfiguration
  1153. switch type {
  1154. case .default:
  1155. configuration = .default
  1156. case .ephemeral:
  1157. configuration = .ephemeral
  1158. case .background:
  1159. let identifier = "org.alamofire.test.manager-configuration-tests"
  1160. configuration = .background(withIdentifier: identifier)
  1161. }
  1162. var headers = HTTPHeaders.default
  1163. headers["Authorization"] = "Bearer 123456"
  1164. configuration.httpHeaders = headers
  1165. return configuration
  1166. }()
  1167. return Session(configuration: configuration)
  1168. }()
  1169. let expectation = self.expectation(description: "request should complete successfully")
  1170. var response: DataResponse<Any>?
  1171. // When
  1172. session.request("https://httpbin.org/headers")
  1173. .responseJSON { closureResponse in
  1174. response = closureResponse
  1175. expectation.fulfill()
  1176. }
  1177. waitForExpectations(timeout: timeout, handler: nil)
  1178. // Then
  1179. if let response = response {
  1180. XCTAssertNotNil(response.request, "request should not be nil")
  1181. XCTAssertNotNil(response.response, "response should not be nil")
  1182. XCTAssertNotNil(response.data, "data should not be nil")
  1183. XCTAssertTrue(response.result.isSuccess, "result should be a success")
  1184. if
  1185. let response = response.result.value as? [String: Any],
  1186. let headers = response["headers"] as? [String: String],
  1187. let authorization = headers["Authorization"]
  1188. {
  1189. XCTAssertEqual(authorization, "Bearer 123456", "authorization header value does not match")
  1190. } else {
  1191. XCTFail("failed to extract authorization header value")
  1192. }
  1193. } else {
  1194. XCTFail("response should not be nil")
  1195. }
  1196. }
  1197. }