Skip to content

Commit 9d36fd0

Browse files
committed
Respect async request timeout of -1 in MockMvc
When falling back on the timeout associated with the async request, a value of -1 must be treated as: never time out. Issue: SPR-16869
1 parent f078e05 commit 9d36fd0

File tree

4 files changed

+94
-10
lines changed

4 files changed

+94
-10
lines changed

spring-test/src/main/java/org/springframework/mock/web/MockAsyncContext.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,17 @@ public <T extends AsyncListener> T createListener(Class<T> clazz) throws Servlet
154154
return BeanUtils.instantiateClass(clazz);
155155
}
156156

157+
/**
158+
* By default this is set to 10000 (10 seconds) even though the Servlet API
159+
* specifies a default async request timeout of 30 seconds. Keep in mind the
160+
* timeout could further be impacted by global configuration through the MVC
161+
* Java config or the XML namespace, as well as be overridden per request on
162+
* {@link org.springframework.web.context.request.async.DeferredResult DeferredResult}
163+
* or on
164+
* {@link org.springframework.web.servlet.mvc.method.annotation.SseEmitter SseEmitter}.
165+
* @param timeout the timeout value to use.
166+
* @see AsyncContext#setTimeout(long)
167+
*/
157168
@Override
158169
public void setTimeout(long timeout) {
159170
this.timeout = timeout;

spring-test/src/main/java/org/springframework/test/web/servlet/DefaultMvcResult.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,9 @@ public Object getAsyncResult() {
138138

139139
@Override
140140
public Object getAsyncResult(long timeToWait) {
141-
if (this.mockRequest.getAsyncContext() != null) {
142-
timeToWait = (timeToWait == -1 ? this.mockRequest.getAsyncContext().getTimeout() : timeToWait);
141+
if (this.mockRequest.getAsyncContext() != null && timeToWait == -1) {
142+
long requestTimeout = this.mockRequest.getAsyncContext().getTimeout();
143+
timeToWait = requestTimeout == -1 ? Long.MAX_VALUE : requestTimeout;
143144
}
144145
if (!awaitAsyncDispatch(timeToWait)) {
145146
throw new IllegalStateException("Async result for handler [" + this.handler + "]" +

spring-test/src/main/java/org/springframework/test/web/servlet/MvcResult.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License; Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -80,19 +80,23 @@ public interface MvcResult {
8080
FlashMap getFlashMap();
8181

8282
/**
83-
* Get the result of async execution. This method will wait for the async result
84-
* to be set for up to the amount of time configured on the async request,
85-
* i.e. {@link org.springframework.mock.web.MockAsyncContext#getTimeout()}.
83+
* Get the result of async execution.
84+
* <p>This method will wait for the async result to be set within the
85+
* timeout value associated with the async request, see
86+
* {@link org.springframework.mock.web.MockAsyncContext#setTimeout
87+
* MockAsyncContext#setTimeout}. Alternatively, use
88+
* {@link #getAsyncResult(long)} to specify the amount of time to wait.
8689
* @throws IllegalStateException if the async result was not set
8790
*/
8891
Object getAsyncResult();
8992

9093
/**
91-
* Get the result of async execution. This method will wait for the async result
92-
* to be set for up to the specified amount of time.
94+
* Get the result of async execution and wait if necessary.
9395
* @param timeToWait how long to wait for the async result to be set, in
94-
* milliseconds; if -1, then the async request timeout value is used,
95-
* i.e.{@link org.springframework.mock.web.MockAsyncContext#getTimeout()}.
96+
* milliseconds; if -1, then fall back on the timeout value associated with
97+
* the async request, see
98+
* {@link org.springframework.mock.web.MockAsyncContext#setTimeout
99+
* MockAsyncContext#setTimeout} for more details.
96100
* @throws IllegalStateException if the async result was not set
97101
*/
98102
Object getAsyncResult(long timeToWait);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright 2002-2018 the original author or authors.
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+
package org.springframework.test.web.servlet.samples.standalone;
17+
18+
import java.time.Duration;
19+
20+
import org.junit.Test;
21+
import reactor.core.publisher.Flux;
22+
23+
import org.springframework.http.MediaType;
24+
import org.springframework.test.web.servlet.MockMvc;
25+
import org.springframework.test.web.servlet.MvcResult;
26+
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
27+
import org.springframework.web.bind.annotation.GetMapping;
28+
import org.springframework.web.bind.annotation.RestController;
29+
30+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
31+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
32+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request;
33+
34+
/**
35+
* Tests with reactive return value types.
36+
*
37+
* @author Rossen Stoyanchev
38+
*/
39+
public class ReactiveReturnTypeTests {
40+
41+
42+
@Test // SPR-16869
43+
public void sseWithFlux() throws Exception {
44+
45+
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(ReactiveController.class).build();
46+
47+
MvcResult mvcResult = mockMvc.perform(get("/spr16869"))
48+
.andExpect(request().asyncStarted())
49+
.andExpect(status().isOk())
50+
.andReturn();
51+
52+
mockMvc.perform(asyncDispatch(mvcResult))
53+
.andExpect(content().string("data:event0\n\ndata:event1\n\ndata:event2\n\n"));
54+
}
55+
56+
57+
58+
@RestController
59+
static class ReactiveController {
60+
61+
@GetMapping(path = "/spr16869", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
62+
Flux<String> sseFlux() {
63+
return Flux.interval(Duration.ofSeconds(1)).take(3)
64+
.map(aLong -> String.format("event%d", aLong));
65+
}
66+
}
67+
68+
}

0 commit comments

Comments
 (0)