@@ -88,6 +88,107 @@ struct WebSocketTests {
8888 }
8989 }
9090
91+ @Test func subscriptionWithInitPayloadError( ) async throws {
92+ try await withApp { app in
93+ let pubsub = SimplePubSub < String > ( )
94+ let schema = try GraphQLSchema (
95+ subscription: GraphQLObjectType (
96+ name: " Subscription " ,
97+ fields: [
98+ " hello " : GraphQLField (
99+ type: GraphQLString,
100+ resolve: { source, _, _, _ in
101+ source as! String
102+ } ,
103+ subscribe: { _, _, _, _ in
104+ await pubsub. subscribe ( )
105+ }
106+ ) ,
107+ ]
108+ )
109+ )
110+
111+ struct InitPayload : Equatable , Codable , Sendable {
112+ let code : String
113+ }
114+ let acceptedCode = " abc "
115+
116+ app. graphql (
117+ schema: schema,
118+ config: . init(
119+ subscriptionProtocols: [ . websocket] ,
120+ websocket: . init(
121+ onWebSocketInit: { ( initPayload: InitPayload , _) in
122+ initPayload. code == acceptedCode
123+ }
124+ )
125+ )
126+ ) { inputs in
127+ // If the codes don't match, this will fail on the subscribe/execute request
128+ guard let codeIsValid = inputs. websocketInitResult, codeIsValid else {
129+ throw GraphQLError ( message: " Unauthorized " )
130+ }
131+ return EmptyContext ( )
132+ }
133+
134+ app. http. server. configuration. port = 0
135+ app. environment. arguments = [ " serve " ]
136+ try await app. startup ( )
137+ let port = try #require( app. http. server. shared. localAddress? . port)
138+ try await WebSocket . connect (
139+ to: " ws://localhost: \( port) /graphql " ,
140+ headers: [ " Connection " : " Upgrade " ] ,
141+ on: MultiThreadedEventLoopGroup ( numberOfThreads: 1 )
142+ ) { websocket in
143+ let decoder = JSONDecoder ( )
144+ websocket. onText { websocket, message in
145+ do {
146+ #expect( !message. starts ( with: " 44 " ) )
147+ let response = try #require( message. data ( using: . utf8) )
148+ if let _ = try ? decoder. decode ( GraphQLTransportWS . ConnectionAckResponse. self, from: response) {
149+ try await websocket. send ( #"""
150+ {
151+ "type": "subscribe",
152+ "payload": {
153+ "query": "subscription { hello }"
154+ },
155+ "id": "1"
156+ }
157+ """# )
158+ // Must wait for a few milliseconds for the subscription to get set up.
159+ try await Task . sleep ( for: . milliseconds( 10 ) )
160+ await pubsub. emit ( event: " World " )
161+ } else if let _ = try ? decoder. decode ( GraphQLTransportWS . NextResponse. self, from: response) {
162+ Issue . record ( " Expected Error: \( message) " )
163+ await pubsub. cancel ( )
164+ } else if let _ = try ? decoder. decode ( GraphQLTransportWS . CompleteResponse. self, from: response) {
165+ Issue . record ( " Expected Error: \( message) " )
166+ try await websocket. close ( )
167+ } else if let errorResult = try ? decoder. decode ( GraphQLTransportWS . ErrorResponse. self, from: response) {
168+ #expect( errorResult. payload [ 0 ] . message == " Unauthorized " )
169+ await pubsub. cancel ( )
170+ try await websocket. close ( )
171+ } else {
172+ Issue . record ( " Unrecognized message: \( message) " )
173+ return
174+ }
175+ } catch {
176+ Issue . record ( " WebSocket error: \( error) " )
177+ return
178+ }
179+ }
180+ do {
181+ // Send incorrect code, expect an "Unauthorized" error on the subscribe call
182+ try await websocket. send ( #"{"type": "connection_init", "payload": {"code": "def"}}"# )
183+ try await websocket. onClose. get ( )
184+ } catch {
185+ Issue . record ( " WebSocket error: \( error) " )
186+ return
187+ }
188+ }
189+ }
190+ }
191+
91192 @Test func subscription_GraphQLWS( ) async throws {
92193 try await withApp { app in
93194 let pubsub = SimplePubSub < String > ( )
0 commit comments