SessionManagerTests.swift 34 KB

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