SessionTests.swift 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581
  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 (AFResult<URLRequest>) -> Void) {
  38. adaptedCount += 1
  39. let result: AFResult<URLRequest> = AFResult {
  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 (AFResult<URLRequest>) -> Void) {
  57. adaptedCount += 1
  58. let result: AFResult<URLRequest> = AFResult {
  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 (AFResult<URLRequest>) -> Void) {
  82. adaptCalledCount += 1
  83. let result: AFResult<URLRequest> = AFResult {
  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 (AFResult<URLRequest>) -> Void) {
  134. adaptCalledCount += 1
  135. let result: AFResult<URLRequest> = AFResult {
  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. XCTAssertTrue(userAgent?.contains(alamofireVersion) == true)
  244. XCTAssertTrue(userAgent?.contains(osNameVersion) == true)
  245. XCTAssertTrue(userAgent?.contains("Unknown/Unknown") == true)
  246. }
  247. // MARK: Tests - Supported Accept-Encodings
  248. func testDefaultAcceptEncodingSupportsAppropriateEncodingsOnAppropriateSystems() {
  249. // Given
  250. let brotliURL = URL(string: "https://httpbin.org/brotli")!
  251. let gzipURL = URL(string: "https://httpbin.org/gzip")!
  252. let deflateURL = URL(string: "https://httpbin.org/deflate")!
  253. let brotliExpectation = expectation(description: "brotli request should complete")
  254. let gzipExpectation = expectation(description: "gzip request should complete")
  255. let deflateExpectation = expectation(description: "deflate request should complete")
  256. var brotliResponse: DataResponse<Any>?
  257. var gzipResponse: DataResponse<Any>?
  258. var deflateResponse: DataResponse<Any>?
  259. // When
  260. AF.request(brotliURL).responseJSON { response in
  261. brotliResponse = response
  262. brotliExpectation.fulfill()
  263. }
  264. AF.request(gzipURL).responseJSON { response in
  265. gzipResponse = response
  266. gzipExpectation.fulfill()
  267. }
  268. AF.request(deflateURL).responseJSON { response in
  269. deflateResponse = response
  270. deflateExpectation.fulfill()
  271. }
  272. waitForExpectations(timeout: timeout, handler: nil)
  273. // Then
  274. if #available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, *) {
  275. XCTAssertTrue(brotliResponse?.result.isSuccess == true)
  276. } else {
  277. XCTAssertTrue(brotliResponse?.result.isFailure == true)
  278. }
  279. XCTAssertTrue(gzipResponse?.result.isSuccess == true)
  280. XCTAssertTrue(deflateResponse?.result.isSuccess == true)
  281. }
  282. // MARK: Tests - Start Requests Immediately
  283. func testSetStartRequestsImmediatelyToFalseAndResumeRequest() {
  284. // Given
  285. let session = Session(startRequestsImmediately: false)
  286. let url = URL(string: "https://httpbin.org/get")!
  287. let urlRequest = URLRequest(url: url)
  288. let expectation = self.expectation(description: "\(url)")
  289. var response: HTTPURLResponse?
  290. // When
  291. session.request(urlRequest)
  292. .response { resp in
  293. response = resp.response
  294. expectation.fulfill()
  295. }
  296. .resume()
  297. waitForExpectations(timeout: timeout, handler: nil)
  298. // Then
  299. XCTAssertNotNil(response, "response should not be nil")
  300. XCTAssertTrue(response?.statusCode == 200, "response status code should be 200")
  301. }
  302. func testSetStartRequestsImmediatelyToFalseAndCancelledCallsResponseHandlers() {
  303. // Given
  304. let session = Session(startRequestsImmediately: false)
  305. let url = URL(string: "https://httpbin.org/get")!
  306. let urlRequest = URLRequest(url: url)
  307. let expectation = self.expectation(description: "\(url)")
  308. var response: DataResponse<Data?>?
  309. // When
  310. let request = session.request(urlRequest)
  311. .cancel()
  312. .response { resp in
  313. response = resp
  314. expectation.fulfill()
  315. }
  316. waitForExpectations(timeout: timeout, handler: nil)
  317. // Then
  318. XCTAssertNotNil(response, "response should not be nil")
  319. XCTAssertTrue(request.isCancelled)
  320. XCTAssertTrue((request.task == nil) || (request.task?.state == .canceling || request.task?.state == .completed))
  321. guard let error = request.error?.asAFError, case .explicitlyCancelled = error else {
  322. XCTFail("Request should have an .explicitlyCancelled error.")
  323. return
  324. }
  325. }
  326. func testSetStartRequestsImmediatelyToFalseAndResumeThenCancelRequestHasCorrectOutput() {
  327. // Given
  328. let session = Session(startRequestsImmediately: false)
  329. let url = URL(string: "https://httpbin.org/get")!
  330. let urlRequest = URLRequest(url: url)
  331. let expectation = self.expectation(description: "\(url)")
  332. var response: DataResponse<Data?>?
  333. // When
  334. let request = session.request(urlRequest)
  335. .resume()
  336. .cancel()
  337. .response { resp in
  338. response = resp
  339. expectation.fulfill()
  340. }
  341. waitForExpectations(timeout: timeout, handler: nil)
  342. // Then
  343. XCTAssertNotNil(response, "response should not be nil")
  344. XCTAssertTrue(request.isCancelled)
  345. XCTAssertTrue((request.task == nil) || (request.task?.state == .canceling || request.task?.state == .completed))
  346. guard let error = request.error?.asAFError, case .explicitlyCancelled = error else {
  347. XCTFail("Request should have an .explicitlyCancelled error.")
  348. return
  349. }
  350. }
  351. func testSetStartRequestsImmediatelyToFalseAndCancelThenResumeRequestDoesntCreateTaskAndStaysCancelled() {
  352. // Given
  353. let session = Session(startRequestsImmediately: false)
  354. let url = URL(string: "https://httpbin.org/get")!
  355. let urlRequest = URLRequest(url: url)
  356. let expectation = self.expectation(description: "\(url)")
  357. var response: DataResponse<Data?>?
  358. // When
  359. let request = session.request(urlRequest)
  360. .cancel()
  361. .resume()
  362. .response { resp in
  363. response = resp
  364. expectation.fulfill()
  365. }
  366. waitForExpectations(timeout: timeout, handler: nil)
  367. // Then
  368. XCTAssertNotNil(response, "response should not be nil")
  369. XCTAssertTrue(request.isCancelled)
  370. XCTAssertTrue((request.task == nil) || (request.task?.state == .canceling || request.task?.state == .completed))
  371. guard let error = request.error?.asAFError, case .explicitlyCancelled = error else {
  372. XCTFail("Request should have an .explicitlyCancelled error.")
  373. return
  374. }
  375. }
  376. // MARK: Tests - Deinitialization
  377. func testReleasingManagerWithPendingRequestDeinitializesSuccessfully() {
  378. // Given
  379. let monitor = ClosureEventMonitor()
  380. let expectation = self.expectation(description: "Request created")
  381. monitor.requestDidCreateTask = { _, _ in expectation.fulfill() }
  382. var session: Session? = Session(startRequestsImmediately: false, eventMonitors: [monitor])
  383. let url = URL(string: "https://httpbin.org/get")!
  384. let urlRequest = URLRequest(url: url)
  385. // When
  386. let request = session?.request(urlRequest)
  387. session = nil
  388. waitForExpectations(timeout: timeout, handler: nil)
  389. // Then
  390. XCTAssertEqual(request?.task?.state, .suspended)
  391. XCTAssertNil(session, "manager should be nil")
  392. }
  393. func testReleasingManagerWithPendingCanceledRequestDeinitializesSuccessfully() {
  394. // Given
  395. var session: Session? = Session(startRequestsImmediately: false)
  396. let url = URL(string: "https://httpbin.org/get")!
  397. let urlRequest = URLRequest(url: url)
  398. // When
  399. let request = session?.request(urlRequest)
  400. request?.cancel()
  401. session = nil
  402. let state = request?.state
  403. // Then
  404. XCTAssertTrue(state == .cancelled, "state should be .cancelled")
  405. XCTAssertNil(session, "manager should be nil")
  406. }
  407. // MARK: Tests - Bad Requests
  408. func testThatDataRequestWithInvalidURLStringThrowsResponseHandlerError() {
  409. // Given
  410. let session = Session()
  411. let expectation = self.expectation(description: "Request should fail with error")
  412. var response: DataResponse<Data?>?
  413. // When
  414. session.request("https://httpbin.org/get/äëïöü").response { resp in
  415. response = resp
  416. expectation.fulfill()
  417. }
  418. waitForExpectations(timeout: timeout, handler: nil)
  419. // Then
  420. XCTAssertNil(response?.request)
  421. XCTAssertNil(response?.response)
  422. XCTAssertNil(response?.data)
  423. XCTAssertNotNil(response?.error)
  424. if let error = response?.error?.asAFError {
  425. XCTAssertTrue(error.isInvalidURLError)
  426. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  427. } else {
  428. XCTFail("error should not be nil")
  429. }
  430. }
  431. func testThatDownloadRequestWithInvalidURLStringThrowsResponseHandlerError() {
  432. // Given
  433. let session = Session()
  434. let expectation = self.expectation(description: "Download should fail with error")
  435. var response: DownloadResponse<URL?>?
  436. // When
  437. session.download("https://httpbin.org/get/äëïöü").response { resp in
  438. response = resp
  439. expectation.fulfill()
  440. }
  441. waitForExpectations(timeout: timeout, handler: nil)
  442. // Then
  443. XCTAssertNil(response?.request)
  444. XCTAssertNil(response?.response)
  445. XCTAssertNil(response?.fileURL)
  446. XCTAssertNil(response?.resumeData)
  447. XCTAssertNotNil(response?.error)
  448. if let error = response?.error?.asAFError {
  449. XCTAssertTrue(error.isInvalidURLError)
  450. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  451. } else {
  452. XCTFail("error should not be nil")
  453. }
  454. }
  455. func testThatUploadDataRequestWithInvalidURLStringThrowsResponseHandlerError() {
  456. // Given
  457. let session = Session()
  458. let expectation = self.expectation(description: "Upload should fail with error")
  459. var response: DataResponse<Data?>?
  460. // When
  461. session.upload(Data(), to: "https://httpbin.org/get/äëïöü").response { resp in
  462. response = resp
  463. expectation.fulfill()
  464. }
  465. waitForExpectations(timeout: timeout, handler: nil)
  466. // Then
  467. XCTAssertNil(response?.request)
  468. XCTAssertNil(response?.response)
  469. XCTAssertNil(response?.data)
  470. XCTAssertNotNil(response?.error)
  471. if let error = response?.error?.asAFError {
  472. XCTAssertTrue(error.isInvalidURLError)
  473. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  474. } else {
  475. XCTFail("error should not be nil")
  476. }
  477. }
  478. func testThatUploadFileRequestWithInvalidURLStringThrowsResponseHandlerError() {
  479. // Given
  480. let session = Session()
  481. let expectation = self.expectation(description: "Upload should fail with error")
  482. var response: DataResponse<Data?>?
  483. // When
  484. session.upload(URL(fileURLWithPath: "/invalid"), to: "https://httpbin.org/get/äëïöü").response { resp in
  485. response = resp
  486. expectation.fulfill()
  487. }
  488. waitForExpectations(timeout: timeout, handler: nil)
  489. // Then
  490. XCTAssertNil(response?.request)
  491. XCTAssertNil(response?.response)
  492. XCTAssertNil(response?.data)
  493. XCTAssertNotNil(response?.error)
  494. if let error = response?.error?.asAFError {
  495. XCTAssertTrue(error.isInvalidURLError)
  496. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  497. } else {
  498. XCTFail("error should not be nil")
  499. }
  500. }
  501. func testThatUploadStreamRequestWithInvalidURLStringThrowsResponseHandlerError() {
  502. // Given
  503. let session = Session()
  504. let expectation = self.expectation(description: "Upload should fail with error")
  505. var response: DataResponse<Data?>?
  506. // When
  507. session.upload(InputStream(data: Data()), to: "https://httpbin.org/get/äëïöü").response { resp in
  508. response = resp
  509. expectation.fulfill()
  510. }
  511. waitForExpectations(timeout: timeout, handler: nil)
  512. // Then
  513. XCTAssertNil(response?.request)
  514. XCTAssertNil(response?.response)
  515. XCTAssertNil(response?.data)
  516. XCTAssertNotNil(response?.error)
  517. if let error = response?.error?.asAFError {
  518. XCTAssertTrue(error.isInvalidURLError)
  519. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  520. } else {
  521. XCTFail("error should not be nil")
  522. }
  523. }
  524. // MARK: Tests - Request Adapter
  525. func testThatSessionCallsRequestAdaptersWhenCreatingDataRequest() {
  526. // Given
  527. let urlString = "https://httpbin.org/get"
  528. let methodAdapter = HTTPMethodAdapter(method: .post)
  529. let headerAdapter = HeaderAdapter()
  530. let monitor = ClosureEventMonitor()
  531. let session = Session(startRequestsImmediately: false, interceptor: methodAdapter, eventMonitors: [monitor])
  532. // When
  533. let expectation1 = self.expectation(description: "Request 1 created")
  534. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  535. let request1 = session.request(urlString)
  536. waitForExpectations(timeout: timeout, handler: nil)
  537. let expectation2 = self.expectation(description: "Request 2 created")
  538. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  539. let request2 = session.request(urlString, interceptor: headerAdapter)
  540. waitForExpectations(timeout: timeout, handler: nil)
  541. // Then
  542. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  543. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  544. XCTAssertEqual(request2.task?.originalRequest?.allHTTPHeaderFields?.count, 1)
  545. XCTAssertEqual(methodAdapter.adaptedCount, 2)
  546. XCTAssertEqual(headerAdapter.adaptedCount, 1)
  547. }
  548. func testThatSessionCallsRequestAdaptersWhenCreatingDownloadRequest() {
  549. // Given
  550. let urlString = "https://httpbin.org/get"
  551. let methodAdapter = HTTPMethodAdapter(method: .post)
  552. let headerAdapter = HeaderAdapter()
  553. let monitor = ClosureEventMonitor()
  554. let session = Session(startRequestsImmediately: false, interceptor: methodAdapter, eventMonitors: [monitor])
  555. // When
  556. let expectation1 = self.expectation(description: "Request 1 created")
  557. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  558. let request1 = session.download(urlString)
  559. waitForExpectations(timeout: timeout, handler: nil)
  560. let expectation2 = self.expectation(description: "Request 2 created")
  561. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  562. let request2 = session.download(urlString, interceptor: headerAdapter)
  563. waitForExpectations(timeout: timeout, handler: nil)
  564. // Then
  565. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  566. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  567. XCTAssertEqual(request2.task?.originalRequest?.allHTTPHeaderFields?.count, 1)
  568. XCTAssertEqual(methodAdapter.adaptedCount, 2)
  569. XCTAssertEqual(headerAdapter.adaptedCount, 1)
  570. }
  571. func testThatSessionCallsRequestAdaptersWhenCreatingUploadRequestWithData() {
  572. // Given
  573. let data = Data("data".utf8)
  574. let urlString = "https://httpbin.org/post"
  575. let methodAdapter = HTTPMethodAdapter(method: .get)
  576. let headerAdapter = HeaderAdapter()
  577. let monitor = ClosureEventMonitor()
  578. let session = Session(startRequestsImmediately: false, interceptor: methodAdapter, eventMonitors: [monitor])
  579. // When
  580. let expectation1 = self.expectation(description: "Request 1 created")
  581. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  582. let request1 = session.upload(data, to: urlString)
  583. waitForExpectations(timeout: timeout, handler: nil)
  584. let expectation2 = self.expectation(description: "Request 2 created")
  585. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  586. let request2 = session.upload(data, to: urlString, interceptor: headerAdapter)
  587. waitForExpectations(timeout: timeout, handler: nil)
  588. // Then
  589. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  590. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  591. XCTAssertEqual(request2.task?.originalRequest?.allHTTPHeaderFields?.count, 1)
  592. XCTAssertEqual(methodAdapter.adaptedCount, 2)
  593. XCTAssertEqual(headerAdapter.adaptedCount, 1)
  594. }
  595. func testThatSessionCallsRequestAdaptersWhenCreatingUploadRequestWithFile() {
  596. // Given
  597. let fileURL = URL(fileURLWithPath: "/path/to/some/file.txt")
  598. let urlString = "https://httpbin.org/post"
  599. let methodAdapter = HTTPMethodAdapter(method: .get)
  600. let headerAdapter = HeaderAdapter()
  601. let monitor = ClosureEventMonitor()
  602. let session = Session(startRequestsImmediately: false, interceptor: methodAdapter, eventMonitors: [monitor])
  603. // When
  604. let expectation1 = self.expectation(description: "Request 1 created")
  605. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  606. let request1 = session.upload(fileURL, to: urlString)
  607. waitForExpectations(timeout: timeout, handler: nil)
  608. let expectation2 = self.expectation(description: "Request 2 created")
  609. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  610. let request2 = session.upload(fileURL, to: urlString, interceptor: headerAdapter)
  611. waitForExpectations(timeout: timeout, handler: nil)
  612. // Then
  613. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  614. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  615. XCTAssertEqual(request2.task?.originalRequest?.allHTTPHeaderFields?.count, 1)
  616. XCTAssertEqual(methodAdapter.adaptedCount, 2)
  617. XCTAssertEqual(headerAdapter.adaptedCount, 1)
  618. }
  619. func testThatSessionCallsRequestAdaptersWhenCreatingUploadRequestWithInputStream() {
  620. // Given
  621. let inputStream = InputStream(data: Data("data".utf8))
  622. let urlString = "https://httpbin.org/post"
  623. let methodAdapter = HTTPMethodAdapter(method: .get)
  624. let headerAdapter = HeaderAdapter()
  625. let monitor = ClosureEventMonitor()
  626. let session = Session(startRequestsImmediately: false, interceptor: methodAdapter, eventMonitors: [monitor])
  627. // When
  628. let expectation1 = self.expectation(description: "Request 1 created")
  629. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  630. let request1 = session.upload(inputStream, to: urlString)
  631. waitForExpectations(timeout: timeout, handler: nil)
  632. let expectation2 = self.expectation(description: "Request 2 created")
  633. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  634. let request2 = session.upload(inputStream, to: urlString, interceptor: headerAdapter)
  635. waitForExpectations(timeout: timeout, handler: nil)
  636. // Then
  637. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  638. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  639. XCTAssertEqual(request2.task?.originalRequest?.allHTTPHeaderFields?.count, 1)
  640. XCTAssertEqual(methodAdapter.adaptedCount, 2)
  641. XCTAssertEqual(headerAdapter.adaptedCount, 1)
  642. }
  643. func testThatSessionReturnsRequestAdaptationErrorWhenRequestAdapterThrowsError() {
  644. // Given
  645. let urlString = "https://httpbin.org/get"
  646. let methodAdapter = HTTPMethodAdapter(method: .post, throwsError: true)
  647. let headerAdapter = HeaderAdapter(throwsError: true)
  648. let monitor = ClosureEventMonitor()
  649. let session = Session(startRequestsImmediately: false, interceptor: methodAdapter, eventMonitors: [monitor])
  650. // When
  651. let expectation1 = self.expectation(description: "Request 1 created")
  652. monitor.requestDidFailToAdaptURLRequestWithError = { _, _, _ in expectation1.fulfill() }
  653. let request1 = session.request(urlString)
  654. waitForExpectations(timeout: timeout, handler: nil)
  655. let expectation2 = self.expectation(description: "Request 2 created")
  656. monitor.requestDidFailToAdaptURLRequestWithError = { _, _, _ in expectation2.fulfill() }
  657. let request2 = session.request(urlString, interceptor: headerAdapter)
  658. waitForExpectations(timeout: timeout, handler: nil)
  659. let requests = [request1, request2]
  660. // Then
  661. for request in requests {
  662. if let error = request.error?.asAFError {
  663. XCTAssertTrue(error.isRequestAdaptationError)
  664. XCTAssertEqual(error.underlyingError?.asAFError?.urlConvertible as? String, "")
  665. } else {
  666. XCTFail("error should not be nil")
  667. }
  668. }
  669. }
  670. // MARK: Tests - Request Retrier
  671. func testThatSessionCallsRequestRetrierWhenRequestEncountersError() {
  672. // Given
  673. let handler = RequestHandler()
  674. let session = Session()
  675. let expectation = self.expectation(description: "request should eventually fail")
  676. var response: DataResponse<Any>?
  677. // When
  678. let request = session.request("https://httpbin.org/basic-auth/user/password", interceptor: handler)
  679. .validate()
  680. .responseJSON { jsonResponse in
  681. response = jsonResponse
  682. expectation.fulfill()
  683. }
  684. waitForExpectations(timeout: timeout, handler: nil)
  685. // Then
  686. XCTAssertEqual(handler.adaptCalledCount, 2)
  687. XCTAssertEqual(handler.adaptedCount, 2)
  688. XCTAssertEqual(handler.retryCalledCount, 3)
  689. XCTAssertEqual(handler.retryCount, 3)
  690. XCTAssertEqual(request.retryCount, 1)
  691. XCTAssertEqual(response?.result.isSuccess, false)
  692. XCTAssertTrue(session.requestTaskMap.isEmpty)
  693. }
  694. func testThatSessionCallsRequestRetrierThenSessionRetrierWhenRequestEncountersError() {
  695. // Given
  696. let sessionHandler = RequestHandler()
  697. let requestHandler = RequestHandler()
  698. let session = Session(interceptor: sessionHandler)
  699. let expectation = self.expectation(description: "request should eventually fail")
  700. var response: DataResponse<Any>?
  701. // When
  702. let request = session.request("https://httpbin.org/basic-auth/user/password", interceptor: requestHandler)
  703. .validate()
  704. .responseJSON { jsonResponse in
  705. response = jsonResponse
  706. expectation.fulfill()
  707. }
  708. waitForExpectations(timeout: timeout, handler: nil)
  709. // Then
  710. XCTAssertEqual(sessionHandler.adaptCalledCount, 3)
  711. XCTAssertEqual(sessionHandler.adaptedCount, 3)
  712. XCTAssertEqual(sessionHandler.retryCalledCount, 3)
  713. XCTAssertEqual(sessionHandler.retryCount, 3)
  714. XCTAssertEqual(requestHandler.adaptCalledCount, 3)
  715. XCTAssertEqual(requestHandler.adaptedCount, 3)
  716. XCTAssertEqual(requestHandler.retryCalledCount, 4)
  717. XCTAssertEqual(requestHandler.retryCount, 4)
  718. XCTAssertEqual(request.retryCount, 2)
  719. XCTAssertEqual(response?.result.isSuccess, false)
  720. XCTAssertTrue(session.requestTaskMap.isEmpty)
  721. }
  722. func testThatSessionCallsRequestRetrierWhenRequestInitiallyEncountersAdaptError() {
  723. // Given
  724. let handler = RequestHandler()
  725. handler.adaptedCount = 1
  726. handler.throwsErrorOnSecondAdapt = true
  727. handler.shouldApplyAuthorizationHeader = true
  728. let session = Session()
  729. let expectation = self.expectation(description: "request should eventually fail")
  730. var response: DataResponse<Any>?
  731. // When
  732. session.request("https://httpbin.org/basic-auth/user/password", interceptor: handler)
  733. .validate()
  734. .responseJSON { jsonResponse in
  735. response = jsonResponse
  736. expectation.fulfill()
  737. }
  738. waitForExpectations(timeout: timeout, handler: nil)
  739. // Then
  740. XCTAssertEqual(handler.adaptCalledCount, 2)
  741. XCTAssertEqual(handler.adaptedCount, 2)
  742. XCTAssertEqual(handler.retryCalledCount, 1)
  743. XCTAssertEqual(handler.retryCount, 1)
  744. XCTAssertEqual(response?.result.isSuccess, true)
  745. XCTAssertTrue(session.requestTaskMap.isEmpty)
  746. }
  747. func testThatSessionCallsRequestRetrierWhenDownloadInitiallyEncountersAdaptError() {
  748. // Given
  749. let handler = RequestHandler()
  750. handler.adaptedCount = 1
  751. handler.throwsErrorOnSecondAdapt = true
  752. handler.shouldApplyAuthorizationHeader = true
  753. let session = Session()
  754. let expectation = self.expectation(description: "request should eventually fail")
  755. var response: DownloadResponse<Any>?
  756. let destination: DownloadRequest.Destination = { _, _ in
  757. let fileURL = self.testDirectoryURL.appendingPathComponent("test-output.json")
  758. return (fileURL, [.removePreviousFile])
  759. }
  760. // When
  761. session.download("https://httpbin.org/basic-auth/user/password", interceptor: handler, to: destination)
  762. .validate()
  763. .responseJSON { jsonResponse in
  764. response = jsonResponse
  765. expectation.fulfill()
  766. }
  767. waitForExpectations(timeout: timeout, handler: nil)
  768. // Then
  769. XCTAssertEqual(handler.adaptCalledCount, 2)
  770. XCTAssertEqual(handler.adaptedCount, 2)
  771. XCTAssertEqual(handler.retryCalledCount, 1)
  772. XCTAssertEqual(handler.retryCount, 1)
  773. XCTAssertEqual(response?.result.isSuccess, true)
  774. XCTAssertTrue(session.requestTaskMap.isEmpty)
  775. }
  776. func testThatSessionCallsRequestRetrierWhenUploadInitiallyEncountersAdaptError() {
  777. // Given
  778. let handler = UploadHandler()
  779. let session = Session(interceptor: handler)
  780. let expectation = self.expectation(description: "request should eventually fail")
  781. var response: DataResponse<Any>?
  782. let uploadData = Data("upload data".utf8)
  783. // When
  784. session.upload(uploadData, to: "https://httpbin.org/post")
  785. .validate()
  786. .responseJSON { jsonResponse in
  787. response = jsonResponse
  788. expectation.fulfill()
  789. }
  790. waitForExpectations(timeout: timeout, handler: nil)
  791. // Then
  792. XCTAssertEqual(handler.adaptCalledCount, 2)
  793. XCTAssertEqual(handler.adaptedCount, 2)
  794. XCTAssertEqual(handler.retryCalledCount, 1)
  795. XCTAssertEqual(handler.retryCount, 1)
  796. XCTAssertEqual(response?.result.isSuccess, true)
  797. XCTAssertTrue(session.requestTaskMap.isEmpty)
  798. }
  799. func testThatSessionCallsAdapterWhenRequestIsRetried() {
  800. // Given
  801. let handler = RequestHandler()
  802. handler.shouldApplyAuthorizationHeader = true
  803. let session = Session(interceptor: handler)
  804. let expectation = self.expectation(description: "request should eventually succeed")
  805. var response: DataResponse<Any>?
  806. // When
  807. let request = session.request("https://httpbin.org/basic-auth/user/password")
  808. .validate()
  809. .responseJSON { jsonResponse in
  810. response = jsonResponse
  811. expectation.fulfill()
  812. }
  813. waitForExpectations(timeout: timeout, handler: nil)
  814. // Then
  815. XCTAssertEqual(handler.adaptCalledCount, 2)
  816. XCTAssertEqual(handler.adaptedCount, 2)
  817. XCTAssertEqual(handler.retryCalledCount, 1)
  818. XCTAssertEqual(handler.retryCount, 1)
  819. XCTAssertEqual(request.retryCount, 1)
  820. XCTAssertEqual(response?.result.isSuccess, true)
  821. XCTAssertTrue(session.requestTaskMap.isEmpty)
  822. }
  823. func testThatSessionReturnsRequestAdaptationErrorWhenRequestIsRetried() {
  824. // Given
  825. let handler = RequestHandler()
  826. handler.throwsErrorOnSecondAdapt = true
  827. let session = Session(interceptor: handler)
  828. let expectation = self.expectation(description: "request should eventually fail")
  829. var response: DataResponse<Any>?
  830. // When
  831. let request = session.request("https://httpbin.org/basic-auth/user/password")
  832. .validate()
  833. .responseJSON { jsonResponse in
  834. response = jsonResponse
  835. expectation.fulfill()
  836. }
  837. waitForExpectations(timeout: timeout, handler: nil)
  838. // Then
  839. XCTAssertEqual(handler.adaptCalledCount, 2)
  840. XCTAssertEqual(handler.adaptedCount, 1)
  841. XCTAssertEqual(handler.retryCalledCount, 3)
  842. XCTAssertEqual(handler.retryCount, 3)
  843. XCTAssertEqual(request.retryCount, 1)
  844. XCTAssertEqual(response?.result.isSuccess, false)
  845. XCTAssertTrue(session.requestTaskMap.isEmpty)
  846. if let error = response?.result.error?.asAFError {
  847. XCTAssertTrue(error.isRequestAdaptationError)
  848. XCTAssertEqual(error.underlyingError?.asAFError?.urlConvertible as? String, "/adapt/error/2")
  849. } else {
  850. XCTFail("error should not be nil")
  851. }
  852. }
  853. func testThatSessionRetriesRequestWithDelayWhenRetryResultContainsDelay() {
  854. // Given
  855. let handler = RequestHandler()
  856. handler.retryDelay = 0.01
  857. handler.throwsErrorOnSecondAdapt = true
  858. let session = Session(interceptor: handler)
  859. let expectation = self.expectation(description: "request should eventually fail")
  860. var response: DataResponse<Any>?
  861. // When
  862. let request = session.request("https://httpbin.org/basic-auth/user/password")
  863. .validate()
  864. .responseJSON { jsonResponse in
  865. response = jsonResponse
  866. expectation.fulfill()
  867. }
  868. waitForExpectations(timeout: timeout, handler: nil)
  869. // Then
  870. XCTAssertEqual(handler.adaptCalledCount, 2)
  871. XCTAssertEqual(handler.adaptedCount, 1)
  872. XCTAssertEqual(handler.retryCalledCount, 3)
  873. XCTAssertEqual(handler.retryCount, 3)
  874. XCTAssertEqual(request.retryCount, 1)
  875. XCTAssertEqual(response?.result.isSuccess, false)
  876. XCTAssertTrue(session.requestTaskMap.isEmpty)
  877. if let error = response?.result.error?.asAFError {
  878. XCTAssertTrue(error.isRequestAdaptationError)
  879. XCTAssertEqual(error.underlyingError?.asAFError?.urlConvertible as? String, "/adapt/error/2")
  880. } else {
  881. XCTFail("error should not be nil")
  882. }
  883. }
  884. func testThatSessionReturnsRequestRetryErrorWhenRequestRetrierThrowsError() {
  885. // Given
  886. let handler = RequestHandler()
  887. handler.throwsErrorOnRetry = true
  888. let session = Session(interceptor: handler)
  889. let expectation = self.expectation(description: "request should eventually fail")
  890. var response: DataResponse<Any>?
  891. // When
  892. let request = session.request("https://httpbin.org/basic-auth/user/password")
  893. .validate()
  894. .responseJSON { jsonResponse in
  895. response = jsonResponse
  896. expectation.fulfill()
  897. }
  898. waitForExpectations(timeout: timeout, handler: nil)
  899. // Then
  900. XCTAssertEqual(handler.adaptCalledCount, 1)
  901. XCTAssertEqual(handler.adaptedCount, 1)
  902. XCTAssertEqual(handler.retryCalledCount, 2)
  903. XCTAssertEqual(handler.retryCount, 0)
  904. XCTAssertEqual(request.retryCount, 0)
  905. XCTAssertEqual(response?.result.isSuccess, false)
  906. XCTAssertTrue(session.requestTaskMap.isEmpty)
  907. if let error = response?.result.error?.asAFError {
  908. XCTAssertTrue(error.isRequestRetryError)
  909. XCTAssertEqual(error.underlyingError?.asAFError?.urlConvertible as? String, "/invalid/url/2")
  910. } else {
  911. XCTFail("error should not be nil")
  912. }
  913. }
  914. // MARK: Tests - Response Serializer Retry
  915. func testThatSessionCallsRequestRetrierWhenResponseSerializerThrowsError() {
  916. // Given
  917. let handler = RequestHandler()
  918. handler.shouldRetry = false
  919. let session = Session()
  920. let expectation = self.expectation(description: "request should eventually fail")
  921. var response: DataResponse<Any>?
  922. // When
  923. let request = session.request("https://httpbin.org/image/jpeg", interceptor: handler)
  924. .validate()
  925. .responseJSON { jsonResponse in
  926. response = jsonResponse
  927. expectation.fulfill()
  928. }
  929. waitForExpectations(timeout: timeout, handler: nil)
  930. // Then
  931. XCTAssertEqual(handler.adaptCalledCount, 1)
  932. XCTAssertEqual(handler.adaptedCount, 1)
  933. XCTAssertEqual(handler.retryCalledCount, 1)
  934. XCTAssertEqual(handler.retryCount, 0)
  935. XCTAssertEqual(request.retryCount, 0)
  936. XCTAssertEqual(response?.result.isSuccess, false)
  937. XCTAssertTrue(session.requestTaskMap.isEmpty)
  938. if let error = response?.error?.asAFError {
  939. XCTAssertTrue(error.isResponseSerializationError)
  940. XCTAssertTrue(error.localizedDescription.starts(with: "JSON could not be serialized"))
  941. } else {
  942. XCTFail("error should not be nil")
  943. }
  944. }
  945. func testThatSessionCallsRequestRetrierForAllResponseSerializersThatThrowError() throws {
  946. // Given
  947. let handler = RequestHandler()
  948. handler.throwsErrorOnRetry = true
  949. let session = Session()
  950. let json1Expectation = self.expectation(description: "request should eventually fail")
  951. var json1Response: DataResponse<Any>?
  952. let json2Expectation = self.expectation(description: "request should eventually fail")
  953. var json2Response: DataResponse<Any>?
  954. // When
  955. let request = session.request("https://httpbin.org/image/jpeg", interceptor: handler)
  956. .validate()
  957. .responseJSON { response in
  958. json1Response = response
  959. json1Expectation.fulfill()
  960. }
  961. .responseJSON { response in
  962. json2Response = response
  963. json2Expectation.fulfill()
  964. }
  965. waitForExpectations(timeout: timeout, handler: nil)
  966. // Then
  967. XCTAssertEqual(handler.adaptCalledCount, 1)
  968. XCTAssertEqual(handler.adaptedCount, 1)
  969. XCTAssertEqual(handler.retryCalledCount, 2)
  970. XCTAssertEqual(handler.retryCount, 0)
  971. XCTAssertEqual(request.retryCount, 0)
  972. XCTAssertEqual(json1Response?.result.isSuccess, false)
  973. XCTAssertEqual(json2Response?.result.isSuccess, false)
  974. XCTAssertTrue(session.requestTaskMap.isEmpty)
  975. let errors: [AFError] = [json1Response, json2Response].compactMap { $0?.error?.asAFError }
  976. XCTAssertEqual(errors.count, 2)
  977. for (index, error) in errors.enumerated() {
  978. XCTAssertTrue(error.isRequestRetryError)
  979. XCTAssertEqual(error.localizedDescription.starts(with: "Request retry failed with retry error"), true)
  980. if case let .requestRetryFailed(retryError, originalError) = error {
  981. XCTAssertEqual(try retryError.asAFError?.urlConvertible?.asURL().absoluteString, "/invalid/url/\(index + 1)")
  982. XCTAssertTrue(originalError.localizedDescription.starts(with: "JSON could not be serialized"))
  983. } else {
  984. XCTFail("Error failure reason should be response serialization failure")
  985. }
  986. }
  987. }
  988. func testThatSessionRetriesRequestImmediatelyWhenResponseSerializerRequestsRetry() throws {
  989. // Given
  990. let handler = RequestHandler()
  991. let session = Session()
  992. let json1Expectation = self.expectation(description: "request should eventually fail")
  993. var json1Response: DataResponse<Any>?
  994. let json2Expectation = self.expectation(description: "request should eventually fail")
  995. var json2Response: DataResponse<Any>?
  996. // When
  997. let request = session.request("https://httpbin.org/image/jpeg", interceptor: handler)
  998. .validate()
  999. .responseJSON { response in
  1000. json1Response = response
  1001. json1Expectation.fulfill()
  1002. }
  1003. .responseJSON { response in
  1004. json2Response = response
  1005. json2Expectation.fulfill()
  1006. }
  1007. waitForExpectations(timeout: 10, handler: nil)
  1008. // Then
  1009. XCTAssertEqual(handler.adaptCalledCount, 2)
  1010. XCTAssertEqual(handler.adaptedCount, 2)
  1011. XCTAssertEqual(handler.retryCalledCount, 3)
  1012. XCTAssertEqual(handler.retryCount, 3)
  1013. XCTAssertEqual(request.retryCount, 1)
  1014. XCTAssertEqual(json1Response?.result.isSuccess, false)
  1015. XCTAssertEqual(json2Response?.result.isSuccess, false)
  1016. XCTAssertTrue(session.requestTaskMap.isEmpty)
  1017. let errors: [AFError] = [json1Response, json2Response].compactMap { $0?.error?.asAFError }
  1018. XCTAssertEqual(errors.count, 2)
  1019. for error in errors {
  1020. XCTAssertTrue(error.isResponseSerializationError)
  1021. XCTAssertTrue(error.localizedDescription.starts(with: "JSON could not be serialized"))
  1022. }
  1023. }
  1024. func testThatSessionCallsResponseSerializerCompletionsWhenAdapterThrowsErrorDuringRetry() {
  1025. // Four retries should occur given this scenario:
  1026. // 1) Retrier is called from first response serializer failure (trips retry)
  1027. // 2) Retrier is called by Session for adapt error thrown
  1028. // 3) Retrier is called again from first response serializer failure
  1029. // 4) Retrier is called from second response serializer failure
  1030. // Given
  1031. let handler = RequestHandler()
  1032. handler.throwsErrorOnSecondAdapt = true
  1033. let session = Session()
  1034. let json1Expectation = self.expectation(description: "request should eventually fail")
  1035. var json1Response: DataResponse<Any>?
  1036. let json2Expectation = self.expectation(description: "request should eventually fail")
  1037. var json2Response: DataResponse<Any>?
  1038. // When
  1039. let request = session.request("https://httpbin.org/image/jpeg", interceptor: handler)
  1040. .validate()
  1041. .responseJSON { response in
  1042. json1Response = response
  1043. json1Expectation.fulfill()
  1044. }
  1045. .responseJSON { response in
  1046. json2Response = response
  1047. json2Expectation.fulfill()
  1048. }
  1049. waitForExpectations(timeout: 10, handler: nil)
  1050. // Then
  1051. XCTAssertEqual(handler.adaptCalledCount, 2)
  1052. XCTAssertEqual(handler.adaptedCount, 1)
  1053. XCTAssertEqual(handler.retryCalledCount, 4)
  1054. XCTAssertEqual(handler.retryCount, 4)
  1055. XCTAssertEqual(request.retryCount, 1)
  1056. XCTAssertEqual(json1Response?.result.isSuccess, false)
  1057. XCTAssertEqual(json2Response?.result.isSuccess, false)
  1058. XCTAssertTrue(session.requestTaskMap.isEmpty)
  1059. let errors: [AFError] = [json1Response, json2Response].compactMap { $0?.error?.asAFError }
  1060. XCTAssertEqual(errors.count, 2)
  1061. for error in errors {
  1062. XCTAssertTrue(error.isRequestAdaptationError)
  1063. XCTAssertEqual(error.localizedDescription, "Request adaption failed with error: URL is not valid: /adapt/error/2")
  1064. }
  1065. }
  1066. func testThatSessionCallsResponseSerializerCompletionsWhenAdapterThrowsErrorDuringRetryForDownloads() {
  1067. // Four retries should occur given this scenario:
  1068. // 1) Retrier is called from first response serializer failure (trips retry)
  1069. // 2) Retrier is called by Session for adapt error thrown
  1070. // 3) Retrier is called again from first response serializer failure
  1071. // 4) Retrier is called from second response serializer failure
  1072. // Given
  1073. let handler = RequestHandler()
  1074. handler.throwsErrorOnSecondAdapt = true
  1075. let session = Session()
  1076. let json1Expectation = self.expectation(description: "request should eventually fail")
  1077. var json1Response: DownloadResponse<Any>?
  1078. let json2Expectation = self.expectation(description: "request should eventually fail")
  1079. var json2Response: DownloadResponse<Any>?
  1080. // When
  1081. let request = session.download("https://httpbin.org/image/jpeg", interceptor: handler)
  1082. .validate()
  1083. .responseJSON { response in
  1084. json1Response = response
  1085. json1Expectation.fulfill()
  1086. }
  1087. .responseJSON { response in
  1088. json2Response = response
  1089. json2Expectation.fulfill()
  1090. }
  1091. waitForExpectations(timeout: 10, handler: nil)
  1092. // Then
  1093. XCTAssertEqual(handler.adaptCalledCount, 2)
  1094. XCTAssertEqual(handler.adaptedCount, 1)
  1095. XCTAssertEqual(handler.retryCalledCount, 4)
  1096. XCTAssertEqual(handler.retryCount, 4)
  1097. XCTAssertEqual(request.retryCount, 1)
  1098. XCTAssertEqual(json1Response?.result.isSuccess, false)
  1099. XCTAssertEqual(json2Response?.result.isSuccess, false)
  1100. XCTAssertTrue(session.requestTaskMap.isEmpty)
  1101. let errors: [AFError] = [json1Response, json2Response].compactMap { $0?.error?.asAFError }
  1102. XCTAssertEqual(errors.count, 2)
  1103. for error in errors {
  1104. XCTAssertTrue(error.isRequestAdaptationError)
  1105. XCTAssertEqual(error.localizedDescription, "Request adaption failed with error: URL is not valid: /adapt/error/2")
  1106. }
  1107. }
  1108. // MARK: Tests - Session Invalidation
  1109. func testThatSessionIsInvalidatedAndAllRequestsCompleteWhenSessionIsDeinitialized() {
  1110. // Given
  1111. let invalidationExpectation = expectation(description: "sessionDidBecomeInvalidWithError should be called")
  1112. let events = ClosureEventMonitor()
  1113. events.sessionDidBecomeInvalidWithError = { (_, _) in
  1114. invalidationExpectation.fulfill()
  1115. }
  1116. var session: Session? = Session(startRequestsImmediately: false, eventMonitors: [events])
  1117. var error: Error?
  1118. let requestExpectation = expectation(description: "request should complete")
  1119. // When
  1120. session?.request(URLRequest.makeHTTPBinRequest()).response { (response) in
  1121. error = response.error
  1122. requestExpectation.fulfill()
  1123. }
  1124. session = nil
  1125. waitForExpectations(timeout: timeout, handler: nil)
  1126. // Then
  1127. assertErrorIsAFError(error) { XCTAssertTrue($0.isSessionDeinitializedError) }
  1128. }
  1129. // MARK: Tests - Request Cancellation
  1130. func testThatSessionOnlyCallsResponseSerializerCompletionWhenCancellingInsideCompletion() {
  1131. // Given
  1132. let handler = RequestHandler()
  1133. let session = Session()
  1134. let expectation = self.expectation(description: "request should complete")
  1135. var response: DataResponse<Any>?
  1136. var completionCallCount = 0
  1137. // When
  1138. let request = session.request("https://httpbin.org/get", interceptor: handler)
  1139. request.validate()
  1140. request.responseJSON { resp in
  1141. request.cancel()
  1142. response = resp
  1143. completionCallCount += 1
  1144. DispatchQueue.main.after(0.01) { expectation.fulfill() }
  1145. }
  1146. waitForExpectations(timeout: timeout, handler: nil)
  1147. // Then
  1148. XCTAssertEqual(handler.adaptCalledCount, 1)
  1149. XCTAssertEqual(handler.adaptedCount, 1)
  1150. XCTAssertEqual(handler.retryCalledCount, 0)
  1151. XCTAssertEqual(handler.retryCount, 0)
  1152. XCTAssertEqual(request.retryCount, 0)
  1153. XCTAssertEqual(response?.result.isSuccess, true)
  1154. XCTAssertTrue(session.requestTaskMap.isEmpty)
  1155. XCTAssertEqual(completionCallCount, 1)
  1156. }
  1157. // MARK: Tests - Request State
  1158. func testThatSessionSetsRequestStateWhenStartRequestsImmediatelyIsTrue() {
  1159. // Given
  1160. let session = Session()
  1161. let expectation = self.expectation(description: "request should complete")
  1162. var response: DataResponse<Any>?
  1163. // When
  1164. let request = session.request("https://httpbin.org/get").responseJSON { resp in
  1165. response = resp
  1166. expectation.fulfill()
  1167. }
  1168. waitForExpectations(timeout: timeout, handler: nil)
  1169. // Then
  1170. XCTAssertEqual(request.state, .resumed)
  1171. XCTAssertEqual(response?.result.isSuccess, true)
  1172. }
  1173. }
  1174. // MARK: -
  1175. class SessionManagerConfigurationHeadersTestCase: BaseTestCase {
  1176. enum ConfigurationType {
  1177. case `default`, ephemeral, background
  1178. }
  1179. func testThatDefaultConfigurationHeadersAreSentWithRequest() {
  1180. // Given, When, Then
  1181. executeAuthorizationHeaderTest(for: .default)
  1182. }
  1183. func testThatEphemeralConfigurationHeadersAreSentWithRequest() {
  1184. // Given, When, Then
  1185. executeAuthorizationHeaderTest(for: .ephemeral)
  1186. }
  1187. #if os(macOS)
  1188. func testThatBackgroundConfigurationHeadersAreSentWithRequest() {
  1189. // Given, When, Then
  1190. executeAuthorizationHeaderTest(for: .background)
  1191. }
  1192. #endif
  1193. private func executeAuthorizationHeaderTest(for type: ConfigurationType) {
  1194. // Given
  1195. let session: Session = {
  1196. let configuration: URLSessionConfiguration = {
  1197. let configuration: URLSessionConfiguration
  1198. switch type {
  1199. case .default:
  1200. configuration = .default
  1201. case .ephemeral:
  1202. configuration = .ephemeral
  1203. case .background:
  1204. let identifier = "org.alamofire.test.manager-configuration-tests"
  1205. configuration = .background(withIdentifier: identifier)
  1206. }
  1207. var headers = HTTPHeaders.default
  1208. headers["Authorization"] = "Bearer 123456"
  1209. configuration.httpHeaders = headers
  1210. return configuration
  1211. }()
  1212. return Session(configuration: configuration)
  1213. }()
  1214. let expectation = self.expectation(description: "request should complete successfully")
  1215. var response: DataResponse<Any>?
  1216. // When
  1217. session.request("https://httpbin.org/headers")
  1218. .responseJSON { closureResponse in
  1219. response = closureResponse
  1220. expectation.fulfill()
  1221. }
  1222. waitForExpectations(timeout: timeout, handler: nil)
  1223. // Then
  1224. if let response = response {
  1225. XCTAssertNotNil(response.request, "request should not be nil")
  1226. XCTAssertNotNil(response.response, "response should not be nil")
  1227. XCTAssertNotNil(response.data, "data should not be nil")
  1228. XCTAssertTrue(response.result.isSuccess, "result should be a success")
  1229. if
  1230. let response = response.result.value as? [String: Any],
  1231. let headers = response["headers"] as? [String: String],
  1232. let authorization = headers["Authorization"]
  1233. {
  1234. XCTAssertEqual(authorization, "Bearer 123456", "authorization header value does not match")
  1235. } else {
  1236. XCTFail("failed to extract authorization header value")
  1237. }
  1238. } else {
  1239. XCTFail("response should not be nil")
  1240. }
  1241. }
  1242. }