ConcurrencyTests.swift 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845
  1. //
  2. // ConcurrencyTests.swift
  3. //
  4. // Copyright (c) 2021 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. #if canImport(_Concurrency)
  25. import Alamofire
  26. import XCTest
  27. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  28. final class DataRequestConcurrencyTests: BaseTestCase {
  29. func testThatDataTaskSerializesResponseUsingSerializer() async throws {
  30. // Given
  31. let session = stored(Session())
  32. // When
  33. let value = try await session.request(.get)
  34. .serializingResponse(using: .data)
  35. .value
  36. // Then
  37. XCTAssertNotNil(value)
  38. }
  39. func testThat500ResponseCanBeRetried() async throws {
  40. // Given
  41. let session = stored(Session())
  42. // When
  43. let value = try await session.request(.endpoints(.status(500), .method(.get)), interceptor: .retryPolicy)
  44. .serializingResponse(using: .data)
  45. .value
  46. // Then
  47. XCTAssertNotNil(value)
  48. }
  49. func testThatDataTaskSerializesDecodable() async throws {
  50. // Given
  51. let session = stored(Session())
  52. // When
  53. let value = try await session.request(.get).serializingDecodable(TestResponse.self).value
  54. // Then
  55. XCTAssertNotNil(value)
  56. }
  57. func testThatDataTaskSerializesString() async throws {
  58. // Given
  59. let session = stored(Session())
  60. // When
  61. let value = try await session.request(.get).serializingString().value
  62. // Then
  63. XCTAssertNotNil(value)
  64. }
  65. func testThatDataTaskSerializesData() async throws {
  66. // Given
  67. let session = stored(Session())
  68. // When
  69. let value = try await session.request(.get).serializingData().value
  70. // Then
  71. XCTAssertNotNil(value)
  72. }
  73. func testThatDataTaskProducesResult() async {
  74. // Given
  75. let session = stored(Session())
  76. // When
  77. let result = await session.request(.get).serializingDecodable(TestResponse.self).result
  78. // Then
  79. XCTAssertNotNil(result.success)
  80. }
  81. func testThatDataTaskProducesValue() async throws {
  82. // Given
  83. let session = stored(Session())
  84. // When
  85. let value = try await session.request(.get).serializingDecodable(TestResponse.self).value
  86. // Then
  87. XCTAssertNotNil(value)
  88. }
  89. func testThatDataTaskProperlySupportsConcurrentRequests() async {
  90. // Given
  91. let session = stored(Session())
  92. // When
  93. async let first = session.request(.get).serializingDecodable(TestResponse.self).response
  94. async let second = session.request(.get).serializingDecodable(TestResponse.self).response
  95. async let third = session.request(.get).serializingDecodable(TestResponse.self).response
  96. // Then
  97. let responses = await [first, second, third]
  98. XCTAssertEqual(responses.count, 3)
  99. XCTAssertTrue(responses.allSatisfy(\.result.isSuccess))
  100. }
  101. func testThatDataTaskCancellationCancelsRequest() async {
  102. // Given
  103. let session = stored(Session())
  104. let request = session.request(.get)
  105. let task = request.serializingDecodable(TestResponse.self)
  106. // When
  107. task.cancel()
  108. let response = await task.response
  109. // Then
  110. XCTAssertTrue(response.error?.isExplicitlyCancelledError == true)
  111. XCTAssertTrue(request.isCancelled, "Underlying DataRequest should be cancelled.")
  112. }
  113. func testThatDataTaskIsAutomaticallyCancelledInTask() async {
  114. // Given
  115. let session = stored(Session())
  116. let request = session.request(.get)
  117. // When
  118. let task = Task {
  119. await request.serializingDecodable(TestResponse.self).result
  120. }
  121. task.cancel()
  122. let result = await task.value
  123. // Then
  124. XCTAssertTrue(result.failure?.isExplicitlyCancelledError == true)
  125. XCTAssertTrue(task.isCancelled, "Task should be cancelled.")
  126. XCTAssertTrue(request.isCancelled, "Underlying DataRequest should be cancelled.")
  127. }
  128. func testThatDataTaskIsNotAutomaticallyCancelledInTaskWhenDisabled() async {
  129. // Given
  130. let session = stored(Session())
  131. let request = session.request(.get)
  132. // When
  133. let task = Task {
  134. await request.serializingDecodable(TestResponse.self, automaticallyCancelling: false).result
  135. }
  136. task.cancel()
  137. let result = await task.value
  138. // Then
  139. XCTAssertTrue(task.isCancelled, "Task should be cancelled.")
  140. XCTAssertFalse(request.isCancelled, "Underlying DataRequest should not be cancelled.")
  141. XCTAssertTrue(result.isSuccess, "DataRequest should succeed.")
  142. }
  143. func testThatDataTaskIsAutomaticallyCancelledInTaskGroup() async {
  144. // Given
  145. let session = stored(Session())
  146. let request = session.request(.get)
  147. // When
  148. let task = Task {
  149. await withTaskGroup(of: Result<TestResponse, AFError>.self) { group -> Result<TestResponse, AFError> in
  150. group.addTask {
  151. await request.serializingDecodable(TestResponse.self).result
  152. }
  153. return await group.first(where: { _ in true })!
  154. }
  155. }
  156. task.cancel()
  157. let result = await task.value
  158. // Then
  159. XCTAssertTrue(result.failure?.isExplicitlyCancelledError == true)
  160. XCTAssertTrue(task.isCancelled, "Task should be cancelled.")
  161. XCTAssertTrue(request.isCancelled, "Underlying DataRequest should be cancelled.")
  162. }
  163. func testThatDataTaskIsNotAutomaticallyCancelledInTaskGroupWhenDisabled() async {
  164. // Given
  165. let session = stored(Session())
  166. let request = session.request(.get)
  167. // When
  168. let task = Task {
  169. await withTaskGroup(of: Result<TestResponse, AFError>.self) { group -> Result<TestResponse, AFError> in
  170. group.addTask {
  171. await request.serializingDecodable(TestResponse.self, automaticallyCancelling: false).result
  172. }
  173. return await group.first(where: { _ in true })!
  174. }
  175. }
  176. task.cancel()
  177. let result = await task.value
  178. // Then
  179. XCTAssertTrue(task.isCancelled, "Task should be cancelled.")
  180. XCTAssertFalse(request.isCancelled, "Underlying DataRequest should not be cancelled.")
  181. XCTAssertTrue(result.isSuccess, "DataRequest should succeed.")
  182. }
  183. }
  184. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  185. final class DownloadConcurrencyTests: BaseTestCase {
  186. func testThatDownloadTaskSerializesResponseFromSerializer() async throws {
  187. // Given
  188. let session = stored(Session())
  189. // When
  190. let value = try await session.download(.get)
  191. .serializingDownload(using: .data)
  192. .value
  193. // Then
  194. XCTAssertNotNil(value)
  195. }
  196. func testThatDownloadTaskSerializesDecodable() async throws {
  197. // Given
  198. let session = stored(Session())
  199. // When
  200. let value = try await session.download(.get).serializingDecodable(TestResponse.self).value
  201. // Then
  202. XCTAssertNotNil(value)
  203. }
  204. func testThatDownloadTaskSerializesString() async throws {
  205. // Given
  206. let session = stored(Session())
  207. // When
  208. let value = try await session.download(.get).serializingString().value
  209. // Then
  210. XCTAssertNotNil(value)
  211. }
  212. func testThatDownloadTaskSerializesData() async throws {
  213. // Given
  214. let session = stored(Session())
  215. // When
  216. let value = try await session.download(.get).serializingData().value
  217. // Then
  218. XCTAssertNotNil(value)
  219. }
  220. func testThatDownloadTaskSerializesURL() async throws {
  221. // Given
  222. let session = stored(Session())
  223. // When
  224. let value = try await session.download(.get).serializingDownloadedFileURL().value
  225. // Then
  226. XCTAssertNotNil(value)
  227. }
  228. func testThatDownloadTaskProducesResult() async {
  229. // Given
  230. let session = stored(Session())
  231. // When
  232. let result = await session.download(.get).serializingDecodable(TestResponse.self).result
  233. // Then
  234. XCTAssertNotNil(result.success)
  235. }
  236. func testThatDownloadTaskProducesValue() async throws {
  237. // Given
  238. let session = stored(Session())
  239. // When
  240. let value = try await session.download(.get).serializingDecodable(TestResponse.self).value
  241. // Then
  242. XCTAssertNotNil(value)
  243. }
  244. func testThatDownloadTaskProperlySupportsConcurrentRequests() async {
  245. // Given
  246. let session = stored(Session())
  247. // When
  248. async let first = session.download(.get).serializingDecodable(TestResponse.self).response
  249. async let second = session.download(.get).serializingDecodable(TestResponse.self).response
  250. async let third = session.download(.get).serializingDecodable(TestResponse.self).response
  251. // Then
  252. let responses = await [first, second, third]
  253. XCTAssertEqual(responses.count, 3)
  254. XCTAssertTrue(responses.allSatisfy(\.result.isSuccess))
  255. }
  256. func testThatDownloadTaskCancelsRequest() async {
  257. // Given
  258. let session = stored(Session())
  259. let request = session.download(.get)
  260. let task = request.serializingDecodable(TestResponse.self)
  261. // When
  262. task.cancel()
  263. let response = await task.response
  264. // Then
  265. XCTAssertTrue(response.error?.isExplicitlyCancelledError == true)
  266. }
  267. func testThatDownloadTaskIsAutomaticallyCancelledInTask() async {
  268. // Given
  269. let session = stored(Session())
  270. let request = session.download(.get)
  271. // When
  272. let task = Task {
  273. await request.serializingDecodable(TestResponse.self).result
  274. }
  275. task.cancel()
  276. let result = await task.value
  277. // Then
  278. XCTAssertTrue(result.failure?.isExplicitlyCancelledError == true)
  279. XCTAssertTrue(task.isCancelled, "Task should be cancelled.")
  280. XCTAssertTrue(request.isCancelled, "Underlying DownloadRequest should be cancelled.")
  281. }
  282. func testThatDownloadTaskIsNotAutomaticallyCancelledInTaskWhenDisabled() async {
  283. // Given
  284. let session = stored(Session())
  285. let request = session.download(.get)
  286. // When
  287. let task = Task {
  288. await request.serializingDecodable(TestResponse.self, automaticallyCancelling: false).result
  289. }
  290. task.cancel()
  291. let result = await task.value
  292. // Then
  293. XCTAssertTrue(task.isCancelled, "Task should be cancelled.")
  294. XCTAssertFalse(request.isCancelled, "Underlying DownloadRequest should not be cancelled.")
  295. XCTAssertTrue(result.isSuccess, "DownloadRequest should succeed.")
  296. }
  297. func testThatDownloadTaskIsAutomaticallyCancelledInTaskGroup() async {
  298. // Given
  299. let session = stored(Session())
  300. let request = session.download(.get)
  301. // When
  302. let task = Task {
  303. await withTaskGroup(of: Result<TestResponse, AFError>.self) { group -> Result<TestResponse, AFError> in
  304. group.addTask {
  305. await request.serializingDecodable(TestResponse.self).result
  306. }
  307. return await group.first(where: { _ in true })!
  308. }
  309. }
  310. task.cancel()
  311. let result = await task.value
  312. // Then
  313. XCTAssertTrue(result.failure?.isExplicitlyCancelledError == true)
  314. XCTAssertTrue(task.isCancelled, "Task should be cancelled.")
  315. XCTAssertTrue(request.isCancelled, "Underlying DownloadRequest should be cancelled.")
  316. }
  317. func testThatDownloadTaskIsNotAutomaticallyCancelledInTaskGroupWhenDisabled() async {
  318. // Given
  319. let session = stored(Session())
  320. let request = session.download(.get)
  321. // When
  322. let task = Task {
  323. await withTaskGroup(of: Result<TestResponse, AFError>.self) { group -> Result<TestResponse, AFError> in
  324. group.addTask {
  325. await request.serializingDecodable(TestResponse.self, automaticallyCancelling: false).result
  326. }
  327. return await group.first(where: { _ in true })!
  328. }
  329. }
  330. task.cancel()
  331. let result = await task.value
  332. // Then
  333. XCTAssertTrue(task.isCancelled, "Task should be cancelled.")
  334. XCTAssertFalse(request.isCancelled, "Underlying DownloadRequest should not be cancelled.")
  335. XCTAssertTrue(result.isSuccess, "DownloadRequest should succeed.")
  336. }
  337. }
  338. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  339. final class DataStreamConcurrencyTests: BaseTestCase {
  340. func testThatDataStreamTaskCanStreamData() async {
  341. // Given
  342. let session = stored(Session())
  343. // When
  344. let task = session.streamRequest(.payloads(2)).streamTask()
  345. var datas: [Data] = []
  346. for await data in task.streamingData().compactMap(\.value) {
  347. datas.append(data)
  348. }
  349. // Then
  350. XCTAssertEqual(datas.count, 2)
  351. }
  352. #if canImport(Darwin)
  353. func testThatDataStreamHasAsyncOnHTTPResponse() async {
  354. // Given
  355. let session = stored(Session())
  356. let functionCalled = expectation(description: "doNothing called")
  357. @Sendable @MainActor func fulfill() async {
  358. functionCalled.fulfill()
  359. }
  360. // When
  361. let task = session.streamRequest(.payloads(2))
  362. .onHTTPResponse { _ in
  363. await fulfill()
  364. }
  365. .streamTask()
  366. var datas: [Data] = []
  367. for await data in task.streamingData().compactMap(\.value) {
  368. datas.append(data)
  369. }
  370. await fulfillment(of: [functionCalled], timeout: timeout)
  371. // Then
  372. XCTAssertEqual(datas.count, 2)
  373. }
  374. func testThatDataOnHTTPResponseCanAllow() async {
  375. // Given
  376. let session = stored(Session())
  377. let functionCalled = expectation(description: "doNothing called")
  378. @Sendable @MainActor func fulfill() async {
  379. functionCalled.fulfill()
  380. }
  381. // When
  382. let task = session.streamRequest(.payloads(2))
  383. .onHTTPResponse { _ in
  384. await fulfill()
  385. return .allow
  386. }
  387. .streamTask()
  388. var datas: [Data] = []
  389. for await data in task.streamingData().compactMap(\.value) {
  390. datas.append(data)
  391. }
  392. await fulfillment(of: [functionCalled], timeout: timeout)
  393. // Then
  394. XCTAssertEqual(datas.count, 2)
  395. }
  396. func testThatDataOnHTTPResponseCanCancel() async {
  397. // Given
  398. let session = stored(Session())
  399. var receivedCompletion: DataStreamRequest.Completion?
  400. let functionCalled = expectation(description: "doNothing called")
  401. @Sendable @MainActor func fulfill() async {
  402. functionCalled.fulfill()
  403. }
  404. // When
  405. let request = session.streamRequest(.payloads(2))
  406. .onHTTPResponse { _ in
  407. await fulfill()
  408. return .cancel
  409. }
  410. let task = request.streamTask()
  411. for await stream in task.streamingResponses(serializedUsing: .passthrough) {
  412. switch stream.event {
  413. case .stream:
  414. XCTFail("cancelled stream should receive no data")
  415. case let .complete(completion):
  416. receivedCompletion = completion
  417. }
  418. }
  419. await fulfillment(of: [functionCalled], timeout: timeout)
  420. // Then
  421. XCTAssertEqual(receivedCompletion?.response?.statusCode, 200)
  422. XCTAssertTrue(request.isCancelled, "onHTTPResponse cancelled request isCancelled should be true")
  423. XCTAssertTrue(request.error?.isExplicitlyCancelledError == true, "onHTTPResponse cancelled request error should be explicitly cancelled")
  424. }
  425. #endif
  426. func testThatDataStreamTaskCanStreamStrings() async {
  427. // Given
  428. let session = stored(Session())
  429. // When
  430. let task = session.streamRequest(.payloads(2)).streamTask()
  431. var strings: [String] = []
  432. for await string in task.streamingStrings().compactMap(\.value) {
  433. strings.append(string)
  434. }
  435. // Then
  436. XCTAssertEqual(strings.count, 2)
  437. }
  438. func testThatDataStreamTaskCanStreamDecodable() async {
  439. // Given
  440. let session = stored(Session())
  441. // When
  442. let task = session.streamRequest(.payloads(2)).streamTask()
  443. let stream = task.streamingResponses(serializedUsing: DecodableStreamSerializer<TestResponse>())
  444. var responses: [TestResponse] = []
  445. for await response in stream.compactMap(\.value) {
  446. responses.append(response)
  447. }
  448. // Then
  449. XCTAssertEqual(responses.count, 2)
  450. }
  451. func testThatDataStreamTaskCanBeDirectlyCancelled() async {
  452. // Given
  453. let session = stored(Session())
  454. // When
  455. let expectedPayloads = 10
  456. let request = session.streamRequest(.payloads(expectedPayloads))
  457. let task = request.streamTask()
  458. var datas: [Data] = []
  459. for await data in task.streamingData().compactMap(\.value) {
  460. datas.append(data)
  461. if datas.count == 1 {
  462. task.cancel()
  463. }
  464. }
  465. // Then
  466. XCTAssertTrue(request.isCancelled)
  467. XCTAssertTrue(datas.count == 1)
  468. }
  469. func testThatDataStreamTaskIsCancelledByCancellingIteration() async {
  470. // Given
  471. let session = stored(Session())
  472. // When
  473. let expectedPayloads = 10
  474. let request = session.streamRequest(.payloads(expectedPayloads))
  475. let task = request.streamTask()
  476. var datas: [Data] = []
  477. for await data in task.streamingData().compactMap(\.value) {
  478. datas.append(data)
  479. if datas.count == 1 {
  480. break
  481. }
  482. }
  483. // Then
  484. XCTAssertTrue(request.isCancelled)
  485. XCTAssertTrue(datas.count == 1)
  486. }
  487. func testThatDataStreamTaskCanBeImplicitlyCancelled() async {
  488. // Given
  489. let session = stored(Session())
  490. // When
  491. let expectedPayloads = 10
  492. let request = session.streamRequest(.payloads(expectedPayloads))
  493. let task = Task<[Data], Never> {
  494. var datas: [Data] = []
  495. for await data in request.streamTask().streamingData().compactMap(\.value) {
  496. datas.append(data)
  497. }
  498. return datas
  499. }
  500. task.cancel()
  501. let datas: [Data] = await task.value
  502. // Then
  503. XCTAssertTrue(request.isCancelled)
  504. XCTAssertTrue(datas.isEmpty)
  505. }
  506. func testThatDataStreamTaskCanBeCancelledAfterStreamTurnsOffAutomaticCancellation() async {
  507. // Given
  508. let session = stored(Session())
  509. // When
  510. let expectedPayloads = 10
  511. let request = session.streamRequest(.payloads(expectedPayloads))
  512. let task = Task<[Data], Never> {
  513. var datas: [Data] = []
  514. let streamTask = request.streamTask()
  515. for await data in streamTask.streamingData(automaticallyCancelling: false).compactMap(\.value) {
  516. datas.append(data)
  517. break
  518. }
  519. for await data in streamTask.streamingData().compactMap(\.value) {
  520. datas.append(data)
  521. break
  522. }
  523. return datas
  524. }
  525. let datas: [Data] = await task.value
  526. // Then
  527. XCTAssertTrue(request.isCancelled)
  528. XCTAssertTrue(datas.count == 2)
  529. }
  530. }
  531. // Avoid when using swift-corelibs-foundation.
  532. // Only Xcode 14.3+ has async fulfillment.
  533. #if !canImport(FoundationNetworking)
  534. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  535. final class UploadConcurrencyTests: BaseTestCase {
  536. func testThatDelayedUploadStreamResultsInMultipleProgressValues() async throws {
  537. // Given
  538. let count = 75
  539. let baseString = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
  540. let baseData = Data(baseString.utf8)
  541. var request = Endpoint.upload.urlRequest
  542. request.headers.add(name: "Content-Length", value: "\(baseData.count * count)")
  543. let expectation = expectation(description: "Bytes upload progress should be reported: \(request.url!)")
  544. var uploadProgressValues: [Double] = []
  545. var downloadProgressValues: [Double] = []
  546. var response: DataResponse<UploadResponse, AFError>?
  547. var inputStream: InputStream!
  548. var outputStream: OutputStream!
  549. Stream.getBoundStreams(withBufferSize: baseData.count, inputStream: &inputStream, outputStream: &outputStream)
  550. CFWriteStreamSetDispatchQueue(outputStream, .main)
  551. outputStream.open()
  552. // When
  553. AF.upload(inputStream, with: request)
  554. .uploadProgress { progress in
  555. uploadProgressValues.append(progress.fractionCompleted)
  556. }
  557. .downloadProgress { progress in
  558. downloadProgressValues.append(progress.fractionCompleted)
  559. }
  560. .responseDecodable(of: UploadResponse.self) { resp in
  561. response = resp
  562. expectation.fulfill()
  563. inputStream.close()
  564. }
  565. func sendData() {
  566. baseData.withUnsafeBytes { (pointer: UnsafeRawBufferPointer) in
  567. let bytesStreamed = outputStream.write(pointer.baseAddress!, maxLength: baseData.count)
  568. switch bytesStreamed {
  569. case baseData.count:
  570. // Successfully sent.
  571. break
  572. case 0:
  573. XCTFail("outputStream somehow reached end")
  574. case -1:
  575. if let streamError = outputStream.streamError {
  576. XCTFail("outputStream.write failed with error: \(streamError)")
  577. } else {
  578. XCTFail("outputStream.write failed with unknown error")
  579. }
  580. default:
  581. XCTFail("outputStream failed to send \(baseData.count) bytes, sent \(bytesStreamed) instead.")
  582. }
  583. }
  584. }
  585. for _ in 0..<count {
  586. sendData()
  587. try await Task.sleep(nanoseconds: 3 * 1_000_000) // milliseconds
  588. }
  589. outputStream.close()
  590. await fulfillment(of: [expectation], timeout: timeout)
  591. // Then
  592. XCTAssertNotNil(response?.request)
  593. XCTAssertNotNil(response?.response)
  594. XCTAssertNotNil(response?.data)
  595. XCTAssertNil(response?.error)
  596. for (progress, nextProgress) in zip(uploadProgressValues, uploadProgressValues.dropFirst()) {
  597. XCTAssertGreaterThanOrEqual(nextProgress, progress)
  598. }
  599. XCTAssertGreaterThan(uploadProgressValues.count, 1, "there should more than 1 uploadProgressValues")
  600. for (progress, nextProgress) in zip(downloadProgressValues, downloadProgressValues.dropFirst()) {
  601. XCTAssertGreaterThanOrEqual(nextProgress, progress)
  602. }
  603. XCTAssertEqual(downloadProgressValues.last, 1.0, "last item in downloadProgressValues should equal 1.0")
  604. XCTAssertEqual(response?.value?.bytes, baseData.count * count)
  605. }
  606. }
  607. #endif
  608. #if canImport(Darwin) && !canImport(FoundationNetworking)
  609. @_spi(WebSocket) import Alamofire
  610. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  611. final class WebSocketConcurrencyTests: BaseTestCase {
  612. func testThatMessageEventsCanBeStreamed() async throws {
  613. // Given
  614. let session = stored(Session())
  615. let receivedEvent = expectation(description: "receivedEvent")
  616. receivedEvent.expectedFulfillmentCount = 4
  617. // When
  618. for await _ in session.webSocketRequest(.websocket()).webSocketTask().streamingMessageEvents() {
  619. receivedEvent.fulfill()
  620. }
  621. await fulfillment(of: [receivedEvent])
  622. // Then
  623. }
  624. func testThatMessagesCanBeStreamed() async throws {
  625. // Given
  626. let session = stored(Session())
  627. // When
  628. let messages = await session.webSocketRequest(.websocket()).webSocketTask().streamingMessages().collect()
  629. // Then
  630. XCTAssertTrue(messages.count == 1)
  631. }
  632. }
  633. #endif
  634. // @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  635. // final class ClosureAPIConcurrencyTests: BaseTestCase {
  636. // func testThatDownloadProgressStreamReturnsProgress() async {
  637. // // Given
  638. // let session = stored(Session())
  639. //
  640. // // When
  641. // let request = session.request(.get)
  642. // async let httpResponses = request.httpResponses().collect()
  643. // async let uploadProgress = request.uploadProgress().collect()
  644. // async let downloadProgress = request.downloadProgress().collect()
  645. // async let requests = request.urlRequests().collect()
  646. // async let tasks = request.urlSessionTasks().collect()
  647. // async let descriptions = request.cURLDescriptions().collect()
  648. // async let response = request.serializingDecodable(TestResponse.self).response
  649. //
  650. // let values: (httpResponses: [HTTPURLResponse],
  651. // uploadProgresses: [Progress],
  652. // downloadProgresses: [Progress],
  653. // requests: [URLRequest],
  654. // tasks: [URLSessionTask],
  655. // descriptions: [String],
  656. // response: AFDataResponse<TestResponse>)
  657. // values = await (httpResponses, uploadProgress, downloadProgress, requests, tasks, descriptions, response)
  658. //
  659. // // Then
  660. // XCTAssertTrue(values.httpResponses.count == 1, "httpResponses should have one response")
  661. // XCTAssertTrue(values.uploadProgresses.isEmpty, "uploadProgresses should be empty")
  662. // XCTAssertNotNil(values.downloadProgresses.last, "downloadProgresses should not be empty")
  663. // XCTAssertTrue(values.downloadProgresses.last?.isFinished == true, "last download progression should be finished")
  664. // XCTAssertNotNil(values.requests.last, "requests should not be empty")
  665. // XCTAssertNotNil(values.tasks.last, "tasks should not be empty")
  666. // XCTAssertNotNil(values.descriptions.last, "descriptions should not be empty")
  667. // XCTAssertTrue(values.response.result.isSuccess, "request should succeed")
  668. // }
  669. // }
  670. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  671. extension AsyncSequence {
  672. func collect() async rethrows -> [Element] {
  673. var elements: [Element] = []
  674. for try await element in self {
  675. elements.append(element)
  676. }
  677. return elements
  678. }
  679. }
  680. #endif