SessionTests.swift 66 KB

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