2016-10-07 23 views
6

Mam komety (long polling) Controller rozmowę, która odbywa się w kilku identyfikatorów i puts następnie w kolejce blokowania jeśli nie Wyliczenie dla tego identyfikatora jest uruchomiony, dla Consumer do take z queue i wykonać obliczenia na tych identyfikatorach. Używam SpringsDeferredResult dla wsparcia asynch.Wiosna DeferredResult onCompletion nie sprawdził z przypadków testowych

Utrzymuję Map z DeferredResult i odpowiednie identyfikatory, które zostały odebrane w żądaniu. Gdy obliczenia dla identyfikatora są zakończone w wątku konsumenckim, sprawdzam pod kątem tego identyfikatora w Map i ustawię powiązane z nim DeferredResultssetResult, które wysyła odpowiedź z powrotem do klienta.

W sposobie Controller mam onCompletion oddzwanianie DeferredResult który usuwa te DeferredResult obiektu z Map.

Klient usuwa ten identyfikator ze swojego żądania i wysyła pozostałe identyfikatory. Jako przykład powiedzmy, że klient wysyła początkowo ids "1,2,3", wszystkie zostały wstawione do BlockingQueue i mówią, że obliczenia dla identyfikatora "2" zostały zakończone wcześniej, to zostanie ustawione jego DeferredResultssetResult, które zwróci odpowiedź na klient. A przez wywołanie zwrotne ta DeferredResult zostanie usunięta z Map. A klient w następnym żądaniu wyśle ​​identyfikatory "1, 3".

Teraz wszystko działa dobrze, ale kiedy zacząłem pisać przypadki testowe, wywołanie zwrotne onCompletion nigdy nie jest wywoływane. Próbowałem nawet na wiosnę oficjalnych przykładów, że wydaje się, że nie ma tam nawet mowy. Czy istnieje sposób na wywołanie go lub coś jest nieprawidłowe w mojej realizacji.

To mój Controller metoda:

@RequestMapping(value = "views/getLongPollingGraphData", method = RequestMethod.GET, headers = "Accept=application/json") 
@ResponseBody 
public DeferredResult<WebServiceResponse> getLongGraphData(
     HttpServletRequest request, 
     @RequestParam(value = "ids") String ids) 
{ 
    //create a default response in case, when no result has been calculated till timeout 
    WebServiceResponse awrDefault = new WebServiceResponse(); 

    //set time out this DeferredResult, after 5 seconds 
    final DeferredResult<WebServiceResponse> deferredResult = new DeferredResult<WebServiceResponse>(5000L, awrDefault); 

    //logic to set in blocking queue 
    //mMapOfDeferredResultAndViews.put(deferredResult, listOfViews.keySet()); 

    deferredResult.onCompletion(new Runnable() { 
     @Override 
     public void run() 
     { 
      mMapOfDeferredResultAndViews.remove(deferredResult); 
     } 
    }); 

    return deferredResult; 
} 

Poniżej jest częścią testu:

@Before 
public void setup() 
{ 
    this.mockMvc = webAppContextSetup(this.wac).build(); 
} 

@Test 
public void testLongPollGraphData() 
{ 
    try 
    {   
     String ids = "22,23,25"; 
     List<Integer> idList = convertStringToList(ids); 

     while(idList.size() > 0) 
     { 
      MvcResult mvcResult = this.mockMvc.perform(get("/views/getLongPollingGraphData") 
       .contentType(MediaType.APPLICATION_JSON) 
       .param("ids", ids)   
       .andReturn(); 

      this.mockMvc.perform(asyncDispatch(mvcResult)); 
      WebServiceResponse result = (WebServiceResponse)mvcResult.getAsyncResult(); 

      if(result != null) 
      { 
       EJSChartsData chartsData = (EJSChartsData)result.getResponse(); 
       if(chartsData != null && chartsData.getViewId() != -1) 
       { 
        int viewId = chartsData.getViewId(); 
        idList.remove((Integer)viewId); 
        ids = idList.toString().replace("[", "").replace("]", ""); 
       } 
      } 
     } 
    } 
    catch(Exception e) 
    { 
     fail(e.toString()); 
    } 
} 

Sposób Controller nazywa i otrzymam odpowiedź, zgodnie z oczekiwaniami, ale jako onCompletion callback nigdy nie jest nazywany moją logiką wywoływania metody ponownie poprzez usunięcie id ma trafienie jako Map posiada w przeszłości Map trzyma się w przeszłości DeferredResult.

Aktualizacja

Adnotacje Klasa testu to:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "/test-context.xml" }) 
@WebAppConfiguration 
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true) 
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW) 

mam inne spostrzeżenie, wezwanie do getLongPollingGraphData nie jest zakończona, to znaczy, że nie czekać do określonego limitu czasu 5 sekund zwraca natychmiast, powodując, że result ma być . Przeczytałem o tym i zalecenie jest dodanie obiektu .andExpect(request().asyncResult("Expected output")) do mockMvc.

Ale to jest cały punkt mojego przypadku testowego, chcę, aby wynik został obliczony i zwrócony, aby móc ponownie wysłać żądanie modyfikujące moją zmienną ids na podstawie otrzymanej odpowiedzi.

+0

Pokaż swój klasówka adnotacje na najwyższym – shazin

+0

@shazin aktualizowane w pytaniu, z pewnymi dodatkowymi uwagami. – rd22

+0

Czy używasz tomcat do swojej aplikacji internetowej? – eg04lt3r

Odpowiedz

0

Jakiej wersji Spring używasz? Otworzyłem SPR-13615 dla podobnego przypadku i zostało naprawione w 4.2.3 (dotyczy 4.2.2).

Jeśli spojrzeć na komentarze, można obejść się bez aktualizacji za pomocą

mvcResult.getRequest().getAsyncContext().complete();