/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.volley; import com.android.volley.Request.Priority; import com.android.volley.RequestQueue.RequestFinishedListener; import com.android.volley.mock.MockRequest; import com.android.volley.mock.ShadowSystemClock; import com.android.volley.toolbox.NoCache; import com.android.volley.utils.ImmediateResponseDelivery; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import static org.junit.Assert.*; import static org.mockito.Mockito.*; import static org.mockito.MockitoAnnotations.initMocks; /** * Integration tests for {@link RequestQueue}, that verify its behavior in conjunction with real dispatcher, queues and * Requests. Network is mocked out */ @RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowSystemClock.class}) public class RequestQueueIntegrationTest { private ResponseDelivery mDelivery; @Mock private Network mMockNetwork; @Before public void setUp() throws Exception { mDelivery = new ImmediateResponseDelivery(); initMocks(this); } @Test public void add_requestProcessedInCorrectOrder() throws Exception { // Enqueue 2 requests with different cache keys, and different priorities. The second, higher priority request // takes 20ms. // Assert that first request is only handled after the first one has been parsed and delivered. MockRequest lowerPriorityReq = new MockRequest(); MockRequest higherPriorityReq = new MockRequest(); lowerPriorityReq.setCacheKey("1"); higherPriorityReq.setCacheKey("2"); lowerPriorityReq.setPriority(Priority.LOW); higherPriorityReq.setPriority(Priority.HIGH); RequestFinishedListener listener = mock(RequestFinishedListener.class); Answer<NetworkResponse> delayAnswer = new Answer<NetworkResponse>() { @Override public NetworkResponse answer(InvocationOnMock invocationOnMock) throws Throwable { Thread.sleep(20); return mock(NetworkResponse.class); } }; //delay only for higher request when(mMockNetwork.performRequest(higherPriorityReq)).thenAnswer(delayAnswer); when(mMockNetwork.performRequest(lowerPriorityReq)).thenReturn(mock(NetworkResponse.class)); RequestQueue queue = new RequestQueue(new NoCache(), mMockNetwork, 1, mDelivery); queue.addRequestFinishedListener(listener); queue.add(lowerPriorityReq); queue.add(higherPriorityReq); queue.start(); // you cannot do strict order verification in combination with timeouts with mockito 1.9.5 :( // as an alternative, first verify no requests have finished, while higherPriorityReq should be processing verifyNoMoreInteractions(listener); // verify higherPriorityReq goes through first verify(listener, timeout(100)).onRequestFinished(higherPriorityReq); // verify lowerPriorityReq goes last verify(listener, timeout(10)).onRequestFinished(lowerPriorityReq); queue.stop(); } /** * Asserts that requests with same cache key are processed in order. * * Needs to be an integration test because relies on complex interations between various queues */ @Test public void add_dedupeByCacheKey() throws Exception { // Enqueue 2 requests with the same cache key. The first request takes 20ms. Assert that the // second request is only handled after the first one has been parsed and delivered. Request req1 = new MockRequest(); Request req2 = new MockRequest(); RequestFinishedListener listener = mock(RequestFinishedListener.class); Answer<NetworkResponse> delayAnswer = new Answer<NetworkResponse>() { @Override public NetworkResponse answer(InvocationOnMock invocationOnMock) throws Throwable { Thread.sleep(20); return mock(NetworkResponse.class); } }; //delay only for first when(mMockNetwork.performRequest(req1)).thenAnswer(delayAnswer); when(mMockNetwork.performRequest(req2)).thenReturn(mock(NetworkResponse.class)); RequestQueue queue = new RequestQueue(new NoCache(), mMockNetwork, 3, mDelivery); queue.addRequestFinishedListener(listener); queue.add(req1); queue.add(req2); queue.start(); // you cannot do strict order verification with mockito 1.9.5 :( // as an alternative, first verify no requests have finished, then verify req1 goes through verifyNoMoreInteractions(listener); verify(listener, timeout(100)).onRequestFinished(req1); verify(listener, timeout(10)).onRequestFinished(req2); queue.stop(); } /** * Verify RequestFinishedListeners are informed when requests are canceled * * Needs to be an integration test because relies on Request -> dispatcher -> RequestQueue interaction */ @Test public void add_requestFinishedListenerCanceled() throws Exception { RequestFinishedListener listener = mock(RequestFinishedListener.class); Request request = new MockRequest(); Answer<NetworkResponse> delayAnswer = new Answer<NetworkResponse>() { @Override public NetworkResponse answer(InvocationOnMock invocationOnMock) throws Throwable { Thread.sleep(200); return mock(NetworkResponse.class); } }; RequestQueue queue = new RequestQueue(new NoCache(), mMockNetwork, 1, mDelivery); when(mMockNetwork.performRequest(request)).thenAnswer(delayAnswer); queue.addRequestFinishedListener(listener); queue.start(); queue.add(request); request.cancel(); verify(listener, timeout(100)).onRequestFinished(request); queue.stop(); } /** * Verify RequestFinishedListeners are informed when requests are successfully delivered * * Needs to be an integration test because relies on Request -> dispatcher -> RequestQueue interaction */ @Test public void add_requestFinishedListenerSuccess() throws Exception { NetworkResponse response = mock(NetworkResponse.class); Request request = new MockRequest(); RequestFinishedListener listener = mock(RequestFinishedListener.class); RequestFinishedListener listener2 = mock(RequestFinishedListener.class); RequestQueue queue = new RequestQueue(new NoCache(), mMockNetwork, 1, mDelivery); queue.addRequestFinishedListener(listener); queue.addRequestFinishedListener(listener2); queue.start(); queue.add(request); verify(listener, timeout(100)).onRequestFinished(request); verify(listener2, timeout(100)).onRequestFinished(request); queue.stop(); } /** * Verify RequestFinishedListeners are informed when request errors * * Needs to be an integration test because relies on Request -> dispatcher -> RequestQueue interaction */ @Test public void add_requestFinishedListenerError() throws Exception { RequestFinishedListener listener = mock(RequestFinishedListener.class); Request request = new MockRequest(); RequestQueue queue = new RequestQueue(new NoCache(), mMockNetwork, 1, mDelivery); when(mMockNetwork.performRequest(request)).thenThrow(new VolleyError()); queue.addRequestFinishedListener(listener); queue.start(); queue.add(request); verify(listener, timeout(100)).onRequestFinished(request); queue.stop(); } }