ConcurrencyTests.swift 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849
  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 swift(>=5.8) && 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) && swift(>=5.8)
  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) && swift(>=5.8)
  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. // When
  640. let request = session.request(.get)
  641. async let httpResponses = request.httpResponses().collect()
  642. async let uploadProgress = request.uploadProgress().collect()
  643. async let downloadProgress = request.downloadProgress().collect()
  644. async let requests = request.urlRequests().collect()
  645. async let tasks = request.urlSessionTasks().collect()
  646. async let descriptions = request.cURLDescriptions().collect()
  647. async let response = request.serializingDecodable(TestResponse.self).response
  648. let values: (httpResponses: [HTTPURLResponse],
  649. uploadProgresses: [Progress],
  650. downloadProgresses: [Progress],
  651. requests: [URLRequest],
  652. tasks: [URLSessionTask],
  653. descriptions: [String],
  654. response: AFDataResponse<TestResponse>)
  655. #if swift(>=5.11)
  656. values = try! await (httpResponses, uploadProgress, downloadProgress, requests, tasks, descriptions, response)
  657. #else
  658. values = await (httpResponses, uploadProgress, downloadProgress, requests, tasks, descriptions, response)
  659. #endif
  660. // Then
  661. XCTAssertTrue(values.httpResponses.count == 1, "httpResponses should have one response")
  662. XCTAssertTrue(values.uploadProgresses.isEmpty, "uploadProgresses should be empty")
  663. XCTAssertNotNil(values.downloadProgresses.last, "downloadProgresses should not be empty")
  664. XCTAssertTrue(values.downloadProgresses.last?.isFinished == true, "last download progression should be finished")
  665. XCTAssertNotNil(values.requests.last, "requests should not be empty")
  666. XCTAssertNotNil(values.tasks.last, "tasks should not be empty")
  667. XCTAssertNotNil(values.descriptions.last, "descriptions should not be empty")
  668. XCTAssertTrue(values.response.result.isSuccess, "request should succeed")
  669. }
  670. }
  671. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  672. extension AsyncSequence {
  673. func collect() async rethrows -> [Element] {
  674. var elements: [Element] = []
  675. for try await element in self {
  676. elements.append(element)
  677. }
  678. return elements
  679. }
  680. }
  681. #endif