SessionTests.swift 75 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016
  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. final class SessionTestCase: BaseTestCase {
  28. // MARK: Helper Types
  29. private final class HTTPMethodAdapter: RequestInterceptor {
  30. let method: HTTPMethod
  31. let throwsError: Bool
  32. let adaptedCount = Protected(0)
  33. init(method: HTTPMethod, throwsError: Bool = false) {
  34. self.method = method
  35. self.throwsError = throwsError
  36. }
  37. func adapt(_ urlRequest: URLRequest, using state: RequestAdapterState, completion: @escaping (Result<URLRequest, any Error>) -> Void) {
  38. adaptedCount.write { $0 += 1 }
  39. let result: Result<URLRequest, any Error> = 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 final class HeaderAdapter: RequestInterceptor {
  49. let headers: HTTPHeaders
  50. let throwsError: Bool
  51. let adaptedCount = Protected(0)
  52. init(headers: HTTPHeaders = ["field": "value"], throwsError: Bool = false) {
  53. self.headers = headers
  54. self.throwsError = throwsError
  55. }
  56. func adapt(_ urlRequest: URLRequest, using state: RequestAdapterState, completion: @escaping (Result<URLRequest, any Error>) -> Void) {
  57. adaptedCount.write { $0 += 1 }
  58. let result: Result<URLRequest, any Error> = Result {
  59. guard !throwsError else { throw AFError.invalidURL(url: "") }
  60. var urlRequest = urlRequest
  61. var finalHeaders = urlRequest.headers
  62. headers.forEach { finalHeaders.add($0) }
  63. urlRequest.headers = finalHeaders
  64. return urlRequest
  65. }
  66. completion(result)
  67. }
  68. }
  69. private final class RequestHandler: RequestInterceptor {
  70. struct MutableState {
  71. var adaptCalledCount = 0
  72. var adaptedCount = 0
  73. var retryCount = 0
  74. var retryCalledCount = 0
  75. var retryErrors: [any Error] = []
  76. var shouldApplyAuthorizationHeader = false
  77. var throwsErrorOnFirstAdapt = false
  78. var throwsErrorOnSecondAdapt = false
  79. var throwsErrorOnRetry = false
  80. var shouldRetry = true
  81. var retryDelay: TimeInterval?
  82. }
  83. private let mutableState: Protected<MutableState>
  84. var adaptCalledCount: Int { mutableState.read(\.adaptCalledCount) }
  85. var adaptedCount: Int { mutableState.read(\.adaptedCount) }
  86. var retryCalledCount: Int { mutableState.read(\.retryCalledCount) }
  87. var retryCount: Int { mutableState.read(\.retryCount) }
  88. var retryErrors: [any Error] { mutableState.read(\.retryErrors) }
  89. init(adaptedCount: Int = 0,
  90. throwsErrorOnSecondAdapt: Bool = false,
  91. throwsErrorOnRetry: Bool = false,
  92. shouldApplyAuthorizationHeader: Bool = false,
  93. shouldRetry: Bool = true,
  94. retryDelay: TimeInterval? = nil) {
  95. mutableState = Protected(.init(adaptedCount: adaptedCount,
  96. shouldApplyAuthorizationHeader: shouldApplyAuthorizationHeader,
  97. throwsErrorOnSecondAdapt: throwsErrorOnSecondAdapt,
  98. throwsErrorOnRetry: throwsErrorOnRetry,
  99. shouldRetry: shouldRetry,
  100. retryDelay: retryDelay))
  101. }
  102. func adapt(_ urlRequest: URLRequest,
  103. using state: RequestAdapterState,
  104. completion: @escaping (Result<URLRequest, any Error>) -> Void) {
  105. let result = mutableState.write { mutableState in
  106. mutableState.adaptCalledCount += 1
  107. return Result {
  108. if mutableState.throwsErrorOnFirstAdapt {
  109. mutableState.throwsErrorOnFirstAdapt = false
  110. throw AFError.invalidURL(url: "/adapt/error/1")
  111. }
  112. if mutableState.throwsErrorOnSecondAdapt && mutableState.adaptedCount == 1 {
  113. mutableState.throwsErrorOnSecondAdapt = false
  114. throw AFError.invalidURL(url: "/adapt/error/2")
  115. }
  116. var urlRequest = urlRequest
  117. mutableState.adaptedCount += 1
  118. if mutableState.shouldApplyAuthorizationHeader && mutableState.adaptedCount > 1 {
  119. urlRequest.headers.update(.authorization(username: "user", password: "password"))
  120. }
  121. return urlRequest
  122. }
  123. }
  124. completion(result)
  125. }
  126. func retry(_ request: Request,
  127. for session: Session,
  128. dueTo error: any Error,
  129. completion: @escaping (RetryResult) -> Void) {
  130. let result: RetryResult = mutableState.write { mutableState in
  131. mutableState.retryCalledCount += 1
  132. if mutableState.throwsErrorOnRetry {
  133. let error = AFError.invalidURL(url: "/invalid/url/\(mutableState.retryCalledCount)")
  134. return .doNotRetryWithError(error)
  135. }
  136. guard mutableState.shouldRetry else { return .doNotRetry }
  137. mutableState.retryCount += 1
  138. mutableState.retryErrors.append(error)
  139. if mutableState.retryCount < 2 {
  140. if let retryDelay = mutableState.retryDelay {
  141. return .retryWithDelay(retryDelay)
  142. } else {
  143. return .retry
  144. }
  145. } else {
  146. return .doNotRetry
  147. }
  148. }
  149. completion(result)
  150. }
  151. }
  152. private final class UploadHandler: RequestInterceptor {
  153. struct MutableState {
  154. var adaptCalledCount = 0
  155. var adaptedCount = 0
  156. var retryCalledCount = 0
  157. var retryCount = 0
  158. var retryErrors: [any Error] = []
  159. }
  160. private let mutableState = Protected(MutableState())
  161. var adaptCalledCount: Int { mutableState.read(\.adaptCalledCount) }
  162. var adaptedCount: Int { mutableState.read(\.adaptedCount) }
  163. var retryCalledCount: Int { mutableState.read(\.retryCalledCount) }
  164. var retryCount: Int { mutableState.read(\.retryCount) }
  165. var retryErrors: [any Error] { mutableState.read(\.retryErrors) }
  166. func adapt(_ urlRequest: URLRequest,
  167. using state: RequestAdapterState,
  168. completion: @escaping (Result<URLRequest, any Error>) -> Void) {
  169. let result: Result<URLRequest, any Error> = mutableState.write { mutableState in
  170. mutableState.adaptCalledCount += 1
  171. return Result {
  172. mutableState.adaptedCount += 1
  173. if mutableState.adaptedCount == 1 { throw AFError.invalidURL(url: "") }
  174. return urlRequest
  175. }
  176. }
  177. completion(result)
  178. }
  179. func retry(_ request: Request,
  180. for session: Session,
  181. dueTo error: any Error,
  182. completion: @escaping (RetryResult) -> Void) {
  183. mutableState.write { mutableState in
  184. mutableState.retryCalledCount += 1
  185. mutableState.retryCount += 1
  186. mutableState.retryErrors.append(error)
  187. }
  188. completion(.retry)
  189. }
  190. }
  191. // MARK: Tests - Initialization
  192. @MainActor
  193. func testInitializerWithDefaultArguments() {
  194. // Given, When
  195. let session = Session()
  196. // Then
  197. XCTAssertNotNil(session.session.delegate, "session delegate should not be nil")
  198. XCTAssertTrue(session.delegate === session.session.delegate, "manager delegate should equal session delegate")
  199. XCTAssertNil(session.serverTrustManager, "session server trust policy manager should be nil")
  200. }
  201. @MainActor
  202. func testInitializerWithSpecifiedArguments() {
  203. // Given
  204. let configuration = URLSessionConfiguration.default
  205. let delegate = SessionDelegate()
  206. let serverTrustManager = ServerTrustManager(evaluators: [:])
  207. // When
  208. let session = Session(configuration: configuration,
  209. delegate: delegate,
  210. serverTrustManager: serverTrustManager)
  211. // Then
  212. XCTAssertNotNil(session.session.delegate, "session delegate should not be nil")
  213. XCTAssertTrue(session.delegate === session.session.delegate, "manager delegate should equal session delegate")
  214. XCTAssertNotNil(session.serverTrustManager, "session server trust policy manager should not be nil")
  215. }
  216. @MainActor
  217. func testThatSessionInitializerSucceedsWithDefaultArguments() {
  218. // Given
  219. let delegate = SessionDelegate()
  220. let underlyingQueue = DispatchQueue(label: "underlyingQueue")
  221. let urlSession: URLSession = {
  222. let configuration = URLSessionConfiguration.default
  223. let queue = OperationQueue(underlyingQueue: underlyingQueue, name: "delegateQueue")
  224. return URLSession(configuration: configuration, delegate: delegate, delegateQueue: queue)
  225. }()
  226. // When
  227. let session = Session(session: urlSession, delegate: delegate, rootQueue: underlyingQueue)
  228. // Then
  229. XCTAssertTrue(session.delegate === session.session.delegate, "manager delegate should equal session delegate")
  230. XCTAssertNil(session.serverTrustManager, "session server trust policy manager should be nil")
  231. }
  232. @MainActor
  233. func testThatSessionInitializerSucceedsWithSpecifiedArguments() {
  234. // Given
  235. let delegate = SessionDelegate()
  236. let underlyingQueue = DispatchQueue(label: "underlyingQueue")
  237. let urlSession: URLSession = {
  238. let configuration = URLSessionConfiguration.default
  239. let queue = OperationQueue(underlyingQueue: underlyingQueue, name: "delegateQueue")
  240. return URLSession(configuration: configuration, delegate: delegate, delegateQueue: queue)
  241. }()
  242. let serverTrustManager = ServerTrustManager(evaluators: [:])
  243. // When
  244. let session = Session(session: urlSession,
  245. delegate: delegate,
  246. rootQueue: underlyingQueue,
  247. serverTrustManager: serverTrustManager)
  248. // Then
  249. XCTAssertTrue(session.delegate === session.session.delegate, "manager delegate should equal session delegate")
  250. XCTAssertNotNil(session.serverTrustManager, "session server trust policy manager should not be nil")
  251. }
  252. // MARK: Tests - Parallel Root Queue
  253. @MainActor
  254. func testThatSessionWorksCorrectlyWhenPassedAConcurrentRootQueue() {
  255. // Given
  256. let queue = DispatchQueue(label: "ohNoAParallelQueue", attributes: .concurrent)
  257. let session = Session(rootQueue: queue)
  258. let didFinish = expectation(description: "request did finish")
  259. var receivedResponse: TestResponse?
  260. // When
  261. session.request(.get).responseDecodable(of: TestResponse.self) { response in
  262. receivedResponse = response.value
  263. didFinish.fulfill()
  264. }
  265. waitForExpectations(timeout: timeout)
  266. // Then
  267. XCTAssertNotNil(receivedResponse, "Should receive TestResponse.")
  268. }
  269. // MARK: Tests - Default HTTP Headers
  270. @MainActor
  271. func testDefaultUserAgentHeader() {
  272. // Given, When
  273. let userAgent = HTTPHeaders.default["User-Agent"]
  274. // Then
  275. let osNameVersion: String = {
  276. let version = ProcessInfo.processInfo.operatingSystemVersion
  277. let versionString = "\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)"
  278. let osName: String = {
  279. #if os(iOS)
  280. #if targetEnvironment(macCatalyst)
  281. return "macOS(Catalyst)"
  282. #else
  283. return "iOS"
  284. #endif
  285. #elseif os(watchOS)
  286. return "watchOS"
  287. #elseif os(tvOS)
  288. return "tvOS"
  289. #elseif os(macOS)
  290. #if targetEnvironment(macCatalyst)
  291. return "macOS(Catalyst)"
  292. #else
  293. return "macOS"
  294. #endif
  295. #elseif os(visionOS)
  296. return "visionOS"
  297. #elseif os(Linux)
  298. return "Linux"
  299. #elseif os(Windows)
  300. return "Windows"
  301. #elseif os(Android)
  302. return "Android"
  303. #elseif os(WASI)
  304. return "WASI"
  305. #else
  306. return "Unknown"
  307. #endif
  308. }()
  309. return "\(osName) \(versionString)"
  310. }()
  311. let alamofireVersion = "Alamofire/\(AFInfo.version)"
  312. XCTAssertTrue(userAgent?.contains(alamofireVersion) == true)
  313. XCTAssertTrue(userAgent?.contains(osNameVersion) == true)
  314. XCTAssertTrue(userAgent?.contains("xctest/") == true)
  315. }
  316. // MARK: Tests - Supported Accept-Encodings
  317. // Disabled due to HTTPBin flakiness.
  318. @MainActor
  319. func disabled_testDefaultAcceptEncodingSupportsAppropriateEncodingsOnAppropriateSystems() {
  320. // Given
  321. let brotliExpectation = expectation(description: "brotli request should complete")
  322. let gzipExpectation = expectation(description: "gzip request should complete")
  323. let deflateExpectation = expectation(description: "deflate request should complete")
  324. var brotliResponse: DataResponse<TestResponse, AFError>?
  325. var gzipResponse: DataResponse<TestResponse, AFError>?
  326. var deflateResponse: DataResponse<TestResponse, AFError>?
  327. // When
  328. AF.request(.compression(.brotli)).responseDecodable(of: TestResponse.self) { response in
  329. brotliResponse = response
  330. brotliExpectation.fulfill()
  331. }
  332. AF.request(.compression(.gzip)).responseDecodable(of: TestResponse.self) { response in
  333. gzipResponse = response
  334. gzipExpectation.fulfill()
  335. }
  336. AF.request(.compression(.deflate)).responseDecodable(of: TestResponse.self) { response in
  337. deflateResponse = response
  338. deflateExpectation.fulfill()
  339. }
  340. waitForExpectations(timeout: timeout)
  341. // Then
  342. if #available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, *) {
  343. XCTAssertTrue(brotliResponse?.result.isSuccess == true)
  344. } else {
  345. XCTAssertTrue(brotliResponse?.result.isFailure == true)
  346. }
  347. XCTAssertTrue(gzipResponse?.result.isSuccess == true)
  348. XCTAssertTrue(deflateResponse?.result.isSuccess == true)
  349. }
  350. // MARK: Tests - Start Requests Immediately
  351. @MainActor
  352. func testSetStartRequestsImmediatelyToFalseAndResumeRequest() {
  353. // Given
  354. let session = Session(startRequestsImmediately: false)
  355. let url = Endpoint().url
  356. let urlRequest = URLRequest(url: url)
  357. let expectation = expectation(description: "\(url)")
  358. var response: HTTPURLResponse?
  359. // When
  360. session.request(urlRequest)
  361. .response { resp in
  362. response = resp.response
  363. expectation.fulfill()
  364. }
  365. .resume()
  366. waitForExpectations(timeout: timeout)
  367. // Then
  368. XCTAssertNotNil(response, "response should not be nil")
  369. XCTAssertTrue(response?.statusCode == 200, "response status code should be 200")
  370. }
  371. @MainActor
  372. func testSetStartRequestsImmediatelyToFalseAndCancelledCallsResponseHandlers() {
  373. // Given
  374. let session = Session(startRequestsImmediately: false)
  375. let url = Endpoint().url
  376. let urlRequest = URLRequest(url: url)
  377. let expectation = expectation(description: "\(url)")
  378. var response: DataResponse<Data?, AFError>?
  379. // When
  380. let request = session.request(urlRequest)
  381. .cancel()
  382. .response { resp in
  383. response = resp
  384. expectation.fulfill()
  385. }
  386. waitForExpectations(timeout: timeout)
  387. // Then
  388. XCTAssertNotNil(response, "response should not be nil")
  389. XCTAssertTrue(request.isCancelled)
  390. XCTAssertTrue((request.task == nil) || (request.task?.state == .canceling || request.task?.state == .completed))
  391. XCTAssertEqual(request.error?.isExplicitlyCancelledError, true)
  392. }
  393. @MainActor
  394. func testSetStartRequestsImmediatelyToFalseAndResumeThenCancelRequestHasCorrectOutput() {
  395. // Given
  396. let session = Session(startRequestsImmediately: false)
  397. let url = Endpoint().url
  398. let urlRequest = URLRequest(url: url)
  399. let expectation = expectation(description: "\(url)")
  400. var response: DataResponse<Data?, AFError>?
  401. // When
  402. let request = session.request(urlRequest)
  403. .response { resp in
  404. response = resp
  405. expectation.fulfill()
  406. }
  407. .resume()
  408. .cancel()
  409. waitForExpectations(timeout: timeout)
  410. // Then
  411. XCTAssertNotNil(response, "response should not be nil")
  412. XCTAssertTrue(request.isCancelled)
  413. XCTAssertTrue((request.task == nil) || (request.task?.state == .canceling || request.task?.state == .completed))
  414. XCTAssertEqual(request.error?.isExplicitlyCancelledError, true)
  415. }
  416. @MainActor
  417. func testSetStartRequestsImmediatelyToFalseAndCancelThenResumeRequestDoesntCreateTaskAndStaysCancelled() {
  418. // Given
  419. let session = Session(startRequestsImmediately: false)
  420. let url = Endpoint().url
  421. let urlRequest = URLRequest(url: url)
  422. let expectation = expectation(description: "\(url)")
  423. var response: DataResponse<Data?, AFError>?
  424. // When
  425. let request = session.request(urlRequest)
  426. .response { resp in
  427. response = resp
  428. expectation.fulfill()
  429. }
  430. .cancel()
  431. .resume()
  432. waitForExpectations(timeout: timeout)
  433. // Then
  434. XCTAssertNotNil(response, "response should not be nil")
  435. XCTAssertTrue(request.isCancelled)
  436. XCTAssertTrue((request.task == nil) || (request.task?.state == .canceling || request.task?.state == .completed))
  437. XCTAssertEqual(request.error?.isExplicitlyCancelledError, true)
  438. }
  439. // MARK: Tests - Deinitialization
  440. @MainActor
  441. func testReleasingManagerWithPendingRequestDeinitializesSuccessfully() {
  442. // Given
  443. let monitor = ClosureEventMonitor()
  444. let didCreateRequest = expectation(description: "Request created")
  445. monitor.requestDidCreateTask = { _, _ in didCreateRequest.fulfill() }
  446. var session: Session? = Session(startRequestsImmediately: false, requestSetup: .eager, eventMonitors: [monitor])
  447. #if compiler(>=6.2.3) // Started emitting a diagnostic in 6.2.2, so lets conditionally use it.
  448. weak let weakSession = session
  449. #else
  450. weak var weakSession = session
  451. #endif
  452. // When
  453. let request = session?.request(.default)
  454. session = nil
  455. waitForExpectations(timeout: timeout)
  456. // Then
  457. if #available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) {
  458. // On 2022 OS versions and later, URLSessionTasks are completed even if not resumed before invalidating a session.
  459. XCTAssertTrue([.canceling, .completed].contains(request?.task?.state))
  460. } else {
  461. XCTAssertEqual(request?.task?.state, .suspended)
  462. }
  463. XCTAssertNil(session, "session should be nil")
  464. XCTAssertNil(weakSession, "weak session should be nil")
  465. }
  466. func testReleasingManagerWithPendingCanceledRequestDeinitializesSuccessfully() {
  467. // Given
  468. var session: Session? = Session(startRequestsImmediately: false)
  469. // When
  470. let request = session?.request(.default)
  471. request?.cancel()
  472. session = nil
  473. let state = request?.state
  474. // Then
  475. XCTAssertTrue(state == .cancelled, "state should be .cancelled")
  476. XCTAssertNil(session, "manager should be nil")
  477. }
  478. // MARK: Tests - Bad Requests
  479. @MainActor
  480. func testThatDataRequestWithInvalidURLStringThrowsResponseHandlerError() {
  481. // Given
  482. let session = Session()
  483. let url = ""
  484. let expectation = expectation(description: "Request should fail with error")
  485. var response: DataResponse<Data?, AFError>?
  486. // When
  487. session.request(url).response { resp in
  488. response = resp
  489. expectation.fulfill()
  490. }
  491. waitForExpectations(timeout: timeout)
  492. // Then
  493. XCTAssertNil(response?.request)
  494. XCTAssertNil(response?.response)
  495. XCTAssertNil(response?.data)
  496. XCTAssertNotNil(response?.error)
  497. XCTAssertEqual(response?.error?.isInvalidURLError, true)
  498. XCTAssertEqual(response?.error?.urlConvertible as? String, url)
  499. }
  500. @MainActor
  501. func testThatDownloadRequestWithInvalidURLStringThrowsResponseHandlerError() {
  502. // Given
  503. let session = Session()
  504. let url = ""
  505. let expectation = expectation(description: "Download should fail with error")
  506. var response: DownloadResponse<URL?, AFError>?
  507. // When
  508. session.download(url).response { resp in
  509. response = resp
  510. expectation.fulfill()
  511. }
  512. waitForExpectations(timeout: timeout)
  513. // Then
  514. XCTAssertNil(response?.request)
  515. XCTAssertNil(response?.response)
  516. XCTAssertNil(response?.fileURL)
  517. XCTAssertNil(response?.resumeData)
  518. XCTAssertNotNil(response?.error)
  519. XCTAssertEqual(response?.error?.isInvalidURLError, true)
  520. XCTAssertEqual(response?.error?.urlConvertible as? String, url)
  521. }
  522. @MainActor
  523. func testThatUploadDataRequestWithInvalidURLStringThrowsResponseHandlerError() {
  524. // Given
  525. let session = Session()
  526. let url = ""
  527. let expectation = expectation(description: "Upload should fail with error")
  528. var response: DataResponse<Data?, AFError>?
  529. // When
  530. session.upload(Data(), to: url).response { resp in
  531. response = resp
  532. expectation.fulfill()
  533. }
  534. waitForExpectations(timeout: timeout)
  535. // Then
  536. XCTAssertNil(response?.request)
  537. XCTAssertNil(response?.response)
  538. XCTAssertNil(response?.data)
  539. XCTAssertNotNil(response?.error)
  540. XCTAssertEqual(response?.error?.isInvalidURLError, true)
  541. XCTAssertEqual(response?.error?.urlConvertible as? String, url)
  542. }
  543. @MainActor
  544. func testThatUploadFileRequestWithInvalidURLStringThrowsResponseHandlerError() {
  545. // Given
  546. let session = Session()
  547. let url = ""
  548. let expectation = expectation(description: "Upload should fail with error")
  549. var response: DataResponse<Data?, AFError>?
  550. // When
  551. session.upload(URL(fileURLWithPath: "/invalid"), to: url).response { resp in
  552. response = resp
  553. expectation.fulfill()
  554. }
  555. waitForExpectations(timeout: timeout)
  556. // Then
  557. XCTAssertNil(response?.request)
  558. XCTAssertNil(response?.response)
  559. XCTAssertNil(response?.data)
  560. XCTAssertNotNil(response?.error)
  561. XCTAssertEqual(response?.error?.isInvalidURLError, true)
  562. XCTAssertEqual(response?.error?.urlConvertible as? String, url)
  563. }
  564. @MainActor
  565. func testThatUploadStreamRequestWithInvalidURLStringThrowsResponseHandlerError() {
  566. // Given
  567. let session = Session()
  568. let url = ""
  569. let expectation = expectation(description: "Upload should fail with error")
  570. var response: DataResponse<Data?, AFError>?
  571. // When
  572. session.upload(InputStream(data: Data()), to: url).response { resp in
  573. response = resp
  574. expectation.fulfill()
  575. }
  576. waitForExpectations(timeout: timeout)
  577. // Then
  578. XCTAssertNil(response?.request)
  579. XCTAssertNil(response?.response)
  580. XCTAssertNil(response?.data)
  581. XCTAssertNotNil(response?.error)
  582. XCTAssertEqual(response?.error?.isInvalidURLError, true)
  583. XCTAssertEqual(response?.error?.urlConvertible as? String, url)
  584. }
  585. // MARK: Tests - Request Adapter
  586. @MainActor
  587. func testThatSessionCallsRequestAdaptersWhenCreatingDataRequest() {
  588. // Given
  589. let endpoint = Endpoint()
  590. let methodAdapter = HTTPMethodAdapter(method: .post)
  591. let headerAdapter = HeaderAdapter()
  592. let monitor = ClosureEventMonitor()
  593. let session = Session(startRequestsImmediately: false, requestSetup: .eager, interceptor: methodAdapter, eventMonitors: [monitor])
  594. // When
  595. let expectation1 = expectation(description: "Request 1 created")
  596. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  597. let request1 = session.request(endpoint)
  598. waitForExpectations(timeout: timeout)
  599. let expectation2 = expectation(description: "Request 2 created")
  600. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  601. let request2 = session.request(endpoint, interceptor: headerAdapter)
  602. waitForExpectations(timeout: timeout)
  603. // Then
  604. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  605. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  606. XCTAssertEqual(request2.task?.originalRequest?.allHTTPHeaderFields?.count, 1)
  607. XCTAssertEqual(methodAdapter.adaptedCount.value, 2)
  608. XCTAssertEqual(headerAdapter.adaptedCount.value, 1)
  609. }
  610. @MainActor
  611. func testThatSessionCallsRequestAdaptersWhenCreatingDownloadRequest() {
  612. // Given
  613. let endpoint = Endpoint()
  614. let methodAdapter = HTTPMethodAdapter(method: .post)
  615. let headerAdapter = HeaderAdapter()
  616. let monitor = ClosureEventMonitor()
  617. let session = Session(startRequestsImmediately: false, requestSetup: .eager, interceptor: methodAdapter, eventMonitors: [monitor])
  618. // When
  619. let expectation1 = expectation(description: "Request 1 created")
  620. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  621. let request1 = session.download(endpoint)
  622. waitForExpectations(timeout: timeout)
  623. let expectation2 = expectation(description: "Request 2 created")
  624. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  625. let request2 = session.download(endpoint, interceptor: headerAdapter)
  626. waitForExpectations(timeout: timeout)
  627. // Then
  628. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  629. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  630. XCTAssertEqual(request2.task?.originalRequest?.allHTTPHeaderFields?.count, 1)
  631. XCTAssertEqual(methodAdapter.adaptedCount.value, 2)
  632. XCTAssertEqual(headerAdapter.adaptedCount.value, 1)
  633. }
  634. @MainActor
  635. func testThatSessionCallsRequestAdaptersWhenCreatingUploadRequestWithData() {
  636. // Given
  637. let data = Data("data".utf8)
  638. let endpoint = Endpoint.method(.post)
  639. let methodAdapter = HTTPMethodAdapter(method: .get)
  640. let headerAdapter = HeaderAdapter()
  641. let monitor = ClosureEventMonitor()
  642. let session = Session(startRequestsImmediately: false, requestSetup: .eager, interceptor: methodAdapter, eventMonitors: [monitor])
  643. // When
  644. let expectation1 = expectation(description: "Request 1 created")
  645. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  646. let request1 = session.upload(data, to: endpoint)
  647. waitForExpectations(timeout: timeout)
  648. let expectation2 = expectation(description: "Request 2 created")
  649. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  650. let request2 = session.upload(data, to: endpoint, interceptor: headerAdapter)
  651. waitForExpectations(timeout: timeout)
  652. // Then
  653. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  654. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  655. XCTAssertEqual(request2.task?.originalRequest?.allHTTPHeaderFields?.count, 1)
  656. XCTAssertEqual(methodAdapter.adaptedCount.value, 2)
  657. XCTAssertEqual(headerAdapter.adaptedCount.value, 1)
  658. }
  659. @MainActor
  660. func testThatSessionCallsRequestAdaptersWhenCreatingUploadRequestWithFile() {
  661. // Given
  662. let fileURL = URL(fileURLWithPath: "/path/to/some/file.txt")
  663. let endpoint = Endpoint.method(.post)
  664. let methodAdapter = HTTPMethodAdapter(method: .get)
  665. let headerAdapter = HeaderAdapter()
  666. let monitor = ClosureEventMonitor()
  667. let session = Session(startRequestsImmediately: false, requestSetup: .eager, interceptor: methodAdapter, eventMonitors: [monitor])
  668. // When
  669. let expectation1 = expectation(description: "Request 1 created")
  670. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  671. let request1 = session.upload(fileURL, to: endpoint)
  672. waitForExpectations(timeout: timeout)
  673. let expectation2 = expectation(description: "Request 2 created")
  674. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  675. let request2 = session.upload(fileURL, to: endpoint, interceptor: headerAdapter)
  676. waitForExpectations(timeout: timeout)
  677. // Then
  678. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  679. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  680. XCTAssertEqual(request2.task?.originalRequest?.allHTTPHeaderFields?.count, 1)
  681. XCTAssertEqual(methodAdapter.adaptedCount.value, 2)
  682. XCTAssertEqual(headerAdapter.adaptedCount.value, 1)
  683. }
  684. @MainActor
  685. func testThatSessionCallsRequestAdaptersWhenCreatingUploadRequestWithInputStream() {
  686. // Given
  687. let inputStream = InputStream(data: Data("data".utf8))
  688. let endpoint = Endpoint.method(.post)
  689. let methodAdapter = HTTPMethodAdapter(method: .get)
  690. let headerAdapter = HeaderAdapter()
  691. let monitor = ClosureEventMonitor()
  692. let session = Session(startRequestsImmediately: false, requestSetup: .eager, interceptor: methodAdapter, eventMonitors: [monitor])
  693. // When
  694. let expectation1 = expectation(description: "Request 1 created")
  695. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  696. let request1 = session.upload(inputStream, to: endpoint)
  697. waitForExpectations(timeout: timeout)
  698. let expectation2 = expectation(description: "Request 2 created")
  699. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  700. let request2 = session.upload(inputStream, to: endpoint, interceptor: headerAdapter)
  701. waitForExpectations(timeout: timeout)
  702. // Then
  703. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  704. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  705. XCTAssertEqual(request2.task?.originalRequest?.allHTTPHeaderFields?.count, 1)
  706. XCTAssertEqual(methodAdapter.adaptedCount.value, 2)
  707. XCTAssertEqual(headerAdapter.adaptedCount.value, 1)
  708. }
  709. @MainActor
  710. func testThatSessionReturnsRequestAdaptationErrorWhenRequestAdapterThrowsError() {
  711. // Given
  712. let endpoint = Endpoint()
  713. let methodAdapter = HTTPMethodAdapter(method: .post, throwsError: true)
  714. let headerAdapter = HeaderAdapter(throwsError: true)
  715. let monitor = ClosureEventMonitor()
  716. let session = Session(startRequestsImmediately: false, requestSetup: .eager, interceptor: methodAdapter, eventMonitors: [monitor])
  717. // When
  718. let expectation1 = expectation(description: "Request 1 created")
  719. monitor.requestDidFailToAdaptURLRequestWithError = { _, _, _ in expectation1.fulfill() }
  720. let request1 = session.request(endpoint)
  721. waitForExpectations(timeout: timeout)
  722. let expectation2 = expectation(description: "Request 2 created")
  723. monitor.requestDidFailToAdaptURLRequestWithError = { _, _, _ in expectation2.fulfill() }
  724. let request2 = session.request(endpoint, interceptor: headerAdapter)
  725. waitForExpectations(timeout: timeout)
  726. let requests = [request1, request2]
  727. // Then
  728. for request in requests {
  729. XCTAssertEqual(request.error?.isRequestAdaptationError, true)
  730. XCTAssertEqual(request.error?.underlyingError?.asAFError?.urlConvertible as? String, "")
  731. }
  732. }
  733. // MARK: Tests - Request Retrier
  734. @MainActor
  735. func testThatSessionCallsRequestRetrierWhenRequestInitiallyEncountersAdaptError() {
  736. // Given
  737. let handler = RequestHandler(adaptedCount: 1, throwsErrorOnSecondAdapt: true, shouldApplyAuthorizationHeader: true)
  738. let session = Session()
  739. let expectation = expectation(description: "request should eventually fail")
  740. var response: DataResponse<TestResponse, AFError>?
  741. // When
  742. session.request(.basicAuth(), interceptor: handler)
  743. .validate()
  744. .responseDecodable(of: TestResponse.self) { jsonResponse in
  745. response = jsonResponse
  746. expectation.fulfill()
  747. }
  748. waitForExpectations(timeout: timeout)
  749. // Then
  750. XCTAssertEqual(handler.adaptCalledCount, 2)
  751. XCTAssertEqual(handler.adaptedCount, 2)
  752. XCTAssertEqual(handler.retryCalledCount, 1)
  753. XCTAssertEqual(handler.retryCount, 1)
  754. XCTAssertEqual(response?.result.isSuccess, true)
  755. assert(on: session.rootQueue) {
  756. XCTAssertTrue(session.requestTaskMap.isEmpty)
  757. XCTAssertTrue(session.activeRequests.isEmpty)
  758. }
  759. }
  760. @MainActor
  761. func testThatSessionCallsRequestRetrierWhenDownloadInitiallyEncountersAdaptError() {
  762. // Given
  763. let handler = RequestHandler(adaptedCount: 1, throwsErrorOnSecondAdapt: true, shouldApplyAuthorizationHeader: true)
  764. let session = Session()
  765. let expectation = expectation(description: "request should eventually fail")
  766. var response: DownloadResponse<TestResponse, AFError>?
  767. let destination: DownloadRequest.Destination = { _, _ in
  768. let fileURL = self.testDirectoryURL.appendingPathComponent("test-output.json")
  769. return (fileURL, [.removePreviousFile])
  770. }
  771. // When
  772. session.download(.basicAuth(), interceptor: handler, to: destination)
  773. .validate()
  774. .responseDecodable(of: TestResponse.self) { jsonResponse in
  775. response = jsonResponse
  776. expectation.fulfill()
  777. }
  778. waitForExpectations(timeout: timeout)
  779. // Then
  780. XCTAssertEqual(handler.adaptCalledCount, 2)
  781. XCTAssertEqual(handler.adaptedCount, 2)
  782. XCTAssertEqual(handler.retryCalledCount, 1)
  783. XCTAssertEqual(handler.retryCount, 1)
  784. XCTAssertEqual(response?.result.isSuccess, true)
  785. assert(on: session.rootQueue) {
  786. XCTAssertTrue(session.requestTaskMap.isEmpty)
  787. XCTAssertTrue(session.activeRequests.isEmpty)
  788. }
  789. }
  790. @MainActor
  791. func testThatSessionCallsRequestRetrierWhenUploadInitiallyEncountersAdaptError() {
  792. // Given
  793. let handler = UploadHandler()
  794. let session = Session(interceptor: handler)
  795. let expectation = expectation(description: "request should eventually fail")
  796. var response: DataResponse<TestResponse, AFError>?
  797. let uploadData = Data("upload data".utf8)
  798. // When
  799. session.upload(uploadData, to: .method(.post))
  800. .validate()
  801. .responseDecodable(of: TestResponse.self) { jsonResponse in
  802. response = jsonResponse
  803. expectation.fulfill()
  804. }
  805. waitForExpectations(timeout: timeout)
  806. // Then
  807. XCTAssertEqual(handler.adaptCalledCount, 2)
  808. XCTAssertEqual(handler.adaptedCount, 2)
  809. XCTAssertEqual(handler.retryCalledCount, 1)
  810. XCTAssertEqual(handler.retryCount, 1)
  811. XCTAssertEqual(response?.result.isSuccess, true)
  812. assert(on: session.rootQueue) {
  813. XCTAssertTrue(session.requestTaskMap.isEmpty)
  814. XCTAssertTrue(session.activeRequests.isEmpty)
  815. }
  816. }
  817. @MainActor
  818. func testThatSessionCallsRequestRetrierWhenRequestEncountersError() {
  819. // Given
  820. let handler = RequestHandler()
  821. let session = Session()
  822. let expectation = expectation(description: "request should eventually fail")
  823. var response: DataResponse<TestResponse, AFError>?
  824. // When
  825. let request = session.request(.basicAuth(), interceptor: handler)
  826. .validate()
  827. .responseDecodable(of: TestResponse.self) { jsonResponse in
  828. response = jsonResponse
  829. expectation.fulfill()
  830. }
  831. waitForExpectations(timeout: timeout)
  832. // Then
  833. XCTAssertEqual(handler.adaptCalledCount, 2)
  834. XCTAssertEqual(handler.adaptedCount, 2)
  835. XCTAssertEqual(handler.retryCalledCount, 3)
  836. XCTAssertEqual(handler.retryCount, 3)
  837. XCTAssertEqual(request.retryCount, 1)
  838. XCTAssertEqual(response?.result.isSuccess, false)
  839. assert(on: session.rootQueue) {
  840. XCTAssertTrue(session.requestTaskMap.isEmpty)
  841. XCTAssertTrue(session.activeRequests.isEmpty)
  842. }
  843. }
  844. @MainActor
  845. func testThatSessionCallsSessionRetrierTheRequestRetrierWhenRequestEncountersError() {
  846. // Given
  847. let sessionHandler = RequestHandler()
  848. let requestHandler = RequestHandler()
  849. let session = Session(interceptor: sessionHandler)
  850. let expectation = expectation(description: "request should eventually fail")
  851. var response: DataResponse<TestResponse, AFError>?
  852. // When
  853. let request = session.request(.basicAuth(), interceptor: requestHandler)
  854. .validate()
  855. .responseDecodable(of: TestResponse.self) { jsonResponse in
  856. response = jsonResponse
  857. expectation.fulfill()
  858. }
  859. waitForExpectations(timeout: timeout)
  860. // Then
  861. XCTAssertEqual(sessionHandler.adaptCalledCount, 3)
  862. XCTAssertEqual(sessionHandler.adaptedCount, 3)
  863. XCTAssertEqual(sessionHandler.retryCalledCount, 4)
  864. XCTAssertEqual(sessionHandler.retryCount, 4)
  865. XCTAssertEqual(requestHandler.adaptCalledCount, 3)
  866. XCTAssertEqual(requestHandler.adaptedCount, 3)
  867. XCTAssertEqual(requestHandler.retryCalledCount, 3)
  868. XCTAssertEqual(requestHandler.retryCount, 3)
  869. XCTAssertEqual(request.retryCount, 2)
  870. XCTAssertEqual(response?.result.isSuccess, false)
  871. assert(on: session.rootQueue) {
  872. XCTAssertTrue(session.requestTaskMap.isEmpty)
  873. XCTAssertTrue(session.activeRequests.isEmpty)
  874. }
  875. }
  876. @MainActor
  877. func testThatSessionCallsAdapterWhenRequestIsRetried() {
  878. // Given
  879. let handler = RequestHandler(shouldApplyAuthorizationHeader: true)
  880. let session = Session(interceptor: handler)
  881. let expectation = expectation(description: "request should eventually succeed")
  882. var response: DataResponse<TestResponse, AFError>?
  883. // When
  884. let request = session.request(.basicAuth())
  885. .validate()
  886. .responseDecodable(of: TestResponse.self) { jsonResponse in
  887. response = jsonResponse
  888. expectation.fulfill()
  889. }
  890. waitForExpectations(timeout: timeout)
  891. // Then
  892. XCTAssertEqual(handler.adaptCalledCount, 2)
  893. XCTAssertEqual(handler.adaptedCount, 2)
  894. XCTAssertEqual(handler.retryCalledCount, 1)
  895. XCTAssertEqual(handler.retryCount, 1)
  896. XCTAssertEqual(request.retryCount, 1)
  897. XCTAssertEqual(response?.result.isSuccess, true)
  898. assert(on: session.rootQueue) {
  899. XCTAssertTrue(session.requestTaskMap.isEmpty)
  900. XCTAssertTrue(session.activeRequests.isEmpty)
  901. }
  902. }
  903. @MainActor
  904. func testThatSessionReturnsRequestAdaptationErrorWhenRequestIsRetried() {
  905. // Given
  906. let handler = RequestHandler(throwsErrorOnSecondAdapt: true)
  907. let session = Session(interceptor: handler)
  908. let expectation = expectation(description: "request should eventually fail")
  909. var response: DataResponse<TestResponse, AFError>?
  910. // When
  911. let request = session.request(.basicAuth())
  912. .validate()
  913. .responseDecodable(of: TestResponse.self) { jsonResponse in
  914. response = jsonResponse
  915. expectation.fulfill()
  916. }
  917. waitForExpectations(timeout: timeout)
  918. // Then
  919. XCTAssertEqual(handler.adaptCalledCount, 2)
  920. XCTAssertEqual(handler.adaptedCount, 1)
  921. XCTAssertEqual(handler.retryCalledCount, 3)
  922. XCTAssertEqual(handler.retryCount, 3)
  923. XCTAssertEqual(request.retryCount, 1)
  924. XCTAssertEqual(response?.result.isSuccess, false)
  925. XCTAssertEqual(request.error?.isRequestAdaptationError, true)
  926. XCTAssertEqual(request.error?.underlyingError?.asAFError?.urlConvertible as? String, "/adapt/error/2")
  927. assert(on: session.rootQueue) {
  928. XCTAssertTrue(session.requestTaskMap.isEmpty)
  929. XCTAssertTrue(session.activeRequests.isEmpty)
  930. }
  931. }
  932. @MainActor
  933. func testThatSessionRetriesRequestWithDelayWhenRetryResultContainsDelay() {
  934. // Given
  935. let handler = RequestHandler(throwsErrorOnSecondAdapt: true, retryDelay: 0.01)
  936. let session = Session(interceptor: handler)
  937. let expectation = expectation(description: "request should eventually fail")
  938. var response: DataResponse<TestResponse, AFError>?
  939. // When
  940. let request = session.request(.basicAuth())
  941. .validate()
  942. .responseDecodable(of: TestResponse.self) { jsonResponse in
  943. response = jsonResponse
  944. expectation.fulfill()
  945. }
  946. waitForExpectations(timeout: timeout)
  947. // Then
  948. XCTAssertEqual(handler.adaptCalledCount, 2)
  949. XCTAssertEqual(handler.adaptedCount, 1)
  950. XCTAssertEqual(handler.retryCalledCount, 3)
  951. XCTAssertEqual(handler.retryCount, 3)
  952. XCTAssertEqual(request.retryCount, 1)
  953. XCTAssertEqual(response?.result.isSuccess, false)
  954. XCTAssertEqual(request.error?.isRequestAdaptationError, true)
  955. XCTAssertEqual(request.error?.underlyingError?.asAFError?.urlConvertible as? String, "/adapt/error/2")
  956. assert(on: session.rootQueue) {
  957. XCTAssertTrue(session.requestTaskMap.isEmpty)
  958. XCTAssertTrue(session.activeRequests.isEmpty)
  959. }
  960. }
  961. @MainActor
  962. func testThatSessionReturnsRequestRetryErrorWhenRequestRetrierThrowsError() {
  963. // Given
  964. let handler = RequestHandler(throwsErrorOnRetry: true)
  965. let session = Session(interceptor: handler)
  966. let expectation = expectation(description: "request should eventually fail")
  967. var response: DataResponse<TestResponse, AFError>?
  968. // When
  969. let request = session.request(.basicAuth())
  970. .validate()
  971. .responseDecodable(of: TestResponse.self) { jsonResponse in
  972. response = jsonResponse
  973. expectation.fulfill()
  974. }
  975. waitForExpectations(timeout: timeout)
  976. // Then
  977. XCTAssertEqual(handler.adaptCalledCount, 1)
  978. XCTAssertEqual(handler.adaptedCount, 1)
  979. XCTAssertEqual(handler.retryCalledCount, 2)
  980. XCTAssertEqual(handler.retryCount, 0)
  981. XCTAssertEqual(request.retryCount, 0)
  982. XCTAssertEqual(response?.result.isSuccess, false)
  983. assert(on: session.rootQueue) {
  984. XCTAssertTrue(session.requestTaskMap.isEmpty)
  985. XCTAssertTrue(session.activeRequests.isEmpty)
  986. }
  987. if let error = response?.result.failure {
  988. XCTAssertTrue(error.isRequestRetryError)
  989. XCTAssertEqual(error.underlyingError?.asAFError?.urlConvertible as? String, "/invalid/url/2")
  990. } else {
  991. XCTFail("error should not be nil")
  992. }
  993. }
  994. // MARK: Tests - Response Serializer Retry
  995. @MainActor
  996. func testThatSessionCallsRequestRetrierWhenResponseSerializerThrowsError() {
  997. // Given
  998. let handler = RequestHandler(shouldRetry: false)
  999. let session = Session()
  1000. let expectation = expectation(description: "request should eventually fail")
  1001. var response: DataResponse<TestResponse, AFError>?
  1002. // When
  1003. let request = session.request(.image(.jpeg), interceptor: handler)
  1004. .validate()
  1005. .responseDecodable(of: TestResponse.self) { jsonResponse in
  1006. response = jsonResponse
  1007. expectation.fulfill()
  1008. }
  1009. waitForExpectations(timeout: timeout)
  1010. // Then
  1011. XCTAssertEqual(handler.adaptCalledCount, 1)
  1012. XCTAssertEqual(handler.adaptedCount, 1)
  1013. XCTAssertEqual(handler.retryCalledCount, 1)
  1014. XCTAssertEqual(handler.retryCount, 0)
  1015. XCTAssertEqual(request.retryCount, 0)
  1016. XCTAssertEqual(response?.result.isSuccess, false)
  1017. XCTAssertEqual(response?.error?.isResponseSerializationError, true)
  1018. XCTAssertNotNil(response?.error?.underlyingError as? DecodingError)
  1019. assert(on: session.rootQueue) {
  1020. XCTAssertTrue(session.requestTaskMap.isEmpty)
  1021. XCTAssertTrue(session.activeRequests.isEmpty)
  1022. }
  1023. }
  1024. @MainActor
  1025. func testThatSessionCallsRequestRetrierForAllResponseSerializersThatThrowError() {
  1026. // Given
  1027. let handler = RequestHandler(throwsErrorOnRetry: true)
  1028. let session = Session()
  1029. let json1Expectation = expectation(description: "request should eventually fail")
  1030. var json1Response: DataResponse<TestResponse, AFError>?
  1031. let json2Expectation = expectation(description: "request should eventually fail")
  1032. var json2Response: DataResponse<TestResponse, AFError>?
  1033. // When
  1034. let request = session.request(.image(.jpeg), interceptor: handler)
  1035. .validate()
  1036. .responseDecodable(of: TestResponse.self) { response in
  1037. json1Response = response
  1038. json1Expectation.fulfill()
  1039. }
  1040. .responseDecodable(of: TestResponse.self) { response in
  1041. json2Response = response
  1042. json2Expectation.fulfill()
  1043. }
  1044. waitForExpectations(timeout: timeout)
  1045. // Then
  1046. XCTAssertEqual(handler.adaptCalledCount, 1)
  1047. XCTAssertEqual(handler.adaptedCount, 1)
  1048. XCTAssertEqual(handler.retryCalledCount, 2)
  1049. XCTAssertEqual(handler.retryCount, 0)
  1050. XCTAssertEqual(request.retryCount, 0)
  1051. XCTAssertEqual(json1Response?.result.isSuccess, false)
  1052. XCTAssertEqual(json2Response?.result.isSuccess, false)
  1053. assert(on: session.rootQueue) {
  1054. XCTAssertTrue(session.requestTaskMap.isEmpty)
  1055. XCTAssertTrue(session.activeRequests.isEmpty)
  1056. }
  1057. let errors = [json1Response, json2Response].compactMap { $0?.error }
  1058. XCTAssertEqual(errors.count, 2)
  1059. for (index, error) in errors.enumerated() {
  1060. XCTAssertTrue(error.isRequestRetryError)
  1061. if case let .requestRetryFailed(retryError, originalError) = error {
  1062. XCTAssertEqual(retryError.asAFError?.urlConvertible as? String, "/invalid/url/\(index + 1)")
  1063. XCTAssertNotNil(originalError.asAFError?.underlyingError as? DecodingError)
  1064. } else {
  1065. XCTFail("Error failure reason should be response serialization failure")
  1066. }
  1067. }
  1068. }
  1069. @MainActor
  1070. func testThatSessionRetriesRequestImmediatelyWhenResponseSerializerRequestsRetry() {
  1071. // Given
  1072. let handler = RequestHandler()
  1073. let session = Session()
  1074. let json1Expectation = expectation(description: "request should eventually fail")
  1075. var json1Response: DataResponse<TestResponse, AFError>?
  1076. let json2Expectation = expectation(description: "request should eventually fail")
  1077. var json2Response: DataResponse<TestResponse, AFError>?
  1078. // When
  1079. let request = session.request(.image(.jpeg), interceptor: handler)
  1080. .validate()
  1081. .responseDecodable(of: TestResponse.self) { response in
  1082. json1Response = response
  1083. json1Expectation.fulfill()
  1084. }
  1085. .responseDecodable(of: TestResponse.self) { response in
  1086. json2Response = response
  1087. json2Expectation.fulfill()
  1088. }
  1089. waitForExpectations(timeout: timeout)
  1090. // Then
  1091. XCTAssertEqual(handler.adaptCalledCount, 2)
  1092. XCTAssertEqual(handler.adaptedCount, 2)
  1093. XCTAssertEqual(handler.retryCalledCount, 3)
  1094. XCTAssertEqual(handler.retryCount, 3)
  1095. XCTAssertEqual(request.retryCount, 1)
  1096. XCTAssertEqual(json1Response?.result.isSuccess, false)
  1097. XCTAssertEqual(json2Response?.result.isSuccess, false)
  1098. assert(on: session.rootQueue) {
  1099. XCTAssertTrue(session.requestTaskMap.isEmpty)
  1100. XCTAssertTrue(session.activeRequests.isEmpty)
  1101. }
  1102. let errors = [json1Response, json2Response].compactMap { $0?.error }
  1103. XCTAssertEqual(errors.count, 2)
  1104. for error in errors {
  1105. XCTAssertTrue(error.isResponseSerializationError)
  1106. XCTAssertNotNil(error.underlyingError as? DecodingError)
  1107. }
  1108. }
  1109. @MainActor
  1110. func testThatSessionCallsResponseSerializerCompletionsWhenAdapterThrowsErrorDuringRetry() {
  1111. // Four retries should occur given this scenario:
  1112. // 1) Retrier is called from first response serializer failure (trips retry)
  1113. // 2) Retrier is called by Session for adapt error thrown
  1114. // 3) Retrier is called again from first response serializer failure
  1115. // 4) Retrier is called from second response serializer failure
  1116. // Given
  1117. let handler = RequestHandler(throwsErrorOnSecondAdapt: true)
  1118. let session = Session()
  1119. let json1Expectation = expectation(description: "request should eventually fail")
  1120. var json1Response: DataResponse<TestResponse, AFError>?
  1121. let json2Expectation = expectation(description: "request should eventually fail")
  1122. var json2Response: DataResponse<TestResponse, AFError>?
  1123. // When
  1124. let request = session.request(.image(.jpeg), interceptor: handler)
  1125. .validate()
  1126. .responseDecodable(of: TestResponse.self) { response in
  1127. json1Response = response
  1128. json1Expectation.fulfill()
  1129. }
  1130. .responseDecodable(of: TestResponse.self) { response in
  1131. json2Response = response
  1132. json2Expectation.fulfill()
  1133. }
  1134. waitForExpectations(timeout: timeout)
  1135. // Then
  1136. XCTAssertEqual(handler.adaptCalledCount, 2)
  1137. XCTAssertEqual(handler.adaptedCount, 1)
  1138. XCTAssertEqual(handler.retryCalledCount, 4)
  1139. XCTAssertEqual(handler.retryCount, 4)
  1140. XCTAssertEqual(request.retryCount, 1)
  1141. XCTAssertEqual(json1Response?.result.isSuccess, false)
  1142. XCTAssertEqual(json2Response?.result.isSuccess, false)
  1143. assert(on: session.rootQueue) {
  1144. XCTAssertTrue(session.requestTaskMap.isEmpty)
  1145. XCTAssertTrue(session.activeRequests.isEmpty)
  1146. }
  1147. let errors = [json1Response, json2Response].compactMap { $0?.error }
  1148. XCTAssertEqual(errors.count, 2)
  1149. for error in errors {
  1150. XCTAssertTrue(error.isRequestAdaptationError)
  1151. XCTAssertEqual(error.underlyingError?.asAFError?.urlConvertible as? String, "/adapt/error/2")
  1152. }
  1153. }
  1154. @MainActor
  1155. func testThatSessionCallsResponseSerializerCompletionsWhenAdapterThrowsErrorDuringRetryForDownloads() {
  1156. // Four retries should occur given this scenario:
  1157. // 1) Retrier is called from first response serializer failure (trips retry)
  1158. // 2) Retrier is called by Session for adapt error thrown
  1159. // 3) Retrier is called again from first response serializer failure
  1160. // 4) Retrier is called from second response serializer failure
  1161. // Given
  1162. let handler = RequestHandler(throwsErrorOnSecondAdapt: true)
  1163. let session = Session()
  1164. let json1Expectation = expectation(description: "request should eventually fail")
  1165. var json1Response: DownloadResponse<TestResponse, AFError>?
  1166. let json2Expectation = expectation(description: "request should eventually fail")
  1167. var json2Response: DownloadResponse<TestResponse, AFError>?
  1168. // When
  1169. let request = session.download(.image(.jpeg), interceptor: handler)
  1170. .validate()
  1171. .responseDecodable(of: TestResponse.self) { response in
  1172. json1Response = response
  1173. json1Expectation.fulfill()
  1174. }
  1175. .responseDecodable(of: TestResponse.self) { response in
  1176. json2Response = response
  1177. json2Expectation.fulfill()
  1178. }
  1179. waitForExpectations(timeout: timeout)
  1180. // Then
  1181. XCTAssertEqual(handler.adaptCalledCount, 2)
  1182. XCTAssertEqual(handler.adaptedCount, 1)
  1183. XCTAssertEqual(handler.retryCalledCount, 4)
  1184. XCTAssertEqual(handler.retryCount, 4)
  1185. XCTAssertEqual(request.retryCount, 1)
  1186. XCTAssertEqual(json1Response?.result.isSuccess, false)
  1187. XCTAssertEqual(json2Response?.result.isSuccess, false)
  1188. assert(on: session.rootQueue) {
  1189. XCTAssertTrue(session.requestTaskMap.isEmpty)
  1190. XCTAssertTrue(session.activeRequests.isEmpty)
  1191. }
  1192. let errors = [json1Response, json2Response].compactMap { $0?.error }
  1193. XCTAssertEqual(errors.count, 2)
  1194. for error in errors {
  1195. XCTAssertTrue(error.isRequestAdaptationError)
  1196. XCTAssertEqual(error.underlyingError?.asAFError?.urlConvertible as? String, "/adapt/error/2")
  1197. }
  1198. }
  1199. // MARK: Tests - Session Invalidation
  1200. @MainActor
  1201. func testThatSessionIsInvalidatedAndAllRequestsCompleteWhenSessionIsDeinitialized() {
  1202. // Given
  1203. let invalidationExpectation = expectation(description: "sessionDidBecomeInvalidWithError should be called")
  1204. let events = ClosureEventMonitor()
  1205. events.sessionDidBecomeInvalidWithError = { _, _ in
  1206. invalidationExpectation.fulfill()
  1207. }
  1208. var session: Session? = Session(startRequestsImmediately: false, requestSetup: .eager, eventMonitors: [events])
  1209. var error: AFError?
  1210. let requestExpectation = expectation(description: "request should complete")
  1211. // When
  1212. session?.request(.default).response { response in
  1213. error = response.error
  1214. requestExpectation.fulfill()
  1215. }
  1216. session = nil
  1217. waitForExpectations(timeout: timeout)
  1218. // Then
  1219. XCTAssertEqual(error?.isSessionDeinitializedError, true)
  1220. }
  1221. // MARK: Tests - Request Cancellation
  1222. @MainActor
  1223. func testThatSessionOnlyCallsResponseSerializerCompletionWhenCancellingInsideCompletion() {
  1224. // Given
  1225. let handler = RequestHandler()
  1226. let session = Session()
  1227. let expectation = expectation(description: "request should complete")
  1228. var response: DataResponse<TestResponse, AFError>?
  1229. var completionCallCount = 0
  1230. // When
  1231. let request = session.request(.default, interceptor: handler)
  1232. request.validate()
  1233. request.responseDecodable(of: TestResponse.self) { resp in
  1234. request.cancel()
  1235. response = resp
  1236. completionCallCount += 1
  1237. DispatchQueue.main.after(0.01) { expectation.fulfill() }
  1238. }
  1239. waitForExpectations(timeout: timeout)
  1240. // Then
  1241. XCTAssertEqual(handler.adaptCalledCount, 1)
  1242. XCTAssertEqual(handler.adaptedCount, 1)
  1243. XCTAssertEqual(handler.retryCalledCount, 0)
  1244. XCTAssertEqual(handler.retryCount, 0)
  1245. XCTAssertEqual(request.retryCount, 0)
  1246. XCTAssertEqual(response?.result.isSuccess, true)
  1247. XCTAssertEqual(completionCallCount, 1)
  1248. assert(on: session.rootQueue) {
  1249. XCTAssertTrue(session.requestTaskMap.isEmpty)
  1250. XCTAssertTrue(session.activeRequests.isEmpty)
  1251. }
  1252. }
  1253. // MARK: Tests - Request State
  1254. @MainActor
  1255. func testThatSessionSetsRequestStateWhenStartRequestsImmediatelyIsTrue() {
  1256. // Given
  1257. let session = Session()
  1258. let expectation = expectation(description: "request should complete")
  1259. var response: DataResponse<TestResponse, AFError>?
  1260. // When
  1261. let request = session.request(.default).responseDecodable(of: TestResponse.self) { resp in
  1262. response = resp
  1263. expectation.fulfill()
  1264. }
  1265. waitForExpectations(timeout: timeout)
  1266. // Then
  1267. XCTAssertEqual(request.state, .finished)
  1268. XCTAssertEqual(response?.result.isSuccess, true)
  1269. }
  1270. // MARK: Invalid Requests
  1271. @MainActor
  1272. func testThatGETRequestsWithBodyDataAreConsideredInvalid() {
  1273. // Given
  1274. let session = Session()
  1275. var request = Endpoint().urlRequest
  1276. request.httpBody = Data("invalid".utf8)
  1277. let expect = expectation(description: "request should complete")
  1278. var response: DataResponse<TestResponse, AFError>?
  1279. // When
  1280. session.request(request).responseDecodable(of: TestResponse.self) { resp in
  1281. response = resp
  1282. expect.fulfill()
  1283. }
  1284. waitForExpectations(timeout: timeout)
  1285. // Then
  1286. XCTAssertEqual(response?.result.isFailure, true)
  1287. XCTAssertEqual(response?.error?.isBodyDataInGETRequest, true)
  1288. }
  1289. @MainActor
  1290. func testThatAdaptedGETRequestsWithBodyDataAreConsideredInvalid() {
  1291. // Given
  1292. struct InvalidAdapter: RequestInterceptor {
  1293. func adapt(_ urlRequest: URLRequest,
  1294. for session: Session,
  1295. completion: @escaping (Result<URLRequest, any Error>) -> Void) {
  1296. var request = urlRequest
  1297. request.httpBody = Data("invalid".utf8)
  1298. completion(.success(request))
  1299. }
  1300. }
  1301. let session = Session(interceptor: InvalidAdapter())
  1302. let expect = expectation(description: "request should complete")
  1303. var response: DataResponse<TestResponse, AFError>?
  1304. // When
  1305. session.request(.default).responseDecodable(of: TestResponse.self) { resp in
  1306. response = resp
  1307. expect.fulfill()
  1308. }
  1309. waitForExpectations(timeout: timeout)
  1310. // Then
  1311. XCTAssertEqual(response?.result.isFailure, true)
  1312. XCTAssertEqual(response?.error?.isRequestAdaptationError, true)
  1313. XCTAssertEqual(response?.error?.underlyingError?.asAFError?.isBodyDataInGETRequest, true)
  1314. }
  1315. }
  1316. // MARK: -
  1317. final class SessionMassActionTestCase: BaseTestCase {
  1318. func testThatRequestsCanHaveMassActionsPerformed() {
  1319. // Given
  1320. let count = 10
  1321. let createdTasks = expectation(description: "all tasks created")
  1322. createdTasks.expectedFulfillmentCount = count
  1323. let massActions = expectation(description: "cancel all requests should be called")
  1324. let monitor = ClosureEventMonitor()
  1325. monitor.requestDidCreateTask = { _, _ in createdTasks.fulfill() }
  1326. let session = Session(requestSetup: .eager, eventMonitors: [monitor])
  1327. let request = Endpoint.delay(1)
  1328. var requests: [DataRequest] = []
  1329. // When
  1330. requests = (0..<count).map { _ in session.request(request) }
  1331. wait(for: [createdTasks], timeout: timeout)
  1332. session.withAllRequests { $0.forEach { $0.suspend() }; massActions.fulfill() }
  1333. wait(for: [massActions], timeout: timeout)
  1334. // Then
  1335. XCTAssertTrue(requests.allSatisfy(\.isSuspended))
  1336. }
  1337. @MainActor
  1338. func testThatAutomaticallyResumedRequestsCanBeMassCancelled() {
  1339. // Given
  1340. let count = 100
  1341. let completion = expectation(description: "all requests should finish")
  1342. completion.expectedFulfillmentCount = count
  1343. let createdTasks = expectation(description: "all tasks created")
  1344. createdTasks.expectedFulfillmentCount = count
  1345. let gatheredMetrics = expectation(description: "metrics gathered for all tasks")
  1346. gatheredMetrics.expectedFulfillmentCount = count
  1347. let cancellation = expectation(description: "cancel all requests should be called")
  1348. let monitor = ClosureEventMonitor()
  1349. monitor.requestDidCreateTask = { _, _ in createdTasks.fulfill() }
  1350. monitor.requestDidGatherMetrics = { _, _ in gatheredMetrics.fulfill() }
  1351. let session = Session(requestSetup: .eager, eventMonitors: [monitor])
  1352. let request = Endpoint.delay(1)
  1353. var requests: [DataRequest] = []
  1354. var responses: [DataResponse<Data?, AFError>] = []
  1355. // When
  1356. requests = (0..<count).map { _ in session.request(request) }
  1357. wait(for: [createdTasks], timeout: timeout)
  1358. for request in requests {
  1359. request.response { response in
  1360. responses.append(response)
  1361. completion.fulfill()
  1362. }
  1363. }
  1364. session.cancelAllRequests {
  1365. cancellation.fulfill()
  1366. }
  1367. wait(for: [gatheredMetrics, cancellation, completion], timeout: timeout)
  1368. // Then
  1369. XCTAssertTrue(responses.allSatisfy { $0.error?.isExplicitlyCancelledError == true })
  1370. assert(on: session.rootQueue) {
  1371. XCTAssertTrue(session.requestTaskMap.isEmpty, "requestTaskMap should be empty but has \(session.requestTaskMap.count) items")
  1372. XCTAssertTrue(session.activeRequests.isEmpty, "activeRequests should be empty but has \(session.activeRequests.count) items")
  1373. }
  1374. }
  1375. @MainActor
  1376. func testThatLazyAutomaticallyResumedRequestsCanBeMassCancelled() {
  1377. // Given
  1378. let count = 100
  1379. let completion = expectation(description: "all requests should finish")
  1380. completion.expectedFulfillmentCount = count
  1381. let createdTasks = expectation(description: "all tasks created")
  1382. createdTasks.expectedFulfillmentCount = count
  1383. let gatheredMetrics = expectation(description: "metrics gathered for all tasks")
  1384. gatheredMetrics.expectedFulfillmentCount = count
  1385. let cancellation = expectation(description: "cancel all requests should be called")
  1386. let monitor = ClosureEventMonitor()
  1387. monitor.requestDidCreateTask = { _, _ in createdTasks.fulfill() }
  1388. monitor.requestDidGatherMetrics = { _, _ in gatheredMetrics.fulfill() }
  1389. let session = Session(eventMonitors: [monitor])
  1390. let request = Endpoint.delay(1)
  1391. var requests: [DataRequest] = []
  1392. var responses: [DataResponse<Data?, AFError>] = []
  1393. // When
  1394. requests = (0..<count).map { _ in session.request(request) }
  1395. for request in requests {
  1396. request.response { response in
  1397. responses.append(response)
  1398. completion.fulfill()
  1399. }
  1400. }
  1401. wait(for: [createdTasks], timeout: timeout)
  1402. session.cancelAllRequests {
  1403. cancellation.fulfill()
  1404. }
  1405. wait(for: [gatheredMetrics, cancellation, completion], timeout: timeout)
  1406. // Then
  1407. XCTAssertTrue(responses.allSatisfy { $0.error?.isExplicitlyCancelledError == true })
  1408. assert(on: session.rootQueue) {
  1409. XCTAssertTrue(session.requestTaskMap.isEmpty, "requestTaskMap should be empty but has \(session.requestTaskMap.count) items")
  1410. XCTAssertTrue(session.activeRequests.isEmpty, "activeRequests should be empty but has \(session.activeRequests.count) items")
  1411. }
  1412. }
  1413. @MainActor
  1414. func testThatInstanceAutomaticallyResumedRequestsCanBeMassCancelled() {
  1415. // Given
  1416. let count = 100
  1417. let completion = expectation(description: "all requests should finish")
  1418. completion.expectedFulfillmentCount = count
  1419. let createdTasks = expectation(description: "all tasks created")
  1420. createdTasks.expectedFulfillmentCount = count
  1421. let gatheredMetrics = expectation(description: "metrics gathered for all tasks")
  1422. gatheredMetrics.expectedFulfillmentCount = count
  1423. let cancellation = expectation(description: "cancel all requests should be called")
  1424. let monitor = ClosureEventMonitor()
  1425. monitor.requestDidCreateTask = { _, _ in createdTasks.fulfill() }
  1426. monitor.requestDidGatherMetrics = { _, _ in gatheredMetrics.fulfill() }
  1427. let session = Session(startRequestsImmediately: false, requestSetup: .eager, eventMonitors: [monitor])
  1428. let request = Endpoint.delay(1)
  1429. var requests: [DataRequest] = []
  1430. var responses: [DataResponse<Data?, AFError>] = []
  1431. // When
  1432. requests = (0..<count).map { _ in session.request(request, shouldAutomaticallyResume: true) }
  1433. wait(for: [createdTasks], timeout: timeout)
  1434. for request in requests {
  1435. request.response { response in
  1436. responses.append(response)
  1437. completion.fulfill()
  1438. }
  1439. }
  1440. session.cancelAllRequests {
  1441. cancellation.fulfill()
  1442. }
  1443. wait(for: [gatheredMetrics, cancellation, completion], timeout: timeout)
  1444. // Then
  1445. XCTAssertTrue(responses.allSatisfy { $0.error?.isExplicitlyCancelledError == true })
  1446. assert(on: session.rootQueue) {
  1447. XCTAssertTrue(session.requestTaskMap.isEmpty, "requestTaskMap should be empty but has \(session.requestTaskMap.count) items")
  1448. XCTAssertTrue(session.activeRequests.isEmpty, "activeRequests should be empty but has \(session.activeRequests.count) items")
  1449. }
  1450. }
  1451. @MainActor
  1452. func testThatManuallyResumedRequestsCanBeMassCancelled() {
  1453. // Given
  1454. let count = 100
  1455. let completion = expectation(description: "all requests should finish")
  1456. completion.expectedFulfillmentCount = count
  1457. let createdTasks = expectation(description: "all tasks created")
  1458. createdTasks.expectedFulfillmentCount = count
  1459. let gatheredMetrics = expectation(description: "metrics gathered for all tasks")
  1460. gatheredMetrics.expectedFulfillmentCount = count
  1461. let cancellation = expectation(description: "cancel all requests should be called")
  1462. let monitor = ClosureEventMonitor()
  1463. monitor.requestDidCreateTask = { _, _ in createdTasks.fulfill() }
  1464. monitor.requestDidGatherMetrics = { _, _ in gatheredMetrics.fulfill() }
  1465. let session = Session(startRequestsImmediately: false, requestSetup: .eager, eventMonitors: [monitor])
  1466. let request = Endpoint.delay(1)
  1467. var responses: [DataResponse<Data?, AFError>] = []
  1468. // When
  1469. for _ in 0..<count {
  1470. session.request(request).response { response in
  1471. responses.append(response)
  1472. completion.fulfill()
  1473. }
  1474. }
  1475. wait(for: [createdTasks], timeout: timeout)
  1476. session.cancelAllRequests {
  1477. cancellation.fulfill()
  1478. }
  1479. wait(for: [gatheredMetrics, cancellation, completion], timeout: timeout)
  1480. // Then
  1481. XCTAssertTrue(responses.allSatisfy { $0.error?.isExplicitlyCancelledError == true })
  1482. assert(on: session.rootQueue) {
  1483. XCTAssertTrue(session.requestTaskMap.isEmpty, "requestTaskMap should be empty but has \(session.requestTaskMap.count) items")
  1484. XCTAssertTrue(session.activeRequests.isEmpty, "activeRequests should be empty but has \(session.activeRequests.count) items")
  1485. }
  1486. }
  1487. @MainActor
  1488. func testThatLazyManuallyResumedRequestsCanBeMassCancelled() {
  1489. // Given
  1490. let count = 100
  1491. let completion = expectation(description: "all requests should finish")
  1492. completion.expectedFulfillmentCount = count
  1493. let createdTasks = expectation(description: "all tasks created")
  1494. createdTasks.expectedFulfillmentCount = count
  1495. let gatheredMetrics = expectation(description: "metrics gathered for all tasks")
  1496. gatheredMetrics.expectedFulfillmentCount = count
  1497. let cancellation = expectation(description: "cancel all requests should be called")
  1498. let monitor = ClosureEventMonitor()
  1499. monitor.requestDidCreateTask = { _, _ in createdTasks.fulfill() }
  1500. monitor.requestDidGatherMetrics = { _, _ in gatheredMetrics.fulfill() }
  1501. let session = Session(startRequestsImmediately: false, eventMonitors: [monitor])
  1502. let request = Endpoint.delay(1)
  1503. var responses: [DataResponse<Data?, AFError>] = []
  1504. // When
  1505. for _ in 0..<count {
  1506. session.request(request).response { response in
  1507. responses.append(response)
  1508. completion.fulfill()
  1509. }
  1510. .resume()
  1511. }
  1512. wait(for: [createdTasks], timeout: timeout)
  1513. session.cancelAllRequests {
  1514. cancellation.fulfill()
  1515. }
  1516. wait(for: [gatheredMetrics, cancellation, completion], timeout: timeout)
  1517. // Then
  1518. XCTAssertTrue(responses.allSatisfy { $0.error?.isExplicitlyCancelledError == true })
  1519. assert(on: session.rootQueue) {
  1520. XCTAssertTrue(session.requestTaskMap.isEmpty, "requestTaskMap should be empty but has \(session.requestTaskMap.count) items")
  1521. XCTAssertTrue(session.activeRequests.isEmpty, "activeRequests should be empty but has \(session.activeRequests.count) items")
  1522. }
  1523. }
  1524. @MainActor
  1525. func testThatRetriedRequestsCanBeMassCancelled() {
  1526. // Given
  1527. final class OnceRetrier: RequestInterceptor {
  1528. private var hasRetried = false
  1529. func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, any Error>) -> Void) {
  1530. if hasRetried {
  1531. var request = urlRequest
  1532. request.url = Endpoint.delay(1).url
  1533. completion(.success(request))
  1534. } else {
  1535. completion(.success(urlRequest))
  1536. }
  1537. }
  1538. func retry(_ request: Request, for session: Session, dueTo error: any Error, completion: @escaping (RetryResult) -> Void) {
  1539. completion(hasRetried ? .doNotRetry : .retry)
  1540. hasRetried = true
  1541. }
  1542. }
  1543. let queue = DispatchQueue(label: "com.alamofire.testQueue")
  1544. let monitor = ClosureEventMonitor(queue: queue)
  1545. let session = Session(rootQueue: queue, interceptor: OnceRetrier(), eventMonitors: [monitor])
  1546. let request = Endpoint.status(401)
  1547. let completion = expectation(description: "all requests should finish")
  1548. let cancellation = expectation(description: "cancel all requests should be called")
  1549. let createTask = expectation(description: "should create task twice")
  1550. createTask.expectedFulfillmentCount = 2
  1551. var tasksCreated = 0
  1552. monitor.requestDidCreateTask = { [unowned session] _, _ in
  1553. tasksCreated += 1
  1554. createTask.fulfill()
  1555. // Cancel after the second task is created to ensure proper lifetime events.
  1556. if tasksCreated == 2 {
  1557. session.cancelAllRequests {
  1558. cancellation.fulfill()
  1559. }
  1560. }
  1561. }
  1562. var received: DataResponse<Data?, AFError>?
  1563. // When
  1564. session.request(request).validate().response { response in
  1565. received = response
  1566. completion.fulfill()
  1567. }
  1568. waitForExpectations(timeout: timeout)
  1569. // Then
  1570. XCTAssertEqual(received?.error?.isExplicitlyCancelledError, true)
  1571. assert(on: session.rootQueue) {
  1572. XCTAssertTrue(session.requestTaskMap.isEmpty, "requestTaskMap should be empty but has \(session.requestTaskMap.count) items")
  1573. XCTAssertTrue(session.activeRequests.isEmpty, "activeRequests should be empty but has \(session.activeRequests.count) items")
  1574. }
  1575. }
  1576. }
  1577. // MARK: -
  1578. final class SessionConfigurationHeadersTestCase: BaseTestCase {
  1579. enum ConfigurationType {
  1580. case `default`, ephemeral
  1581. }
  1582. @MainActor
  1583. func testThatDefaultConfigurationHeadersAreSentWithRequest() {
  1584. // Given, When, Then
  1585. executeAuthorizationHeaderTest(for: .default)
  1586. }
  1587. @MainActor
  1588. func testThatEphemeralConfigurationHeadersAreSentWithRequest() {
  1589. // Given, When, Then
  1590. executeAuthorizationHeaderTest(for: .ephemeral)
  1591. }
  1592. @MainActor
  1593. private func executeAuthorizationHeaderTest(for type: ConfigurationType) {
  1594. // Given
  1595. let session: Session = {
  1596. let configuration: URLSessionConfiguration = {
  1597. let configuration: URLSessionConfiguration = switch type {
  1598. case .default:
  1599. .default
  1600. case .ephemeral:
  1601. .ephemeral
  1602. }
  1603. var headers = HTTPHeaders.default
  1604. headers["Authorization"] = "Bearer 123456"
  1605. configuration.headers = headers
  1606. return configuration
  1607. }()
  1608. return Session(configuration: configuration)
  1609. }()
  1610. let expectation = expectation(description: "request should complete successfully")
  1611. var response: DataResponse<TestResponse, AFError>?
  1612. // When
  1613. session.request(.default)
  1614. .responseDecodable(of: TestResponse.self) { closureResponse in
  1615. response = closureResponse
  1616. expectation.fulfill()
  1617. }
  1618. waitForExpectations(timeout: timeout)
  1619. // Then
  1620. XCTAssertNotNil(response?.request, "request should not be nil")
  1621. XCTAssertNotNil(response?.response, "response should not be nil")
  1622. XCTAssertNotNil(response?.data, "data should not be nil")
  1623. XCTAssertEqual(response?.result.isSuccess, true)
  1624. XCTAssertEqual(response?.value?.headers["Authorization"], "Bearer 123456", "Authorization header should match")
  1625. }
  1626. }