2
0

SessionTests.swift 69 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881
  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.adaptCalledCount }
  85. var adaptedCount: Int { mutableState.adaptedCount }
  86. var retryCalledCount: Int { mutableState.retryCalledCount }
  87. var retryCount: Int { mutableState.retryCount }
  88. var retryErrors: [any Error] { mutableState.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.adaptCalledCount }
  163. var adaptedCount: Int { mutableState.adaptedCount }
  164. var retryCalledCount: Int { mutableState.retryCalledCount }
  165. var retryCount: Int { mutableState.retryCount }
  166. var retryErrors: [any Error] { mutableState.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, eventMonitors: [monitor])
  448. weak var weakSession = session
  449. // When
  450. let request = session?.request(.default)
  451. session = nil
  452. waitForExpectations(timeout: timeout)
  453. // Then
  454. if #available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) {
  455. // On 2022 OS versions and later, URLSessionTasks are completed even if not resumed before invalidating a session.
  456. XCTAssertTrue([.canceling, .completed].contains(request?.task?.state))
  457. } else {
  458. XCTAssertEqual(request?.task?.state, .suspended)
  459. }
  460. XCTAssertNil(session, "session should be nil")
  461. XCTAssertNil(weakSession, "weak session should be nil")
  462. }
  463. func testReleasingManagerWithPendingCanceledRequestDeinitializesSuccessfully() {
  464. // Given
  465. var session: Session? = Session(startRequestsImmediately: false)
  466. // When
  467. let request = session?.request(.default)
  468. request?.cancel()
  469. session = nil
  470. let state = request?.state
  471. // Then
  472. XCTAssertTrue(state == .cancelled, "state should be .cancelled")
  473. XCTAssertNil(session, "manager should be nil")
  474. }
  475. // MARK: Tests - Bad Requests
  476. @MainActor
  477. func testThatDataRequestWithInvalidURLStringThrowsResponseHandlerError() {
  478. // Given
  479. let session = Session()
  480. let url = ""
  481. let expectation = expectation(description: "Request should fail with error")
  482. var response: DataResponse<Data?, AFError>?
  483. // When
  484. session.request(url).response { resp in
  485. response = resp
  486. expectation.fulfill()
  487. }
  488. waitForExpectations(timeout: timeout)
  489. // Then
  490. XCTAssertNil(response?.request)
  491. XCTAssertNil(response?.response)
  492. XCTAssertNil(response?.data)
  493. XCTAssertNotNil(response?.error)
  494. XCTAssertEqual(response?.error?.isInvalidURLError, true)
  495. XCTAssertEqual(response?.error?.urlConvertible as? String, url)
  496. }
  497. @MainActor
  498. func testThatDownloadRequestWithInvalidURLStringThrowsResponseHandlerError() {
  499. // Given
  500. let session = Session()
  501. let url = ""
  502. let expectation = expectation(description: "Download should fail with error")
  503. var response: DownloadResponse<URL?, AFError>?
  504. // When
  505. session.download(url).response { resp in
  506. response = resp
  507. expectation.fulfill()
  508. }
  509. waitForExpectations(timeout: timeout)
  510. // Then
  511. XCTAssertNil(response?.request)
  512. XCTAssertNil(response?.response)
  513. XCTAssertNil(response?.fileURL)
  514. XCTAssertNil(response?.resumeData)
  515. XCTAssertNotNil(response?.error)
  516. XCTAssertEqual(response?.error?.isInvalidURLError, true)
  517. XCTAssertEqual(response?.error?.urlConvertible as? String, url)
  518. }
  519. @MainActor
  520. func testThatUploadDataRequestWithInvalidURLStringThrowsResponseHandlerError() {
  521. // Given
  522. let session = Session()
  523. let url = ""
  524. let expectation = expectation(description: "Upload should fail with error")
  525. var response: DataResponse<Data?, AFError>?
  526. // When
  527. session.upload(Data(), to: url).response { resp in
  528. response = resp
  529. expectation.fulfill()
  530. }
  531. waitForExpectations(timeout: timeout)
  532. // Then
  533. XCTAssertNil(response?.request)
  534. XCTAssertNil(response?.response)
  535. XCTAssertNil(response?.data)
  536. XCTAssertNotNil(response?.error)
  537. XCTAssertEqual(response?.error?.isInvalidURLError, true)
  538. XCTAssertEqual(response?.error?.urlConvertible as? String, url)
  539. }
  540. @MainActor
  541. func testThatUploadFileRequestWithInvalidURLStringThrowsResponseHandlerError() {
  542. // Given
  543. let session = Session()
  544. let url = ""
  545. let expectation = expectation(description: "Upload should fail with error")
  546. var response: DataResponse<Data?, AFError>?
  547. // When
  548. session.upload(URL(fileURLWithPath: "/invalid"), to: url).response { resp in
  549. response = resp
  550. expectation.fulfill()
  551. }
  552. waitForExpectations(timeout: timeout)
  553. // Then
  554. XCTAssertNil(response?.request)
  555. XCTAssertNil(response?.response)
  556. XCTAssertNil(response?.data)
  557. XCTAssertNotNil(response?.error)
  558. XCTAssertEqual(response?.error?.isInvalidURLError, true)
  559. XCTAssertEqual(response?.error?.urlConvertible as? String, url)
  560. }
  561. @MainActor
  562. func testThatUploadStreamRequestWithInvalidURLStringThrowsResponseHandlerError() {
  563. // Given
  564. let session = Session()
  565. let url = ""
  566. let expectation = expectation(description: "Upload should fail with error")
  567. var response: DataResponse<Data?, AFError>?
  568. // When
  569. session.upload(InputStream(data: Data()), to: url).response { resp in
  570. response = resp
  571. expectation.fulfill()
  572. }
  573. waitForExpectations(timeout: timeout)
  574. // Then
  575. XCTAssertNil(response?.request)
  576. XCTAssertNil(response?.response)
  577. XCTAssertNil(response?.data)
  578. XCTAssertNotNil(response?.error)
  579. XCTAssertEqual(response?.error?.isInvalidURLError, true)
  580. XCTAssertEqual(response?.error?.urlConvertible as? String, url)
  581. }
  582. // MARK: Tests - Request Adapter
  583. @MainActor
  584. func testThatSessionCallsRequestAdaptersWhenCreatingDataRequest() {
  585. // Given
  586. let endpoint = Endpoint()
  587. let methodAdapter = HTTPMethodAdapter(method: .post)
  588. let headerAdapter = HeaderAdapter()
  589. let monitor = ClosureEventMonitor()
  590. let session = Session(startRequestsImmediately: false, interceptor: methodAdapter, eventMonitors: [monitor])
  591. // When
  592. let expectation1 = expectation(description: "Request 1 created")
  593. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  594. let request1 = session.request(endpoint)
  595. waitForExpectations(timeout: timeout)
  596. let expectation2 = expectation(description: "Request 2 created")
  597. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  598. let request2 = session.request(endpoint, interceptor: headerAdapter)
  599. waitForExpectations(timeout: timeout)
  600. // Then
  601. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  602. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  603. XCTAssertEqual(request2.task?.originalRequest?.allHTTPHeaderFields?.count, 1)
  604. XCTAssertEqual(methodAdapter.adaptedCount.value, 2)
  605. XCTAssertEqual(headerAdapter.adaptedCount.value, 1)
  606. }
  607. @MainActor
  608. func testThatSessionCallsRequestAdaptersWhenCreatingDownloadRequest() {
  609. // Given
  610. let endpoint = Endpoint()
  611. let methodAdapter = HTTPMethodAdapter(method: .post)
  612. let headerAdapter = HeaderAdapter()
  613. let monitor = ClosureEventMonitor()
  614. let session = Session(startRequestsImmediately: false, interceptor: methodAdapter, eventMonitors: [monitor])
  615. // When
  616. let expectation1 = expectation(description: "Request 1 created")
  617. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  618. let request1 = session.download(endpoint)
  619. waitForExpectations(timeout: timeout)
  620. let expectation2 = expectation(description: "Request 2 created")
  621. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  622. let request2 = session.download(endpoint, interceptor: headerAdapter)
  623. waitForExpectations(timeout: timeout)
  624. // Then
  625. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  626. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  627. XCTAssertEqual(request2.task?.originalRequest?.allHTTPHeaderFields?.count, 1)
  628. XCTAssertEqual(methodAdapter.adaptedCount.value, 2)
  629. XCTAssertEqual(headerAdapter.adaptedCount.value, 1)
  630. }
  631. @MainActor
  632. func testThatSessionCallsRequestAdaptersWhenCreatingUploadRequestWithData() {
  633. // Given
  634. let data = Data("data".utf8)
  635. let endpoint = Endpoint.method(.post)
  636. let methodAdapter = HTTPMethodAdapter(method: .get)
  637. let headerAdapter = HeaderAdapter()
  638. let monitor = ClosureEventMonitor()
  639. let session = Session(startRequestsImmediately: false, interceptor: methodAdapter, eventMonitors: [monitor])
  640. // When
  641. let expectation1 = expectation(description: "Request 1 created")
  642. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  643. let request1 = session.upload(data, to: endpoint)
  644. waitForExpectations(timeout: timeout)
  645. let expectation2 = expectation(description: "Request 2 created")
  646. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  647. let request2 = session.upload(data, to: endpoint, interceptor: headerAdapter)
  648. waitForExpectations(timeout: timeout)
  649. // Then
  650. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  651. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  652. XCTAssertEqual(request2.task?.originalRequest?.allHTTPHeaderFields?.count, 1)
  653. XCTAssertEqual(methodAdapter.adaptedCount.value, 2)
  654. XCTAssertEqual(headerAdapter.adaptedCount.value, 1)
  655. }
  656. @MainActor
  657. func testThatSessionCallsRequestAdaptersWhenCreatingUploadRequestWithFile() {
  658. // Given
  659. let fileURL = URL(fileURLWithPath: "/path/to/some/file.txt")
  660. let endpoint = Endpoint.method(.post)
  661. let methodAdapter = HTTPMethodAdapter(method: .get)
  662. let headerAdapter = HeaderAdapter()
  663. let monitor = ClosureEventMonitor()
  664. let session = Session(startRequestsImmediately: false, interceptor: methodAdapter, eventMonitors: [monitor])
  665. // When
  666. let expectation1 = expectation(description: "Request 1 created")
  667. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  668. let request1 = session.upload(fileURL, to: endpoint)
  669. waitForExpectations(timeout: timeout)
  670. let expectation2 = expectation(description: "Request 2 created")
  671. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  672. let request2 = session.upload(fileURL, to: endpoint, interceptor: headerAdapter)
  673. waitForExpectations(timeout: timeout)
  674. // Then
  675. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  676. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  677. XCTAssertEqual(request2.task?.originalRequest?.allHTTPHeaderFields?.count, 1)
  678. XCTAssertEqual(methodAdapter.adaptedCount.value, 2)
  679. XCTAssertEqual(headerAdapter.adaptedCount.value, 1)
  680. }
  681. @MainActor
  682. func testThatSessionCallsRequestAdaptersWhenCreatingUploadRequestWithInputStream() {
  683. // Given
  684. let inputStream = InputStream(data: Data("data".utf8))
  685. let endpoint = Endpoint.method(.post)
  686. let methodAdapter = HTTPMethodAdapter(method: .get)
  687. let headerAdapter = HeaderAdapter()
  688. let monitor = ClosureEventMonitor()
  689. let session = Session(startRequestsImmediately: false, interceptor: methodAdapter, eventMonitors: [monitor])
  690. // When
  691. let expectation1 = expectation(description: "Request 1 created")
  692. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  693. let request1 = session.upload(inputStream, to: endpoint)
  694. waitForExpectations(timeout: timeout)
  695. let expectation2 = expectation(description: "Request 2 created")
  696. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  697. let request2 = session.upload(inputStream, to: endpoint, interceptor: headerAdapter)
  698. waitForExpectations(timeout: timeout)
  699. // Then
  700. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  701. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, methodAdapter.method.rawValue)
  702. XCTAssertEqual(request2.task?.originalRequest?.allHTTPHeaderFields?.count, 1)
  703. XCTAssertEqual(methodAdapter.adaptedCount.value, 2)
  704. XCTAssertEqual(headerAdapter.adaptedCount.value, 1)
  705. }
  706. @MainActor
  707. func testThatSessionReturnsRequestAdaptationErrorWhenRequestAdapterThrowsError() {
  708. // Given
  709. let endpoint = Endpoint()
  710. let methodAdapter = HTTPMethodAdapter(method: .post, throwsError: true)
  711. let headerAdapter = HeaderAdapter(throwsError: true)
  712. let monitor = ClosureEventMonitor()
  713. let session = Session(startRequestsImmediately: false, interceptor: methodAdapter, eventMonitors: [monitor])
  714. // When
  715. let expectation1 = expectation(description: "Request 1 created")
  716. monitor.requestDidFailToAdaptURLRequestWithError = { _, _, _ in expectation1.fulfill() }
  717. let request1 = session.request(endpoint)
  718. waitForExpectations(timeout: timeout)
  719. let expectation2 = expectation(description: "Request 2 created")
  720. monitor.requestDidFailToAdaptURLRequestWithError = { _, _, _ in expectation2.fulfill() }
  721. let request2 = session.request(endpoint, interceptor: headerAdapter)
  722. waitForExpectations(timeout: timeout)
  723. let requests = [request1, request2]
  724. // Then
  725. for request in requests {
  726. XCTAssertEqual(request.error?.isRequestAdaptationError, true)
  727. XCTAssertEqual(request.error?.underlyingError?.asAFError?.urlConvertible as? String, "")
  728. }
  729. }
  730. // MARK: Tests - Request Retrier
  731. @MainActor
  732. func testThatSessionCallsRequestRetrierWhenRequestInitiallyEncountersAdaptError() {
  733. // Given
  734. let handler = RequestHandler(adaptedCount: 1, throwsErrorOnSecondAdapt: true, shouldApplyAuthorizationHeader: true)
  735. let session = Session()
  736. let expectation = expectation(description: "request should eventually fail")
  737. var response: DataResponse<TestResponse, AFError>?
  738. // When
  739. session.request(.basicAuth(), interceptor: handler)
  740. .validate()
  741. .responseDecodable(of: TestResponse.self) { jsonResponse in
  742. response = jsonResponse
  743. expectation.fulfill()
  744. }
  745. waitForExpectations(timeout: timeout)
  746. // Then
  747. XCTAssertEqual(handler.adaptCalledCount, 2)
  748. XCTAssertEqual(handler.adaptedCount, 2)
  749. XCTAssertEqual(handler.retryCalledCount, 1)
  750. XCTAssertEqual(handler.retryCount, 1)
  751. XCTAssertEqual(response?.result.isSuccess, true)
  752. assert(on: session.rootQueue) {
  753. XCTAssertTrue(session.requestTaskMap.isEmpty)
  754. XCTAssertTrue(session.activeRequests.isEmpty)
  755. }
  756. }
  757. @MainActor
  758. func testThatSessionCallsRequestRetrierWhenDownloadInitiallyEncountersAdaptError() {
  759. // Given
  760. let handler = RequestHandler(adaptedCount: 1, throwsErrorOnSecondAdapt: true, shouldApplyAuthorizationHeader: true)
  761. let session = Session()
  762. let expectation = expectation(description: "request should eventually fail")
  763. var response: DownloadResponse<TestResponse, AFError>?
  764. let destination: DownloadRequest.Destination = { _, _ in
  765. let fileURL = self.testDirectoryURL.appendingPathComponent("test-output.json")
  766. return (fileURL, [.removePreviousFile])
  767. }
  768. // When
  769. session.download(.basicAuth(), interceptor: handler, to: destination)
  770. .validate()
  771. .responseDecodable(of: TestResponse.self) { jsonResponse in
  772. response = jsonResponse
  773. expectation.fulfill()
  774. }
  775. waitForExpectations(timeout: timeout)
  776. // Then
  777. XCTAssertEqual(handler.adaptCalledCount, 2)
  778. XCTAssertEqual(handler.adaptedCount, 2)
  779. XCTAssertEqual(handler.retryCalledCount, 1)
  780. XCTAssertEqual(handler.retryCount, 1)
  781. XCTAssertEqual(response?.result.isSuccess, true)
  782. assert(on: session.rootQueue) {
  783. XCTAssertTrue(session.requestTaskMap.isEmpty)
  784. XCTAssertTrue(session.activeRequests.isEmpty)
  785. }
  786. }
  787. @MainActor
  788. func testThatSessionCallsRequestRetrierWhenUploadInitiallyEncountersAdaptError() {
  789. // Given
  790. let handler = UploadHandler()
  791. let session = Session(interceptor: handler)
  792. let expectation = expectation(description: "request should eventually fail")
  793. var response: DataResponse<TestResponse, AFError>?
  794. let uploadData = Data("upload data".utf8)
  795. // When
  796. session.upload(uploadData, to: .method(.post))
  797. .validate()
  798. .responseDecodable(of: TestResponse.self) { jsonResponse in
  799. response = jsonResponse
  800. expectation.fulfill()
  801. }
  802. waitForExpectations(timeout: timeout)
  803. // Then
  804. XCTAssertEqual(handler.adaptCalledCount, 2)
  805. XCTAssertEqual(handler.adaptedCount, 2)
  806. XCTAssertEqual(handler.retryCalledCount, 1)
  807. XCTAssertEqual(handler.retryCount, 1)
  808. XCTAssertEqual(response?.result.isSuccess, true)
  809. assert(on: session.rootQueue) {
  810. XCTAssertTrue(session.requestTaskMap.isEmpty)
  811. XCTAssertTrue(session.activeRequests.isEmpty)
  812. }
  813. }
  814. @MainActor
  815. func testThatSessionCallsRequestRetrierWhenRequestEncountersError() {
  816. // Given
  817. let handler = RequestHandler()
  818. let session = Session()
  819. let expectation = expectation(description: "request should eventually fail")
  820. var response: DataResponse<TestResponse, AFError>?
  821. // When
  822. let request = session.request(.basicAuth(), interceptor: handler)
  823. .validate()
  824. .responseDecodable(of: TestResponse.self) { jsonResponse in
  825. response = jsonResponse
  826. expectation.fulfill()
  827. }
  828. waitForExpectations(timeout: timeout)
  829. // Then
  830. XCTAssertEqual(handler.adaptCalledCount, 2)
  831. XCTAssertEqual(handler.adaptedCount, 2)
  832. XCTAssertEqual(handler.retryCalledCount, 3)
  833. XCTAssertEqual(handler.retryCount, 3)
  834. XCTAssertEqual(request.retryCount, 1)
  835. XCTAssertEqual(response?.result.isSuccess, false)
  836. assert(on: session.rootQueue) {
  837. XCTAssertTrue(session.requestTaskMap.isEmpty)
  838. XCTAssertTrue(session.activeRequests.isEmpty)
  839. }
  840. }
  841. @MainActor
  842. func testThatSessionCallsRequestRetrierThenSessionRetrierWhenRequestEncountersError() {
  843. // Given
  844. let sessionHandler = RequestHandler()
  845. let requestHandler = RequestHandler()
  846. let session = Session(interceptor: sessionHandler)
  847. let expectation = expectation(description: "request should eventually fail")
  848. var response: DataResponse<TestResponse, AFError>?
  849. // When
  850. let request = session.request(.basicAuth(), interceptor: requestHandler)
  851. .validate()
  852. .responseDecodable(of: TestResponse.self) { jsonResponse in
  853. response = jsonResponse
  854. expectation.fulfill()
  855. }
  856. waitForExpectations(timeout: timeout)
  857. // Then
  858. XCTAssertEqual(sessionHandler.adaptCalledCount, 3)
  859. XCTAssertEqual(sessionHandler.adaptedCount, 3)
  860. XCTAssertEqual(sessionHandler.retryCalledCount, 3)
  861. XCTAssertEqual(sessionHandler.retryCount, 3)
  862. XCTAssertEqual(requestHandler.adaptCalledCount, 3)
  863. XCTAssertEqual(requestHandler.adaptedCount, 3)
  864. XCTAssertEqual(requestHandler.retryCalledCount, 4)
  865. XCTAssertEqual(requestHandler.retryCount, 4)
  866. XCTAssertEqual(request.retryCount, 2)
  867. XCTAssertEqual(response?.result.isSuccess, false)
  868. assert(on: session.rootQueue) {
  869. XCTAssertTrue(session.requestTaskMap.isEmpty)
  870. XCTAssertTrue(session.activeRequests.isEmpty)
  871. }
  872. }
  873. @MainActor
  874. func testThatSessionCallsAdapterWhenRequestIsRetried() {
  875. // Given
  876. let handler = RequestHandler(shouldApplyAuthorizationHeader: true)
  877. let session = Session(interceptor: handler)
  878. let expectation = expectation(description: "request should eventually succeed")
  879. var response: DataResponse<TestResponse, AFError>?
  880. // When
  881. let request = session.request(.basicAuth())
  882. .validate()
  883. .responseDecodable(of: TestResponse.self) { jsonResponse in
  884. response = jsonResponse
  885. expectation.fulfill()
  886. }
  887. waitForExpectations(timeout: timeout)
  888. // Then
  889. XCTAssertEqual(handler.adaptCalledCount, 2)
  890. XCTAssertEqual(handler.adaptedCount, 2)
  891. XCTAssertEqual(handler.retryCalledCount, 1)
  892. XCTAssertEqual(handler.retryCount, 1)
  893. XCTAssertEqual(request.retryCount, 1)
  894. XCTAssertEqual(response?.result.isSuccess, true)
  895. assert(on: session.rootQueue) {
  896. XCTAssertTrue(session.requestTaskMap.isEmpty)
  897. XCTAssertTrue(session.activeRequests.isEmpty)
  898. }
  899. }
  900. @MainActor
  901. func testThatSessionReturnsRequestAdaptationErrorWhenRequestIsRetried() {
  902. // Given
  903. let handler = RequestHandler(throwsErrorOnSecondAdapt: true)
  904. let session = Session(interceptor: handler)
  905. let expectation = expectation(description: "request should eventually fail")
  906. var response: DataResponse<TestResponse, AFError>?
  907. // When
  908. let request = session.request(.basicAuth())
  909. .validate()
  910. .responseDecodable(of: TestResponse.self) { jsonResponse in
  911. response = jsonResponse
  912. expectation.fulfill()
  913. }
  914. waitForExpectations(timeout: timeout)
  915. // Then
  916. XCTAssertEqual(handler.adaptCalledCount, 2)
  917. XCTAssertEqual(handler.adaptedCount, 1)
  918. XCTAssertEqual(handler.retryCalledCount, 3)
  919. XCTAssertEqual(handler.retryCount, 3)
  920. XCTAssertEqual(request.retryCount, 1)
  921. XCTAssertEqual(response?.result.isSuccess, false)
  922. XCTAssertEqual(request.error?.isRequestAdaptationError, true)
  923. XCTAssertEqual(request.error?.underlyingError?.asAFError?.urlConvertible as? String, "/adapt/error/2")
  924. assert(on: session.rootQueue) {
  925. XCTAssertTrue(session.requestTaskMap.isEmpty)
  926. XCTAssertTrue(session.activeRequests.isEmpty)
  927. }
  928. }
  929. @MainActor
  930. func testThatSessionRetriesRequestWithDelayWhenRetryResultContainsDelay() {
  931. // Given
  932. let handler = RequestHandler(throwsErrorOnSecondAdapt: true, retryDelay: 0.01)
  933. let session = Session(interceptor: handler)
  934. let expectation = expectation(description: "request should eventually fail")
  935. var response: DataResponse<TestResponse, AFError>?
  936. // When
  937. let request = session.request(.basicAuth())
  938. .validate()
  939. .responseDecodable(of: TestResponse.self) { jsonResponse in
  940. response = jsonResponse
  941. expectation.fulfill()
  942. }
  943. waitForExpectations(timeout: timeout)
  944. // Then
  945. XCTAssertEqual(handler.adaptCalledCount, 2)
  946. XCTAssertEqual(handler.adaptedCount, 1)
  947. XCTAssertEqual(handler.retryCalledCount, 3)
  948. XCTAssertEqual(handler.retryCount, 3)
  949. XCTAssertEqual(request.retryCount, 1)
  950. XCTAssertEqual(response?.result.isSuccess, false)
  951. XCTAssertEqual(request.error?.isRequestAdaptationError, true)
  952. XCTAssertEqual(request.error?.underlyingError?.asAFError?.urlConvertible as? String, "/adapt/error/2")
  953. assert(on: session.rootQueue) {
  954. XCTAssertTrue(session.requestTaskMap.isEmpty)
  955. XCTAssertTrue(session.activeRequests.isEmpty)
  956. }
  957. }
  958. @MainActor
  959. func testThatSessionReturnsRequestRetryErrorWhenRequestRetrierThrowsError() {
  960. // Given
  961. let handler = RequestHandler(throwsErrorOnRetry: true)
  962. let session = Session(interceptor: handler)
  963. let expectation = expectation(description: "request should eventually fail")
  964. var response: DataResponse<TestResponse, AFError>?
  965. // When
  966. let request = session.request(.basicAuth())
  967. .validate()
  968. .responseDecodable(of: TestResponse.self) { jsonResponse in
  969. response = jsonResponse
  970. expectation.fulfill()
  971. }
  972. waitForExpectations(timeout: timeout)
  973. // Then
  974. XCTAssertEqual(handler.adaptCalledCount, 1)
  975. XCTAssertEqual(handler.adaptedCount, 1)
  976. XCTAssertEqual(handler.retryCalledCount, 2)
  977. XCTAssertEqual(handler.retryCount, 0)
  978. XCTAssertEqual(request.retryCount, 0)
  979. XCTAssertEqual(response?.result.isSuccess, false)
  980. assert(on: session.rootQueue) {
  981. XCTAssertTrue(session.requestTaskMap.isEmpty)
  982. XCTAssertTrue(session.activeRequests.isEmpty)
  983. }
  984. if let error = response?.result.failure {
  985. XCTAssertTrue(error.isRequestRetryError)
  986. XCTAssertEqual(error.underlyingError?.asAFError?.urlConvertible as? String, "/invalid/url/2")
  987. } else {
  988. XCTFail("error should not be nil")
  989. }
  990. }
  991. // MARK: Tests - Response Serializer Retry
  992. @MainActor
  993. func testThatSessionCallsRequestRetrierWhenResponseSerializerThrowsError() {
  994. // Given
  995. let handler = RequestHandler(shouldRetry: false)
  996. let session = Session()
  997. let expectation = expectation(description: "request should eventually fail")
  998. var response: DataResponse<TestResponse, AFError>?
  999. // When
  1000. let request = session.request(.image(.jpeg), interceptor: handler)
  1001. .validate()
  1002. .responseDecodable(of: TestResponse.self) { jsonResponse in
  1003. response = jsonResponse
  1004. expectation.fulfill()
  1005. }
  1006. waitForExpectations(timeout: timeout)
  1007. // Then
  1008. XCTAssertEqual(handler.adaptCalledCount, 1)
  1009. XCTAssertEqual(handler.adaptedCount, 1)
  1010. XCTAssertEqual(handler.retryCalledCount, 1)
  1011. XCTAssertEqual(handler.retryCount, 0)
  1012. XCTAssertEqual(request.retryCount, 0)
  1013. XCTAssertEqual(response?.result.isSuccess, false)
  1014. XCTAssertEqual(response?.error?.isResponseSerializationError, true)
  1015. XCTAssertNotNil(response?.error?.underlyingError as? DecodingError)
  1016. assert(on: session.rootQueue) {
  1017. XCTAssertTrue(session.requestTaskMap.isEmpty)
  1018. XCTAssertTrue(session.activeRequests.isEmpty)
  1019. }
  1020. }
  1021. @MainActor
  1022. func testThatSessionCallsRequestRetrierForAllResponseSerializersThatThrowError() throws {
  1023. // Given
  1024. let handler = RequestHandler(throwsErrorOnRetry: true)
  1025. let session = Session()
  1026. let json1Expectation = expectation(description: "request should eventually fail")
  1027. var json1Response: DataResponse<TestResponse, AFError>?
  1028. let json2Expectation = expectation(description: "request should eventually fail")
  1029. var json2Response: DataResponse<TestResponse, AFError>?
  1030. // When
  1031. let request = session.request(.image(.jpeg), interceptor: handler)
  1032. .validate()
  1033. .responseDecodable(of: TestResponse.self) { response in
  1034. json1Response = response
  1035. json1Expectation.fulfill()
  1036. }
  1037. .responseDecodable(of: TestResponse.self) { response in
  1038. json2Response = response
  1039. json2Expectation.fulfill()
  1040. }
  1041. waitForExpectations(timeout: timeout)
  1042. // Then
  1043. XCTAssertEqual(handler.adaptCalledCount, 1)
  1044. XCTAssertEqual(handler.adaptedCount, 1)
  1045. XCTAssertEqual(handler.retryCalledCount, 2)
  1046. XCTAssertEqual(handler.retryCount, 0)
  1047. XCTAssertEqual(request.retryCount, 0)
  1048. XCTAssertEqual(json1Response?.result.isSuccess, false)
  1049. XCTAssertEqual(json2Response?.result.isSuccess, false)
  1050. assert(on: session.rootQueue) {
  1051. XCTAssertTrue(session.requestTaskMap.isEmpty)
  1052. XCTAssertTrue(session.activeRequests.isEmpty)
  1053. }
  1054. let errors = [json1Response, json2Response].compactMap { $0?.error }
  1055. XCTAssertEqual(errors.count, 2)
  1056. for (index, error) in errors.enumerated() {
  1057. XCTAssertTrue(error.isRequestRetryError)
  1058. if case let .requestRetryFailed(retryError, originalError) = error {
  1059. XCTAssertEqual(retryError.asAFError?.urlConvertible as? String, "/invalid/url/\(index + 1)")
  1060. XCTAssertNotNil(originalError.asAFError?.underlyingError as? DecodingError)
  1061. } else {
  1062. XCTFail("Error failure reason should be response serialization failure")
  1063. }
  1064. }
  1065. }
  1066. @MainActor
  1067. func testThatSessionRetriesRequestImmediatelyWhenResponseSerializerRequestsRetry() throws {
  1068. // Given
  1069. let handler = RequestHandler()
  1070. let session = Session()
  1071. let json1Expectation = expectation(description: "request should eventually fail")
  1072. var json1Response: DataResponse<TestResponse, AFError>?
  1073. let json2Expectation = expectation(description: "request should eventually fail")
  1074. var json2Response: DataResponse<TestResponse, AFError>?
  1075. // When
  1076. let request = session.request(.image(.jpeg), interceptor: handler)
  1077. .validate()
  1078. .responseDecodable(of: TestResponse.self) { response in
  1079. json1Response = response
  1080. json1Expectation.fulfill()
  1081. }
  1082. .responseDecodable(of: TestResponse.self) { response in
  1083. json2Response = response
  1084. json2Expectation.fulfill()
  1085. }
  1086. waitForExpectations(timeout: timeout)
  1087. // Then
  1088. XCTAssertEqual(handler.adaptCalledCount, 2)
  1089. XCTAssertEqual(handler.adaptedCount, 2)
  1090. XCTAssertEqual(handler.retryCalledCount, 3)
  1091. XCTAssertEqual(handler.retryCount, 3)
  1092. XCTAssertEqual(request.retryCount, 1)
  1093. XCTAssertEqual(json1Response?.result.isSuccess, false)
  1094. XCTAssertEqual(json2Response?.result.isSuccess, false)
  1095. assert(on: session.rootQueue) {
  1096. XCTAssertTrue(session.requestTaskMap.isEmpty)
  1097. XCTAssertTrue(session.activeRequests.isEmpty)
  1098. }
  1099. let errors = [json1Response, json2Response].compactMap { $0?.error }
  1100. XCTAssertEqual(errors.count, 2)
  1101. for error in errors {
  1102. XCTAssertTrue(error.isResponseSerializationError)
  1103. XCTAssertNotNil(error.underlyingError as? DecodingError)
  1104. }
  1105. }
  1106. @MainActor
  1107. func testThatSessionCallsResponseSerializerCompletionsWhenAdapterThrowsErrorDuringRetry() {
  1108. // Four retries should occur given this scenario:
  1109. // 1) Retrier is called from first response serializer failure (trips retry)
  1110. // 2) Retrier is called by Session for adapt error thrown
  1111. // 3) Retrier is called again from first response serializer failure
  1112. // 4) Retrier is called from second response serializer failure
  1113. // Given
  1114. let handler = RequestHandler(throwsErrorOnSecondAdapt: true)
  1115. let session = Session()
  1116. let json1Expectation = expectation(description: "request should eventually fail")
  1117. var json1Response: DataResponse<TestResponse, AFError>?
  1118. let json2Expectation = expectation(description: "request should eventually fail")
  1119. var json2Response: DataResponse<TestResponse, AFError>?
  1120. // When
  1121. let request = session.request(.image(.jpeg), interceptor: handler)
  1122. .validate()
  1123. .responseDecodable(of: TestResponse.self) { response in
  1124. json1Response = response
  1125. json1Expectation.fulfill()
  1126. }
  1127. .responseDecodable(of: TestResponse.self) { response in
  1128. json2Response = response
  1129. json2Expectation.fulfill()
  1130. }
  1131. waitForExpectations(timeout: timeout)
  1132. // Then
  1133. XCTAssertEqual(handler.adaptCalledCount, 2)
  1134. XCTAssertEqual(handler.adaptedCount, 1)
  1135. XCTAssertEqual(handler.retryCalledCount, 4)
  1136. XCTAssertEqual(handler.retryCount, 4)
  1137. XCTAssertEqual(request.retryCount, 1)
  1138. XCTAssertEqual(json1Response?.result.isSuccess, false)
  1139. XCTAssertEqual(json2Response?.result.isSuccess, false)
  1140. assert(on: session.rootQueue) {
  1141. XCTAssertTrue(session.requestTaskMap.isEmpty)
  1142. XCTAssertTrue(session.activeRequests.isEmpty)
  1143. }
  1144. let errors = [json1Response, json2Response].compactMap { $0?.error }
  1145. XCTAssertEqual(errors.count, 2)
  1146. for error in errors {
  1147. XCTAssertTrue(error.isRequestAdaptationError)
  1148. XCTAssertEqual(error.underlyingError?.asAFError?.urlConvertible as? String, "/adapt/error/2")
  1149. }
  1150. }
  1151. @MainActor
  1152. func testThatSessionCallsResponseSerializerCompletionsWhenAdapterThrowsErrorDuringRetryForDownloads() {
  1153. // Four retries should occur given this scenario:
  1154. // 1) Retrier is called from first response serializer failure (trips retry)
  1155. // 2) Retrier is called by Session for adapt error thrown
  1156. // 3) Retrier is called again from first response serializer failure
  1157. // 4) Retrier is called from second response serializer failure
  1158. // Given
  1159. let handler = RequestHandler(throwsErrorOnSecondAdapt: true)
  1160. let session = Session()
  1161. let json1Expectation = expectation(description: "request should eventually fail")
  1162. var json1Response: DownloadResponse<TestResponse, AFError>?
  1163. let json2Expectation = expectation(description: "request should eventually fail")
  1164. var json2Response: DownloadResponse<TestResponse, AFError>?
  1165. // When
  1166. let request = session.download(.image(.jpeg), interceptor: handler)
  1167. .validate()
  1168. .responseDecodable(of: TestResponse.self) { response in
  1169. json1Response = response
  1170. json1Expectation.fulfill()
  1171. }
  1172. .responseDecodable(of: TestResponse.self) { response in
  1173. json2Response = response
  1174. json2Expectation.fulfill()
  1175. }
  1176. waitForExpectations(timeout: timeout)
  1177. // Then
  1178. XCTAssertEqual(handler.adaptCalledCount, 2)
  1179. XCTAssertEqual(handler.adaptedCount, 1)
  1180. XCTAssertEqual(handler.retryCalledCount, 4)
  1181. XCTAssertEqual(handler.retryCount, 4)
  1182. XCTAssertEqual(request.retryCount, 1)
  1183. XCTAssertEqual(json1Response?.result.isSuccess, false)
  1184. XCTAssertEqual(json2Response?.result.isSuccess, false)
  1185. assert(on: session.rootQueue) {
  1186. XCTAssertTrue(session.requestTaskMap.isEmpty)
  1187. XCTAssertTrue(session.activeRequests.isEmpty)
  1188. }
  1189. let errors = [json1Response, json2Response].compactMap { $0?.error }
  1190. XCTAssertEqual(errors.count, 2)
  1191. for error in errors {
  1192. XCTAssertTrue(error.isRequestAdaptationError)
  1193. XCTAssertEqual(error.underlyingError?.asAFError?.urlConvertible as? String, "/adapt/error/2")
  1194. }
  1195. }
  1196. // MARK: Tests - Session Invalidation
  1197. @MainActor
  1198. func testThatSessionIsInvalidatedAndAllRequestsCompleteWhenSessionIsDeinitialized() {
  1199. // Given
  1200. let invalidationExpectation = expectation(description: "sessionDidBecomeInvalidWithError should be called")
  1201. let events = ClosureEventMonitor()
  1202. events.sessionDidBecomeInvalidWithError = { _, _ in
  1203. invalidationExpectation.fulfill()
  1204. }
  1205. var session: Session? = Session(startRequestsImmediately: false, eventMonitors: [events])
  1206. var error: AFError?
  1207. let requestExpectation = expectation(description: "request should complete")
  1208. // When
  1209. session?.request(.default).response { response in
  1210. error = response.error
  1211. requestExpectation.fulfill()
  1212. }
  1213. session = nil
  1214. waitForExpectations(timeout: timeout)
  1215. // Then
  1216. XCTAssertEqual(error?.isSessionDeinitializedError, true)
  1217. }
  1218. // MARK: Tests - Request Cancellation
  1219. @MainActor
  1220. func testThatSessionOnlyCallsResponseSerializerCompletionWhenCancellingInsideCompletion() {
  1221. // Given
  1222. let handler = RequestHandler()
  1223. let session = Session()
  1224. let expectation = expectation(description: "request should complete")
  1225. var response: DataResponse<TestResponse, AFError>?
  1226. var completionCallCount = 0
  1227. // When
  1228. let request = session.request(.default, interceptor: handler)
  1229. request.validate()
  1230. request.responseDecodable(of: TestResponse.self) { resp in
  1231. request.cancel()
  1232. response = resp
  1233. completionCallCount += 1
  1234. DispatchQueue.main.after(0.01) { expectation.fulfill() }
  1235. }
  1236. waitForExpectations(timeout: timeout)
  1237. // Then
  1238. XCTAssertEqual(handler.adaptCalledCount, 1)
  1239. XCTAssertEqual(handler.adaptedCount, 1)
  1240. XCTAssertEqual(handler.retryCalledCount, 0)
  1241. XCTAssertEqual(handler.retryCount, 0)
  1242. XCTAssertEqual(request.retryCount, 0)
  1243. XCTAssertEqual(response?.result.isSuccess, true)
  1244. XCTAssertEqual(completionCallCount, 1)
  1245. assert(on: session.rootQueue) {
  1246. XCTAssertTrue(session.requestTaskMap.isEmpty)
  1247. XCTAssertTrue(session.activeRequests.isEmpty)
  1248. }
  1249. }
  1250. // MARK: Tests - Request State
  1251. @MainActor
  1252. func testThatSessionSetsRequestStateWhenStartRequestsImmediatelyIsTrue() {
  1253. // Given
  1254. let session = Session()
  1255. let expectation = expectation(description: "request should complete")
  1256. var response: DataResponse<TestResponse, AFError>?
  1257. // When
  1258. let request = session.request(.default).responseDecodable(of: TestResponse.self) { resp in
  1259. response = resp
  1260. expectation.fulfill()
  1261. }
  1262. waitForExpectations(timeout: timeout)
  1263. // Then
  1264. XCTAssertEqual(request.state, .finished)
  1265. XCTAssertEqual(response?.result.isSuccess, true)
  1266. }
  1267. // MARK: Invalid Requests
  1268. @MainActor
  1269. func testThatGETRequestsWithBodyDataAreConsideredInvalid() {
  1270. // Given
  1271. let session = Session()
  1272. var request = Endpoint().urlRequest
  1273. request.httpBody = Data("invalid".utf8)
  1274. let expect = expectation(description: "request should complete")
  1275. var response: DataResponse<TestResponse, AFError>?
  1276. // When
  1277. session.request(request).responseDecodable(of: TestResponse.self) { resp in
  1278. response = resp
  1279. expect.fulfill()
  1280. }
  1281. waitForExpectations(timeout: timeout)
  1282. // Then
  1283. XCTAssertEqual(response?.result.isFailure, true)
  1284. XCTAssertEqual(response?.error?.isBodyDataInGETRequest, true)
  1285. }
  1286. @MainActor
  1287. func testThatAdaptedGETRequestsWithBodyDataAreConsideredInvalid() {
  1288. // Given
  1289. struct InvalidAdapter: RequestInterceptor {
  1290. func adapt(_ urlRequest: URLRequest,
  1291. for session: Session,
  1292. completion: @escaping (Result<URLRequest, any Error>) -> Void) {
  1293. var request = urlRequest
  1294. request.httpBody = Data("invalid".utf8)
  1295. completion(.success(request))
  1296. }
  1297. }
  1298. let session = Session(interceptor: InvalidAdapter())
  1299. let expect = expectation(description: "request should complete")
  1300. var response: DataResponse<TestResponse, AFError>?
  1301. // When
  1302. session.request(.default).responseDecodable(of: TestResponse.self) { resp in
  1303. response = resp
  1304. expect.fulfill()
  1305. }
  1306. waitForExpectations(timeout: timeout)
  1307. // Then
  1308. XCTAssertEqual(response?.result.isFailure, true)
  1309. XCTAssertEqual(response?.error?.isRequestAdaptationError, true)
  1310. XCTAssertEqual(response?.error?.underlyingError?.asAFError?.isBodyDataInGETRequest, true)
  1311. }
  1312. }
  1313. // MARK: -
  1314. final class SessionMassActionTestCase: BaseTestCase {
  1315. func testThatRequestsCanHaveMassActionsPerformed() {
  1316. // Given
  1317. let count = 10
  1318. let createdTasks = expectation(description: "all tasks created")
  1319. createdTasks.expectedFulfillmentCount = count
  1320. let massActions = expectation(description: "cancel all requests should be called")
  1321. let monitor = ClosureEventMonitor()
  1322. monitor.requestDidCreateTask = { _, _ in createdTasks.fulfill() }
  1323. let session = Session(eventMonitors: [monitor])
  1324. let request = Endpoint.delay(1)
  1325. var requests: [DataRequest] = []
  1326. // When
  1327. requests = (0..<count).map { _ in session.request(request) }
  1328. wait(for: [createdTasks], timeout: timeout)
  1329. session.withAllRequests { $0.forEach { $0.suspend() }; massActions.fulfill() }
  1330. wait(for: [massActions], timeout: timeout)
  1331. // Then
  1332. XCTAssertTrue(requests.allSatisfy(\.isSuspended))
  1333. }
  1334. @MainActor
  1335. func testThatAutomaticallyResumedRequestsCanBeMassCancelled() {
  1336. // Given
  1337. let count = 100
  1338. let completion = expectation(description: "all requests should finish")
  1339. completion.expectedFulfillmentCount = count
  1340. let createdTasks = expectation(description: "all tasks created")
  1341. createdTasks.expectedFulfillmentCount = count
  1342. let gatheredMetrics = expectation(description: "metrics gathered for all tasks")
  1343. gatheredMetrics.expectedFulfillmentCount = count
  1344. let cancellation = expectation(description: "cancel all requests should be called")
  1345. let monitor = ClosureEventMonitor()
  1346. monitor.requestDidCreateTask = { _, _ in createdTasks.fulfill() }
  1347. monitor.requestDidGatherMetrics = { _, _ in gatheredMetrics.fulfill() }
  1348. let session = Session(eventMonitors: [monitor])
  1349. let request = Endpoint.delay(1)
  1350. var requests: [DataRequest] = []
  1351. var responses: [DataResponse<Data?, AFError>] = []
  1352. // When
  1353. requests = (0..<count).map { _ in session.request(request) }
  1354. wait(for: [createdTasks], timeout: timeout)
  1355. for request in requests {
  1356. request.response { response in
  1357. responses.append(response)
  1358. completion.fulfill()
  1359. }
  1360. }
  1361. session.cancelAllRequests {
  1362. cancellation.fulfill()
  1363. }
  1364. wait(for: [gatheredMetrics, cancellation, completion], timeout: timeout)
  1365. // Then
  1366. XCTAssertTrue(responses.allSatisfy { $0.error?.isExplicitlyCancelledError == true })
  1367. assert(on: session.rootQueue) {
  1368. XCTAssertTrue(session.requestTaskMap.isEmpty, "requestTaskMap should be empty but has \(session.requestTaskMap.count) items")
  1369. XCTAssertTrue(session.activeRequests.isEmpty, "activeRequests should be empty but has \(session.activeRequests.count) items")
  1370. }
  1371. }
  1372. @MainActor
  1373. func testThatManuallyResumedRequestsCanBeMassCancelled() {
  1374. // Given
  1375. let count = 100
  1376. let completion = expectation(description: "all requests should finish")
  1377. completion.expectedFulfillmentCount = count
  1378. let createdTasks = expectation(description: "all tasks created")
  1379. createdTasks.expectedFulfillmentCount = count
  1380. let gatheredMetrics = expectation(description: "metrics gathered for all tasks")
  1381. gatheredMetrics.expectedFulfillmentCount = count
  1382. let cancellation = expectation(description: "cancel all requests should be called")
  1383. let monitor = ClosureEventMonitor()
  1384. monitor.requestDidCreateTask = { _, _ in createdTasks.fulfill() }
  1385. monitor.requestDidGatherMetrics = { _, _ in gatheredMetrics.fulfill() }
  1386. let session = Session(startRequestsImmediately: false, eventMonitors: [monitor])
  1387. let request = Endpoint.delay(1)
  1388. var responses: [DataResponse<Data?, AFError>] = []
  1389. // When
  1390. for _ in 0..<count {
  1391. session.request(request).response { response in
  1392. responses.append(response)
  1393. completion.fulfill()
  1394. }
  1395. }
  1396. wait(for: [createdTasks], timeout: timeout)
  1397. session.cancelAllRequests {
  1398. cancellation.fulfill()
  1399. }
  1400. wait(for: [gatheredMetrics, cancellation, completion], timeout: timeout)
  1401. // Then
  1402. XCTAssertTrue(responses.allSatisfy { $0.error?.isExplicitlyCancelledError == true })
  1403. assert(on: session.rootQueue) {
  1404. XCTAssertTrue(session.requestTaskMap.isEmpty, "requestTaskMap should be empty but has \(session.requestTaskMap.count) items")
  1405. XCTAssertTrue(session.activeRequests.isEmpty, "activeRequests should be empty but has \(session.activeRequests.count) items")
  1406. }
  1407. }
  1408. @MainActor
  1409. func testThatRetriedRequestsCanBeMassCancelled() {
  1410. // Given
  1411. final class OnceRetrier: RequestInterceptor {
  1412. private var hasRetried = false
  1413. func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, any Error>) -> Void) {
  1414. if hasRetried {
  1415. var request = urlRequest
  1416. request.url = Endpoint.delay(1).url
  1417. completion(.success(request))
  1418. } else {
  1419. completion(.success(urlRequest))
  1420. }
  1421. }
  1422. func retry(_ request: Request, for session: Session, dueTo error: any Error, completion: @escaping (RetryResult) -> Void) {
  1423. completion(hasRetried ? .doNotRetry : .retry)
  1424. hasRetried = true
  1425. }
  1426. }
  1427. let queue = DispatchQueue(label: "com.alamofire.testQueue")
  1428. let monitor = ClosureEventMonitor(queue: queue)
  1429. let session = Session(rootQueue: queue, interceptor: OnceRetrier(), eventMonitors: [monitor])
  1430. let request = Endpoint.status(401)
  1431. let completion = expectation(description: "all requests should finish")
  1432. let cancellation = expectation(description: "cancel all requests should be called")
  1433. let createTask = expectation(description: "should create task twice")
  1434. createTask.expectedFulfillmentCount = 2
  1435. var tasksCreated = 0
  1436. monitor.requestDidCreateTask = { [unowned session] _, _ in
  1437. tasksCreated += 1
  1438. createTask.fulfill()
  1439. // Cancel after the second task is created to ensure proper lifetime events.
  1440. if tasksCreated == 2 {
  1441. session.cancelAllRequests {
  1442. cancellation.fulfill()
  1443. }
  1444. }
  1445. }
  1446. var received: DataResponse<Data?, AFError>?
  1447. // When
  1448. session.request(request).validate().response { response in
  1449. received = response
  1450. completion.fulfill()
  1451. }
  1452. waitForExpectations(timeout: timeout)
  1453. // Then
  1454. XCTAssertEqual(received?.error?.isExplicitlyCancelledError, true)
  1455. assert(on: session.rootQueue) {
  1456. XCTAssertTrue(session.requestTaskMap.isEmpty, "requestTaskMap should be empty but has \(session.requestTaskMap.count) items")
  1457. XCTAssertTrue(session.activeRequests.isEmpty, "activeRequests should be empty but has \(session.activeRequests.count) items")
  1458. }
  1459. }
  1460. }
  1461. // MARK: -
  1462. final class SessionConfigurationHeadersTestCase: BaseTestCase {
  1463. enum ConfigurationType {
  1464. case `default`, ephemeral
  1465. }
  1466. @MainActor
  1467. func testThatDefaultConfigurationHeadersAreSentWithRequest() {
  1468. // Given, When, Then
  1469. executeAuthorizationHeaderTest(for: .default)
  1470. }
  1471. @MainActor
  1472. func testThatEphemeralConfigurationHeadersAreSentWithRequest() {
  1473. // Given, When, Then
  1474. executeAuthorizationHeaderTest(for: .ephemeral)
  1475. }
  1476. @MainActor
  1477. private func executeAuthorizationHeaderTest(for type: ConfigurationType) {
  1478. // Given
  1479. let session: Session = {
  1480. let configuration: URLSessionConfiguration = {
  1481. let configuration: URLSessionConfiguration = switch type {
  1482. case .default:
  1483. .default
  1484. case .ephemeral:
  1485. .ephemeral
  1486. }
  1487. var headers = HTTPHeaders.default
  1488. headers["Authorization"] = "Bearer 123456"
  1489. configuration.headers = headers
  1490. return configuration
  1491. }()
  1492. return Session(configuration: configuration)
  1493. }()
  1494. let expectation = expectation(description: "request should complete successfully")
  1495. var response: DataResponse<TestResponse, AFError>?
  1496. // When
  1497. session.request(.default)
  1498. .responseDecodable(of: TestResponse.self) { closureResponse in
  1499. response = closureResponse
  1500. expectation.fulfill()
  1501. }
  1502. waitForExpectations(timeout: timeout)
  1503. // Then
  1504. XCTAssertNotNil(response?.request, "request should not be nil")
  1505. XCTAssertNotNil(response?.response, "response should not be nil")
  1506. XCTAssertNotNil(response?.data, "data should not be nil")
  1507. XCTAssertEqual(response?.result.isSuccess, true)
  1508. XCTAssertEqual(response?.value?.headers["Authorization"], "Bearer 123456", "Authorization header should match")
  1509. }
  1510. }