1/* 2 * Copyright (C) 2011 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.mock.MockNetwork; 21import com.android.volley.mock.MockRequest; 22import com.android.volley.toolbox.NoCache; 23import com.android.volley.utils.CacheTestUtils; 24import com.android.volley.utils.ImmediateResponseDelivery; 25 26import android.os.SystemClock; 27import android.test.InstrumentationTestCase; 28import android.test.UiThreadTest; 29import android.test.suitebuilder.annotation.LargeTest; 30 31import java.util.ArrayList; 32import java.util.List; 33import java.util.Random; 34import java.util.concurrent.Semaphore; 35import java.util.concurrent.TimeUnit; 36import java.util.concurrent.atomic.AtomicInteger; 37 38@LargeTest 39public class RequestQueueTest extends InstrumentationTestCase { 40 private ResponseDelivery mDelivery; 41 42 @Override 43 protected void setUp() throws Exception { 44 super.setUp(); 45 46 mDelivery = new ImmediateResponseDelivery(); 47 } 48 49 /** 50 * Make a list of requests with random priorities. 51 * @param count Number of requests to make 52 */ 53 private List<MockRequest> makeRequests(int count) { 54 Request.Priority[] allPriorities = Request.Priority.values(); 55 Random random = new Random(); 56 57 List<MockRequest> requests = new ArrayList<MockRequest>(); 58 for (int i = 0; i < count; i++) { 59 MockRequest request = new MockRequest(); 60 Request.Priority priority = allPriorities[random.nextInt(allPriorities.length)]; 61 request.setCacheKey(String.valueOf(i)); 62 request.setPriority(priority); 63 requests.add(request); 64 } 65 return requests; 66 } 67 68 @UiThreadTest 69 public void testAdd_requestProcessedInCorrectOrder() throws Exception { 70 int requestsToMake = 100; 71 72 OrderCheckingNetwork network = new OrderCheckingNetwork(); 73 RequestQueue queue = new RequestQueue(new NoCache(), network, 1, mDelivery); 74 75 for (Request<?> request : makeRequests(requestsToMake)) { 76 queue.add(request); 77 } 78 79 network.setExpectedRequests(requestsToMake); 80 queue.start(); 81 network.waitUntilExpectedDone(2000); // 2 seconds 82 queue.stop(); 83 } 84 85 public void testAdd_dedupeByCacheKey() throws Exception { 86 OrderCheckingNetwork network = new OrderCheckingNetwork(); 87 final AtomicInteger parsed = new AtomicInteger(); 88 final AtomicInteger delivered = new AtomicInteger(); 89 // Enqueue 2 requests with the same cache key. The first request takes 1.5s. Assert that the 90 // second request is only handled after the first one has been parsed and delivered. 91 DelayedRequest req1 = new DelayedRequest(1500, parsed, delivered); 92 DelayedRequest req2 = new DelayedRequest(0, parsed, delivered) { 93 @Override 94 protected Response<Object> parseNetworkResponse(NetworkResponse response) { 95 assertEquals(1, parsed.get()); // req1 must have been parsed. 96 assertEquals(1, delivered.get()); // req1 must have been parsed. 97 return super.parseNetworkResponse(response); 98 } 99 }; 100 network.setExpectedRequests(2); 101 RequestQueue queue = new RequestQueue(new NoCache(), network, 3, mDelivery); 102 queue.add(req1); 103 queue.add(req2); 104 queue.start(); 105 network.waitUntilExpectedDone(2000); 106 queue.stop(); 107 } 108 109 public void testCancelAll_onlyCorrectTag() throws Exception { 110 MockNetwork network = new MockNetwork(); 111 RequestQueue queue = new RequestQueue(new NoCache(), network, 3, mDelivery); 112 Object tagA = new Object(); 113 Object tagB = new Object(); 114 MockRequest req1 = new MockRequest(); 115 req1.setTag(tagA); 116 MockRequest req2 = new MockRequest(); 117 req2.setTag(tagB); 118 MockRequest req3 = new MockRequest(); 119 req3.setTag(tagA); 120 MockRequest req4 = new MockRequest(); 121 req4.setTag(tagA); 122 123 queue.add(req1); // A 124 queue.add(req2); // B 125 queue.add(req3); // A 126 queue.cancelAll(tagA); 127 queue.add(req4); // A 128 129 assertTrue(req1.cancel_called); // A cancelled 130 assertFalse(req2.cancel_called); // B not cancelled 131 assertTrue(req3.cancel_called); // A cancelled 132 assertFalse(req4.cancel_called); // A added after cancel not cancelled 133 } 134 135 private class OrderCheckingNetwork implements Network { 136 private Priority mLastPriority = Priority.IMMEDIATE; 137 private int mLastSequence = -1; 138 private Semaphore mSemaphore; 139 140 public void setExpectedRequests(int expectedRequests) { 141 // Leave one permit available so the waiter can find it. 142 expectedRequests--; 143 mSemaphore = new Semaphore(-expectedRequests); 144 } 145 146 public void waitUntilExpectedDone(long timeout) 147 throws InterruptedException, TimeoutError { 148 if (mSemaphore.tryAcquire(timeout, TimeUnit.MILLISECONDS) == false) { 149 throw new TimeoutError(); 150 } 151 } 152 153 @Override 154 public NetworkResponse performRequest(Request<?> request) { 155 Priority thisPriority = request.getPriority(); 156 int thisSequence = request.getSequence(); 157 158 int priorityDiff = thisPriority.compareTo(mLastPriority); 159 160 // Should never experience a higher priority after a lower priority 161 assertFalse(priorityDiff > 0); 162 163 // If we're not transitioning to a new priority block, check sequence numbers 164 if (priorityDiff == 0) { 165 assertTrue(thisSequence > mLastSequence); 166 } 167 mLastSequence = thisSequence; 168 mLastPriority = thisPriority; 169 170 mSemaphore.release(); 171 return new NetworkResponse(new byte[16]); 172 } 173 } 174 175 private class DelayedRequest extends Request<Object> { 176 private final long mDelayMillis; 177 private final AtomicInteger mParsedCount; 178 private final AtomicInteger mDeliveredCount; 179 180 public DelayedRequest(long delayMillis, AtomicInteger parsed, AtomicInteger delivered) { 181 super("http://buganizer/", null); 182 mDelayMillis = delayMillis; 183 mParsedCount = parsed; 184 mDeliveredCount = delivered; 185 } 186 187 @Override 188 protected Response<Object> parseNetworkResponse(NetworkResponse response) { 189 mParsedCount.incrementAndGet(); 190 SystemClock.sleep(mDelayMillis); 191 return Response.success(new Object(), CacheTestUtils.makeRandomCacheEntry(null)); 192 } 193 194 @Override 195 protected void deliverResponse(Object response) { 196 mDeliveredCount.incrementAndGet(); 197 } 198 } 199 200} 201