InteroperabilityTestCases.swift 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. /*
  2. * Copyright 2019, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import Foundation
  17. import SwiftGRPCNIO
  18. import NIOHTTP1
  19. /// Missing tests:
  20. /// - client_compressed_unary
  21. /// - server_compressed_unary
  22. /// - client_compressed_streaming
  23. /// - server_compressed_streaming
  24. /// - compute_engine_creds
  25. /// - jwt_token_creds
  26. /// - oauth2_auth_token
  27. /// - per_rpc_creds
  28. /// - google_default_credentials
  29. /// - compute_engine_channel_credentials
  30. /// This test verifies that implementations support zero-size messages. Ideally, client
  31. /// implementations would verify that the request and response were zero bytes serialized, but
  32. /// this is generally prohibitive to perform, so is not required.
  33. ///
  34. /// Server features:
  35. /// - EmptyCall
  36. ///
  37. /// Procedure:
  38. /// 1. Client calls EmptyCall with the default Empty message
  39. ///
  40. /// Client asserts:
  41. /// - call was successful
  42. /// - response is non-null
  43. class EmptyUnary: InteroperabilityTest {
  44. func run(using connection: GRPCClientConnection) throws {
  45. let client = Grpc_Testing_TestServiceService_NIOClient(connection: connection)
  46. let call = client.emptyCall(Grpc_Testing_Empty())
  47. try waitAndAssertEqual(call.response, Grpc_Testing_Empty())
  48. try waitAndAssertEqual(call.status.map { $0.code }, .ok)
  49. }
  50. }
  51. /// This test verifies that gRPC requests marked as cacheable use GET verb instead of POST, and
  52. /// that server sets appropriate cache control headers for the response to be cached by a proxy.
  53. /// This test requires that the server is behind a caching proxy. Use of current timestamp in the
  54. /// request prevents accidental cache matches left over from previous tests.
  55. ///
  56. /// Server features:
  57. /// - CacheableUnaryCall
  58. ///
  59. /// Procedure:
  60. /// 1. Client calls CacheableUnaryCall with SimpleRequest request with payload set to current
  61. /// timestamp. Timestamp format is irrelevant, and resolution is in nanoseconds. Client adds a
  62. /// x-user-ip header with value 1.2.3.4 to the request. This is done since some proxys such as
  63. /// GFE will not cache requests from localhost. Client marks the request as cacheable by
  64. /// setting the cacheable flag in the request context. Longer term this should be driven by
  65. /// the method option specified in the proto file itself.
  66. /// 2. Client calls CacheableUnaryCall again immediately with the same request and configuration
  67. /// as the previous call.
  68. ///
  69. /// Client asserts:
  70. /// - Both calls were successful
  71. /// - The payload body of both responses is the same.
  72. class CacheableUnary: InteroperabilityTest {
  73. func run(using connection: GRPCClientConnection) throws {
  74. let client = Grpc_Testing_TestServiceService_NIOClient(connection: connection)
  75. var timestamp = DispatchTime.now().rawValue
  76. let request = Grpc_Testing_SimpleRequest.withPayload(of: .bytes(of: &timestamp))
  77. var headers = HTTPHeaders()
  78. headers.add(name: "x-user-ip", value: "1.2.3.4")
  79. let callOptions = CallOptions(customMetadata: headers, cacheable: true)
  80. let call1 = client.cacheableUnaryCall(request, callOptions: callOptions)
  81. let call2 = client.cacheableUnaryCall(request, callOptions: callOptions)
  82. // The server ignores the request payload so we must not validate against it.
  83. try waitAndAssertEqual(call1.response.map { $0.payload }, call2.response.map { $0.payload })
  84. try waitAndAssertEqual(call1.status.map { $0.code }, .ok)
  85. try waitAndAssertEqual(call2.status.map { $0.code }, .ok)
  86. }
  87. }
  88. /// This test verifies unary calls succeed in sending messages, and touches on flow control (even
  89. /// if compression is enabled on the channel).
  90. ///
  91. /// Server features:
  92. /// - UnaryCall
  93. ///
  94. /// Procedure:
  95. /// 1. Client calls UnaryCall with:
  96. /// ```
  97. /// {
  98. /// response_size: 314159
  99. /// payload:{
  100. /// body: 271828 bytes of zeros
  101. /// }
  102. /// }
  103. /// ```
  104. ///
  105. /// Client asserts:
  106. /// - call was successful
  107. /// - response payload body is 314159 bytes in size
  108. /// - clients are free to assert that the response payload body contents are zero and comparing
  109. /// the entire response message against a golden response
  110. class LargeUnary: InteroperabilityTest {
  111. func run(using connection: GRPCClientConnection) throws {
  112. let client = Grpc_Testing_TestServiceService_NIOClient(connection: connection)
  113. let request = Grpc_Testing_SimpleRequest.with { request in
  114. request.responseSize = 314_159
  115. request.payload = .zeros(count: 271_828)
  116. }
  117. let call = client.unaryCall(request)
  118. try waitAndAssertEqual(call.response.map { $0.payload }, .zeros(count: 314_159))
  119. try waitAndAssertEqual(call.status.map { $0.code }, .ok)
  120. }
  121. }
  122. /// This test verifies that client-only streaming succeeds.
  123. ///
  124. /// Server features:
  125. /// - StreamingInputCall
  126. ///
  127. /// Procedure:
  128. /// 1. Client calls StreamingInputCall
  129. /// 2. Client sends:
  130. /// ```
  131. /// {
  132. /// payload:{
  133. /// body: 27182 bytes of zeros
  134. /// }
  135. /// }
  136. /// ```
  137. /// 3. Client then sends:
  138. /// ```
  139. /// {
  140. /// payload:{
  141. /// body: 8 bytes of zeros
  142. /// }
  143. /// }
  144. /// ```
  145. /// 4. Client then sends:
  146. /// ```
  147. /// {
  148. /// payload:{
  149. /// body: 1828 bytes of zeros
  150. /// }
  151. /// }
  152. /// ```
  153. /// 5. Client then sends:
  154. /// ```
  155. /// {
  156. /// payload:{
  157. /// body: 45904 bytes of zeros
  158. /// }
  159. /// }
  160. /// ```
  161. /// 6. Client half-closes
  162. ///
  163. /// Client asserts:
  164. /// - call was successful
  165. /// - response aggregated_payload_size is 74922
  166. class ClientStreaming: InteroperabilityTest {
  167. func run(using connection: GRPCClientConnection) throws {
  168. let client = Grpc_Testing_TestServiceService_NIOClient(connection: connection)
  169. let call = client.streamingInputCall()
  170. let messagesSent = call.newMessageQueue().flatMap {
  171. call.sendMessage(.withPayload(of: .zeros(count: 27_182)))
  172. }.flatMap {
  173. call.sendMessage(.withPayload(of: .zeros(count: 8)))
  174. }.flatMap {
  175. call.sendMessage(.withPayload(of: .zeros(count: 1_828)))
  176. }.flatMap {
  177. call.sendMessage(.withPayload(of: .zeros(count: 45_904)))
  178. }.flatMap {
  179. call.sendEnd()
  180. }
  181. try messagesSent.wait()
  182. try waitAndAssertEqual(call.response.map { $0.aggregatedPayloadSize }, 74_922)
  183. try waitAndAssertEqual(call.status.map { $0.code }, .ok)
  184. }
  185. }
  186. /// This test verifies that server-only streaming succeeds.
  187. ///
  188. /// Server features:
  189. /// - StreamingOutputCall
  190. ///
  191. /// Procedure:
  192. /// 1. Client calls StreamingOutputCall with StreamingOutputCallRequest:
  193. /// ```
  194. /// {
  195. /// response_parameters:{
  196. /// size: 31415
  197. /// }
  198. /// response_parameters:{
  199. /// size: 9
  200. /// }
  201. /// response_parameters:{
  202. /// size: 2653
  203. /// }
  204. /// response_parameters:{
  205. /// size: 58979
  206. /// }
  207. /// }
  208. /// ```
  209. ///
  210. /// Client asserts:
  211. /// - call was successful
  212. /// - exactly four responses
  213. /// - response payload bodies are sized (in order): 31415, 9, 2653, 58979
  214. /// - clients are free to assert that the response payload body contents are zero and
  215. /// comparing the entire response messages against golden responses
  216. class ServerStreaming: InteroperabilityTest {
  217. func run(using connection: GRPCClientConnection) throws {
  218. let client = Grpc_Testing_TestServiceService_NIOClient(connection: connection)
  219. let responseSizes = [31_415, 9, 2_653, 58_979]
  220. let request = Grpc_Testing_StreamingOutputCallRequest.with { request in
  221. request.responseParameters = responseSizes.map { .size($0) }
  222. }
  223. var payloads: [Grpc_Testing_Payload] = []
  224. let call = client.streamingOutputCall(request) { response in
  225. payloads.append(response.payload)
  226. }
  227. // Wait for the status first to ensure we've finished collecting responses.
  228. try waitAndAssertEqual(call.status.map { $0.code }, .ok)
  229. try assertEqual(payloads, responseSizes.map { .zeros(count: $0) })
  230. }
  231. }
  232. /// This test verifies that full duplex bidi is supported.
  233. ///
  234. /// Server features:
  235. /// - FullDuplexCall
  236. ///
  237. /// Procedure:
  238. /// 1. Client calls FullDuplexCall with:
  239. /// ```
  240. /// {
  241. /// response_parameters:{
  242. /// size: 31415
  243. /// }
  244. /// payload:{
  245. /// body: 27182 bytes of zeros
  246. /// }
  247. /// }
  248. /// ```
  249. /// 2. After getting a reply, it sends:
  250. /// ```
  251. /// {
  252. /// response_parameters:{
  253. /// size: 9
  254. /// }
  255. /// payload:{
  256. /// body: 8 bytes of zeros
  257. /// }
  258. /// }
  259. /// ```
  260. /// 3. After getting a reply, it sends:
  261. /// ```
  262. /// {
  263. /// response_parameters:{
  264. /// size: 2653
  265. /// }
  266. /// payload:{
  267. /// body: 1828 bytes of zeros
  268. /// }
  269. /// }
  270. /// ```
  271. /// 4. After getting a reply, it sends:
  272. /// ```
  273. /// {
  274. /// response_parameters:{
  275. /// size: 58979
  276. /// }
  277. /// payload:{
  278. /// body: 45904 bytes of zeros
  279. /// }
  280. /// }
  281. /// ```
  282. /// 5. After getting a reply, client half-closes
  283. ///
  284. /// Client asserts:
  285. /// - call was successful
  286. /// - exactly four responses
  287. /// - response payload bodies are sized (in order): 31415, 9, 2653, 58979
  288. /// - clients are free to assert that the response payload body contents are zero and
  289. /// comparing the entire response messages against golden responses
  290. class PingPong: InteroperabilityTest {
  291. func run(using connection: GRPCClientConnection) throws {
  292. let client = Grpc_Testing_TestServiceService_NIOClient(connection: connection)
  293. let requestSizes = [27_182, 8, 1_828, 45_904]
  294. let responseSizes = [31_415, 9, 2_653, 58_979]
  295. let responseReceived = DispatchSemaphore(value: 0)
  296. var payloads: [Grpc_Testing_Payload] = []
  297. let call = client.fullDuplexCall { response in
  298. payloads.append(response.payload)
  299. responseReceived.signal()
  300. }
  301. try zip(requestSizes, responseSizes).map { requestSize, responseSize in
  302. Grpc_Testing_StreamingOutputCallRequest.with { request in
  303. request.payload = .zeros(count: requestSize)
  304. request.responseParameters = [.size(responseSize)]
  305. }
  306. }.forEach { request in
  307. call.sendMessage(request, promise: nil)
  308. try assertEqual(responseReceived.wait(timeout: .now() + .seconds(1)), .success)
  309. }
  310. call.sendEnd(promise: nil)
  311. try waitAndAssertEqual(call.status.map { $0.code }, .ok)
  312. try assertEqual(payloads, responseSizes.map { .zeros(count: $0) })
  313. }
  314. }
  315. /// This test verifies that streams support having zero-messages in both directions.
  316. ///
  317. /// Server features:
  318. /// - FullDuplexCall
  319. ///
  320. /// Procedure:
  321. /// 1. Client calls FullDuplexCall and then half-closes
  322. ///
  323. /// Client asserts:
  324. /// - call was successful
  325. /// - exactly zero responses
  326. class EmptyStream: InteroperabilityTest {
  327. func run(using connection: GRPCClientConnection) throws {
  328. let client = Grpc_Testing_TestServiceService_NIOClient(connection: connection)
  329. var responses: [Grpc_Testing_StreamingOutputCallResponse] = []
  330. let call = client.fullDuplexCall { response in
  331. responses.append(response)
  332. }
  333. try call.sendEnd().wait()
  334. try waitAndAssertEqual(call.status.map { $0.code }, .ok)
  335. try assertEqual(responses, [])
  336. }
  337. }
  338. /// This test verifies that custom metadata in either binary or ascii format can be sent as
  339. /// initial-metadata by the client and as both initial- and trailing-metadata by the server.
  340. ///
  341. /// Server features:
  342. /// - UnaryCall
  343. /// - FullDuplexCall
  344. /// - Echo Metadata
  345. ///
  346. /// Procedure:
  347. /// 1. The client attaches custom metadata with the following keys and values
  348. /// to a UnaryCall with request:
  349. /// - key: "x-grpc-test-echo-initial", value: "test_initial_metadata_value"
  350. /// - key: "x-grpc-test-echo-trailing-bin", value: 0xababab
  351. /// ```
  352. /// {
  353. /// response_size: 314159
  354. /// payload:{
  355. /// body: 271828 bytes of zeros
  356. /// }
  357. /// }
  358. /// ```
  359. /// 2. The client attaches custom metadata with the following keys and values
  360. /// to a FullDuplexCall with request:
  361. /// - key: "x-grpc-test-echo-initial", value: "test_initial_metadata_value"
  362. /// - key: "x-grpc-test-echo-trailing-bin", value: 0xababab
  363. /// ```
  364. /// {
  365. /// response_parameters:{
  366. /// size: 314159
  367. /// }
  368. /// payload:{
  369. /// body: 271828 bytes of zeros
  370. /// }
  371. /// }
  372. /// ```
  373. /// and then half-closes
  374. ///
  375. /// Client asserts:
  376. /// - call was successful
  377. /// - metadata with key "x-grpc-test-echo-initial" and value "test_initial_metadata_value" is
  378. /// received in the initial metadata for calls in Procedure steps 1 and 2.
  379. /// - metadata with key "x-grpc-test-echo-trailing-bin" and value 0xababab is received in the
  380. /// trailing metadata for calls in Procedure steps 1 and 2.
  381. class CustomMetadata: InteroperabilityTest {
  382. let initialMetadataName = "x-grpc-test-echo-initial"
  383. let initialMetadataValue = "test_initial_metadata_value"
  384. let trailingMetadataName = "x-grpc-test-echo-trailing-bin"
  385. let trailingMetadataValue = Data([0xab, 0xab, 0xab]).base64EncodedString()
  386. func checkMetadata<SpecificClientCall>(call: SpecificClientCall) throws where SpecificClientCall: ClientCall {
  387. let initialName = call.initialMetadata.map { $0[self.initialMetadataName] }
  388. try waitAndAssertEqual(initialName, [self.initialMetadataValue])
  389. let trailingName = call.trailingMetadata.map { $0[self.trailingMetadataName] }
  390. try waitAndAssertEqual(trailingName, [self.trailingMetadataValue])
  391. try waitAndAssertEqual(call.status.map { $0.code }, .ok)
  392. }
  393. func run(using connection: GRPCClientConnection) throws {
  394. let client = Grpc_Testing_TestServiceService_NIOClient(connection: connection)
  395. let unaryRequest = Grpc_Testing_SimpleRequest.with { request in
  396. request.responseSize = 314_159
  397. request.payload = .zeros(count: 217_828)
  398. }
  399. var customMetadata = HTTPHeaders()
  400. customMetadata.add(name: self.initialMetadataName, value: self.initialMetadataValue)
  401. customMetadata.add(name: self.trailingMetadataName, value: self.trailingMetadataValue)
  402. let callOptions = CallOptions(customMetadata: customMetadata)
  403. let unaryCall = client.unaryCall(unaryRequest, callOptions: callOptions)
  404. try self.checkMetadata(call: unaryCall)
  405. let duplexCall = client.fullDuplexCall(callOptions: callOptions) { _ in }
  406. let duplexRequest = Grpc_Testing_StreamingOutputCallRequest.with { request in
  407. request.responseParameters = [.size(314_159)]
  408. request.payload = .zeros(count: 271_828)
  409. }
  410. let messagesSent = duplexCall.newMessageQueue().flatMap {
  411. duplexCall.sendMessage(duplexRequest)
  412. }.flatMap {
  413. duplexCall.sendEnd()
  414. }
  415. try messagesSent.wait()
  416. try self.checkMetadata(call: duplexCall)
  417. }
  418. }
  419. /// This test verifies unary calls succeed in sending messages, and propagate back status code and
  420. /// message sent along with the messages.
  421. ///
  422. /// Server features:
  423. /// - UnaryCall
  424. /// - FullDuplexCall
  425. /// - Echo Status
  426. ///
  427. /// Procedure:
  428. /// 1. Client calls UnaryCall with:
  429. /// ```
  430. /// {
  431. /// response_status:{
  432. /// code: 2
  433. /// message: "test status message"
  434. /// }
  435. /// }
  436. /// ```
  437. /// 2. Client calls FullDuplexCall with:
  438. /// ```
  439. /// {
  440. /// response_status:{
  441. /// code: 2
  442. /// message: "test status message"
  443. /// }
  444. /// }
  445. /// ```
  446. /// 3. and then half-closes
  447. ///
  448. /// Client asserts:
  449. /// - received status code is the same as the sent code for both Procedure steps 1 and 2
  450. /// - received status message is the same as the sent message for both Procedure steps 1 and 2
  451. class StatusCodeAndMessage: InteroperabilityTest {
  452. let expectedCode = 2
  453. let expectedMessage = "test status message"
  454. func checkStatus<SpecificClientCall>(call: SpecificClientCall) throws where SpecificClientCall: ClientCall {
  455. try waitAndAssertEqual(call.status.map { $0.code.rawValue }, self.expectedCode)
  456. try waitAndAssertEqual(call.status.map { $0.message }, self.expectedMessage)
  457. }
  458. func run(using connection: GRPCClientConnection) throws {
  459. let client = Grpc_Testing_TestServiceService_NIOClient(connection: connection)
  460. let echoStatus = Grpc_Testing_EchoStatus(code: Int32(self.expectedCode), message: self.expectedMessage)
  461. let unaryCall = client.unaryCall(.withStatus(of: echoStatus))
  462. try self.checkStatus(call: unaryCall)
  463. var responses: [Grpc_Testing_StreamingOutputCallResponse] = []
  464. let duplexCall = client.fullDuplexCall { response in
  465. responses.append(response)
  466. }
  467. try duplexCall.newMessageQueue().flatMap {
  468. duplexCall.sendMessage(.withStatus(of: echoStatus))
  469. }.wait()
  470. try self.checkStatus(call: duplexCall)
  471. try assertEqual(responses, [])
  472. }
  473. }
  474. /// This test verifies Unicode and whitespace is correctly processed in status message. "\t" is
  475. /// horizontal tab. "\r" is carriage return. "\n" is line feed.
  476. ///
  477. /// Server features:
  478. /// - UnaryCall
  479. /// - Echo Status
  480. ///
  481. /// Procedure:
  482. /// 1. Client calls UnaryCall with:
  483. /// ```
  484. /// {
  485. /// response_status:{
  486. /// code: 2
  487. /// message: "\t\ntest with whitespace\r\nand Unicode BMP ☺ and non-BMP 😈\t\n"
  488. /// }
  489. /// }
  490. /// ```
  491. ///
  492. /// Client asserts:
  493. /// - received status code is the same as the sent code for Procedure step 1
  494. /// - received status message is the same as the sent message for Procedure step 1, including all
  495. /// whitespace characters
  496. class SpecialStatusMessage: InteroperabilityTest {
  497. func run(using connection: GRPCClientConnection) throws {
  498. let client = Grpc_Testing_TestServiceService_NIOClient(connection: connection)
  499. let code = 2
  500. let message = "\t\ntest with whitespace\r\nand Unicode BMP ☺ and non-BMP 😈\t\n"
  501. let call = client.unaryCall(.withStatus(of: .init(code: Int32(code), message: message)))
  502. try waitAndAssertEqual(call.status.map { $0.code.rawValue }, code)
  503. try waitAndAssertEqual(call.status.map { $0.message }, message)
  504. }
  505. }
  506. /// This test verifies that calling an unimplemented RPC method returns the UNIMPLEMENTED status
  507. /// code.
  508. ///
  509. /// Server features: N/A
  510. ///
  511. /// Procedure:
  512. /// 1. Client calls grpc.testing.TestService/UnimplementedCall with an empty request (defined as
  513. /// grpc.testing.Empty):
  514. /// ```
  515. /// {
  516. /// }
  517. /// ```
  518. ///
  519. /// Client asserts:
  520. /// - received status code is 12 (UNIMPLEMENTED)
  521. class UnimplementedMethod: InteroperabilityTest {
  522. func run(using connection: GRPCClientConnection) throws {
  523. let client = Grpc_Testing_TestServiceService_NIOClient(connection: connection)
  524. let call = client.unimplementedCall(Grpc_Testing_Empty())
  525. try waitAndAssertEqual(call.status.map { $0.code }, .unimplemented)
  526. }
  527. }
  528. /// This test verifies calling an unimplemented server returns the UNIMPLEMENTED status code.
  529. ///
  530. /// Server features: N/A
  531. ///
  532. /// Procedure:
  533. /// 1. Client calls grpc.testing.UnimplementedService/UnimplementedCall with an empty request
  534. /// (defined as grpc.testing.Empty):
  535. /// ```
  536. /// {
  537. /// }
  538. /// ```
  539. ///
  540. /// Client asserts:
  541. /// - received status code is 12 (UNIMPLEMENTED)
  542. class UnimplementedService: InteroperabilityTest {
  543. func run(using connection: GRPCClientConnection) throws {
  544. let client = Grpc_Testing_UnimplementedServiceService_NIOClient(connection: connection)
  545. let call = client.unimplementedCall(Grpc_Testing_Empty())
  546. try waitAndAssertEqual(call.status.map { $0.code }, .unimplemented)
  547. }
  548. }
  549. /// This test verifies that a request can be cancelled after metadata has been sent but before
  550. /// payloads are sent.
  551. ///
  552. /// Server features:
  553. /// - StreamingInputCall
  554. ///
  555. /// Procedure:
  556. /// 1. Client starts StreamingInputCall
  557. /// 2. Client immediately cancels request
  558. ///
  559. /// Client asserts:
  560. /// - Call completed with status CANCELLED
  561. class CancelAfterBegin: InteroperabilityTest {
  562. func run(using connection: GRPCClientConnection) throws {
  563. let client = Grpc_Testing_TestServiceService_NIOClient(connection: connection)
  564. let call = client.streamingInputCall()
  565. call.cancel()
  566. try waitAndAssertEqual(call.status.map { $0.code }, .cancelled)
  567. }
  568. }
  569. /// This test verifies that a request can be cancelled after receiving a message from the server.
  570. ///
  571. /// Server features:
  572. /// - FullDuplexCall
  573. ///
  574. /// Procedure:
  575. /// 1. Client starts FullDuplexCall with
  576. /// ```
  577. /// {
  578. /// response_parameters:{
  579. /// size: 31415
  580. /// }
  581. /// payload:{
  582. /// body: 27182 bytes of zeros
  583. /// }
  584. /// }
  585. /// ```
  586. /// 2. After receiving a response, client cancels request
  587. ///
  588. /// Client asserts:
  589. /// - Call completed with status CANCELLED
  590. class CancelAfterFirstResponse: InteroperabilityTest {
  591. func run(using connection: GRPCClientConnection) throws {
  592. let client = Grpc_Testing_TestServiceService_NIOClient(connection: connection)
  593. let promise = client.connection.channel.eventLoop.makePromise(of: Void.self)
  594. let call = client.fullDuplexCall { _ in
  595. promise.succeed(())
  596. }
  597. promise.futureResult.whenSuccess {
  598. call.cancel()
  599. }
  600. let request = Grpc_Testing_StreamingOutputCallRequest.with { request in
  601. request.responseParameters = [.size(31_415)]
  602. request.payload = .zeros(count: 27_182)
  603. }
  604. call.sendMessage(request, promise: nil)
  605. try waitAndAssertEqual(call.status.map { $0.code }, .cancelled)
  606. }
  607. }
  608. /// This test verifies that an RPC request whose lifetime exceeds its configured timeout value
  609. /// will end with the DeadlineExceeded status.
  610. ///
  611. /// Server features:
  612. /// - FullDuplexCall
  613. ///
  614. /// Procedure:
  615. /// 1. Client calls FullDuplexCall with the following request and sets its timeout to 1ms
  616. /// ```
  617. /// {
  618. /// payload:{
  619. /// body: 27182 bytes of zeros
  620. /// }
  621. /// }
  622. /// ```
  623. /// 2. Client waits
  624. ///
  625. /// Client asserts:
  626. /// - Call completed with status DEADLINE_EXCEEDED.
  627. class TimeoutOnSleepingServer: InteroperabilityTest {
  628. func run(using connection: GRPCClientConnection) throws {
  629. let client = Grpc_Testing_TestServiceService_NIOClient(connection: connection)
  630. let callOptions = CallOptions(timeout: try .milliseconds(1))
  631. let call = client.fullDuplexCall(callOptions: callOptions) { _ in }
  632. try waitAndAssertEqual(call.status.map { $0.code }, .deadlineExceeded)
  633. }
  634. }