SessionTests.swift 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068
  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. class SessionTestCase: BaseTestCase {
  28. // MARK: Helper Types
  29. private class HTTPMethodAdapter: RequestInterceptor {
  30. let method: HTTPMethod
  31. let throwsError: Bool
  32. init(method: HTTPMethod, throwsError: Bool = false) {
  33. self.method = method
  34. self.throwsError = throwsError
  35. }
  36. func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest>) -> Void) {
  37. let result: Result<URLRequest> = Result {
  38. guard !throwsError else { throw AFError.invalidURL(url: "") }
  39. var urlRequest = urlRequest
  40. urlRequest.httpMethod = method.rawValue
  41. return urlRequest
  42. }
  43. completion(result)
  44. }
  45. }
  46. private class RequestHandler: RequestInterceptor {
  47. var adaptedCount = 0
  48. var retryCount = 0
  49. var retryErrors: [Error] = []
  50. var shouldApplyAuthorizationHeader = false
  51. var throwsErrorOnFirstAdapt = false
  52. var throwsErrorOnSecondAdapt = false
  53. var shouldRetry = true
  54. func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest>) -> Void) {
  55. let result: Result<URLRequest> = Result {
  56. if throwsErrorOnFirstAdapt {
  57. throwsErrorOnFirstAdapt = false
  58. throw AFError.invalidURL(url: "")
  59. }
  60. if throwsErrorOnSecondAdapt && adaptedCount == 1 {
  61. throwsErrorOnSecondAdapt = false
  62. throw AFError.invalidURL(url: "")
  63. }
  64. var urlRequest = urlRequest
  65. adaptedCount += 1
  66. if shouldApplyAuthorizationHeader && adaptedCount > 1 {
  67. urlRequest.httpHeaders.update(.authorization(username: "user", password: "password"))
  68. }
  69. return urlRequest
  70. }
  71. completion(result)
  72. }
  73. func retry(
  74. _ request: Request,
  75. for session: Session,
  76. dueTo error: Error,
  77. completion: @escaping (RetryResult) -> Void)
  78. {
  79. guard shouldRetry else { completion(.doNotRetry); return }
  80. retryCount += 1
  81. retryErrors.append(error)
  82. if retryCount < 2 {
  83. completion(.retry)
  84. } else {
  85. completion(.doNotRetry)
  86. }
  87. }
  88. }
  89. private class UploadHandler: RequestInterceptor {
  90. var adaptedCount = 0
  91. var retryCount = 0
  92. var retryErrors: [Error] = []
  93. func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest>) -> Void) {
  94. let result: Result<URLRequest> = Result {
  95. adaptedCount += 1
  96. if adaptedCount == 1 { throw AFError.invalidURL(url: "") }
  97. return urlRequest
  98. }
  99. completion(result)
  100. }
  101. func retry(
  102. _ request: Request,
  103. for session: Session,
  104. dueTo error: Error,
  105. completion: @escaping (RetryResult) -> Void)
  106. {
  107. retryCount += 1
  108. retryErrors.append(error)
  109. completion(.retry)
  110. }
  111. }
  112. // MARK: Tests - Initialization
  113. func testInitializerWithDefaultArguments() {
  114. // Given, When
  115. let session = Session()
  116. // Then
  117. XCTAssertNotNil(session.session.delegate, "session delegate should not be nil")
  118. XCTAssertTrue(session.delegate === session.session.delegate, "manager delegate should equal session delegate")
  119. XCTAssertNil(session.serverTrustManager, "session server trust policy manager should be nil")
  120. }
  121. func testInitializerWithSpecifiedArguments() {
  122. // Given
  123. let configuration = URLSessionConfiguration.default
  124. let delegate = SessionDelegate()
  125. let serverTrustManager = ServerTrustManager(evaluators: [:])
  126. // When
  127. let session = Session(configuration: configuration,
  128. delegate: delegate,
  129. serverTrustManager: serverTrustManager)
  130. // Then
  131. XCTAssertNotNil(session.session.delegate, "session delegate should not be nil")
  132. XCTAssertTrue(session.delegate === session.session.delegate, "manager delegate should equal session delegate")
  133. XCTAssertNotNil(session.serverTrustManager, "session server trust policy manager should not be nil")
  134. }
  135. func testThatSessionInitializerSucceedsWithDefaultArguments() {
  136. // Given
  137. let delegate = SessionDelegate()
  138. let underlyingQueue = DispatchQueue(label: "underlyingQueue")
  139. let urlSession: URLSession = {
  140. let configuration = URLSessionConfiguration.default
  141. let queue = OperationQueue(underlyingQueue: underlyingQueue, name: "delegateQueue")
  142. return URLSession(configuration: configuration, delegate: delegate, delegateQueue: queue)
  143. }()
  144. // When
  145. let session = Session(session: urlSession, delegate: delegate, rootQueue: underlyingQueue)
  146. // Then
  147. XCTAssertTrue(session.delegate === session.session.delegate, "manager delegate should equal session delegate")
  148. XCTAssertNil(session.serverTrustManager, "session server trust policy manager should be nil")
  149. }
  150. func testThatSessionInitializerSucceedsWithSpecifiedArguments() {
  151. // Given
  152. let delegate = SessionDelegate()
  153. let underlyingQueue = DispatchQueue(label: "underlyingQueue")
  154. let urlSession: URLSession = {
  155. let configuration = URLSessionConfiguration.default
  156. let queue = OperationQueue(underlyingQueue: underlyingQueue, name: "delegateQueue")
  157. return URLSession(configuration: configuration, delegate: delegate, delegateQueue: queue)
  158. }()
  159. let serverTrustManager = ServerTrustManager(evaluators: [:])
  160. // When
  161. let session = Session(session: urlSession,
  162. delegate: delegate,
  163. rootQueue: underlyingQueue,
  164. serverTrustManager: serverTrustManager)
  165. // Then
  166. XCTAssertTrue(session.delegate === session.session.delegate, "manager delegate should equal session delegate")
  167. XCTAssertNotNil(session.serverTrustManager, "session server trust policy manager should not be nil")
  168. }
  169. // MARK: Tests - Default HTTP Headers
  170. func testDefaultUserAgentHeader() {
  171. // Given, When
  172. let userAgent = HTTPHeaders.default["User-Agent"]
  173. // Then
  174. let osNameVersion: String = {
  175. let version = ProcessInfo.processInfo.operatingSystemVersion
  176. let versionString = "\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)"
  177. let osName: String = {
  178. #if os(iOS)
  179. return "iOS"
  180. #elseif os(watchOS)
  181. return "watchOS"
  182. #elseif os(tvOS)
  183. return "tvOS"
  184. #elseif os(macOS)
  185. return "macOS"
  186. #elseif os(Linux)
  187. return "Linux"
  188. #else
  189. return "Unknown"
  190. #endif
  191. }()
  192. return "\(osName) \(versionString)"
  193. }()
  194. let alamofireVersion: String = {
  195. guard
  196. let afInfo = Bundle(for: Session.self).infoDictionary,
  197. let build = afInfo["CFBundleShortVersionString"]
  198. else { return "Unknown" }
  199. return "Alamofire/\(build)"
  200. }()
  201. let expectedUserAgent = "Unknown/Unknown (Unknown; build:Unknown; \(osNameVersion)) \(alamofireVersion)"
  202. XCTAssertEqual(userAgent, expectedUserAgent)
  203. }
  204. // MARK: Tests - Supported Accept-Encodings
  205. func testDefaultAcceptEncodingSupportsAppropriateEncodingsOnAppropriateSystems() {
  206. // Given
  207. let brotliURL = URL(string: "https://httpbin.org/brotli")!
  208. let gzipURL = URL(string: "https://httpbin.org/gzip")!
  209. let deflateURL = URL(string: "https://httpbin.org/deflate")!
  210. let brotliExpectation = expectation(description: "brotli request should complete")
  211. let gzipExpectation = expectation(description: "gzip request should complete")
  212. let deflateExpectation = expectation(description: "deflate request should complete")
  213. var brotliResponse: DataResponse<Any>?
  214. var gzipResponse: DataResponse<Any>?
  215. var deflateResponse: DataResponse<Any>?
  216. // When
  217. AF.request(brotliURL).responseJSON { response in
  218. brotliResponse = response
  219. brotliExpectation.fulfill()
  220. }
  221. AF.request(gzipURL).responseJSON { response in
  222. gzipResponse = response
  223. gzipExpectation.fulfill()
  224. }
  225. AF.request(deflateURL).responseJSON { response in
  226. deflateResponse = response
  227. deflateExpectation.fulfill()
  228. }
  229. waitForExpectations(timeout: timeout, handler: nil)
  230. // Then
  231. if #available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, *) {
  232. XCTAssertTrue(brotliResponse?.result.isSuccess == true)
  233. } else {
  234. XCTAssertTrue(brotliResponse?.result.isFailure == true)
  235. }
  236. XCTAssertTrue(gzipResponse?.result.isSuccess == true)
  237. XCTAssertTrue(deflateResponse?.result.isSuccess == true)
  238. }
  239. // MARK: Tests - Start Requests Immediately
  240. func testSetStartRequestsImmediatelyToFalseAndResumeRequest() {
  241. // Given
  242. let session = Session(startRequestsImmediately: false)
  243. let url = URL(string: "https://httpbin.org/get")!
  244. let urlRequest = URLRequest(url: url)
  245. let expectation = self.expectation(description: "\(url)")
  246. var response: HTTPURLResponse?
  247. // When
  248. session.request(urlRequest)
  249. .response { resp in
  250. response = resp.response
  251. expectation.fulfill()
  252. }
  253. .resume()
  254. waitForExpectations(timeout: timeout, handler: nil)
  255. // Then
  256. XCTAssertNotNil(response, "response should not be nil")
  257. XCTAssertTrue(response?.statusCode == 200, "response status code should be 200")
  258. }
  259. func testSetStartRequestsImmediatelyToFalseAndCancelledCallsResponseHandlers() {
  260. // Given
  261. let session = Session(startRequestsImmediately: false)
  262. let url = URL(string: "https://httpbin.org/get")!
  263. let urlRequest = URLRequest(url: url)
  264. let expectation = self.expectation(description: "\(url)")
  265. var response: DataResponse<Data?>?
  266. // When
  267. let request = session.request(urlRequest)
  268. .cancel()
  269. .response { resp in
  270. response = resp
  271. expectation.fulfill()
  272. }
  273. waitForExpectations(timeout: timeout, handler: nil)
  274. // Then
  275. XCTAssertNotNil(response, "response should not be nil")
  276. XCTAssertTrue(request.isCancelled)
  277. XCTAssertTrue((request.task == nil) || (request.task?.state == .canceling || request.task?.state == .completed))
  278. guard let error = request.error?.asAFError, case .explicitlyCancelled = error else {
  279. XCTFail("Request should have an .explicitlyCancelled error.")
  280. return
  281. }
  282. }
  283. func testSetStartRequestsImmediatelyToFalseAndResumeThenCancelRequestHasCorrectOutput() {
  284. // Given
  285. let session = Session(startRequestsImmediately: false)
  286. let url = URL(string: "https://httpbin.org/get")!
  287. let urlRequest = URLRequest(url: url)
  288. let expectation = self.expectation(description: "\(url)")
  289. var response: DataResponse<Data?>?
  290. // When
  291. let request = session.request(urlRequest)
  292. .resume()
  293. .cancel()
  294. .response { resp in
  295. response = resp
  296. expectation.fulfill()
  297. }
  298. waitForExpectations(timeout: timeout, handler: nil)
  299. // Then
  300. XCTAssertNotNil(response, "response should not be nil")
  301. XCTAssertTrue(request.isCancelled)
  302. XCTAssertTrue((request.task == nil) || (request.task?.state == .canceling || request.task?.state == .completed))
  303. guard let error = request.error?.asAFError, case .explicitlyCancelled = error else {
  304. XCTFail("Request should have an .explicitlyCancelled error.")
  305. return
  306. }
  307. }
  308. func testSetStartRequestsImmediatelyToFalseAndCancelThenResumeRequestDoesntCreateTaskAndStaysCancelled() {
  309. // Given
  310. let session = Session(startRequestsImmediately: false)
  311. let url = URL(string: "https://httpbin.org/get")!
  312. let urlRequest = URLRequest(url: url)
  313. let expectation = self.expectation(description: "\(url)")
  314. var response: DataResponse<Data?>?
  315. // When
  316. let request = session.request(urlRequest)
  317. .cancel()
  318. .resume()
  319. .response { resp in
  320. response = resp
  321. expectation.fulfill()
  322. }
  323. waitForExpectations(timeout: timeout, handler: nil)
  324. // Then
  325. XCTAssertNotNil(response, "response should not be nil")
  326. XCTAssertTrue(request.isCancelled)
  327. XCTAssertTrue((request.task == nil) || (request.task?.state == .canceling || request.task?.state == .completed))
  328. guard let error = request.error?.asAFError, case .explicitlyCancelled = error else {
  329. XCTFail("Request should have an .explicitlyCancelled error.")
  330. return
  331. }
  332. }
  333. // MARK: Tests - Deinitialization
  334. func testReleasingManagerWithPendingRequestDeinitializesSuccessfully() {
  335. // Given
  336. let monitor = ClosureEventMonitor()
  337. let expectation = self.expectation(description: "Request created")
  338. monitor.requestDidCreateTask = { _, _ in expectation.fulfill() }
  339. var session: Session? = Session(startRequestsImmediately: false, eventMonitors: [monitor])
  340. let url = URL(string: "https://httpbin.org/get")!
  341. let urlRequest = URLRequest(url: url)
  342. // When
  343. let request = session?.request(urlRequest)
  344. session = nil
  345. waitForExpectations(timeout: timeout, handler: nil)
  346. // Then
  347. XCTAssertEqual(request?.task?.state, .suspended)
  348. XCTAssertNil(session, "manager should be nil")
  349. }
  350. func testReleasingManagerWithPendingCanceledRequestDeinitializesSuccessfully() {
  351. // Given
  352. var session: Session? = Session(startRequestsImmediately: false)
  353. let url = URL(string: "https://httpbin.org/get")!
  354. let urlRequest = URLRequest(url: url)
  355. // When
  356. let request = session?.request(urlRequest)
  357. request?.cancel()
  358. session = nil
  359. let state = request?.state
  360. // Then
  361. XCTAssertTrue(state == .cancelled, "state should be .cancelled")
  362. XCTAssertNil(session, "manager should be nil")
  363. }
  364. // MARK: Tests - Bad Requests
  365. func testThatDataRequestWithInvalidURLStringThrowsResponseHandlerError() {
  366. // Given
  367. let session = Session()
  368. let expectation = self.expectation(description: "Request should fail with error")
  369. var response: DataResponse<Data?>?
  370. // When
  371. session.request("https://httpbin.org/get/äëïöü").response { resp in
  372. response = resp
  373. expectation.fulfill()
  374. }
  375. waitForExpectations(timeout: timeout, handler: nil)
  376. // Then
  377. XCTAssertNil(response?.request)
  378. XCTAssertNil(response?.response)
  379. XCTAssertNil(response?.data)
  380. XCTAssertNotNil(response?.error)
  381. if let error = response?.error?.asAFError {
  382. XCTAssertTrue(error.isInvalidURLError)
  383. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  384. } else {
  385. XCTFail("error should not be nil")
  386. }
  387. }
  388. func testThatDownloadRequestWithInvalidURLStringThrowsResponseHandlerError() {
  389. // Given
  390. let session = Session()
  391. let expectation = self.expectation(description: "Download should fail with error")
  392. var response: DownloadResponse<URL?>?
  393. // When
  394. session.download("https://httpbin.org/get/äëïöü").response { resp in
  395. response = resp
  396. expectation.fulfill()
  397. }
  398. waitForExpectations(timeout: timeout, handler: nil)
  399. // Then
  400. XCTAssertNil(response?.request)
  401. XCTAssertNil(response?.response)
  402. XCTAssertNil(response?.fileURL)
  403. XCTAssertNil(response?.resumeData)
  404. XCTAssertNotNil(response?.error)
  405. if let error = response?.error?.asAFError {
  406. XCTAssertTrue(error.isInvalidURLError)
  407. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  408. } else {
  409. XCTFail("error should not be nil")
  410. }
  411. }
  412. func testThatUploadDataRequestWithInvalidURLStringThrowsResponseHandlerError() {
  413. // Given
  414. let session = Session()
  415. let expectation = self.expectation(description: "Upload should fail with error")
  416. var response: DataResponse<Data?>?
  417. // When
  418. session.upload(Data(), to: "https://httpbin.org/get/äëïöü").response { resp in
  419. response = resp
  420. expectation.fulfill()
  421. }
  422. waitForExpectations(timeout: timeout, handler: nil)
  423. // Then
  424. XCTAssertNil(response?.request)
  425. XCTAssertNil(response?.response)
  426. XCTAssertNil(response?.data)
  427. XCTAssertNotNil(response?.error)
  428. if let error = response?.error?.asAFError {
  429. XCTAssertTrue(error.isInvalidURLError)
  430. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  431. } else {
  432. XCTFail("error should not be nil")
  433. }
  434. }
  435. func testThatUploadFileRequestWithInvalidURLStringThrowsResponseHandlerError() {
  436. // Given
  437. let session = Session()
  438. let expectation = self.expectation(description: "Upload should fail with error")
  439. var response: DataResponse<Data?>?
  440. // When
  441. session.upload(URL(fileURLWithPath: "/invalid"), to: "https://httpbin.org/get/äëïöü").response { resp in
  442. response = resp
  443. expectation.fulfill()
  444. }
  445. waitForExpectations(timeout: timeout, handler: nil)
  446. // Then
  447. XCTAssertNil(response?.request)
  448. XCTAssertNil(response?.response)
  449. XCTAssertNil(response?.data)
  450. XCTAssertNotNil(response?.error)
  451. if let error = response?.error?.asAFError {
  452. XCTAssertTrue(error.isInvalidURLError)
  453. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  454. } else {
  455. XCTFail("error should not be nil")
  456. }
  457. }
  458. func testThatUploadStreamRequestWithInvalidURLStringThrowsResponseHandlerError() {
  459. // Given
  460. let session = Session()
  461. let expectation = self.expectation(description: "Upload should fail with error")
  462. var response: DataResponse<Data?>?
  463. // When
  464. session.upload(InputStream(data: Data()), to: "https://httpbin.org/get/äëïöü").response { resp in
  465. response = resp
  466. expectation.fulfill()
  467. }
  468. waitForExpectations(timeout: timeout, handler: nil)
  469. // Then
  470. XCTAssertNil(response?.request)
  471. XCTAssertNil(response?.response)
  472. XCTAssertNil(response?.data)
  473. XCTAssertNotNil(response?.error)
  474. if let error = response?.error?.asAFError {
  475. XCTAssertTrue(error.isInvalidURLError)
  476. XCTAssertEqual(error.urlConvertible as? String, "https://httpbin.org/get/äëïöü")
  477. } else {
  478. XCTFail("error should not be nil")
  479. }
  480. }
  481. // MARK: Tests - Request Adapter
  482. func testThatSessionCallsRequestAdapterWhenCreatingDataRequest() {
  483. // Given
  484. let urlString = "https://httpbin.org/get"
  485. let adapter = HTTPMethodAdapter(method: .post)
  486. let requestHandler = RequestHandler()
  487. let monitor = ClosureEventMonitor()
  488. let session = Session(startRequestsImmediately: false, interceptor: adapter, eventMonitors: [monitor])
  489. // When
  490. let expectation1 = self.expectation(description: "Request 1 created")
  491. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  492. let request1 = session.request(urlString)
  493. waitForExpectations(timeout: timeout, handler: nil)
  494. let expectation2 = self.expectation(description: "Request 2 created")
  495. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  496. let request2 = session.request(urlString, interceptor: requestHandler)
  497. waitForExpectations(timeout: timeout, handler: nil)
  498. // Then
  499. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, adapter.method.rawValue)
  500. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, HTTPMethod.post.rawValue)
  501. XCTAssertEqual(requestHandler.adaptedCount, 1)
  502. }
  503. func testThatSessionCallsRequestAdapterWhenCreatingDownloadRequest() {
  504. // Given
  505. let urlString = "https://httpbin.org/get"
  506. let adapter = HTTPMethodAdapter(method: .post)
  507. let requestHandler = RequestHandler()
  508. let monitor = ClosureEventMonitor()
  509. let session = Session(startRequestsImmediately: false, interceptor: adapter, eventMonitors: [monitor])
  510. // When
  511. let expectation1 = self.expectation(description: "Request 1 created")
  512. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  513. let request1 = session.download(urlString)
  514. waitForExpectations(timeout: timeout, handler: nil)
  515. let expectation2 = self.expectation(description: "Request 2 created")
  516. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  517. let request2 = session.download(urlString, interceptor: requestHandler)
  518. waitForExpectations(timeout: timeout, handler: nil)
  519. // Then
  520. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, adapter.method.rawValue)
  521. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, HTTPMethod.post.rawValue)
  522. XCTAssertEqual(requestHandler.adaptedCount, 1)
  523. }
  524. func testThatSessionCallsRequestAdapterWhenCreatingUploadRequestWithData() {
  525. // Given
  526. let data = Data("data".utf8)
  527. let urlString = "https://httpbin.org/post"
  528. let adapter = HTTPMethodAdapter(method: .get)
  529. let requestHandler = RequestHandler()
  530. let monitor = ClosureEventMonitor()
  531. let session = Session(startRequestsImmediately: false, interceptor: adapter, eventMonitors: [monitor])
  532. // When
  533. let expectation1 = self.expectation(description: "Request 1 created")
  534. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  535. let request1 = session.upload(data, to: urlString)
  536. waitForExpectations(timeout: timeout, handler: nil)
  537. let expectation2 = self.expectation(description: "Request 2 created")
  538. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  539. let request2 = session.upload(data, to: urlString, interceptor: requestHandler)
  540. waitForExpectations(timeout: timeout, handler: nil)
  541. // Then
  542. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, adapter.method.rawValue)
  543. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, HTTPMethod.get.rawValue)
  544. XCTAssertEqual(requestHandler.adaptedCount, 1)
  545. }
  546. func testThatSessionCallsRequestAdapterWhenCreatingUploadRequestWithFile() {
  547. // Given
  548. let fileURL = URL(fileURLWithPath: "/path/to/some/file.txt")
  549. let urlString = "https://httpbin.org/post"
  550. let adapter = HTTPMethodAdapter(method: .get)
  551. let requestHandler = RequestHandler()
  552. let monitor = ClosureEventMonitor()
  553. let session = Session(startRequestsImmediately: false, interceptor: adapter, eventMonitors: [monitor])
  554. // When
  555. let expectation1 = self.expectation(description: "Request 1 created")
  556. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  557. let request1 = session.upload(fileURL, to: urlString)
  558. waitForExpectations(timeout: timeout, handler: nil)
  559. let expectation2 = self.expectation(description: "Request 2 created")
  560. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  561. let request2 = session.upload(fileURL, to: urlString, interceptor: requestHandler)
  562. waitForExpectations(timeout: timeout, handler: nil)
  563. // Then
  564. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, adapter.method.rawValue)
  565. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, HTTPMethod.get.rawValue)
  566. XCTAssertEqual(requestHandler.adaptedCount, 1)
  567. }
  568. func testThatSessionCallsRequestAdapterWhenCreatingUploadRequestWithInputStream() {
  569. // Given
  570. let inputStream = InputStream(data: Data("data".utf8))
  571. let urlString = "https://httpbin.org/post"
  572. let adapter = HTTPMethodAdapter(method: .get)
  573. let requestHandler = RequestHandler()
  574. let monitor = ClosureEventMonitor()
  575. let session = Session(startRequestsImmediately: false, interceptor: adapter, eventMonitors: [monitor])
  576. // When
  577. let expectation1 = self.expectation(description: "Request 1 created")
  578. monitor.requestDidCreateTask = { _, _ in expectation1.fulfill() }
  579. let request1 = session.upload(inputStream, to: urlString)
  580. waitForExpectations(timeout: timeout, handler: nil)
  581. let expectation2 = self.expectation(description: "Request 2 created")
  582. monitor.requestDidCreateTask = { _, _ in expectation2.fulfill() }
  583. let request2 = session.upload(inputStream, to: urlString, interceptor: requestHandler)
  584. waitForExpectations(timeout: timeout, handler: nil)
  585. // Then
  586. XCTAssertEqual(request1.task?.originalRequest?.httpMethod, adapter.method.rawValue)
  587. XCTAssertEqual(request2.task?.originalRequest?.httpMethod, HTTPMethod.get.rawValue)
  588. XCTAssertEqual(requestHandler.adaptedCount, 1)
  589. }
  590. func testThatRequestAdapterErrorThrowsResponseHandlerError() {
  591. // Given
  592. let urlString = "https://httpbin.org/get"
  593. let adapter = HTTPMethodAdapter(method: .post, throwsError: true)
  594. let monitor = ClosureEventMonitor()
  595. let requestHandler = RequestHandler()
  596. requestHandler.throwsErrorOnFirstAdapt = true
  597. requestHandler.shouldRetry = false
  598. let session = Session(startRequestsImmediately: false, interceptor: adapter, eventMonitors: [monitor])
  599. // When
  600. let expectation1 = self.expectation(description: "Request 1 created")
  601. monitor.requestDidFailToAdaptURLRequestWithError = { _, _, _ in expectation1.fulfill() }
  602. let request1 = session.request(urlString)
  603. waitForExpectations(timeout: timeout, handler: nil)
  604. let expectation2 = self.expectation(description: "Request 2 created")
  605. monitor.requestDidFailToAdaptURLRequestWithError = { _, _, _ in expectation2.fulfill() }
  606. let request2 = session.request(urlString, interceptor: requestHandler)
  607. waitForExpectations(timeout: timeout, handler: nil)
  608. let requests = [request1, request2]
  609. // Then
  610. for request in requests {
  611. if let error = request.error?.asAFError {
  612. XCTAssertTrue(error.isRequestAdaptationError)
  613. XCTAssertEqual(error.underlyingError?.asAFError?.urlConvertible as? String, "")
  614. } else {
  615. XCTFail("error should not be nil")
  616. }
  617. }
  618. }
  619. // MARK: Tests - Request Retrier
  620. func testThatSessionCallsRequestRetrierWhenRequestEncountersError() {
  621. // Given
  622. let handler = RequestHandler()
  623. let session = Session()
  624. let expectation = self.expectation(description: "request should eventually fail")
  625. var response: DataResponse<Any>?
  626. // When
  627. let request = session.request("https://httpbin.org/basic-auth/user/password", interceptor: handler)
  628. .validate()
  629. .responseJSON { jsonResponse in
  630. response = jsonResponse
  631. expectation.fulfill()
  632. }
  633. waitForExpectations(timeout: timeout, handler: nil)
  634. // Then
  635. XCTAssertEqual(handler.adaptedCount, 2)
  636. XCTAssertEqual(handler.retryCount, 2)
  637. XCTAssertEqual(request.retryCount, 1)
  638. XCTAssertEqual(response?.result.isSuccess, false)
  639. XCTAssertTrue(session.requestTaskMap.isEmpty)
  640. }
  641. func testThatSessionCallsRequestRetrierWhenRequestInitiallyEncountersAdaptError() {
  642. // Given
  643. let handler = RequestHandler()
  644. handler.adaptedCount = 1
  645. handler.throwsErrorOnSecondAdapt = true
  646. handler.shouldApplyAuthorizationHeader = true
  647. let session = Session()
  648. let expectation = self.expectation(description: "request should eventually fail")
  649. var response: DataResponse<Any>?
  650. // When
  651. session.request("https://httpbin.org/basic-auth/user/password", interceptor: handler)
  652. .validate()
  653. .responseJSON { jsonResponse in
  654. response = jsonResponse
  655. expectation.fulfill()
  656. }
  657. waitForExpectations(timeout: timeout, handler: nil)
  658. // Then
  659. XCTAssertEqual(handler.adaptedCount, 2)
  660. XCTAssertEqual(handler.retryCount, 1)
  661. XCTAssertEqual(response?.result.isSuccess, true)
  662. XCTAssertTrue(session.requestTaskMap.isEmpty)
  663. }
  664. func testThatSessionCallsRequestRetrierWhenDownloadInitiallyEncountersAdaptError() {
  665. // Given
  666. let handler = RequestHandler()
  667. handler.adaptedCount = 1
  668. handler.throwsErrorOnSecondAdapt = true
  669. handler.shouldApplyAuthorizationHeader = true
  670. let session = Session()
  671. let expectation = self.expectation(description: "request should eventually fail")
  672. var response: DownloadResponse<Any>?
  673. let destination: DownloadRequest.Destination = { _, _ in
  674. let fileURL = self.testDirectoryURL.appendingPathComponent("test-output.json")
  675. return (fileURL, [.removePreviousFile])
  676. }
  677. // When
  678. session.download("https://httpbin.org/basic-auth/user/password", interceptor: handler, to: destination)
  679. .validate()
  680. .responseJSON { jsonResponse in
  681. response = jsonResponse
  682. expectation.fulfill()
  683. }
  684. waitForExpectations(timeout: timeout, handler: nil)
  685. // Then
  686. XCTAssertEqual(handler.adaptedCount, 2)
  687. XCTAssertEqual(handler.retryCount, 1)
  688. XCTAssertEqual(response?.result.isSuccess, true)
  689. XCTAssertTrue(session.requestTaskMap.isEmpty)
  690. }
  691. func testThatSessionCallsRequestRetrierWhenUploadInitiallyEncountersAdaptError() {
  692. // Given
  693. let handler = UploadHandler()
  694. let session = Session(interceptor: handler)
  695. let expectation = self.expectation(description: "request should eventually fail")
  696. var response: DataResponse<Any>?
  697. let uploadData = Data("upload data".utf8)
  698. // When
  699. session.upload(uploadData, to: "https://httpbin.org/post")
  700. .validate()
  701. .responseJSON { jsonResponse in
  702. response = jsonResponse
  703. expectation.fulfill()
  704. }
  705. waitForExpectations(timeout: timeout, handler: nil)
  706. // Then
  707. XCTAssertEqual(handler.adaptedCount, 2)
  708. XCTAssertEqual(handler.retryCount, 1)
  709. XCTAssertEqual(response?.result.isSuccess, true)
  710. XCTAssertTrue(session.requestTaskMap.isEmpty)
  711. }
  712. func testThatSessionCallsAdapterWhenRequestIsRetried() {
  713. // Given
  714. let handler = RequestHandler()
  715. handler.shouldApplyAuthorizationHeader = true
  716. let session = Session(interceptor: handler)
  717. let expectation = self.expectation(description: "request should eventually succeed")
  718. var response: DataResponse<Any>?
  719. // When
  720. let request = session.request("https://httpbin.org/basic-auth/user/password")
  721. .validate()
  722. .responseJSON { jsonResponse in
  723. response = jsonResponse
  724. expectation.fulfill()
  725. }
  726. waitForExpectations(timeout: timeout, handler: nil)
  727. // Then
  728. XCTAssertEqual(handler.adaptedCount, 2)
  729. XCTAssertEqual(handler.retryCount, 1)
  730. XCTAssertEqual(request.retryCount, 1)
  731. XCTAssertEqual(response?.result.isSuccess, true)
  732. XCTAssertTrue(session.requestTaskMap.isEmpty)
  733. }
  734. func testThatRequestAdapterErrorThrowsResponseHandlerErrorWhenRequestIsRetried() {
  735. // Given
  736. let handler = RequestHandler()
  737. handler.throwsErrorOnSecondAdapt = true
  738. let session = Session(interceptor: handler)
  739. let expectation = self.expectation(description: "request should eventually fail")
  740. var response: DataResponse<Any>?
  741. // When
  742. let request = session.request("https://httpbin.org/basic-auth/user/password")
  743. .validate()
  744. .responseJSON { jsonResponse in
  745. response = jsonResponse
  746. expectation.fulfill()
  747. }
  748. waitForExpectations(timeout: timeout, handler: nil)
  749. // Then
  750. XCTAssertEqual(handler.adaptedCount, 1)
  751. XCTAssertEqual(handler.retryCount, 2)
  752. XCTAssertEqual(request.retryCount, 1)
  753. XCTAssertEqual(response?.result.isSuccess, false)
  754. XCTAssertTrue(session.requestTaskMap.isEmpty)
  755. if let error = response?.result.error?.asAFError {
  756. XCTAssertTrue(error.isRequestAdaptationError)
  757. XCTAssertEqual(error.underlyingError?.asAFError?.urlConvertible as? String, "")
  758. } else {
  759. XCTFail("error should not be nil")
  760. }
  761. }
  762. }
  763. // MARK: -
  764. class SessionManagerConfigurationHeadersTestCase: BaseTestCase {
  765. enum ConfigurationType {
  766. case `default`, ephemeral, background
  767. }
  768. func testThatDefaultConfigurationHeadersAreSentWithRequest() {
  769. // Given, When, Then
  770. executeAuthorizationHeaderTest(for: .default)
  771. }
  772. func testThatEphemeralConfigurationHeadersAreSentWithRequest() {
  773. // Given, When, Then
  774. executeAuthorizationHeaderTest(for: .ephemeral)
  775. }
  776. #if os(macOS)
  777. func testThatBackgroundConfigurationHeadersAreSentWithRequest() {
  778. // Given, When, Then
  779. executeAuthorizationHeaderTest(for: .background)
  780. }
  781. #endif
  782. private func executeAuthorizationHeaderTest(for type: ConfigurationType) {
  783. // Given
  784. let session: Session = {
  785. let configuration: URLSessionConfiguration = {
  786. let configuration: URLSessionConfiguration
  787. switch type {
  788. case .default:
  789. configuration = .default
  790. case .ephemeral:
  791. configuration = .ephemeral
  792. case .background:
  793. let identifier = "org.alamofire.test.manager-configuration-tests"
  794. configuration = .background(withIdentifier: identifier)
  795. }
  796. var headers = HTTPHeaders.default
  797. headers["Authorization"] = "Bearer 123456"
  798. configuration.httpHeaders = headers
  799. return configuration
  800. }()
  801. return Session(configuration: configuration)
  802. }()
  803. let expectation = self.expectation(description: "request should complete successfully")
  804. var response: DataResponse<Any>?
  805. // When
  806. session.request("https://httpbin.org/headers")
  807. .responseJSON { closureResponse in
  808. response = closureResponse
  809. expectation.fulfill()
  810. }
  811. waitForExpectations(timeout: timeout, handler: nil)
  812. // Then
  813. if let response = response {
  814. XCTAssertNotNil(response.request, "request should not be nil")
  815. XCTAssertNotNil(response.response, "response should not be nil")
  816. XCTAssertNotNil(response.data, "data should not be nil")
  817. XCTAssertTrue(response.result.isSuccess, "result should be a success")
  818. if
  819. let response = response.result.value as? [String: Any],
  820. let headers = response["headers"] as? [String: String],
  821. let authorization = headers["Authorization"]
  822. {
  823. XCTAssertEqual(authorization, "Bearer 123456", "authorization header value does not match")
  824. } else {
  825. XCTFail("failed to extract authorization header value")
  826. }
  827. } else {
  828. XCTFail("response should not be nil")
  829. }
  830. }
  831. }