SessionTests.swift 69 KB

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