34
34
import org .springframework .graphql .RequestInput ;
35
35
import org .springframework .graphql .data .method .annotation .Argument ;
36
36
import org .springframework .graphql .data .method .annotation .MutationMapping ;
37
+ import org .springframework .graphql .data .method .annotation .QueryMapping ;
38
+ import org .springframework .graphql .data .method .annotation .SubscriptionMapping ;
37
39
import org .springframework .graphql .data .method .annotation .support .AnnotatedControllerConfigurer ;
38
- import org .springframework .graphql .execution .BatchLoaderRegistry ;
39
- import org .springframework .graphql .execution .DefaultBatchLoaderRegistry ;
40
40
import org .springframework .graphql .execution .ExecutionGraphQlService ;
41
41
import org .springframework .graphql .execution .GraphQlSource ;
42
42
import org .springframework .integration .channel .FluxMessageChannel ;
57
57
58
58
import graphql .ExecutionResult ;
59
59
import graphql .ExecutionResultImpl ;
60
+ import graphql .execution .reactive .SubscriptionPublisher ;
60
61
import reactor .core .publisher .Flux ;
61
62
import reactor .core .publisher .Mono ;
62
63
import reactor .test .StepVerifier ;
66
67
* @author Daniel Frey
67
68
*
68
69
*/
69
- @ SpringJUnitConfig (GraphQlMutationMessageHandlerTests .TestConfig .class )
70
+ @ SpringJUnitConfig (GraphQlMessageHandlerTests .TestConfig .class )
70
71
@ DirtiesContext
71
- public class GraphQlMutationMessageHandlerTests {
72
+ public class GraphQlMessageHandlerTests {
72
73
73
74
@ Autowired
74
75
private FluxMessageChannel inputChannel ;
@@ -80,14 +81,11 @@ public class GraphQlMutationMessageHandlerTests {
80
81
private PollableChannel errorChannel ;
81
82
82
83
@ Autowired
83
- UpdateRepository updateRepository ;
84
+ private UpdateRepository updateRepository ;
84
85
85
86
@ Test
86
87
@ SuppressWarnings ("unchecked" )
87
- void testHandleMessageForMutation () {
88
-
89
- String fakeId = UUID .randomUUID ().toString ();
90
- Update expected = new Update (fakeId );
88
+ void testHandleMessageForQuery () {
91
89
92
90
StepVerifier verifier = StepVerifier .create (
93
91
Flux .from (this .resultChannel )
@@ -97,15 +95,46 @@ void testHandleMessageForMutation() {
97
95
.consumeNextWith (result -> {
98
96
assertThat (result ).isInstanceOf (ExecutionResultImpl .class );
99
97
Map <String , Object > data = result .getData ();
100
- Map <String , Object > update = (Map <String , Object >) data .get ("update" );
101
- assertThat (update .get ("id" )).isEqualTo (fakeId );
102
-
103
- assertThat (this .updateRepository .current ().block ()).isEqualTo (expected );
98
+ Map <String , Object > testQuery = (Map <String , Object >) data .get ("testQuery" );
99
+ assertThat (testQuery .get ("id" )).isEqualTo ("test-data" );
104
100
}
105
101
)
106
102
.thenCancel ()
107
103
.verifyLater ();
108
104
105
+ this .inputChannel .send (
106
+ MessageBuilder
107
+ .withPayload (new RequestInput ("{ testQuery { id } }" , null , Collections .emptyMap ()))
108
+ .build ()
109
+ );
110
+
111
+ verifier .verify (Duration .ofSeconds (10 ));
112
+ }
113
+
114
+ @ Test
115
+ @ SuppressWarnings ("unchecked" )
116
+ void testHandleMessageForMutation () {
117
+
118
+ String fakeId = UUID .randomUUID ().toString ();
119
+ Update expected = new Update (fakeId );
120
+
121
+ StepVerifier verifier = StepVerifier .create (
122
+ Flux .from (this .resultChannel )
123
+ .map (Message ::getPayload )
124
+ .cast (ExecutionResult .class )
125
+ )
126
+ .consumeNextWith (result -> {
127
+ assertThat (result ).isInstanceOf (ExecutionResultImpl .class );
128
+ Map <String , Object > data = result .getData ();
129
+ Map <String , Object > update = (Map <String , Object >) data .get ("update" );
130
+ assertThat (update .get ("id" )).isEqualTo (fakeId );
131
+
132
+ assertThat (this .updateRepository .current ().block ()).isEqualTo (expected );
133
+ }
134
+ )
135
+ .thenCancel ()
136
+ .verifyLater ();
137
+
109
138
this .inputChannel .send (
110
139
MessageBuilder
111
140
.withPayload (new RequestInput ("mutation { update(id: \" " + fakeId + "\" ) { id } }" , null , Collections .emptyMap ()))
@@ -121,9 +150,65 @@ void testHandleMessageForMutation() {
121
150
122
151
}
123
152
153
+ @ Test
154
+ @ SuppressWarnings ("unchecked" )
155
+ void testHandleMessageForSubscription () {
156
+
157
+ StepVerifier verifier = StepVerifier .create (
158
+ Flux .from (this .resultChannel )
159
+ .map (Message ::getPayload )
160
+ .cast (ExecutionResult .class )
161
+ .map (ExecutionResult ::getData )
162
+ .cast (SubscriptionPublisher .class )
163
+ .map (Flux ::from )
164
+ .flatMap (data -> data )
165
+ )
166
+ .consumeNextWith (executionResult -> {
167
+ Map <String , Object > results = (Map <String , Object >) executionResult .getData ();
168
+ assertThat (results ).containsKey ("results" );
169
+
170
+ Map <String , Object > queryResult = (Map <String , Object >) results .get ("results" );
171
+ assertThat (queryResult )
172
+ .containsKey ("id" )
173
+ .containsValue ("test-data-01" );
174
+
175
+ })
176
+ .expectNextCount (9 )
177
+ .thenCancel ()
178
+ .verifyLater ();
179
+
180
+ this .inputChannel .send (
181
+ MessageBuilder
182
+ .withPayload (new RequestInput ("subscription { results { id } }" , null , Collections .emptyMap ()))
183
+ .build ()
184
+ );
185
+
186
+ verifier .verify (Duration .ofSeconds (10 ));
187
+ }
188
+
124
189
@ Test
125
190
void testHandleMessageForQueryWithInvalidPayload () {
126
191
192
+ this .inputChannel .send (
193
+ MessageBuilder
194
+ .withPayload ("{ testQuery { id } }" )
195
+ .build ()
196
+ );
197
+
198
+ Message <?> errorMessage = errorChannel .receive (10_000 );
199
+ assertThat (errorMessage ).isNotNull ()
200
+ .isInstanceOf (ErrorMessage .class )
201
+ .extracting (Message ::getPayload )
202
+ .isInstanceOf (MessageHandlingException .class )
203
+ .satisfies ((ex ) -> assertThat ((Exception ) ex )
204
+ .hasMessageContaining (
205
+ "Message payload needs to be 'org.springframework.graphql.RequestInput'" ));
206
+
207
+ }
208
+
209
+ @ Test
210
+ void testHandleMessageForMutationWithInvalidPayload () {
211
+
127
212
String fakeId = UUID .randomUUID ().toString ();
128
213
129
214
this .inputChannel .send (
@@ -143,20 +228,61 @@ void testHandleMessageForQueryWithInvalidPayload() {
143
228
144
229
}
145
230
231
+ @ Test
232
+ void testHandleMessageForSubscriptionWithInvalidPayload () {
233
+
234
+ this .inputChannel .send (
235
+ MessageBuilder
236
+ .withPayload ("subscription { results { id } }" )
237
+ .build ()
238
+ );
239
+
240
+ Message <?> errorMessage = errorChannel .receive (10_000 );
241
+ assertThat (errorMessage ).isNotNull ()
242
+ .isInstanceOf (ErrorMessage .class )
243
+ .extracting (Message ::getPayload )
244
+ .isInstanceOf (MessageHandlingException .class )
245
+ .satisfies ((ex ) -> assertThat ((Exception ) ex )
246
+ .hasMessageContaining (
247
+ "Message payload needs to be 'org.springframework.graphql.RequestInput'" ));
248
+
249
+ }
250
+
146
251
@ Controller
147
- static class GraphqlMutationController {
252
+ static class GraphQlController {
148
253
149
254
final UpdateRepository updateRepository ;
150
255
151
- GraphqlMutationController (UpdateRepository updateRepository ) {
256
+ GraphQlController (UpdateRepository updateRepository ) {
152
257
this .updateRepository = updateRepository ;
153
258
}
154
259
260
+ @ QueryMapping
261
+ public Mono <QueryResult > testQuery () {
262
+ return Mono .just (new QueryResult ("test-data" ));
263
+ }
264
+
155
265
@ MutationMapping
156
266
public Mono <Update > update (@ Argument String id ) {
157
267
return this .updateRepository .save (new Update (id ));
158
268
}
159
269
270
+ @ SubscriptionMapping
271
+ public Flux <QueryResult > results () {
272
+ return Flux .just (
273
+ new QueryResult ("test-data-01" ),
274
+ new QueryResult ("test-data-02" ),
275
+ new QueryResult ("test-data-03" ),
276
+ new QueryResult ("test-data-04" ),
277
+ new QueryResult ("test-data-05" ),
278
+ new QueryResult ("test-data-06" ),
279
+ new QueryResult ("test-data-07" ),
280
+ new QueryResult ("test-data-08" ),
281
+ new QueryResult ("test-data-09" ),
282
+ new QueryResult ("test-data-10" )
283
+ );
284
+ }
285
+
160
286
}
161
287
162
288
@ Repository
@@ -206,18 +332,15 @@ UpdateRepository updateRepository() {
206
332
}
207
333
208
334
@ Bean
209
- GraphqlMutationController graphqlMutationController (final UpdateRepository updateRepository ) {
335
+ GraphQlController graphqlQueryController (final UpdateRepository updateRepository ) {
210
336
211
- return new GraphqlMutationController (updateRepository );
337
+ return new GraphQlController (updateRepository );
212
338
}
213
339
214
340
@ Bean
215
- GraphQlService graphQlService (GraphQlSource graphQlSource , BatchLoaderRegistry batchLoaderRegistry ) {
216
-
217
- ExecutionGraphQlService service = new ExecutionGraphQlService (graphQlSource );
218
- service .addDataLoaderRegistrar (batchLoaderRegistry );
341
+ GraphQlService graphQlService (GraphQlSource graphQlSource ) {
219
342
220
- return service ;
343
+ return new ExecutionGraphQlService ( graphQlSource ) ;
221
344
}
222
345
223
346
@ Bean
@@ -235,12 +358,43 @@ AnnotatedControllerConfigurer annotatedDataFetcherConfigurer() {
235
358
return new AnnotatedControllerConfigurer ();
236
359
}
237
360
238
- @ Bean
239
- BatchLoaderRegistry batchLoaderRegistry () {
361
+ }
362
+
363
+ static class QueryResult {
364
+
365
+ private final String id ;
366
+
367
+ QueryResult (final String id ) {
368
+ this .id = id ;
369
+ }
370
+
371
+ String getId () {
372
+ return this .id ;
373
+ }
240
374
241
- return new DefaultBatchLoaderRegistry ();
375
+ @ Override
376
+ public boolean equals (Object o ) {
377
+ if (this == o ) {
378
+ return true ;
379
+ }
380
+ if (!(o instanceof QueryResult )) {
381
+ return false ;
382
+ }
383
+ QueryResult that = (QueryResult ) o ;
384
+ return getId ().equals (that .getId ());
242
385
}
243
386
387
+ @ Override
388
+ public int hashCode () {
389
+ return Objects .hash (getId ());
390
+ }
391
+
392
+ @ Override
393
+ public String toString () {
394
+ return "QueryResult{" +
395
+ "id='" + id + '\'' +
396
+ '}' ;
397
+ }
244
398
}
245
399
246
400
static class Update {
0 commit comments