MockMvc - IllegalStateException: Async result for handler was not set during specified timeToWait=-1 [SPR-16869]
See original GitHub issueAdrian S opened SPR-16869 and commented
When trying to test Server-Sent Events endpoint created using rxjava2 and spring’s ReactiveTypeHandler you encounter:
java.lang.IllegalStateException: Async result for handler [io.reactivex.Flowable<java.lang.String> com.example.asyncssebug.MockMvcAsyncBugTest$TestApp.sse()] was not set during the specified timeToWait=-1java.lang.IllegalStateException: Async result for handler [io.reactivex.Flowable<java.lang.String> com.example.asyncssebug.MockMvcAsyncBugTest$TestApp.sse()] was not set during the specified timeToWait=-1
at org.springframework.test.web.servlet.DefaultMvcResult.getAsyncResult(DefaultMvcResult.java:145) at org.springframework.test.web.servlet.DefaultMvcResult.getAsyncResult(DefaultMvcResult.java:136) at org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch(MockMvcRequestBuilders.java:269)
Example test code to reproduce bug along with walkaround:
package com.example.asyncssebug;
import io.reactivex.Flowable;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.awt.*;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.Matchers.nullValue;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MockMvcAsyncBugTest.TestApp.class)
@AutoConfigureMockMvc
public class MockMvcAsyncBugTest {
@RestController
@RequestMapping("/events")
@SpringBootApplication
public static class TestApp {
@GetMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE)
Flowable<String> sse() {
return Flowable.intervalRange(0, 3, 0, 1, TimeUnit.SECONDS)
.map(aLong -> String.format("event%d", aLong));
}
}
@Autowired
MockMvc mockMvc;
@Test
public void failsWithIllegalStateExceptionAsyncResultForHandlerWasNotSetDuringSpecifiedTimeToWait() throws Exception {
MvcResult mvcResult = mockMvc.perform(get("/events"))
.andExpect(request().asyncStarted())
.andExpect(status().isOk())
.andReturn();
mockMvc.perform(asyncDispatch(mvcResult))
.andExpect(content().string("data:event0\n\ndata:event1\n\ndata:event2\n\n"));
}
@Test
public void alsoFailsWithIllegalStateExceptionAsyncResultForHandlerWasNotSetDuringSpecifiedTimeToWait() throws Exception {
mockMvc.perform(get("/events"))
.andExpect(request().asyncStarted())
.andExpect(request().asyncResult(nullValue()))
.andExpect(status().isOk())
.andExpect(content().string("data:event0\n\ndata:event1\n\ndata:event2\n\n"))
.andReturn();
}
@Test
public void walkaroundToMakeItWork() throws Exception {
MvcResult mvcResult = mockMvc.perform(get("/events"))
.andExpect(request().asyncStarted())
.andExpect(status().isOk())
.andReturn();
mvcResult.getAsyncResult(5000L); // walkaround
mockMvc.perform(asyncDispatch(mvcResult))
.andExpect(content().string("data:event0\n\ndata:event1\n\ndata:event2\n\n"));
}
}
Spring Boot version used is 2.0.2.RELEASE
Seems like default getAsyncResult(-1) instead of waiting forever doesn’t wait at all. As a walkaround you can add mvcResult.getAsyncResult(5000L) and then perform asyncDispatch on the mvcResult
Affects: 5.0.6
Referenced from: commits https://github.com/spring-projects/spring-framework/commit/2a993bf9ff7c9a4fbb1edef8ea1e7f96ac0a1afc, https://github.com/spring-projects/spring-framework/commit/9d36fd0b68883847260863cec7131d4e77720522
Issue Analytics
- State:
- Created 5 years ago
- Comments:5 (4 by maintainers)
Top Results From Across the Web
Async result for handler was not set during the specified ...
Fixed by telling the TestRunner to consider that the current test makes the context "dirty". Add @DirtiesContext(classMode = DirtiesContext.
Read more >Testing async responses using MockMvc - Sadique Ali
This blog post describes how to write tests in such scenarios. Let's take a look at the following example. In this example, we...
Read more >MockHttpServletRequest.getAsyncContext - Java - Tabnine
... IllegalStateException("Async result for handler [" + this.handler + "]" + " was not set during the specified timeToWait=" + timeToWait); } Object...
Read more >Async result for handler was not set during the specified ...
Coding example for the question Async RestController endpoints :: Async result for handler was not set during the specified timeToWait=0-Spring MVC.
Read more >org.springframework.test.web.servlet.MvcResult ...
getAsyncResult (); result= mockMvc.perform(asyncDispatch(result)) . ... getAsyncResult(0); } catch (IllegalStateException ex) { // Not set } this.printer.
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
I have an example project written with WebMvc
SseEmitter.When switching to use
MockMvcWebTestCientin tests, I still got the same exception.I have to add
sseEmitter.completein the controller to make theMockMvcandMockMvcWebTestClientwork, else it will be blocked till it is timeout, and threw the exceptions.The idea is you would use
WebTestClientas the API for all tests but for SSE tests it would be against a live server, i.e.WebTestClient.bindToServer.