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 Springs
DeferredResult
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 DeferredResults
setResult
, 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 DeferredResults
setResult
, 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.
Pokaż swój klasówka adnotacje na najwyższym – shazin
@shazin aktualizowane w pytaniu, z pewnymi dodatkowymi uwagami. – rd22
Czy używasz tomcat do swojej aplikacji internetowej? – eg04lt3r