GRPCStreamStateMachineTests.swift 86 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426
  1. /*
  2. * Copyright 2024, 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 GRPCCore
  17. import NIOCore
  18. import NIOEmbedded
  19. import NIOHPACK
  20. import XCTest
  21. @testable import GRPCHTTP2Core
  22. private enum TargetStateMachineState: CaseIterable {
  23. case clientIdleServerIdle
  24. case clientOpenServerIdle
  25. case clientOpenServerOpen
  26. case clientOpenServerClosed
  27. case clientClosedServerIdle
  28. case clientClosedServerOpen
  29. case clientClosedServerClosed
  30. }
  31. extension HPACKHeaders {
  32. // Client
  33. fileprivate static let clientInitialMetadata: Self = [
  34. GRPCHTTP2Keys.path.rawValue: "test/test",
  35. GRPCHTTP2Keys.scheme.rawValue: "http",
  36. GRPCHTTP2Keys.method.rawValue: "POST",
  37. GRPCHTTP2Keys.contentType.rawValue: "application/grpc",
  38. GRPCHTTP2Keys.te.rawValue: "trailers",
  39. ]
  40. fileprivate static let clientInitialMetadataWithDeflateCompression: Self = [
  41. GRPCHTTP2Keys.path.rawValue: "test/test",
  42. GRPCHTTP2Keys.contentType.rawValue: "application/grpc",
  43. GRPCHTTP2Keys.method.rawValue: "POST",
  44. GRPCHTTP2Keys.scheme.rawValue: "https",
  45. GRPCHTTP2Keys.te.rawValue: "trailers",
  46. GRPCHTTP2Keys.acceptEncoding.rawValue: "deflate",
  47. GRPCHTTP2Keys.encoding.rawValue: "deflate",
  48. ]
  49. fileprivate static let clientInitialMetadataWithGzipCompression: Self = [
  50. GRPCHTTP2Keys.path.rawValue: "test/test",
  51. GRPCHTTP2Keys.contentType.rawValue: "application/grpc",
  52. GRPCHTTP2Keys.method.rawValue: "POST",
  53. GRPCHTTP2Keys.scheme.rawValue: "https",
  54. GRPCHTTP2Keys.te.rawValue: "trailers",
  55. GRPCHTTP2Keys.acceptEncoding.rawValue: "gzip",
  56. GRPCHTTP2Keys.encoding.rawValue: "gzip",
  57. ]
  58. fileprivate static let receivedWithoutContentType: Self = [
  59. GRPCHTTP2Keys.path.rawValue: "test/test"
  60. ]
  61. fileprivate static let receivedWithInvalidContentType: Self = [
  62. GRPCHTTP2Keys.path.rawValue: "test/test",
  63. GRPCHTTP2Keys.contentType.rawValue: "invalid/invalid",
  64. ]
  65. fileprivate static let receivedWithoutEndpoint: Self = [
  66. GRPCHTTP2Keys.contentType.rawValue: "application/grpc"
  67. ]
  68. fileprivate static let receivedWithoutTE: Self = [
  69. GRPCHTTP2Keys.path.rawValue: "test/test",
  70. GRPCHTTP2Keys.scheme.rawValue: "http",
  71. GRPCHTTP2Keys.method.rawValue: "POST",
  72. GRPCHTTP2Keys.contentType.rawValue: "application/grpc",
  73. ]
  74. fileprivate static let receivedWithInvalidTE: Self = [
  75. GRPCHTTP2Keys.path.rawValue: "test/test",
  76. GRPCHTTP2Keys.scheme.rawValue: "http",
  77. GRPCHTTP2Keys.method.rawValue: "POST",
  78. GRPCHTTP2Keys.contentType.rawValue: "application/grpc",
  79. GRPCHTTP2Keys.te.rawValue: "invalidte",
  80. ]
  81. fileprivate static let receivedWithoutMethod: Self = [
  82. GRPCHTTP2Keys.path.rawValue: "test/test",
  83. GRPCHTTP2Keys.scheme.rawValue: "http",
  84. GRPCHTTP2Keys.contentType.rawValue: "application/grpc",
  85. GRPCHTTP2Keys.te.rawValue: "trailers",
  86. ]
  87. fileprivate static let receivedWithInvalidMethod: Self = [
  88. GRPCHTTP2Keys.path.rawValue: "test/test",
  89. GRPCHTTP2Keys.scheme.rawValue: "http",
  90. GRPCHTTP2Keys.method.rawValue: "GET",
  91. GRPCHTTP2Keys.contentType.rawValue: "application/grpc",
  92. GRPCHTTP2Keys.te.rawValue: "trailers",
  93. ]
  94. fileprivate static let receivedWithoutScheme: Self = [
  95. GRPCHTTP2Keys.path.rawValue: "test/test",
  96. GRPCHTTP2Keys.method.rawValue: "POST",
  97. GRPCHTTP2Keys.contentType.rawValue: "application/grpc",
  98. GRPCHTTP2Keys.te.rawValue: "trailers",
  99. ]
  100. fileprivate static let receivedWithInvalidScheme: Self = [
  101. GRPCHTTP2Keys.path.rawValue: "test/test",
  102. GRPCHTTP2Keys.scheme.rawValue: "invalidscheme",
  103. GRPCHTTP2Keys.method.rawValue: "POST",
  104. GRPCHTTP2Keys.contentType.rawValue: "application/grpc",
  105. GRPCHTTP2Keys.te.rawValue: "trailers",
  106. ]
  107. // Server
  108. fileprivate static let serverInitialMetadata: Self = [
  109. GRPCHTTP2Keys.status.rawValue: "200",
  110. GRPCHTTP2Keys.contentType.rawValue: ContentType.grpc.canonicalValue,
  111. GRPCHTTP2Keys.acceptEncoding.rawValue: "deflate",
  112. ]
  113. fileprivate static let serverInitialMetadataWithDeflateCompression: Self = [
  114. GRPCHTTP2Keys.status.rawValue: "200",
  115. GRPCHTTP2Keys.contentType.rawValue: ContentType.grpc.canonicalValue,
  116. GRPCHTTP2Keys.encoding.rawValue: "deflate",
  117. GRPCHTTP2Keys.acceptEncoding.rawValue: "deflate",
  118. ]
  119. fileprivate static let serverTrailers: Self = [
  120. GRPCHTTP2Keys.status.rawValue: "200",
  121. GRPCHTTP2Keys.contentType.rawValue: ContentType.grpc.canonicalValue,
  122. GRPCHTTP2Keys.grpcStatus.rawValue: "0",
  123. ]
  124. }
  125. @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
  126. final class GRPCStreamClientStateMachineTests: XCTestCase {
  127. private func makeClientStateMachine(
  128. targetState: TargetStateMachineState,
  129. compressionEnabled: Bool = false
  130. ) -> GRPCStreamStateMachine {
  131. var stateMachine = GRPCStreamStateMachine(
  132. configuration: .client(
  133. .init(
  134. methodDescriptor: .init(service: "test", method: "test"),
  135. scheme: .http,
  136. outboundEncoding: compressionEnabled ? .deflate : .identity,
  137. acceptedEncodings: [.deflate]
  138. )
  139. ),
  140. maximumPayloadSize: 100,
  141. skipAssertions: true
  142. )
  143. let serverMetadata: HPACKHeaders =
  144. compressionEnabled ? .serverInitialMetadataWithDeflateCompression : .serverInitialMetadata
  145. switch targetState {
  146. case .clientIdleServerIdle:
  147. break
  148. case .clientOpenServerIdle:
  149. // Open client
  150. XCTAssertNoThrow(try stateMachine.send(metadata: []))
  151. case .clientOpenServerOpen:
  152. // Open client
  153. XCTAssertNoThrow(try stateMachine.send(metadata: []))
  154. // Open server
  155. XCTAssertNoThrow(try stateMachine.receive(headers: serverMetadata, endStream: false))
  156. case .clientOpenServerClosed:
  157. // Open client
  158. XCTAssertNoThrow(try stateMachine.send(metadata: []))
  159. // Open server
  160. XCTAssertNoThrow(try stateMachine.receive(headers: serverMetadata, endStream: false))
  161. // Close server
  162. XCTAssertNoThrow(try stateMachine.receive(headers: .serverTrailers, endStream: true))
  163. case .clientClosedServerIdle:
  164. // Open client
  165. XCTAssertNoThrow(try stateMachine.send(metadata: []))
  166. // Close client
  167. XCTAssertNoThrow(try stateMachine.closeOutbound())
  168. case .clientClosedServerOpen:
  169. // Open client
  170. XCTAssertNoThrow(try stateMachine.send(metadata: []))
  171. // Open server
  172. XCTAssertNoThrow(try stateMachine.receive(headers: serverMetadata, endStream: false))
  173. // Close client
  174. XCTAssertNoThrow(try stateMachine.closeOutbound())
  175. case .clientClosedServerClosed:
  176. // Open client
  177. XCTAssertNoThrow(try stateMachine.send(metadata: []))
  178. // Open server
  179. XCTAssertNoThrow(try stateMachine.receive(headers: serverMetadata, endStream: false))
  180. // Close client
  181. XCTAssertNoThrow(try stateMachine.closeOutbound())
  182. // Close server
  183. XCTAssertNoThrow(try stateMachine.receive(headers: .serverTrailers, endStream: true))
  184. }
  185. return stateMachine
  186. }
  187. // - MARK: Send Metadata
  188. func testSendMetadataWhenClientIdleAndServerIdle() throws {
  189. var stateMachine = self.makeClientStateMachine(targetState: .clientIdleServerIdle)
  190. XCTAssertNoThrow(try stateMachine.send(metadata: []))
  191. }
  192. func testSendMetadataWhenClientAlreadyOpen() throws {
  193. for targetState in [
  194. TargetStateMachineState.clientOpenServerIdle, .clientOpenServerOpen, .clientOpenServerClosed,
  195. ] {
  196. var stateMachine = self.makeClientStateMachine(targetState: targetState)
  197. // Try sending metadata again: should throw
  198. XCTAssertThrowsError(ofType: RPCError.self, try stateMachine.send(metadata: .init())) {
  199. error in
  200. XCTAssertEqual(error.code, .internalError)
  201. XCTAssertEqual(error.message, "Client is already open: shouldn't be sending metadata.")
  202. }
  203. }
  204. }
  205. func testSendMetadataWhenClientAlreadyClosed() throws {
  206. for targetState in [
  207. TargetStateMachineState.clientClosedServerIdle, .clientClosedServerOpen,
  208. .clientClosedServerClosed,
  209. ] {
  210. var stateMachine = self.makeClientStateMachine(targetState: targetState)
  211. // Try sending metadata again: should throw
  212. XCTAssertThrowsError(ofType: RPCError.self, try stateMachine.send(metadata: .init())) {
  213. error in
  214. XCTAssertEqual(error.code, .internalError)
  215. XCTAssertEqual(error.message, "Client is closed: can't send metadata.")
  216. }
  217. }
  218. }
  219. // - MARK: Send Message
  220. func testSendMessageWhenClientIdleAndServerIdle() {
  221. var stateMachine = self.makeClientStateMachine(targetState: .clientIdleServerIdle)
  222. // Try to send a message without opening (i.e. without sending initial metadata)
  223. XCTAssertThrowsError(
  224. ofType: RPCError.self,
  225. try stateMachine.send(message: [], promise: nil)
  226. ) { error in
  227. XCTAssertEqual(error.code, .internalError)
  228. XCTAssertEqual(error.message, "Client not yet open.")
  229. }
  230. }
  231. func testSendMessageWhenClientOpen() {
  232. for targetState in [
  233. TargetStateMachineState.clientOpenServerIdle, .clientOpenServerOpen, .clientOpenServerClosed,
  234. ] {
  235. var stateMachine = self.makeClientStateMachine(targetState: targetState)
  236. // Now send a message
  237. XCTAssertNoThrow(try stateMachine.send(message: [], promise: nil))
  238. }
  239. }
  240. func testSendMessageWhenClientClosed() {
  241. for targetState in [
  242. TargetStateMachineState.clientClosedServerIdle, .clientClosedServerOpen,
  243. .clientClosedServerClosed,
  244. ] {
  245. var stateMachine = self.makeClientStateMachine(targetState: targetState)
  246. // Try sending another message: it should fail
  247. XCTAssertThrowsError(
  248. ofType: RPCError.self,
  249. try stateMachine.send(message: [], promise: nil)
  250. ) { error in
  251. XCTAssertEqual(error.code, .internalError)
  252. XCTAssertEqual(error.message, "Client is closed, cannot send a message.")
  253. }
  254. }
  255. }
  256. // - MARK: Send Status and Trailers
  257. func testSendStatusAndTrailers() {
  258. for targetState in TargetStateMachineState.allCases {
  259. var stateMachine = self.makeClientStateMachine(targetState: targetState)
  260. // This operation is never allowed on the client.
  261. XCTAssertThrowsError(
  262. ofType: RPCError.self,
  263. try stateMachine.send(
  264. status: Status(code: .ok, message: ""),
  265. metadata: .init()
  266. )
  267. ) { error in
  268. XCTAssertEqual(error.code, .internalError)
  269. XCTAssertEqual(error.message, "Client cannot send status and trailer.")
  270. }
  271. }
  272. }
  273. // - MARK: Receive initial metadata
  274. func testReceiveInitialMetadataWhenClientIdleAndServerIdle() {
  275. var stateMachine = self.makeClientStateMachine(targetState: .clientIdleServerIdle)
  276. XCTAssertThrowsError(
  277. ofType: RPCError.self,
  278. try stateMachine.receive(headers: .init(), endStream: false)
  279. ) { error in
  280. XCTAssertEqual(error.code, .internalError)
  281. XCTAssertEqual(error.message, "Server cannot have sent metadata if the client is idle.")
  282. }
  283. }
  284. func testReceiveInvalidInitialMetadataWhenServerIdle() throws {
  285. for targetState in [
  286. TargetStateMachineState.clientOpenServerIdle, .clientClosedServerIdle,
  287. ] {
  288. var stateMachine = self.makeClientStateMachine(targetState: targetState)
  289. // Receive metadata with unexpected non-200 status code
  290. let action = try stateMachine.receive(
  291. headers: [GRPCHTTP2Keys.status.rawValue: "300"],
  292. endStream: false
  293. )
  294. XCTAssertEqual(
  295. action,
  296. .receivedStatusAndMetadata(
  297. status: .init(code: .unknown, message: "Unexpected non-200 HTTP Status Code."),
  298. metadata: [":status": "300"]
  299. )
  300. )
  301. }
  302. }
  303. func testReceiveInitialMetadataWhenServerIdle() throws {
  304. for targetState in [
  305. TargetStateMachineState.clientOpenServerIdle, .clientClosedServerIdle,
  306. ] {
  307. var stateMachine = self.makeClientStateMachine(targetState: targetState)
  308. // Receive metadata = open server
  309. let action = try stateMachine.receive(
  310. headers: [
  311. GRPCHTTP2Keys.status.rawValue: "200",
  312. GRPCHTTP2Keys.contentType.rawValue: ContentType.grpc.canonicalValue,
  313. GRPCHTTP2Keys.encoding.rawValue: "deflate",
  314. "custom": "123",
  315. "custom-bin": String(base64Encoding: [42, 43, 44]),
  316. ],
  317. endStream: false
  318. )
  319. var expectedMetadata: Metadata = [
  320. ":status": "200",
  321. "content-type": "application/grpc",
  322. "grpc-encoding": "deflate",
  323. "custom": "123",
  324. ]
  325. expectedMetadata.addBinary([42, 43, 44], forKey: "custom-bin")
  326. XCTAssertEqual(action, .receivedMetadata(expectedMetadata))
  327. }
  328. }
  329. func testReceiveInitialMetadataWhenServerOpen() throws {
  330. for targetState in [
  331. TargetStateMachineState.clientOpenServerOpen, .clientClosedServerOpen,
  332. ] {
  333. var stateMachine = self.makeClientStateMachine(targetState: targetState)
  334. // Receiving initial metadata again should throw if grpc-status is not present.
  335. XCTAssertThrowsError(
  336. ofType: RPCError.self,
  337. try stateMachine.receive(
  338. headers: [
  339. GRPCHTTP2Keys.status.rawValue: "200",
  340. GRPCHTTP2Keys.contentType.rawValue: ContentType.grpc.canonicalValue,
  341. GRPCHTTP2Keys.encoding.rawValue: "deflate",
  342. "custom": "123",
  343. "custom-bin": String(base64Encoding: [42, 43, 44]),
  344. ],
  345. endStream: false
  346. )
  347. ) { error in
  348. XCTAssertEqual(error.code, .unknown)
  349. XCTAssertEqual(
  350. error.message,
  351. "Non-initial metadata must be a trailer containing a valid grpc-status"
  352. )
  353. }
  354. // Now make sure everything works well if we include grpc-status
  355. let action = try stateMachine.receive(
  356. headers: [
  357. GRPCHTTP2Keys.status.rawValue: "200",
  358. GRPCHTTP2Keys.grpcStatus.rawValue: String(Status.Code.ok.rawValue),
  359. GRPCHTTP2Keys.contentType.rawValue: ContentType.grpc.canonicalValue,
  360. GRPCHTTP2Keys.encoding.rawValue: "deflate",
  361. "custom": "123",
  362. "custom-bin": String(base64Encoding: [42, 43, 44]),
  363. ],
  364. endStream: false
  365. )
  366. var expectedMetadata: Metadata = [
  367. ":status": "200",
  368. "content-type": "application/grpc",
  369. "grpc-encoding": "deflate",
  370. "custom": "123",
  371. ]
  372. expectedMetadata.removeAllValues(forKey: GRPCHTTP2Keys.grpcStatus.rawValue)
  373. expectedMetadata.addBinary([42, 43, 44], forKey: "custom-bin")
  374. XCTAssertEqual(
  375. action,
  376. .receivedStatusAndMetadata(
  377. status: Status(code: .ok, message: ""),
  378. metadata: expectedMetadata
  379. )
  380. )
  381. }
  382. }
  383. func testReceiveInitialMetadataWhenServerClosed() {
  384. for targetState in [TargetStateMachineState.clientOpenServerClosed, .clientClosedServerClosed] {
  385. var stateMachine = self.makeClientStateMachine(targetState: targetState)
  386. XCTAssertThrowsError(
  387. ofType: RPCError.self,
  388. try stateMachine.receive(headers: .init(), endStream: false)
  389. ) { error in
  390. XCTAssertEqual(error.code, .internalError)
  391. XCTAssertEqual(error.message, "Server is closed, nothing could have been sent.")
  392. }
  393. }
  394. }
  395. // - MARK: Receive end trailers
  396. func testReceiveEndTrailerWhenClientIdleAndServerIdle() {
  397. var stateMachine = self.makeClientStateMachine(targetState: .clientIdleServerIdle)
  398. // Receive an end trailer
  399. XCTAssertThrowsError(
  400. ofType: RPCError.self,
  401. try stateMachine.receive(headers: .init(), endStream: true)
  402. ) { error in
  403. XCTAssertEqual(error.code, .internalError)
  404. XCTAssertEqual(error.message, "Server cannot have sent metadata if the client is idle.")
  405. }
  406. }
  407. func testReceiveEndTrailerWhenClientOpenAndServerIdle() throws {
  408. var stateMachine = self.makeClientStateMachine(targetState: .clientOpenServerIdle)
  409. // Receive a trailers-only response
  410. let trailersOnlyResponse: HPACKHeaders = [
  411. GRPCHTTP2Keys.status.rawValue: "200",
  412. GRPCHTTP2Keys.contentType.rawValue: ContentType.grpc.canonicalValue,
  413. GRPCHTTP2Keys.grpcStatus.rawValue: String(Status.Code.internalError.rawValue),
  414. GRPCHTTP2Keys.grpcStatusMessage.rawValue: GRPCStatusMessageMarshaller.marshall(
  415. "Some status message"
  416. )!,
  417. "custom-key": "custom-value",
  418. ]
  419. let trailers = try stateMachine.receive(headers: trailersOnlyResponse, endStream: true)
  420. switch trailers {
  421. case .receivedStatusAndMetadata(let status, let metadata):
  422. XCTAssertEqual(status, Status(code: .internalError, message: "Some status message"))
  423. XCTAssertEqual(
  424. metadata,
  425. [
  426. ":status": "200",
  427. "content-type": "application/grpc",
  428. "custom-key": "custom-value",
  429. ]
  430. )
  431. case .receivedMetadata, .doNothing, .rejectRPC:
  432. XCTFail("Expected .receivedStatusAndMetadata")
  433. }
  434. }
  435. func testReceiveEndTrailerWhenServerOpen() throws {
  436. for targetState in [TargetStateMachineState.clientOpenServerOpen, .clientClosedServerOpen] {
  437. var stateMachine = self.makeClientStateMachine(targetState: targetState)
  438. // Receive an end trailer
  439. let action = try stateMachine.receive(
  440. headers: [
  441. GRPCHTTP2Keys.status.rawValue: "200",
  442. GRPCHTTP2Keys.grpcStatus.rawValue: String(Status.Code.ok.rawValue),
  443. GRPCHTTP2Keys.contentType.rawValue: ContentType.grpc.canonicalValue,
  444. GRPCHTTP2Keys.encoding.rawValue: "deflate",
  445. "custom": "123",
  446. ],
  447. endStream: true
  448. )
  449. let expectedMetadata: Metadata = [
  450. ":status": "200",
  451. "content-type": "application/grpc",
  452. "grpc-encoding": "deflate",
  453. "custom": "123",
  454. ]
  455. XCTAssertEqual(
  456. action,
  457. .receivedStatusAndMetadata(
  458. status: .init(code: .ok, message: ""),
  459. metadata: expectedMetadata
  460. )
  461. )
  462. }
  463. }
  464. func testReceiveEndTrailerWhenClientOpenAndServerClosed() {
  465. var stateMachine = self.makeClientStateMachine(targetState: .clientOpenServerClosed)
  466. // Receive another end trailer
  467. XCTAssertThrowsError(
  468. ofType: RPCError.self,
  469. try stateMachine.receive(headers: .init(), endStream: true)
  470. ) { error in
  471. XCTAssertEqual(error.code, .internalError)
  472. XCTAssertEqual(error.message, "Server is closed, nothing could have been sent.")
  473. }
  474. }
  475. func testReceiveEndTrailerWhenClientClosedAndServerIdle() throws {
  476. var stateMachine = self.makeClientStateMachine(targetState: .clientClosedServerIdle)
  477. // Server sends a trailers-only response
  478. let trailersOnlyResponse: HPACKHeaders = [
  479. GRPCHTTP2Keys.status.rawValue: "200",
  480. GRPCHTTP2Keys.contentType.rawValue: ContentType.grpc.canonicalValue,
  481. GRPCHTTP2Keys.grpcStatus.rawValue: String(Status.Code.internalError.rawValue),
  482. GRPCHTTP2Keys.grpcStatusMessage.rawValue: GRPCStatusMessageMarshaller.marshall(
  483. "Some status message"
  484. )!,
  485. "custom-key": "custom-value",
  486. ]
  487. let trailers = try stateMachine.receive(headers: trailersOnlyResponse, endStream: true)
  488. switch trailers {
  489. case .receivedStatusAndMetadata(let status, let metadata):
  490. XCTAssertEqual(status, Status(code: .internalError, message: "Some status message"))
  491. XCTAssertEqual(
  492. metadata,
  493. [
  494. ":status": "200",
  495. "content-type": "application/grpc",
  496. "custom-key": "custom-value",
  497. ]
  498. )
  499. case .receivedMetadata, .doNothing, .rejectRPC:
  500. XCTFail("Expected .receivedStatusAndMetadata")
  501. }
  502. }
  503. func testReceiveEndTrailerWhenClientClosedAndServerClosed() {
  504. var stateMachine = self.makeClientStateMachine(targetState: .clientClosedServerClosed)
  505. // Close server again (endStream = true) and assert we don't throw.
  506. // This can happen if the previous close was caused by a grpc-status header
  507. // and then the server sends an empty frame with EOS set.
  508. XCTAssertEqual(try stateMachine.receive(headers: .init(), endStream: true), .doNothing)
  509. }
  510. // - MARK: Receive message
  511. func testReceiveMessageWhenClientIdleAndServerIdle() {
  512. var stateMachine = self.makeClientStateMachine(targetState: .clientIdleServerIdle)
  513. XCTAssertThrowsError(
  514. ofType: RPCError.self,
  515. try stateMachine.receive(buffer: .init(), endStream: false)
  516. ) { error in
  517. XCTAssertEqual(error.code, .internalError)
  518. XCTAssertEqual(
  519. error.message,
  520. "Cannot have received anything from server if client is not yet open."
  521. )
  522. }
  523. }
  524. func testReceiveMessageWhenServerIdle() {
  525. for targetState in [TargetStateMachineState.clientOpenServerIdle, .clientClosedServerIdle] {
  526. var stateMachine = self.makeClientStateMachine(targetState: targetState)
  527. XCTAssertThrowsError(
  528. ofType: RPCError.self,
  529. try stateMachine.receive(buffer: .init(), endStream: false)
  530. ) { error in
  531. XCTAssertEqual(error.code, .internalError)
  532. XCTAssertEqual(
  533. error.message,
  534. "Server cannot have sent a message before sending the initial metadata."
  535. )
  536. }
  537. }
  538. }
  539. func testReceiveMessageWhenServerOpen() throws {
  540. for targetState in [TargetStateMachineState.clientOpenServerOpen, .clientClosedServerOpen] {
  541. var stateMachine = self.makeClientStateMachine(targetState: targetState)
  542. XCTAssertNoThrow(try stateMachine.receive(buffer: .init(), endStream: false))
  543. XCTAssertNoThrow(try stateMachine.receive(buffer: .init(), endStream: true))
  544. }
  545. }
  546. func testReceiveMessageWhenServerClosed() {
  547. for targetState in [TargetStateMachineState.clientOpenServerClosed, .clientClosedServerClosed] {
  548. var stateMachine = self.makeClientStateMachine(targetState: targetState)
  549. XCTAssertThrowsError(
  550. ofType: RPCError.self,
  551. try stateMachine.receive(buffer: .init(), endStream: false)
  552. ) { error in
  553. XCTAssertEqual(error.code, .internalError)
  554. XCTAssertEqual(error.message, "Cannot have received anything from a closed server.")
  555. }
  556. }
  557. }
  558. // - MARK: Next outbound message
  559. func testNextOutboundMessageWhenClientIdleAndServerIdle() {
  560. var stateMachine = self.makeClientStateMachine(targetState: .clientIdleServerIdle)
  561. XCTAssertThrowsError(
  562. ofType: RPCError.self,
  563. try stateMachine.nextOutboundFrame()
  564. ) { error in
  565. XCTAssertEqual(error.code, .internalError)
  566. XCTAssertEqual(error.message, "Client is not open yet.")
  567. }
  568. }
  569. func testNextOutboundMessageWhenClientOpenAndServerOpenOrIdle() throws {
  570. for targetState in [TargetStateMachineState.clientOpenServerIdle, .clientOpenServerOpen] {
  571. var stateMachine = self.makeClientStateMachine(targetState: targetState)
  572. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .awaitMoreMessages)
  573. XCTAssertNoThrow(try stateMachine.send(message: [42, 42], promise: nil))
  574. let expectedBytes: [UInt8] = [
  575. 0, // compression flag: unset
  576. 0, 0, 0, 2, // message length: 2 bytes
  577. 42, 42, // original message
  578. ]
  579. XCTAssertEqual(
  580. try stateMachine.nextOutboundFrame(),
  581. .sendFrame(frame: ByteBuffer(bytes: expectedBytes), promise: nil)
  582. )
  583. // And then make sure that nothing else is returned anymore
  584. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .awaitMoreMessages)
  585. }
  586. }
  587. func testNextOutboundMessageWhenClientOpenAndServerIdle_WithCompression() throws {
  588. var stateMachine = self.makeClientStateMachine(
  589. targetState: .clientOpenServerIdle,
  590. compressionEnabled: true
  591. )
  592. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .awaitMoreMessages)
  593. let originalMessage = [UInt8]([42, 42, 43, 43])
  594. XCTAssertNoThrow(try stateMachine.send(message: originalMessage, promise: nil))
  595. let request = try stateMachine.nextOutboundFrame()
  596. let framedMessage = try self.frameMessage(originalMessage, compress: true)
  597. XCTAssertEqual(request, .sendFrame(frame: framedMessage, promise: nil))
  598. }
  599. func testNextOutboundMessageWhenClientOpenAndServerOpen_WithCompression() throws {
  600. var stateMachine = self.makeClientStateMachine(
  601. targetState: .clientOpenServerOpen,
  602. compressionEnabled: true
  603. )
  604. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .awaitMoreMessages)
  605. let originalMessage = [UInt8]([42, 42, 43, 43])
  606. XCTAssertNoThrow(try stateMachine.send(message: originalMessage, promise: nil))
  607. let request = try stateMachine.nextOutboundFrame()
  608. let framedMessage = try self.frameMessage(originalMessage, compress: true)
  609. XCTAssertEqual(request, .sendFrame(frame: framedMessage, promise: nil))
  610. }
  611. func testNextOutboundMessageWhenClientOpenAndServerClosed() throws {
  612. var stateMachine = self.makeClientStateMachine(targetState: .clientOpenServerClosed)
  613. // No more messages to send
  614. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .noMoreMessages)
  615. // Queue a message, but assert the action is .noMoreMessages nevertheless,
  616. // because the server is closed.
  617. XCTAssertNoThrow(try stateMachine.send(message: [42, 42], promise: nil))
  618. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .noMoreMessages)
  619. }
  620. func testNextOutboundMessageWhenClientClosedAndServerIdle() throws {
  621. var stateMachine = self.makeClientStateMachine(targetState: .clientOpenServerIdle)
  622. // Send a message and close client
  623. XCTAssertNoThrow(try stateMachine.send(message: [42, 42], promise: nil))
  624. XCTAssertNoThrow(try stateMachine.closeOutbound())
  625. // Make sure that getting the next outbound message _does_ return the message
  626. // we have enqueued.
  627. let request = try stateMachine.nextOutboundFrame()
  628. let expectedBytes: [UInt8] = [
  629. 0, // compression flag: unset
  630. 0, 0, 0, 2, // message length: 2 bytes
  631. 42, 42, // original message
  632. ]
  633. XCTAssertEqual(request, .sendFrame(frame: ByteBuffer(bytes: expectedBytes), promise: nil))
  634. // And then make sure that nothing else is returned anymore
  635. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .noMoreMessages)
  636. }
  637. func testNextOutboundMessageWhenClientClosedAndServerOpen() throws {
  638. var stateMachine = self.makeClientStateMachine(targetState: .clientOpenServerOpen)
  639. // Send a message and close client
  640. XCTAssertNoThrow(try stateMachine.send(message: [42, 42], promise: nil))
  641. XCTAssertNoThrow(try stateMachine.closeOutbound())
  642. // Make sure that getting the next outbound message _does_ return the message
  643. // we have enqueued.
  644. let request = try stateMachine.nextOutboundFrame()
  645. let expectedBytes: [UInt8] = [
  646. 0, // compression flag: unset
  647. 0, 0, 0, 2, // message length: 2 bytes
  648. 42, 42, // original message
  649. ]
  650. XCTAssertEqual(request, .sendFrame(frame: ByteBuffer(bytes: expectedBytes), promise: nil))
  651. // And then make sure that nothing else is returned anymore
  652. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .noMoreMessages)
  653. }
  654. func testNextOutboundMessageWhenClientClosedAndServerClosed() throws {
  655. var stateMachine = self.makeClientStateMachine(targetState: .clientOpenServerOpen)
  656. // Send a message
  657. XCTAssertNoThrow(try stateMachine.send(message: [42, 42], promise: nil))
  658. // Close server
  659. XCTAssertNoThrow(try stateMachine.receive(headers: .serverTrailers, endStream: true))
  660. // Close client
  661. XCTAssertNoThrow(try stateMachine.closeOutbound())
  662. // Even though we have enqueued a message, don't send it, because the server
  663. // is closed.
  664. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .noMoreMessages)
  665. }
  666. // - MARK: Next inbound message
  667. func testNextInboundMessageWhenServerIdle() {
  668. for targetState in [
  669. TargetStateMachineState.clientIdleServerIdle, .clientOpenServerIdle, .clientClosedServerIdle,
  670. ] {
  671. var stateMachine = self.makeClientStateMachine(targetState: targetState)
  672. XCTAssertEqual(stateMachine.nextInboundMessage(), .awaitMoreMessages)
  673. }
  674. }
  675. func testNextInboundMessageWhenClientOpenAndServerOpen() throws {
  676. var stateMachine = self.makeClientStateMachine(targetState: .clientOpenServerOpen)
  677. let receivedBytes = ByteBuffer(bytes: [
  678. 0, // compression flag: unset
  679. 0, 0, 0, 2, // message length: 2 bytes
  680. 42, 42, // original message
  681. ])
  682. try stateMachine.receive(buffer: receivedBytes, endStream: false)
  683. XCTAssertEqual(stateMachine.nextInboundMessage(), .receiveMessage([42, 42]))
  684. XCTAssertEqual(stateMachine.nextInboundMessage(), .awaitMoreMessages)
  685. }
  686. func testNextInboundMessageWhenClientOpenAndServerOpen_WithCompression() throws {
  687. var stateMachine = self.makeClientStateMachine(
  688. targetState: .clientOpenServerOpen,
  689. compressionEnabled: true
  690. )
  691. let originalMessage = [UInt8]([42, 42, 43, 43])
  692. let receivedBytes = try self.frameMessage(originalMessage, compress: true)
  693. try stateMachine.receive(buffer: receivedBytes, endStream: false)
  694. XCTAssertEqual(stateMachine.nextInboundMessage(), .receiveMessage(originalMessage))
  695. XCTAssertEqual(stateMachine.nextInboundMessage(), .awaitMoreMessages)
  696. }
  697. func testNextInboundMessageWhenClientOpenAndServerClosed() throws {
  698. var stateMachine = self.makeClientStateMachine(targetState: .clientOpenServerOpen)
  699. let receivedBytes = ByteBuffer(bytes: [
  700. 0, // compression flag: unset
  701. 0, 0, 0, 2, // message length: 2 bytes
  702. 42, 42, // original message
  703. ])
  704. try stateMachine.receive(buffer: receivedBytes, endStream: false)
  705. // Close server
  706. XCTAssertNoThrow(try stateMachine.receive(headers: .serverTrailers, endStream: true))
  707. XCTAssertEqual(stateMachine.nextInboundMessage(), .receiveMessage([42, 42]))
  708. XCTAssertEqual(stateMachine.nextInboundMessage(), .noMoreMessages)
  709. }
  710. func testNextInboundMessageWhenClientClosedAndServerOpen() throws {
  711. var stateMachine = self.makeClientStateMachine(targetState: .clientOpenServerOpen)
  712. let receivedBytes = ByteBuffer(bytes: [
  713. 0, // compression flag: unset
  714. 0, 0, 0, 2, // message length: 2 bytes
  715. 42, 42, // original message
  716. ])
  717. try stateMachine.receive(buffer: receivedBytes, endStream: false)
  718. // Close client
  719. XCTAssertNoThrow(try stateMachine.closeOutbound())
  720. // Even though the client is closed, because it received a message while open,
  721. // we must get the message now.
  722. XCTAssertEqual(stateMachine.nextInboundMessage(), .receiveMessage([42, 42]))
  723. XCTAssertEqual(stateMachine.nextInboundMessage(), .awaitMoreMessages)
  724. }
  725. func testNextInboundMessageWhenClientClosedAndServerClosed() throws {
  726. var stateMachine = self.makeClientStateMachine(targetState: .clientOpenServerOpen)
  727. let receivedBytes = ByteBuffer(bytes: [
  728. 0, // compression flag: unset
  729. 0, 0, 0, 2, // message length: 2 bytes
  730. 42, 42, // original message
  731. ])
  732. try stateMachine.receive(buffer: receivedBytes, endStream: false)
  733. // Close server
  734. XCTAssertNoThrow(try stateMachine.receive(headers: .serverTrailers, endStream: true))
  735. // Close client
  736. XCTAssertNoThrow(try stateMachine.closeOutbound())
  737. // Even though the client is closed, because it received a message while open,
  738. // we must get the message now.
  739. XCTAssertEqual(stateMachine.nextInboundMessage(), .receiveMessage([42, 42]))
  740. XCTAssertEqual(stateMachine.nextInboundMessage(), .noMoreMessages)
  741. }
  742. // - MARK: Common paths
  743. func testNormalFlow() throws {
  744. var stateMachine = self.makeClientStateMachine(targetState: .clientIdleServerIdle)
  745. // Client sends metadata
  746. let clientInitialMetadata = try stateMachine.send(metadata: .init())
  747. XCTAssertEqual(
  748. clientInitialMetadata,
  749. [
  750. GRPCHTTP2Keys.path.rawValue: "test/test",
  751. GRPCHTTP2Keys.scheme.rawValue: "http",
  752. GRPCHTTP2Keys.method.rawValue: "POST",
  753. GRPCHTTP2Keys.contentType.rawValue: "application/grpc",
  754. GRPCHTTP2Keys.te.rawValue: "trailers",
  755. GRPCHTTP2Keys.acceptEncoding.rawValue: "deflate",
  756. ]
  757. )
  758. // Server sends initial metadata
  759. let serverInitialHeadersAction = try stateMachine.receive(
  760. headers: .serverInitialMetadata,
  761. endStream: false
  762. )
  763. XCTAssertEqual(
  764. serverInitialHeadersAction,
  765. .receivedMetadata([
  766. ":status": "200",
  767. "content-type": "application/grpc",
  768. "grpc-accept-encoding": "deflate",
  769. ])
  770. )
  771. // Client sends messages
  772. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .awaitMoreMessages)
  773. let message = [UInt8]([1, 2, 3, 4])
  774. let framedMessage = try self.frameMessage(message, compress: false)
  775. try stateMachine.send(message: message, promise: nil)
  776. XCTAssertEqual(
  777. try stateMachine.nextOutboundFrame(),
  778. .sendFrame(frame: framedMessage, promise: nil)
  779. )
  780. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .awaitMoreMessages)
  781. // Server sends response
  782. XCTAssertEqual(stateMachine.nextInboundMessage(), .awaitMoreMessages)
  783. let firstResponseBytes = [UInt8]([5, 6, 7])
  784. let firstResponse = try self.frameMessage(firstResponseBytes, compress: false)
  785. let secondResponseBytes = [UInt8]([8, 9, 10])
  786. let secondResponse = try self.frameMessage(secondResponseBytes, compress: false)
  787. try stateMachine.receive(buffer: firstResponse, endStream: false)
  788. try stateMachine.receive(buffer: secondResponse, endStream: false)
  789. // Make sure messages have arrived
  790. XCTAssertEqual(stateMachine.nextInboundMessage(), .receiveMessage(firstResponseBytes))
  791. XCTAssertEqual(stateMachine.nextInboundMessage(), .receiveMessage(secondResponseBytes))
  792. XCTAssertEqual(stateMachine.nextInboundMessage(), .awaitMoreMessages)
  793. // Client sends end
  794. XCTAssertNoThrow(try stateMachine.closeOutbound())
  795. // Server ends
  796. let metadataReceivedAction = try stateMachine.receive(
  797. headers: .serverTrailers,
  798. endStream: true
  799. )
  800. let receivedMetadata = {
  801. var m = Metadata(headers: .serverTrailers)
  802. m.removeAllValues(forKey: GRPCHTTP2Keys.grpcStatus.rawValue)
  803. m.removeAllValues(forKey: GRPCHTTP2Keys.grpcStatusMessage.rawValue)
  804. return m
  805. }()
  806. XCTAssertEqual(
  807. metadataReceivedAction,
  808. .receivedStatusAndMetadata(status: .init(code: .ok, message: ""), metadata: receivedMetadata)
  809. )
  810. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .noMoreMessages)
  811. XCTAssertEqual(stateMachine.nextInboundMessage(), .noMoreMessages)
  812. }
  813. func testClientClosesBeforeServerOpens() throws {
  814. var stateMachine = self.makeClientStateMachine(targetState: .clientIdleServerIdle)
  815. // Client sends metadata
  816. let clientInitialMetadata = try stateMachine.send(metadata: .init())
  817. XCTAssertEqual(
  818. clientInitialMetadata,
  819. [
  820. GRPCHTTP2Keys.path.rawValue: "test/test",
  821. GRPCHTTP2Keys.scheme.rawValue: "http",
  822. GRPCHTTP2Keys.method.rawValue: "POST",
  823. GRPCHTTP2Keys.contentType.rawValue: "application/grpc",
  824. GRPCHTTP2Keys.te.rawValue: "trailers",
  825. GRPCHTTP2Keys.acceptEncoding.rawValue: "deflate",
  826. ]
  827. )
  828. // Client sends messages and ends
  829. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .awaitMoreMessages)
  830. let message = [UInt8]([1, 2, 3, 4])
  831. let framedMessage = try self.frameMessage(message, compress: false)
  832. XCTAssertNoThrow(try stateMachine.send(message: message, promise: nil))
  833. XCTAssertNoThrow(try stateMachine.closeOutbound())
  834. XCTAssertEqual(
  835. try stateMachine.nextOutboundFrame(),
  836. .sendFrame(frame: framedMessage, promise: nil)
  837. )
  838. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .noMoreMessages)
  839. // Server sends initial metadata
  840. let serverInitialHeadersAction = try stateMachine.receive(
  841. headers: .serverInitialMetadata,
  842. endStream: false
  843. )
  844. XCTAssertEqual(
  845. serverInitialHeadersAction,
  846. .receivedMetadata([
  847. ":status": "200",
  848. "content-type": "application/grpc",
  849. "grpc-accept-encoding": "deflate",
  850. ])
  851. )
  852. // Server sends response
  853. XCTAssertEqual(stateMachine.nextInboundMessage(), .awaitMoreMessages)
  854. let firstResponseBytes = [UInt8]([5, 6, 7])
  855. let firstResponse = try self.frameMessage(firstResponseBytes, compress: false)
  856. let secondResponseBytes = [UInt8]([8, 9, 10])
  857. let secondResponse = try self.frameMessage(secondResponseBytes, compress: false)
  858. try stateMachine.receive(buffer: firstResponse, endStream: false)
  859. try stateMachine.receive(buffer: secondResponse, endStream: false)
  860. // Make sure messages have arrived
  861. XCTAssertEqual(stateMachine.nextInboundMessage(), .receiveMessage(firstResponseBytes))
  862. XCTAssertEqual(stateMachine.nextInboundMessage(), .receiveMessage(secondResponseBytes))
  863. XCTAssertEqual(stateMachine.nextInboundMessage(), .awaitMoreMessages)
  864. // Server ends
  865. let metadataReceivedAction = try stateMachine.receive(
  866. headers: .serverTrailers,
  867. endStream: true
  868. )
  869. let receivedMetadata = {
  870. var m = Metadata(headers: .serverTrailers)
  871. m.removeAllValues(forKey: GRPCHTTP2Keys.grpcStatus.rawValue)
  872. m.removeAllValues(forKey: GRPCHTTP2Keys.grpcStatusMessage.rawValue)
  873. return m
  874. }()
  875. XCTAssertEqual(
  876. metadataReceivedAction,
  877. .receivedStatusAndMetadata(status: .init(code: .ok, message: ""), metadata: receivedMetadata)
  878. )
  879. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .noMoreMessages)
  880. XCTAssertEqual(stateMachine.nextInboundMessage(), .noMoreMessages)
  881. }
  882. func testClientClosesBeforeServerResponds() throws {
  883. var stateMachine = self.makeClientStateMachine(targetState: .clientIdleServerIdle)
  884. // Client sends metadata
  885. let clientInitialMetadata = try stateMachine.send(metadata: .init())
  886. XCTAssertEqual(
  887. clientInitialMetadata,
  888. [
  889. GRPCHTTP2Keys.path.rawValue: "test/test",
  890. GRPCHTTP2Keys.scheme.rawValue: "http",
  891. GRPCHTTP2Keys.method.rawValue: "POST",
  892. GRPCHTTP2Keys.contentType.rawValue: "application/grpc",
  893. GRPCHTTP2Keys.te.rawValue: "trailers",
  894. GRPCHTTP2Keys.acceptEncoding.rawValue: "deflate",
  895. ]
  896. )
  897. // Client sends messages
  898. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .awaitMoreMessages)
  899. let message = [UInt8]([1, 2, 3, 4])
  900. let framedMessage = try self.frameMessage(message, compress: false)
  901. try stateMachine.send(message: message, promise: nil)
  902. XCTAssertEqual(
  903. try stateMachine.nextOutboundFrame(),
  904. .sendFrame(frame: framedMessage, promise: nil)
  905. )
  906. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .awaitMoreMessages)
  907. // Server sends initial metadata
  908. let serverInitialHeadersAction = try stateMachine.receive(
  909. headers: .serverInitialMetadata,
  910. endStream: false
  911. )
  912. XCTAssertEqual(
  913. serverInitialHeadersAction,
  914. .receivedMetadata([
  915. ":status": "200",
  916. "content-type": "application/grpc",
  917. "grpc-accept-encoding": "deflate",
  918. ])
  919. )
  920. // Client closes
  921. XCTAssertNoThrow(try stateMachine.closeOutbound())
  922. // Server sends response
  923. XCTAssertEqual(stateMachine.nextInboundMessage(), .awaitMoreMessages)
  924. let firstResponseBytes = [UInt8]([5, 6, 7])
  925. let firstResponse = try self.frameMessage(firstResponseBytes, compress: false)
  926. let secondResponseBytes = [UInt8]([8, 9, 10])
  927. let secondResponse = try self.frameMessage(secondResponseBytes, compress: false)
  928. try stateMachine.receive(buffer: firstResponse, endStream: false)
  929. try stateMachine.receive(buffer: secondResponse, endStream: false)
  930. // Make sure messages have arrived
  931. XCTAssertEqual(stateMachine.nextInboundMessage(), .receiveMessage(firstResponseBytes))
  932. XCTAssertEqual(stateMachine.nextInboundMessage(), .receiveMessage(secondResponseBytes))
  933. XCTAssertEqual(stateMachine.nextInboundMessage(), .awaitMoreMessages)
  934. // Server ends
  935. let metadataReceivedAction = try stateMachine.receive(
  936. headers: .serverTrailers,
  937. endStream: true
  938. )
  939. let receivedMetadata = {
  940. var m = Metadata(headers: .serverTrailers)
  941. m.removeAllValues(forKey: GRPCHTTP2Keys.grpcStatus.rawValue)
  942. m.removeAllValues(forKey: GRPCHTTP2Keys.grpcStatusMessage.rawValue)
  943. return m
  944. }()
  945. XCTAssertEqual(
  946. metadataReceivedAction,
  947. .receivedStatusAndMetadata(status: .init(code: .ok, message: ""), metadata: receivedMetadata)
  948. )
  949. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .noMoreMessages)
  950. XCTAssertEqual(stateMachine.nextInboundMessage(), .noMoreMessages)
  951. }
  952. }
  953. @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
  954. final class GRPCStreamServerStateMachineTests: XCTestCase {
  955. private func makeServerStateMachine(
  956. targetState: TargetStateMachineState,
  957. compressionEnabled: Bool = false
  958. ) -> GRPCStreamStateMachine {
  959. var stateMachine = GRPCStreamStateMachine(
  960. configuration: .server(
  961. .init(
  962. scheme: .http,
  963. acceptedEncodings: [.deflate]
  964. )
  965. ),
  966. maximumPayloadSize: 100,
  967. skipAssertions: true
  968. )
  969. let clientMetadata: HPACKHeaders =
  970. compressionEnabled ? .clientInitialMetadataWithDeflateCompression : .clientInitialMetadata
  971. switch targetState {
  972. case .clientIdleServerIdle:
  973. break
  974. case .clientOpenServerIdle:
  975. // Open client
  976. XCTAssertNoThrow(try stateMachine.receive(headers: clientMetadata, endStream: false))
  977. case .clientOpenServerOpen:
  978. // Open client
  979. XCTAssertNoThrow(try stateMachine.receive(headers: clientMetadata, endStream: false))
  980. // Open server
  981. XCTAssertNoThrow(try stateMachine.send(metadata: Metadata(headers: .serverInitialMetadata)))
  982. case .clientOpenServerClosed:
  983. // Open client
  984. XCTAssertNoThrow(try stateMachine.receive(headers: clientMetadata, endStream: false))
  985. // Open server
  986. XCTAssertNoThrow(try stateMachine.send(metadata: Metadata(headers: .serverInitialMetadata)))
  987. // Close server
  988. XCTAssertNoThrow(
  989. try stateMachine.send(
  990. status: .init(code: .ok, message: ""),
  991. metadata: []
  992. )
  993. )
  994. case .clientClosedServerIdle:
  995. // Open client
  996. XCTAssertNoThrow(try stateMachine.receive(headers: clientMetadata, endStream: false))
  997. // Close client
  998. XCTAssertNoThrow(try stateMachine.receive(buffer: .init(), endStream: true))
  999. case .clientClosedServerOpen:
  1000. // Open client
  1001. XCTAssertNoThrow(try stateMachine.receive(headers: clientMetadata, endStream: false))
  1002. // Open server
  1003. XCTAssertNoThrow(try stateMachine.send(metadata: Metadata(headers: .serverInitialMetadata)))
  1004. // Close client
  1005. XCTAssertNoThrow(try stateMachine.receive(buffer: .init(), endStream: true))
  1006. case .clientClosedServerClosed:
  1007. // Open client
  1008. XCTAssertNoThrow(try stateMachine.receive(headers: clientMetadata, endStream: false))
  1009. // Open server
  1010. XCTAssertNoThrow(try stateMachine.send(metadata: Metadata(headers: .serverInitialMetadata)))
  1011. // Close client
  1012. XCTAssertNoThrow(try stateMachine.receive(buffer: .init(), endStream: true))
  1013. // Close server
  1014. XCTAssertNoThrow(
  1015. try stateMachine.send(
  1016. status: .init(code: .ok, message: ""),
  1017. metadata: []
  1018. )
  1019. )
  1020. }
  1021. return stateMachine
  1022. }
  1023. // - MARK: Send Metadata
  1024. func testSendMetadataWhenClientIdleAndServerIdle() throws {
  1025. var stateMachine = self.makeServerStateMachine(targetState: .clientIdleServerIdle)
  1026. XCTAssertThrowsError(
  1027. ofType: RPCError.self,
  1028. try stateMachine.send(metadata: .init())
  1029. ) { error in
  1030. XCTAssertEqual(error.code, .internalError)
  1031. XCTAssertEqual(
  1032. error.message,
  1033. "Client cannot be idle if server is sending initial metadata: it must have opened."
  1034. )
  1035. }
  1036. }
  1037. func testSendMetadataWhenClientOpenAndServerIdle() throws {
  1038. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerIdle)
  1039. XCTAssertNoThrow(try stateMachine.send(metadata: .init()))
  1040. }
  1041. func testSendMetadataWhenClientOpenAndServerOpen() throws {
  1042. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerOpen)
  1043. // Try sending metadata again: should throw
  1044. XCTAssertThrowsError(
  1045. ofType: RPCError.self,
  1046. try stateMachine.send(metadata: .init())
  1047. ) { error in
  1048. XCTAssertEqual(error.code, .internalError)
  1049. XCTAssertEqual(error.message, "Server has already sent initial metadata.")
  1050. }
  1051. }
  1052. func testSendMetadataWhenClientOpenAndServerClosed() throws {
  1053. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerClosed)
  1054. // Try sending metadata again: should throw
  1055. XCTAssertThrowsError(ofType: RPCError.self, try stateMachine.send(metadata: .init())) { error in
  1056. XCTAssertEqual(error.code, .internalError)
  1057. XCTAssertEqual(error.message, "Server cannot send metadata if closed.")
  1058. }
  1059. }
  1060. func testSendMetadataWhenClientClosedAndServerIdle() throws {
  1061. var stateMachine = self.makeServerStateMachine(targetState: .clientClosedServerIdle)
  1062. // We should be allowed to send initial metadata if client is closed:
  1063. // client may be finished sending request but may still be awaiting response.
  1064. XCTAssertNoThrow(try stateMachine.send(metadata: .init()))
  1065. }
  1066. func testSendMetadataWhenClientClosedAndServerOpen() throws {
  1067. var stateMachine = self.makeServerStateMachine(targetState: .clientClosedServerOpen)
  1068. // Try sending metadata again: should throw
  1069. XCTAssertThrowsError(ofType: RPCError.self, try stateMachine.send(metadata: .init())) { error in
  1070. XCTAssertEqual(error.code, .internalError)
  1071. XCTAssertEqual(error.message, "Server has already sent initial metadata.")
  1072. }
  1073. }
  1074. func testSendMetadataWhenClientClosedAndServerClosed() throws {
  1075. var stateMachine = self.makeServerStateMachine(targetState: .clientClosedServerClosed)
  1076. // Try sending metadata again: should throw
  1077. XCTAssertThrowsError(ofType: RPCError.self, try stateMachine.send(metadata: .init())) { error in
  1078. XCTAssertEqual(error.code, .internalError)
  1079. XCTAssertEqual(error.message, "Server cannot send metadata if closed.")
  1080. }
  1081. }
  1082. // - MARK: Send Message
  1083. func testSendMessageWhenClientIdleAndServerIdle() {
  1084. var stateMachine = self.makeServerStateMachine(targetState: .clientIdleServerIdle)
  1085. XCTAssertThrowsError(
  1086. ofType: RPCError.self,
  1087. try stateMachine.send(message: [], promise: nil)
  1088. ) { error in
  1089. XCTAssertEqual(error.code, .internalError)
  1090. XCTAssertEqual(
  1091. error.message,
  1092. "Server must have sent initial metadata before sending a message."
  1093. )
  1094. }
  1095. }
  1096. func testSendMessageWhenClientOpenAndServerIdle() {
  1097. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerIdle)
  1098. // Now send a message
  1099. XCTAssertThrowsError(
  1100. ofType: RPCError.self,
  1101. try stateMachine.send(message: [], promise: nil)
  1102. ) { error in
  1103. XCTAssertEqual(error.code, .internalError)
  1104. XCTAssertEqual(
  1105. error.message,
  1106. "Server must have sent initial metadata before sending a message."
  1107. )
  1108. }
  1109. }
  1110. func testSendMessageWhenClientOpenAndServerOpen() {
  1111. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerOpen)
  1112. // Now send a message
  1113. XCTAssertNoThrow(try stateMachine.send(message: [], promise: nil))
  1114. }
  1115. func testSendMessageWhenClientOpenAndServerClosed() {
  1116. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerClosed)
  1117. // Try sending another message: it should fail
  1118. XCTAssertThrowsError(
  1119. ofType: RPCError.self,
  1120. try stateMachine.send(message: [], promise: nil)
  1121. ) { error in
  1122. XCTAssertEqual(error.code, .internalError)
  1123. XCTAssertEqual(error.message, "Server can't send a message if it's closed.")
  1124. }
  1125. }
  1126. func testSendMessageWhenClientClosedAndServerIdle() {
  1127. var stateMachine = self.makeServerStateMachine(targetState: .clientClosedServerIdle)
  1128. XCTAssertThrowsError(
  1129. ofType: RPCError.self,
  1130. try stateMachine.send(message: [], promise: nil)
  1131. ) { error in
  1132. XCTAssertEqual(error.code, .internalError)
  1133. XCTAssertEqual(
  1134. error.message,
  1135. "Server must have sent initial metadata before sending a message."
  1136. )
  1137. }
  1138. }
  1139. func testSendMessageWhenClientClosedAndServerOpen() {
  1140. var stateMachine = self.makeServerStateMachine(targetState: .clientClosedServerOpen)
  1141. // Try sending a message: even though client is closed, we should send it
  1142. // because it may be expecting a response.
  1143. XCTAssertNoThrow(try stateMachine.send(message: [], promise: nil))
  1144. }
  1145. func testSendMessageWhenClientClosedAndServerClosed() {
  1146. var stateMachine = self.makeServerStateMachine(targetState: .clientClosedServerClosed)
  1147. // Try sending another message: it should fail
  1148. XCTAssertThrowsError(
  1149. ofType: RPCError.self,
  1150. try stateMachine.send(message: [], promise: nil)
  1151. ) { error in
  1152. XCTAssertEqual(error.code, .internalError)
  1153. XCTAssertEqual(error.message, "Server can't send a message if it's closed.")
  1154. }
  1155. }
  1156. // - MARK: Send Status and Trailers
  1157. func testSendStatusAndTrailersWhenClientIdle() {
  1158. var stateMachine = self.makeServerStateMachine(targetState: .clientIdleServerIdle)
  1159. XCTAssertThrowsError(
  1160. ofType: RPCError.self,
  1161. try stateMachine.send(
  1162. status: .init(code: .ok, message: ""),
  1163. metadata: .init()
  1164. )
  1165. ) { error in
  1166. XCTAssertEqual(error.code, .internalError)
  1167. XCTAssertEqual(error.message, "Server can't send status if client is idle.")
  1168. }
  1169. }
  1170. func testSendStatusAndTrailersWhenClientOpenAndServerIdle() throws {
  1171. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerIdle)
  1172. let trailers = try stateMachine.send(
  1173. status: .init(code: .unknown, message: "RPC unknown"),
  1174. metadata: .init()
  1175. )
  1176. // Make sure it's a trailers-only response: it must have :status header and content-type
  1177. XCTAssertEqual(
  1178. trailers,
  1179. [
  1180. ":status": "200",
  1181. "content-type": "application/grpc",
  1182. "grpc-status": "2",
  1183. "grpc-status-message": "RPC unknown",
  1184. ]
  1185. )
  1186. // Try sending another message: it should fail because server is now closed.
  1187. XCTAssertThrowsError(
  1188. ofType: RPCError.self,
  1189. try stateMachine.send(message: [], promise: nil)
  1190. ) { error in
  1191. XCTAssertEqual(error.code, .internalError)
  1192. XCTAssertEqual(error.message, "Server can't send a message if it's closed.")
  1193. }
  1194. }
  1195. func testSendStatusAndTrailersWhenClientOpenAndServerOpen() throws {
  1196. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerOpen)
  1197. let trailers = try stateMachine.send(
  1198. status: .init(code: .ok, message: ""),
  1199. metadata: .init()
  1200. )
  1201. // Make sure it's NOT a trailers-only response, because the server was
  1202. // already open (so it sent initial metadata): it shouldn't have :status or content-type headers
  1203. XCTAssertEqual(trailers, ["grpc-status": "0"])
  1204. // Try sending another message: it should fail because server is now closed.
  1205. XCTAssertThrowsError(
  1206. ofType: RPCError.self,
  1207. try stateMachine.send(message: [], promise: nil)
  1208. ) { error in
  1209. XCTAssertEqual(error.code, .internalError)
  1210. XCTAssertEqual(error.message, "Server can't send a message if it's closed.")
  1211. }
  1212. }
  1213. func testSendStatusAndTrailersWhenClientOpenAndServerClosed() {
  1214. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerClosed)
  1215. XCTAssertThrowsError(
  1216. ofType: RPCError.self,
  1217. try stateMachine.send(
  1218. status: .init(code: .ok, message: ""),
  1219. metadata: .init()
  1220. )
  1221. ) { error in
  1222. XCTAssertEqual(error.code, .internalError)
  1223. XCTAssertEqual(error.message, "Server can't send anything if closed.")
  1224. }
  1225. }
  1226. func testSendStatusAndTrailersWhenClientClosedAndServerIdle() throws {
  1227. var stateMachine = self.makeServerStateMachine(targetState: .clientClosedServerIdle)
  1228. let trailers = try stateMachine.send(
  1229. status: .init(code: .unknown, message: "RPC unknown"),
  1230. metadata: .init()
  1231. )
  1232. // Make sure it's a trailers-only response: it must have :status header and content-type
  1233. XCTAssertEqual(
  1234. trailers,
  1235. [
  1236. ":status": "200",
  1237. "content-type": "application/grpc",
  1238. "grpc-status": "2",
  1239. "grpc-status-message": "RPC unknown",
  1240. ]
  1241. )
  1242. // Try sending another message: it should fail because server is now closed.
  1243. XCTAssertThrowsError(
  1244. ofType: RPCError.self,
  1245. try stateMachine.send(message: [], promise: nil)
  1246. ) { error in
  1247. XCTAssertEqual(error.code, .internalError)
  1248. XCTAssertEqual(error.message, "Server can't send a message if it's closed.")
  1249. }
  1250. }
  1251. func testSendStatusAndTrailersWhenClientClosedAndServerOpen() throws {
  1252. var stateMachine = self.makeServerStateMachine(targetState: .clientClosedServerOpen)
  1253. let trailers = try stateMachine.send(
  1254. status: .init(code: .ok, message: ""),
  1255. metadata: .init()
  1256. )
  1257. // Make sure it's NOT a trailers-only response, because the server was
  1258. // already open (so it sent initial metadata): it shouldn't have :status or content-type headers
  1259. XCTAssertEqual(trailers, ["grpc-status": "0"])
  1260. // Try sending another message: it should fail because server is now closed.
  1261. XCTAssertThrowsError(
  1262. ofType: RPCError.self,
  1263. try stateMachine.send(message: [], promise: nil)
  1264. ) { error in
  1265. XCTAssertEqual(error.code, .internalError)
  1266. XCTAssertEqual(error.message, "Server can't send a message if it's closed.")
  1267. }
  1268. }
  1269. func testSendStatusAndTrailersWhenClientClosedAndServerClosed() {
  1270. var stateMachine = self.makeServerStateMachine(targetState: .clientClosedServerClosed)
  1271. XCTAssertThrowsError(
  1272. ofType: RPCError.self,
  1273. try stateMachine.send(
  1274. status: .init(code: .ok, message: ""),
  1275. metadata: .init()
  1276. )
  1277. ) { error in
  1278. XCTAssertEqual(error.code, .internalError)
  1279. XCTAssertEqual(error.message, "Server can't send anything if closed.")
  1280. }
  1281. }
  1282. // - MARK: Receive metadata
  1283. func testReceiveMetadataWhenClientIdleAndServerIdle() throws {
  1284. var stateMachine = self.makeServerStateMachine(targetState: .clientIdleServerIdle)
  1285. let action = try stateMachine.receive(headers: .clientInitialMetadata, endStream: false)
  1286. XCTAssertEqual(
  1287. action,
  1288. .receivedMetadata(Metadata(headers: .clientInitialMetadata))
  1289. )
  1290. }
  1291. func testReceiveMetadataWhenClientIdleAndServerIdle_WithEndStream() throws {
  1292. var stateMachine = self.makeServerStateMachine(targetState: .clientIdleServerIdle)
  1293. let action = try stateMachine.receive(headers: .clientInitialMetadata, endStream: true)
  1294. XCTAssertEqual(
  1295. action,
  1296. .receivedMetadata(Metadata(headers: .clientInitialMetadata))
  1297. )
  1298. }
  1299. func testReceiveMetadataWhenClientIdleAndServerIdle_MissingContentType() throws {
  1300. var stateMachine = self.makeServerStateMachine(targetState: .clientIdleServerIdle)
  1301. let action = try stateMachine.receive(
  1302. headers: .receivedWithoutContentType,
  1303. endStream: false
  1304. )
  1305. self.assertRejectedRPC(action) { trailers in
  1306. XCTAssertEqual(trailers.count, 1)
  1307. XCTAssertEqual(trailers.firstString(forKey: .status), "415")
  1308. }
  1309. }
  1310. func testReceiveMetadataWhenClientIdleAndServerIdle_InvalidContentType() throws {
  1311. var stateMachine = self.makeServerStateMachine(targetState: .clientIdleServerIdle)
  1312. let action = try stateMachine.receive(
  1313. headers: .receivedWithInvalidContentType,
  1314. endStream: false
  1315. )
  1316. self.assertRejectedRPC(action) { trailers in
  1317. XCTAssertEqual(trailers.count, 1)
  1318. XCTAssertEqual(trailers.firstString(forKey: .status), "415")
  1319. }
  1320. }
  1321. func testReceiveMetadataWhenClientIdleAndServerIdle_MissingPath() throws {
  1322. var stateMachine = self.makeServerStateMachine(targetState: .clientIdleServerIdle)
  1323. let action = try stateMachine.receive(
  1324. headers: .receivedWithoutEndpoint,
  1325. endStream: false
  1326. )
  1327. self.assertRejectedRPC(action) { trailers in
  1328. XCTAssertEqual(
  1329. trailers,
  1330. [
  1331. ":status": "200",
  1332. "content-type": "application/grpc",
  1333. "grpc-status": "12",
  1334. "grpc-status-message": "No :path header has been set.",
  1335. ]
  1336. )
  1337. }
  1338. }
  1339. func testReceiveMetadataWhenClientIdleAndServerIdle_MissingTE() throws {
  1340. var stateMachine = self.makeServerStateMachine(targetState: .clientIdleServerIdle)
  1341. let action = try stateMachine.receive(
  1342. headers: .receivedWithoutTE,
  1343. endStream: false
  1344. )
  1345. self.assertRejectedRPC(action) { trailers in
  1346. XCTAssertEqual(
  1347. trailers,
  1348. [
  1349. ":status": "200",
  1350. "content-type": "application/grpc",
  1351. "grpc-status": "3",
  1352. "grpc-status-message":
  1353. "\"te\" header is expected to be present and have a value of \"trailers\".",
  1354. ]
  1355. )
  1356. }
  1357. }
  1358. func testReceiveMetadataWhenClientIdleAndServerIdle_InvalidTE() throws {
  1359. var stateMachine = self.makeServerStateMachine(targetState: .clientIdleServerIdle)
  1360. let action = try stateMachine.receive(
  1361. headers: .receivedWithInvalidTE,
  1362. endStream: false
  1363. )
  1364. self.assertRejectedRPC(action) { trailers in
  1365. XCTAssertEqual(
  1366. trailers,
  1367. [
  1368. ":status": "200",
  1369. "content-type": "application/grpc",
  1370. "grpc-status": "3",
  1371. "grpc-status-message":
  1372. "\"te\" header is expected to be present and have a value of \"trailers\".",
  1373. ]
  1374. )
  1375. }
  1376. }
  1377. func testReceiveMetadataWhenClientIdleAndServerIdle_MissingMethod() throws {
  1378. var stateMachine = self.makeServerStateMachine(targetState: .clientIdleServerIdle)
  1379. let action = try stateMachine.receive(
  1380. headers: .receivedWithoutMethod,
  1381. endStream: false
  1382. )
  1383. self.assertRejectedRPC(action) { trailers in
  1384. XCTAssertEqual(
  1385. trailers,
  1386. [
  1387. ":status": "200",
  1388. "content-type": "application/grpc",
  1389. "grpc-status": "3",
  1390. "grpc-status-message":
  1391. ":method header is expected to be present and have a value of \"POST\".",
  1392. ]
  1393. )
  1394. }
  1395. }
  1396. func testReceiveMetadataWhenClientIdleAndServerIdle_InvalidMethod() throws {
  1397. var stateMachine = self.makeServerStateMachine(targetState: .clientIdleServerIdle)
  1398. let action = try stateMachine.receive(
  1399. headers: .receivedWithInvalidMethod,
  1400. endStream: false
  1401. )
  1402. self.assertRejectedRPC(action) { trailers in
  1403. XCTAssertEqual(
  1404. trailers,
  1405. [
  1406. ":status": "200",
  1407. "content-type": "application/grpc",
  1408. "grpc-status": "3",
  1409. "grpc-status-message":
  1410. ":method header is expected to be present and have a value of \"POST\".",
  1411. ]
  1412. )
  1413. }
  1414. }
  1415. func testReceiveMetadataWhenClientIdleAndServerIdle_MissingScheme() throws {
  1416. var stateMachine = self.makeServerStateMachine(targetState: .clientIdleServerIdle)
  1417. let action = try stateMachine.receive(
  1418. headers: .receivedWithoutScheme,
  1419. endStream: false
  1420. )
  1421. self.assertRejectedRPC(action) { trailers in
  1422. XCTAssertEqual(
  1423. trailers,
  1424. [
  1425. ":status": "200",
  1426. "content-type": "application/grpc",
  1427. "grpc-status": "3",
  1428. "grpc-status-message": ":scheme header must be present and one of \"http\" or \"https\".",
  1429. ]
  1430. )
  1431. }
  1432. }
  1433. func testReceiveMetadataWhenClientIdleAndServerIdle_InvalidScheme() throws {
  1434. var stateMachine = self.makeServerStateMachine(targetState: .clientIdleServerIdle)
  1435. let action = try stateMachine.receive(
  1436. headers: .receivedWithInvalidScheme,
  1437. endStream: false
  1438. )
  1439. self.assertRejectedRPC(action) { trailers in
  1440. XCTAssertEqual(
  1441. trailers,
  1442. [
  1443. ":status": "200",
  1444. "content-type": "application/grpc",
  1445. "grpc-status": "3",
  1446. "grpc-status-message": ":scheme header must be present and one of \"http\" or \"https\".",
  1447. ]
  1448. )
  1449. }
  1450. }
  1451. func testReceiveMetadataWhenClientIdleAndServerIdle_ServerUnsupportedEncoding() throws {
  1452. var stateMachine = self.makeServerStateMachine(targetState: .clientIdleServerIdle)
  1453. // Try opening client with a compression algorithm that is not accepted
  1454. // by the server.
  1455. let action = try stateMachine.receive(
  1456. headers: .clientInitialMetadataWithGzipCompression,
  1457. endStream: false
  1458. )
  1459. self.assertRejectedRPC(action) { trailers in
  1460. XCTAssertEqual(
  1461. trailers,
  1462. [
  1463. ":status": "200",
  1464. "content-type": "application/grpc",
  1465. "grpc-accept-encoding": "deflate",
  1466. "grpc-status": "12",
  1467. "grpc-status-message":
  1468. "gzip compression is not supported; supported algorithms are listed in grpc-accept-encoding",
  1469. ]
  1470. )
  1471. }
  1472. }
  1473. //TODO: add more encoding-related validation tests (for both client and server)
  1474. // and message encoding tests
  1475. func testReceiveMetadataWhenClientOpenAndServerIdle() throws {
  1476. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerIdle)
  1477. // Try receiving initial metadata again - should fail
  1478. XCTAssertThrowsError(
  1479. ofType: RPCError.self,
  1480. try stateMachine.receive(headers: .clientInitialMetadata, endStream: false)
  1481. ) { error in
  1482. XCTAssertEqual(error.code, .internalError)
  1483. XCTAssertEqual(error.message, "Client shouldn't have sent metadata twice.")
  1484. }
  1485. }
  1486. func testReceiveMetadataWhenClientOpenAndServerOpen() throws {
  1487. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerOpen)
  1488. XCTAssertThrowsError(
  1489. ofType: RPCError.self,
  1490. try stateMachine.receive(headers: .clientInitialMetadata, endStream: false)
  1491. ) { error in
  1492. XCTAssertEqual(error.code, .internalError)
  1493. XCTAssertEqual(error.message, "Client shouldn't have sent metadata twice.")
  1494. }
  1495. }
  1496. func testReceiveMetadataWhenClientOpenAndServerClosed() {
  1497. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerClosed)
  1498. XCTAssertThrowsError(
  1499. ofType: RPCError.self,
  1500. try stateMachine.receive(headers: .clientInitialMetadata, endStream: false)
  1501. ) { error in
  1502. XCTAssertEqual(error.code, .internalError)
  1503. XCTAssertEqual(error.message, "Client shouldn't have sent metadata twice.")
  1504. }
  1505. }
  1506. func testReceiveMetadataWhenClientClosedAndServerIdle() {
  1507. var stateMachine = self.makeServerStateMachine(targetState: .clientClosedServerIdle)
  1508. XCTAssertThrowsError(
  1509. ofType: RPCError.self,
  1510. try stateMachine.receive(headers: .clientInitialMetadata, endStream: false)
  1511. ) { error in
  1512. XCTAssertEqual(error.code, .internalError)
  1513. XCTAssertEqual(error.message, "Client can't have sent metadata if closed.")
  1514. }
  1515. }
  1516. func testReceiveMetadataWhenClientClosedAndServerOpen() {
  1517. var stateMachine = self.makeServerStateMachine(targetState: .clientClosedServerOpen)
  1518. XCTAssertThrowsError(
  1519. ofType: RPCError.self,
  1520. try stateMachine.receive(headers: .clientInitialMetadata, endStream: false)
  1521. ) { error in
  1522. XCTAssertEqual(error.code, .internalError)
  1523. XCTAssertEqual(error.message, "Client can't have sent metadata if closed.")
  1524. }
  1525. }
  1526. func testReceiveMetadataWhenClientClosedAndServerClosed() {
  1527. var stateMachine = self.makeServerStateMachine(targetState: .clientClosedServerClosed)
  1528. XCTAssertThrowsError(
  1529. ofType: RPCError.self,
  1530. try stateMachine.receive(headers: .clientInitialMetadata, endStream: false)
  1531. ) { error in
  1532. XCTAssertEqual(error.code, .internalError)
  1533. XCTAssertEqual(error.message, "Client can't have sent metadata if closed.")
  1534. }
  1535. }
  1536. // - MARK: Receive message
  1537. func testReceiveMessageWhenClientIdleAndServerIdle() {
  1538. var stateMachine = self.makeServerStateMachine(targetState: .clientIdleServerIdle)
  1539. XCTAssertThrowsError(
  1540. ofType: RPCError.self,
  1541. try stateMachine.receive(buffer: .init(), endStream: false)
  1542. ) { error in
  1543. XCTAssertEqual(error.code, .internalError)
  1544. XCTAssertEqual(error.message, "Can't have received a message if client is idle.")
  1545. }
  1546. }
  1547. func testReceiveMessageWhenClientOpenAndServerIdle() {
  1548. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerIdle)
  1549. // Receive messages successfully: the second one should close client.
  1550. XCTAssertNoThrow(try stateMachine.receive(buffer: .init(), endStream: false))
  1551. XCTAssertNoThrow(try stateMachine.receive(buffer: .init(), endStream: true))
  1552. // Verify client is now closed
  1553. XCTAssertThrowsError(
  1554. ofType: RPCError.self,
  1555. try stateMachine.receive(buffer: .init(), endStream: false)
  1556. ) { error in
  1557. XCTAssertEqual(error.code, .internalError)
  1558. XCTAssertEqual(error.message, "Client can't send a message if closed.")
  1559. }
  1560. }
  1561. func testReceiveMessageWhenClientOpenAndServerOpen() throws {
  1562. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerOpen)
  1563. // Receive messages successfully: the second one should close client.
  1564. XCTAssertNoThrow(try stateMachine.receive(buffer: .init(), endStream: false))
  1565. XCTAssertNoThrow(try stateMachine.receive(buffer: .init(), endStream: true))
  1566. // Verify client is now closed
  1567. XCTAssertThrowsError(
  1568. ofType: RPCError.self,
  1569. try stateMachine.receive(buffer: .init(), endStream: false)
  1570. ) { error in
  1571. XCTAssertEqual(error.code, .internalError)
  1572. XCTAssertEqual(error.message, "Client can't send a message if closed.")
  1573. }
  1574. }
  1575. func testReceiveMessageWhenClientOpenAndServerClosed() {
  1576. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerClosed)
  1577. // Client is not done sending request, don't fail.
  1578. XCTAssertNoThrow(try stateMachine.receive(buffer: .init(), endStream: false))
  1579. }
  1580. func testReceiveMessageWhenClientClosedAndServerIdle() {
  1581. var stateMachine = self.makeServerStateMachine(targetState: .clientClosedServerIdle)
  1582. XCTAssertThrowsError(
  1583. ofType: RPCError.self,
  1584. try stateMachine.receive(buffer: .init(), endStream: false)
  1585. ) { error in
  1586. XCTAssertEqual(error.code, .internalError)
  1587. XCTAssertEqual(error.message, "Client can't send a message if closed.")
  1588. }
  1589. }
  1590. func testReceiveMessageWhenClientClosedAndServerOpen() {
  1591. var stateMachine = self.makeServerStateMachine(targetState: .clientClosedServerOpen)
  1592. XCTAssertThrowsError(
  1593. ofType: RPCError.self,
  1594. try stateMachine.receive(buffer: .init(), endStream: false)
  1595. ) { error in
  1596. XCTAssertEqual(error.code, .internalError)
  1597. XCTAssertEqual(error.message, "Client can't send a message if closed.")
  1598. }
  1599. }
  1600. func testReceiveMessageWhenClientClosedAndServerClosed() {
  1601. var stateMachine = self.makeServerStateMachine(targetState: .clientClosedServerClosed)
  1602. XCTAssertThrowsError(
  1603. ofType: RPCError.self,
  1604. try stateMachine.receive(buffer: .init(), endStream: false)
  1605. ) { error in
  1606. XCTAssertEqual(error.code, .internalError)
  1607. XCTAssertEqual(error.message, "Client can't send a message if closed.")
  1608. }
  1609. }
  1610. // - MARK: Next outbound message
  1611. func testNextOutboundMessageWhenClientIdleAndServerIdle() {
  1612. var stateMachine = self.makeServerStateMachine(targetState: .clientIdleServerIdle)
  1613. XCTAssertThrowsError(
  1614. ofType: RPCError.self,
  1615. try stateMachine.nextOutboundFrame()
  1616. ) { error in
  1617. XCTAssertEqual(error.code, .internalError)
  1618. XCTAssertEqual(error.message, "Server is not open yet.")
  1619. }
  1620. }
  1621. func testNextOutboundMessageWhenClientOpenAndServerIdle() throws {
  1622. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerIdle)
  1623. XCTAssertThrowsError(
  1624. ofType: RPCError.self,
  1625. try stateMachine.nextOutboundFrame()
  1626. ) { error in
  1627. XCTAssertEqual(error.code, .internalError)
  1628. XCTAssertEqual(error.message, "Server is not open yet.")
  1629. }
  1630. }
  1631. func testNextOutboundMessageWhenClientOpenAndServerIdle_WithCompression() throws {
  1632. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerIdle)
  1633. XCTAssertThrowsError(
  1634. ofType: RPCError.self,
  1635. try stateMachine.nextOutboundFrame()
  1636. ) { error in
  1637. XCTAssertEqual(error.code, .internalError)
  1638. XCTAssertEqual(error.message, "Server is not open yet.")
  1639. }
  1640. }
  1641. func testNextOutboundMessageWhenClientOpenAndServerOpen() throws {
  1642. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerOpen)
  1643. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .awaitMoreMessages)
  1644. XCTAssertNoThrow(try stateMachine.send(message: [42, 42], promise: nil))
  1645. let response = try stateMachine.nextOutboundFrame()
  1646. let expectedBytes: [UInt8] = [
  1647. 0, // compression flag: unset
  1648. 0, 0, 0, 2, // message length: 2 bytes
  1649. 42, 42, // original message
  1650. ]
  1651. XCTAssertEqual(response, .sendFrame(frame: ByteBuffer(bytes: expectedBytes), promise: nil))
  1652. // And then make sure that nothing else is returned
  1653. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .awaitMoreMessages)
  1654. }
  1655. func testNextOutboundMessageWhenClientOpenAndServerOpen_WithCompression() throws {
  1656. var stateMachine = self.makeServerStateMachine(
  1657. targetState: .clientOpenServerOpen,
  1658. compressionEnabled: true
  1659. )
  1660. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .awaitMoreMessages)
  1661. let originalMessage = [UInt8]([42, 42, 43, 43])
  1662. XCTAssertNoThrow(try stateMachine.send(message: originalMessage, promise: nil))
  1663. let response = try stateMachine.nextOutboundFrame()
  1664. let framedMessage = try self.frameMessage(originalMessage, compress: true)
  1665. XCTAssertEqual(response, .sendFrame(frame: framedMessage, promise: nil))
  1666. }
  1667. func testNextOutboundMessageWhenClientOpenAndServerClosed() throws {
  1668. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerOpen)
  1669. // Send message and close server
  1670. XCTAssertNoThrow(try stateMachine.send(message: [42, 42], promise: nil))
  1671. XCTAssertNoThrow(
  1672. try stateMachine.send(
  1673. status: .init(code: .ok, message: ""),
  1674. metadata: []
  1675. )
  1676. )
  1677. let response = try stateMachine.nextOutboundFrame()
  1678. let expectedBytes: [UInt8] = [
  1679. 0, // compression flag: unset
  1680. 0, 0, 0, 2, // message length: 2 bytes
  1681. 42, 42, // original message
  1682. ]
  1683. XCTAssertEqual(response, .sendFrame(frame: ByteBuffer(bytes: expectedBytes), promise: nil))
  1684. // And then make sure that nothing else is returned anymore
  1685. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .noMoreMessages)
  1686. }
  1687. func testNextOutboundMessageWhenClientClosedAndServerIdle() throws {
  1688. var stateMachine = self.makeServerStateMachine(targetState: .clientClosedServerIdle)
  1689. XCTAssertThrowsError(
  1690. ofType: RPCError.self,
  1691. try stateMachine.nextOutboundFrame()
  1692. ) { error in
  1693. XCTAssertEqual(error.code, .internalError)
  1694. XCTAssertEqual(error.message, "Server is not open yet.")
  1695. }
  1696. }
  1697. func testNextOutboundMessageWhenClientClosedAndServerOpen() throws {
  1698. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerOpen)
  1699. // Send a message
  1700. XCTAssertNoThrow(try stateMachine.send(message: [42, 42], promise: nil))
  1701. // Close client
  1702. XCTAssertNoThrow(try stateMachine.receive(buffer: .init(), endStream: true))
  1703. // Send another message
  1704. XCTAssertNoThrow(try stateMachine.send(message: [43, 43], promise: nil))
  1705. // Make sure that getting the next outbound message _does_ return the message
  1706. // we have enqueued.
  1707. let response = try stateMachine.nextOutboundFrame()
  1708. let expectedBytes: [UInt8] = [
  1709. 0, // compression flag: unset
  1710. 0, 0, 0, 2, // message length: 2 bytes
  1711. 42, 42, // original message
  1712. // End of first message - beginning of second
  1713. 0, // compression flag: unset
  1714. 0, 0, 0, 2, // message length: 2 bytes
  1715. 43, 43, // original message
  1716. ]
  1717. XCTAssertEqual(response, .sendFrame(frame: ByteBuffer(bytes: expectedBytes), promise: nil))
  1718. // And then make sure that nothing else is returned anymore
  1719. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .awaitMoreMessages)
  1720. }
  1721. func testNextOutboundMessageWhenClientClosedAndServerClosed() throws {
  1722. var stateMachine = self.makeServerStateMachine(targetState: .clientClosedServerOpen)
  1723. // Send a message and close server
  1724. XCTAssertNoThrow(try stateMachine.send(message: [42, 42], promise: nil))
  1725. XCTAssertNoThrow(
  1726. try stateMachine.send(
  1727. status: .init(code: .ok, message: ""),
  1728. metadata: []
  1729. )
  1730. )
  1731. // We have enqueued a message, make sure we return it even though server is closed,
  1732. // because we haven't yet drained all of the pending messages.
  1733. let response = try stateMachine.nextOutboundFrame()
  1734. let expectedBytes: [UInt8] = [
  1735. 0, // compression flag: unset
  1736. 0, 0, 0, 2, // message length: 2 bytes
  1737. 42, 42, // original message
  1738. ]
  1739. XCTAssertEqual(response, .sendFrame(frame: ByteBuffer(bytes: expectedBytes), promise: nil))
  1740. // And then make sure that nothing else is returned anymore
  1741. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .noMoreMessages)
  1742. }
  1743. // - MARK: Next inbound message
  1744. func testNextInboundMessageWhenClientIdleAndServerIdle() {
  1745. var stateMachine = self.makeServerStateMachine(targetState: .clientIdleServerIdle)
  1746. XCTAssertEqual(stateMachine.nextInboundMessage(), .awaitMoreMessages)
  1747. }
  1748. func testNextInboundMessageWhenClientOpenAndServerIdle() {
  1749. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerIdle)
  1750. XCTAssertEqual(stateMachine.nextInboundMessage(), .awaitMoreMessages)
  1751. }
  1752. func testNextInboundMessageWhenClientOpenAndServerOpen() throws {
  1753. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerOpen)
  1754. let receivedBytes = ByteBuffer(bytes: [
  1755. 0, // compression flag: unset
  1756. 0, 0, 0, 2, // message length: 2 bytes
  1757. 42, 42, // original message
  1758. ])
  1759. try stateMachine.receive(buffer: receivedBytes, endStream: false)
  1760. XCTAssertEqual(stateMachine.nextInboundMessage(), .receiveMessage([42, 42]))
  1761. XCTAssertEqual(stateMachine.nextInboundMessage(), .awaitMoreMessages)
  1762. }
  1763. func testNextInboundMessageWhenClientOpenAndServerOpen_WithCompression() throws {
  1764. var stateMachine = self.makeServerStateMachine(
  1765. targetState: .clientOpenServerOpen,
  1766. compressionEnabled: true
  1767. )
  1768. let originalMessage = [UInt8]([42, 42, 43, 43])
  1769. let receivedBytes = try self.frameMessage(originalMessage, compress: true)
  1770. try stateMachine.receive(buffer: receivedBytes, endStream: false)
  1771. XCTAssertEqual(stateMachine.nextInboundMessage(), .receiveMessage(originalMessage))
  1772. XCTAssertEqual(stateMachine.nextInboundMessage(), .awaitMoreMessages)
  1773. }
  1774. func testNextInboundMessageWhenClientOpenAndServerClosed() throws {
  1775. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerOpen)
  1776. let receivedBytes = ByteBuffer(bytes: [
  1777. 0, // compression flag: unset
  1778. 0, 0, 0, 2, // message length: 2 bytes
  1779. 42, 42, // original message
  1780. ])
  1781. try stateMachine.receive(buffer: receivedBytes, endStream: false)
  1782. // Close server
  1783. XCTAssertNoThrow(
  1784. try stateMachine.send(
  1785. status: .init(code: .ok, message: ""),
  1786. metadata: []
  1787. )
  1788. )
  1789. XCTAssertEqual(stateMachine.nextInboundMessage(), .receiveMessage([42, 42]))
  1790. XCTAssertEqual(stateMachine.nextInboundMessage(), .awaitMoreMessages)
  1791. }
  1792. func testNextInboundMessageWhenClientClosedAndServerIdle() {
  1793. var stateMachine = self.makeServerStateMachine(targetState: .clientClosedServerIdle)
  1794. XCTAssertEqual(stateMachine.nextInboundMessage(), .noMoreMessages)
  1795. }
  1796. func testNextInboundMessageWhenClientClosedAndServerOpen() throws {
  1797. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerOpen)
  1798. let receivedBytes = ByteBuffer(bytes: [
  1799. 0, // compression flag: unset
  1800. 0, 0, 0, 2, // message length: 2 bytes
  1801. 42, 42, // original message
  1802. ])
  1803. try stateMachine.receive(buffer: receivedBytes, endStream: false)
  1804. // Close client
  1805. XCTAssertNoThrow(try stateMachine.receive(buffer: .init(), endStream: true))
  1806. // Even though the client is closed, because the server received a message
  1807. // while it was still open, we must get the message now.
  1808. XCTAssertEqual(stateMachine.nextInboundMessage(), .receiveMessage([42, 42]))
  1809. XCTAssertEqual(stateMachine.nextInboundMessage(), .noMoreMessages)
  1810. }
  1811. func testNextInboundMessageWhenClientClosedAndServerClosed() throws {
  1812. var stateMachine = self.makeServerStateMachine(targetState: .clientOpenServerOpen)
  1813. let receivedBytes = ByteBuffer(bytes: [
  1814. 0, // compression flag: unset
  1815. 0, 0, 0, 2, // message length: 2 bytes
  1816. 42, 42, // original message
  1817. ])
  1818. try stateMachine.receive(buffer: receivedBytes, endStream: false)
  1819. // Close server
  1820. XCTAssertNoThrow(
  1821. try stateMachine.send(
  1822. status: .init(code: .ok, message: ""),
  1823. metadata: []
  1824. )
  1825. )
  1826. // Close client
  1827. XCTAssertNoThrow(try stateMachine.receive(buffer: .init(), endStream: true))
  1828. // Even though the client and server are closed, because the server received
  1829. // a message while the client was still open, we must get the message now.
  1830. XCTAssertEqual(stateMachine.nextInboundMessage(), .receiveMessage([42, 42]))
  1831. XCTAssertEqual(stateMachine.nextInboundMessage(), .noMoreMessages)
  1832. }
  1833. // - MARK: Common paths
  1834. func testNormalFlow() throws {
  1835. var stateMachine = self.makeServerStateMachine(targetState: .clientIdleServerIdle)
  1836. // Client sends metadata
  1837. let receiveMetadataAction = try stateMachine.receive(
  1838. headers: .clientInitialMetadata,
  1839. endStream: false
  1840. )
  1841. XCTAssertEqual(
  1842. receiveMetadataAction,
  1843. .receivedMetadata(Metadata(headers: .clientInitialMetadata))
  1844. )
  1845. // Server sends initial metadata
  1846. let sentInitialHeaders = try stateMachine.send(metadata: Metadata(headers: ["custom": "value"]))
  1847. XCTAssertEqual(
  1848. sentInitialHeaders,
  1849. [
  1850. ":status": "200",
  1851. "content-type": "application/grpc",
  1852. "grpc-accept-encoding": "deflate",
  1853. "custom": "value",
  1854. ]
  1855. )
  1856. // Client sends messages
  1857. let deframedMessage = [UInt8]([1, 2, 3, 4])
  1858. let completeMessage = try self.frameMessage(deframedMessage, compress: false)
  1859. // Split message into two parts to make sure the stitching together of the frames works well
  1860. let firstMessage = completeMessage.getSlice(at: 0, length: 4)!
  1861. let secondMessage = completeMessage.getSlice(at: 4, length: completeMessage.readableBytes - 4)!
  1862. try stateMachine.receive(buffer: firstMessage, endStream: false)
  1863. XCTAssertEqual(stateMachine.nextInboundMessage(), .awaitMoreMessages)
  1864. try stateMachine.receive(buffer: secondMessage, endStream: false)
  1865. XCTAssertEqual(stateMachine.nextInboundMessage(), .receiveMessage(deframedMessage))
  1866. // Server sends response
  1867. let eventLoop = EmbeddedEventLoop()
  1868. let firstPromise = eventLoop.makePromise(of: Void.self)
  1869. let secondPromise = eventLoop.makePromise(of: Void.self)
  1870. let firstResponse = [UInt8]([5, 6, 7])
  1871. let secondResponse = [UInt8]([8, 9, 10])
  1872. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .awaitMoreMessages)
  1873. try stateMachine.send(message: firstResponse, promise: firstPromise)
  1874. try stateMachine.send(message: secondResponse, promise: secondPromise)
  1875. // Make sure messages are outbound
  1876. let framedMessages = try self.frameMessages([firstResponse, secondResponse], compress: false)
  1877. guard
  1878. case .sendFrame(let nextOutboundByteBuffer, let nextOutboundPromise) =
  1879. try stateMachine.nextOutboundFrame()
  1880. else {
  1881. XCTFail("Should have received .sendMessage")
  1882. return
  1883. }
  1884. XCTAssertEqual(nextOutboundByteBuffer, framedMessages)
  1885. XCTAssertTrue(firstPromise.futureResult === nextOutboundPromise?.futureResult)
  1886. // Make sure that the promises associated with each sent message are chained
  1887. // together: when succeeding the one returned by the state machine on
  1888. // `nextOutboundMessage()`, the others should also be succeeded.
  1889. firstPromise.succeed()
  1890. try secondPromise.futureResult.assertSuccess().wait()
  1891. // Client sends end
  1892. try stateMachine.receive(buffer: ByteBuffer(), endStream: true)
  1893. // Server ends
  1894. let response = try stateMachine.send(
  1895. status: .init(code: .ok, message: ""),
  1896. metadata: []
  1897. )
  1898. XCTAssertEqual(response, ["grpc-status": "0"])
  1899. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .noMoreMessages)
  1900. XCTAssertEqual(stateMachine.nextInboundMessage(), .noMoreMessages)
  1901. }
  1902. func testClientClosesBeforeServerOpens() throws {
  1903. var stateMachine = self.makeServerStateMachine(targetState: .clientIdleServerIdle)
  1904. // Client sends metadata
  1905. let receiveMetadataAction = try stateMachine.receive(
  1906. headers: .clientInitialMetadata,
  1907. endStream: false
  1908. )
  1909. XCTAssertEqual(
  1910. receiveMetadataAction,
  1911. .receivedMetadata(Metadata(headers: .clientInitialMetadata))
  1912. )
  1913. // Client sends messages
  1914. let deframedMessage = [UInt8]([1, 2, 3, 4])
  1915. let completeMessage = try self.frameMessage(deframedMessage, compress: false)
  1916. // Split message into two parts to make sure the stitching together of the frames works well
  1917. let firstMessage = completeMessage.getSlice(at: 0, length: 4)!
  1918. let secondMessage = completeMessage.getSlice(at: 4, length: completeMessage.readableBytes - 4)!
  1919. try stateMachine.receive(buffer: firstMessage, endStream: false)
  1920. XCTAssertEqual(stateMachine.nextInboundMessage(), .awaitMoreMessages)
  1921. try stateMachine.receive(buffer: secondMessage, endStream: false)
  1922. XCTAssertEqual(stateMachine.nextInboundMessage(), .receiveMessage(deframedMessage))
  1923. // Client sends end
  1924. try stateMachine.receive(buffer: ByteBuffer(), endStream: true)
  1925. // Server sends initial metadata
  1926. let sentInitialHeaders = try stateMachine.send(metadata: Metadata(headers: ["custom": "value"]))
  1927. XCTAssertEqual(
  1928. sentInitialHeaders,
  1929. [
  1930. "custom": "value",
  1931. ":status": "200",
  1932. "content-type": "application/grpc",
  1933. "grpc-accept-encoding": "deflate",
  1934. ]
  1935. )
  1936. // Server sends response
  1937. let firstResponse = [UInt8]([5, 6, 7])
  1938. let secondResponse = [UInt8]([8, 9, 10])
  1939. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .awaitMoreMessages)
  1940. try stateMachine.send(message: firstResponse, promise: nil)
  1941. try stateMachine.send(message: secondResponse, promise: nil)
  1942. // Make sure messages are outbound
  1943. let framedMessages = try self.frameMessages([firstResponse, secondResponse], compress: false)
  1944. XCTAssertEqual(
  1945. try stateMachine.nextOutboundFrame(),
  1946. .sendFrame(frame: framedMessages, promise: nil)
  1947. )
  1948. // Server ends
  1949. let response = try stateMachine.send(
  1950. status: .init(code: .ok, message: ""),
  1951. metadata: []
  1952. )
  1953. XCTAssertEqual(response, ["grpc-status": "0"])
  1954. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .noMoreMessages)
  1955. XCTAssertEqual(stateMachine.nextInboundMessage(), .noMoreMessages)
  1956. }
  1957. func testClientClosesBeforeServerResponds() throws {
  1958. var stateMachine = self.makeServerStateMachine(targetState: .clientIdleServerIdle)
  1959. // Client sends metadata
  1960. let receiveMetadataAction = try stateMachine.receive(
  1961. headers: .clientInitialMetadata,
  1962. endStream: false
  1963. )
  1964. XCTAssertEqual(
  1965. receiveMetadataAction,
  1966. .receivedMetadata(Metadata(headers: .clientInitialMetadata))
  1967. )
  1968. // Client sends messages
  1969. let deframedMessage = [UInt8]([1, 2, 3, 4])
  1970. let completeMessage = try self.frameMessage(deframedMessage, compress: false)
  1971. // Split message into two parts to make sure the stitching together of the frames works well
  1972. let firstMessage = completeMessage.getSlice(at: 0, length: 4)!
  1973. let secondMessage = completeMessage.getSlice(at: 4, length: completeMessage.readableBytes - 4)!
  1974. try stateMachine.receive(buffer: firstMessage, endStream: false)
  1975. XCTAssertEqual(stateMachine.nextInboundMessage(), .awaitMoreMessages)
  1976. try stateMachine.receive(buffer: secondMessage, endStream: false)
  1977. XCTAssertEqual(stateMachine.nextInboundMessage(), .receiveMessage(deframedMessage))
  1978. // Server sends initial metadata
  1979. let sentInitialHeaders = try stateMachine.send(metadata: Metadata(headers: ["custom": "value"]))
  1980. XCTAssertEqual(
  1981. sentInitialHeaders,
  1982. [
  1983. "custom": "value",
  1984. ":status": "200",
  1985. "content-type": "application/grpc",
  1986. "grpc-accept-encoding": "deflate",
  1987. ]
  1988. )
  1989. // Client sends end
  1990. try stateMachine.receive(buffer: ByteBuffer(), endStream: true)
  1991. // Server sends response
  1992. let firstResponse = [UInt8]([5, 6, 7])
  1993. let secondResponse = [UInt8]([8, 9, 10])
  1994. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .awaitMoreMessages)
  1995. try stateMachine.send(message: firstResponse, promise: nil)
  1996. try stateMachine.send(message: secondResponse, promise: nil)
  1997. // Make sure messages are outbound
  1998. let framedMessages = try self.frameMessages([firstResponse, secondResponse], compress: false)
  1999. XCTAssertEqual(
  2000. try stateMachine.nextOutboundFrame(),
  2001. .sendFrame(frame: framedMessages, promise: nil)
  2002. )
  2003. // Server ends
  2004. let response = try stateMachine.send(
  2005. status: .init(code: .ok, message: ""),
  2006. metadata: []
  2007. )
  2008. XCTAssertEqual(response, ["grpc-status": "0"])
  2009. XCTAssertEqual(try stateMachine.nextOutboundFrame(), .noMoreMessages)
  2010. XCTAssertEqual(stateMachine.nextInboundMessage(), .noMoreMessages)
  2011. }
  2012. }
  2013. extension XCTestCase {
  2014. @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
  2015. func assertRejectedRPC(
  2016. _ action: GRPCStreamStateMachine.OnMetadataReceived,
  2017. expression: (HPACKHeaders) throws -> Void
  2018. ) rethrows {
  2019. guard case .rejectRPC(let trailers) = action else {
  2020. XCTFail("RPC should have been rejected.")
  2021. return
  2022. }
  2023. try expression(trailers)
  2024. }
  2025. func frameMessage(_ message: [UInt8], compress: Bool) throws -> ByteBuffer {
  2026. try frameMessages([message], compress: compress)
  2027. }
  2028. func frameMessages(_ messages: [[UInt8]], compress: Bool) throws -> ByteBuffer {
  2029. var framer = GRPCMessageFramer()
  2030. let compressor: Zlib.Compressor? = {
  2031. if compress {
  2032. return Zlib.Compressor(method: .deflate)
  2033. } else {
  2034. return nil
  2035. }
  2036. }()
  2037. defer { compressor?.end() }
  2038. for message in messages {
  2039. framer.append(message, promise: nil)
  2040. }
  2041. return try XCTUnwrap(framer.next(compressor: compressor)).bytes
  2042. }
  2043. }
  2044. @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
  2045. extension GRPCStreamStateMachine.OnNextOutboundFrame: Equatable {
  2046. public static func == (
  2047. lhs: GRPCStreamStateMachine.OnNextOutboundFrame,
  2048. rhs: GRPCStreamStateMachine.OnNextOutboundFrame
  2049. ) -> Bool {
  2050. switch (lhs, rhs) {
  2051. case (.noMoreMessages, .noMoreMessages):
  2052. return true
  2053. case (.awaitMoreMessages, .awaitMoreMessages):
  2054. return true
  2055. case (.sendFrame(let lhsMessage, _), .sendFrame(let rhsMessage, _)):
  2056. // Note that we're not comparing the EventLoopPromises here, as they're
  2057. // not Equatable. This is fine though, since we only use this in tests.
  2058. return lhsMessage == rhsMessage
  2059. default:
  2060. return false
  2061. }
  2062. }
  2063. }