1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.volley; 18 19import com.android.volley.Request.Priority; 20import com.android.volley.RequestQueue.RequestFinishedListener; 21import com.android.volley.mock.MockRequest; 22import com.android.volley.mock.ShadowSystemClock; 23import com.android.volley.toolbox.NoCache; 24import com.android.volley.utils.ImmediateResponseDelivery; 25import org.junit.Before; 26import org.junit.Test; 27import org.junit.runner.RunWith; 28import org.mockito.Mock; 29import org.mockito.invocation.InvocationOnMock; 30import org.mockito.stubbing.Answer; 31import org.robolectric.RobolectricTestRunner; 32import org.robolectric.annotation.Config; 33 34import java.util.ArrayList; 35import java.util.List; 36import java.util.Random; 37import java.util.concurrent.Semaphore; 38import java.util.concurrent.TimeUnit; 39 40import static org.junit.Assert.*; 41import static org.mockito.Mockito.*; 42import static org.mockito.MockitoAnnotations.initMocks; 43 44 45/** 46 * Integration tests for {@link RequestQueue}, that verify its behavior in conjunction with real dispatcher, queues and 47 * Requests. Network is mocked out 48 */ 49@RunWith(RobolectricTestRunner.class) 50@Config(shadows = {ShadowSystemClock.class}) 51public class RequestQueueIntegrationTest { 52 53 private ResponseDelivery mDelivery; 54 @Mock private Network mMockNetwork; 55 56 @Before public void setUp() throws Exception { 57 mDelivery = new ImmediateResponseDelivery(); 58 initMocks(this); 59 } 60 61 @Test public void add_requestProcessedInCorrectOrder() throws Exception { 62 // Enqueue 2 requests with different cache keys, and different priorities. The second, higher priority request 63 // takes 20ms. 64 // Assert that first request is only handled after the first one has been parsed and delivered. 65 MockRequest lowerPriorityReq = new MockRequest(); 66 MockRequest higherPriorityReq = new MockRequest(); 67 lowerPriorityReq.setCacheKey("1"); 68 higherPriorityReq.setCacheKey("2"); 69 lowerPriorityReq.setPriority(Priority.LOW); 70 higherPriorityReq.setPriority(Priority.HIGH); 71 72 RequestFinishedListener listener = mock(RequestFinishedListener.class); 73 Answer<NetworkResponse> delayAnswer = new Answer<NetworkResponse>() { 74 @Override 75 public NetworkResponse answer(InvocationOnMock invocationOnMock) throws Throwable { 76 Thread.sleep(20); 77 return mock(NetworkResponse.class); 78 } 79 }; 80 //delay only for higher request 81 when(mMockNetwork.performRequest(higherPriorityReq)).thenAnswer(delayAnswer); 82 when(mMockNetwork.performRequest(lowerPriorityReq)).thenReturn(mock(NetworkResponse.class)); 83 84 RequestQueue queue = new RequestQueue(new NoCache(), mMockNetwork, 1, mDelivery); 85 queue.addRequestFinishedListener(listener); 86 queue.add(lowerPriorityReq); 87 queue.add(higherPriorityReq); 88 queue.start(); 89 90 // you cannot do strict order verification in combination with timeouts with mockito 1.9.5 :( 91 // as an alternative, first verify no requests have finished, while higherPriorityReq should be processing 92 verifyNoMoreInteractions(listener); 93 // verify higherPriorityReq goes through first 94 verify(listener, timeout(100)).onRequestFinished(higherPriorityReq); 95 // verify lowerPriorityReq goes last 96 verify(listener, timeout(10)).onRequestFinished(lowerPriorityReq); 97 queue.stop(); 98 } 99 100 /** 101 * Asserts that requests with same cache key are processed in order. 102 * 103 * Needs to be an integration test because relies on complex interations between various queues 104 */ 105 @Test public void add_dedupeByCacheKey() throws Exception { 106 // Enqueue 2 requests with the same cache key. The first request takes 20ms. Assert that the 107 // second request is only handled after the first one has been parsed and delivered. 108 Request req1 = new MockRequest(); 109 Request req2 = new MockRequest(); 110 RequestFinishedListener listener = mock(RequestFinishedListener.class); 111 Answer<NetworkResponse> delayAnswer = new Answer<NetworkResponse>() { 112 @Override 113 public NetworkResponse answer(InvocationOnMock invocationOnMock) throws Throwable { 114 Thread.sleep(20); 115 return mock(NetworkResponse.class); 116 } 117 }; 118 //delay only for first 119 when(mMockNetwork.performRequest(req1)).thenAnswer(delayAnswer); 120 when(mMockNetwork.performRequest(req2)).thenReturn(mock(NetworkResponse.class)); 121 122 RequestQueue queue = new RequestQueue(new NoCache(), mMockNetwork, 3, mDelivery); 123 queue.addRequestFinishedListener(listener); 124 queue.add(req1); 125 queue.add(req2); 126 queue.start(); 127 128 // you cannot do strict order verification with mockito 1.9.5 :( 129 // as an alternative, first verify no requests have finished, then verify req1 goes through 130 verifyNoMoreInteractions(listener); 131 verify(listener, timeout(100)).onRequestFinished(req1); 132 verify(listener, timeout(10)).onRequestFinished(req2); 133 queue.stop(); 134 } 135 136 /** 137 * Verify RequestFinishedListeners are informed when requests are canceled 138 * 139 * Needs to be an integration test because relies on Request -> dispatcher -> RequestQueue interaction 140 */ 141 @Test public void add_requestFinishedListenerCanceled() throws Exception { 142 RequestFinishedListener listener = mock(RequestFinishedListener.class); 143 Request request = new MockRequest(); 144 Answer<NetworkResponse> delayAnswer = new Answer<NetworkResponse>() { 145 @Override 146 public NetworkResponse answer(InvocationOnMock invocationOnMock) throws Throwable { 147 Thread.sleep(200); 148 return mock(NetworkResponse.class); 149 } 150 }; 151 RequestQueue queue = new RequestQueue(new NoCache(), mMockNetwork, 1, mDelivery); 152 153 when(mMockNetwork.performRequest(request)).thenAnswer(delayAnswer); 154 155 queue.addRequestFinishedListener(listener); 156 queue.start(); 157 queue.add(request); 158 159 request.cancel(); 160 verify(listener, timeout(100)).onRequestFinished(request); 161 queue.stop(); 162 } 163 164 /** 165 * Verify RequestFinishedListeners are informed when requests are successfully delivered 166 * 167 * Needs to be an integration test because relies on Request -> dispatcher -> RequestQueue interaction 168 */ 169 @Test public void add_requestFinishedListenerSuccess() throws Exception { 170 NetworkResponse response = mock(NetworkResponse.class); 171 Request request = new MockRequest(); 172 RequestFinishedListener listener = mock(RequestFinishedListener.class); 173 RequestFinishedListener listener2 = mock(RequestFinishedListener.class); 174 RequestQueue queue = new RequestQueue(new NoCache(), mMockNetwork, 1, mDelivery); 175 176 queue.addRequestFinishedListener(listener); 177 queue.addRequestFinishedListener(listener2); 178 queue.start(); 179 queue.add(request); 180 181 verify(listener, timeout(100)).onRequestFinished(request); 182 verify(listener2, timeout(100)).onRequestFinished(request); 183 184 queue.stop(); 185 } 186 187 /** 188 * Verify RequestFinishedListeners are informed when request errors 189 * 190 * Needs to be an integration test because relies on Request -> dispatcher -> RequestQueue interaction 191 */ 192 @Test public void add_requestFinishedListenerError() throws Exception { 193 RequestFinishedListener listener = mock(RequestFinishedListener.class); 194 Request request = new MockRequest(); 195 RequestQueue queue = new RequestQueue(new NoCache(), mMockNetwork, 1, mDelivery); 196 197 when(mMockNetwork.performRequest(request)).thenThrow(new VolleyError()); 198 199 queue.addRequestFinishedListener(listener); 200 queue.start(); 201 queue.add(request); 202 203 verify(listener, timeout(100)).onRequestFinished(request); 204 queue.stop(); 205 } 206 207} 208