SessionTests.swift 34 KB

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