SessionTests.swift 75 KB

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