SessionManagerTests.swift 35 KB

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