24
24
import java .util .concurrent .atomic .AtomicBoolean ;
25
25
26
26
import graphql .schema .DataFetcher ;
27
+ import jakarta .servlet .AsyncEvent ;
28
+ import jakarta .servlet .AsyncListener ;
27
29
import jakarta .servlet .ServletException ;
28
30
import jakarta .servlet .ServletOutputStream ;
29
31
import jakarta .servlet .http .HttpServletResponse ;
35
37
import org .springframework .http .MediaType ;
36
38
import org .springframework .http .converter .HttpMessageConverter ;
37
39
import org .springframework .http .converter .json .MappingJackson2HttpMessageConverter ;
40
+ import org .springframework .mock .web .MockAsyncContext ;
38
41
import org .springframework .mock .web .MockHttpServletRequest ;
39
42
import org .springframework .mock .web .MockHttpServletResponse ;
40
43
import org .springframework .web .servlet .function .AsyncServerResponse ;
@@ -72,7 +75,7 @@ class GraphQlSseHandlerTests {
72
75
void shouldRejectQueryOperations () throws Exception {
73
76
GraphQlSseHandler handler = createSseHandler (SEARCH_DATA_FETCHER );
74
77
MockHttpServletRequest request = createServletRequest ("{ \" query\" : \" { bookById(id: 42) {name} }\" }" );
75
- MockHttpServletResponse response = handleRequest (request , handler );
78
+ MockHttpServletResponse response = handleAndAwait (request , handler );
76
79
77
80
assertThat (response .getContentType ()).isEqualTo (MediaType .TEXT_EVENT_STREAM_VALUE );
78
81
assertThat (response .getContentAsString ()).isEqualTo ("""
@@ -91,7 +94,7 @@ void shouldWriteMultipleEventsForSubscription() throws Exception {
91
94
MockHttpServletRequest request = createServletRequest ("""
92
95
{ "query": "subscription TestSubscription { bookSearch(author:\\ \" Orwell\\ \" ) { id name } }" }
93
96
""" );
94
- MockHttpServletResponse response = handleRequest (request , handler );
97
+ MockHttpServletResponse response = handleAndAwait (request , handler );
95
98
96
99
assertThat (response .getContentType ()).isEqualTo (MediaType .TEXT_EVENT_STREAM_VALUE );
97
100
assertThat (response .getContentAsString ()).isEqualTo ("""
@@ -117,7 +120,7 @@ void shouldWriteEventsAndTerminalError() throws Exception {
117
120
MockHttpServletRequest request = createServletRequest ("""
118
121
{ "query": "subscription TestSubscription { bookSearch(author:\\ \" Orwell\\ \" ) { id name } }" }
119
122
""" );
120
- MockHttpServletResponse response = handleRequest (request , handler );
123
+ MockHttpServletResponse response = handleAndAwait (request , handler );
121
124
122
125
assertThat (response .getContentType ()).isEqualTo (MediaType .TEXT_EVENT_STREAM_VALUE );
123
126
assertThat (response .getContentAsString ()).isEqualTo ("""
@@ -153,7 +156,26 @@ void shouldCancelDataFetcherPublisherWhenWritingFails() throws Exception {
153
156
154
157
response .writeTo (servletRequest , servletResponse , new DefaultContext ());
155
158
await ().atMost (Duration .ofMillis (500 )).until (DATA_FETCHER_CANCELLED ::get );
159
+ }
160
+
161
+ @ Test
162
+ void shouldCancelDataFetcherWhenAsyncTimeout () throws Exception {
163
+ DataFetcher <?> errorDataFetcher = env -> Flux .just (BookSource .getBook (1L ))
164
+ .delayElements (Duration .ofMillis (500 )).doOnCancel (() -> DATA_FETCHER_CANCELLED .set (true ));
165
+
166
+ GraphQlSseHandler handler = createSseHandler (errorDataFetcher );
167
+ MockHttpServletRequest servletRequest = createServletRequest ("""
168
+ { "query": "subscription TestSubscription { bookSearch(author:\\ \" Orwell\\ \" ) { id name } }" }
169
+ """ );
156
170
171
+ MockHttpServletResponse servletResponse = handleRequest (servletRequest , handler );
172
+ for (AsyncListener listener : ((MockAsyncContext ) servletRequest .getAsyncContext ()).getListeners ()) {
173
+ listener .onTimeout (new AsyncEvent (servletRequest .getAsyncContext ()));
174
+ }
175
+
176
+ assertThat (DATA_FETCHER_CANCELLED .get ()).isTrue ();
177
+ assertThat (servletResponse .getContentType ()).isEqualTo (MediaType .TEXT_EVENT_STREAM_VALUE );
178
+ assertThat (servletResponse .getContentAsString ()).isEmpty ();
157
179
}
158
180
159
181
private GraphQlSseHandler createSseHandler (DataFetcher <?> dataFetcher ) {
@@ -174,15 +196,19 @@ private MockHttpServletRequest createServletRequest(String query) {
174
196
175
197
private MockHttpServletResponse handleRequest (
176
198
MockHttpServletRequest servletRequest , GraphQlSseHandler handler ) throws ServletException , IOException {
177
-
178
199
ServerRequest request = ServerRequest .create (servletRequest , MESSAGE_READERS );
179
200
ServerResponse response = handler .handleRequest (request );
180
201
if (response instanceof AsyncServerResponse asyncResponse ) {
181
202
asyncResponse .block ();
182
203
}
183
-
184
204
MockHttpServletResponse servletResponse = new MockHttpServletResponse ();
185
205
response .writeTo (servletRequest , servletResponse , new DefaultContext ());
206
+ return servletResponse ;
207
+ }
208
+
209
+ private MockHttpServletResponse handleAndAwait (
210
+ MockHttpServletRequest servletRequest , GraphQlSseHandler handler ) throws ServletException , IOException {
211
+ MockHttpServletResponse servletResponse = handleRequest (servletRequest , handler );
186
212
await ().atMost (Duration .ofMillis (500 )).until (() -> servletResponse .getContentAsString ().contains ("complete" ));
187
213
return servletResponse ;
188
214
}
0 commit comments