Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I'm implementing long polling as per the Spring blog from some time ago.

Here my converted method with same response signature as before, but instead of responding immediately, it now uses long polling:

private Map<String, DeferredResult<ResponseEntity<?>>> requests = new ConcurrentHashMap<>();

@RequestMapping(value = "/{uuid}", method = RequestMethod.GET)
public DeferredResult<ResponseEntity<?>> poll(@PathVariable("uuid") final String uuid) {
    // Create & store a new instance
    ResponseEntity<?> pendingOnTimeout = ResponseEntity.accepted().build();
    DeferredResult<ResponseEntity<?>> deferredResult = new DeferredResult<>(TWENTYFIVE_SECONDS, pendingOnTimeout);
    requests.put(uuid, deferredResult);

    // Clean up poll requests when done
    deferredResult.onCompletion(() -> {
        requests.remove(deferredResult);
    });

    // Set result if already available
    Task task = taskHolder.retrieve(uuid);
    if (task == null)
        deferredResult.setResult(ResponseEntity.status(HttpStatus.GONE).build());
    else
        // Done (or canceled): Redirect to retrieve file contents
        if (task.getFutureFile().isDone())
            deferredResult.setResult(ResponseEntity.created(RetrieveController.uri(uuid)).build());

    // Return result
    return deferredResult;
}

In particular I'd like to return the pendingOnTimeout response when the request takes too long (which I returned immediately before), to prevent proxies from cutting off the request.

Now I think I've gotten this working as is, but I'd like to write a unittest that confirms this. However all my attempts at using MockMvc (via webAppContextSetup) fail to provide me with a means of asserting that I get an accepted header. When I for instance try the following:

@Test
public void pollPending() throws Exception {
    MvcResult result = mockMvc.perform(get("/poll/{uuid}", uuidPending)).andReturn();
    mockMvc.perform(asyncDispatch(result))
            .andExpect(status().isAccepted());
}

I get the following stacktrace:

java.lang.IllegalStateException: Async result for handler [public org.springframework.web.context.request.async.DeferredResult> nl.bioprodict.blast.api.PollController.poll(java.lang.String)] was not set during the specified timeToWait=25000 at org.springframework.util.Assert.state(Assert.java:392) at org.springframework.test.web.servlet.DefaultMvcResult.getAsyncResult(DefaultMvcResult.java:143) at org.springframework.test.web.servlet.DefaultMvcResult.getAsyncResult(DefaultMvcResult.java:120) at org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch(MockMvcRequestBuilders.java:235) at nl.bioprodict.blast.docs.PollControllerDocumentation.pollPending(PollControllerDocumentation.java:53) ...

The Spring framework tests related to this that I could find all use mocking it seems: https://github.com/spring-projects/spring-framework/blob/master/spring-web/src/test/java/org/springframework/web/context/request/async/WebAsyncManagerTimeoutTests.java

How can I test the correct handling of the DeferredResult timeoutResult?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
1.1k views
Welcome To Ask or Share your Answers For Others

1 Answer

In my case, after going through spring source code and setting the timeout (10000 millisecond) and getting async result solved it for me, as;

 mvcResult.getRequest().getAsyncContext().setTimeout(10000);
 mvcResult.getAsyncResult();

My whole test code was;

MvcResult mvcResult = this.mockMvc.perform(
                                post("<SOME_RELATIVE_URL>")
                                .contentType(MediaType.APPLICATION_JSON)
                                .content(<JSON_DATA>))
                        ***.andExpect(request().asyncStarted())***
                            .andReturn();

***mvcResult.getRequest().getAsyncContext().setTimeout(10000);***
***mvcResult.getAsyncResult();***

this.mockMvc
    .perform(asyncDispatch(mvcResult))
    .andDo(print())
    .andExpect(status().isOk());

Hope it helps..


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...