SessionTests.swift 65 KB

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