blob: f45688790731ddad965d7720871dd119982afdf7 [file] [log] [blame]
/*
* Copyright (C) 2011 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.mock.MockNetwork;
import com.android.volley.mock.MockRequest;
import com.android.volley.toolbox.NoCache;
import com.android.volley.utils.CacheTestUtils;
import com.android.volley.utils.ImmediateResponseDelivery;
import android.os.SystemClock;
import android.test.InstrumentationTestCase;
import android.test.UiThreadTest;
import android.test.suitebuilder.annotation.LargeTest;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@LargeTest
public class RequestQueueTest extends InstrumentationTestCase {
private ResponseDelivery mDelivery;
@Override
protected void setUp() throws Exception {
super.setUp();
mDelivery = new ImmediateResponseDelivery();
}
/**
* Make a list of requests with random priorities.
* @param count Number of requests to make
*/
private List<MockRequest> makeRequests(int count) {
Request.Priority[] allPriorities = Request.Priority.values();
Random random = new Random();
List<MockRequest> requests = new ArrayList<MockRequest>();
for (int i = 0; i < count; i++) {
MockRequest request = new MockRequest();
Request.Priority priority = allPriorities[random.nextInt(allPriorities.length)];
request.setCacheKey(String.valueOf(i));
request.setPriority(priority);
requests.add(request);
}
return requests;
}
@UiThreadTest
public void testAdd_requestProcessedInCorrectOrder() throws Exception {
int requestsToMake = 100;
OrderCheckingNetwork network = new OrderCheckingNetwork();
RequestQueue queue = new RequestQueue(new NoCache(), network, 1, mDelivery);
for (Request<?> request : makeRequests(requestsToMake)) {
queue.add(request);
}
network.setExpectedRequests(requestsToMake);
queue.start();
network.waitUntilExpectedDone(2000); // 2 seconds
queue.stop();
}
public void testAdd_dedupeByCacheKey() throws Exception {
OrderCheckingNetwork network = new OrderCheckingNetwork();
final AtomicInteger parsed = new AtomicInteger();
final AtomicInteger delivered = new AtomicInteger();
// Enqueue 2 requests with the same cache key. The first request takes 1.5s. Assert that the
// second request is only handled after the first one has been parsed and delivered.
DelayedRequest req1 = new DelayedRequest(1500, parsed, delivered);
DelayedRequest req2 = new DelayedRequest(0, parsed, delivered) {
@Override
protected Response<Object> parseNetworkResponse(NetworkResponse response) {
assertEquals(1, parsed.get()); // req1 must have been parsed.
assertEquals(1, delivered.get()); // req1 must have been parsed.
return super.parseNetworkResponse(response);
}
};
network.setExpectedRequests(2);
RequestQueue queue = new RequestQueue(new NoCache(), network, 3, mDelivery);
queue.add(req1);
queue.add(req2);
queue.start();
network.waitUntilExpectedDone(2000);
queue.stop();
}
public void testCancelAll_onlyCorrectTag() throws Exception {
MockNetwork network = new MockNetwork();
RequestQueue queue = new RequestQueue(new NoCache(), network, 3, mDelivery);
Object tagA = new Object();
Object tagB = new Object();
MockRequest req1 = new MockRequest();
req1.setTag(tagA);
MockRequest req2 = new MockRequest();
req2.setTag(tagB);
MockRequest req3 = new MockRequest();
req3.setTag(tagA);
MockRequest req4 = new MockRequest();
req4.setTag(tagA);
queue.add(req1); // A
queue.add(req2); // B
queue.add(req3); // A
queue.cancelAll(tagA);
queue.add(req4); // A
assertTrue(req1.cancel_called); // A cancelled
assertFalse(req2.cancel_called); // B not cancelled
assertTrue(req3.cancel_called); // A cancelled
assertFalse(req4.cancel_called); // A added after cancel not cancelled
}
private class OrderCheckingNetwork implements Network {
private Priority mLastPriority = Priority.IMMEDIATE;
private int mLastSequence = -1;
private Semaphore mSemaphore;
public void setExpectedRequests(int expectedRequests) {
// Leave one permit available so the waiter can find it.
expectedRequests--;
mSemaphore = new Semaphore(-expectedRequests);
}
public void waitUntilExpectedDone(long timeout)
throws InterruptedException, TimeoutError {
if (mSemaphore.tryAcquire(timeout, TimeUnit.MILLISECONDS) == false) {
throw new TimeoutError();
}
}
@Override
public NetworkResponse performRequest(Request<?> request) {
Priority thisPriority = request.getPriority();
int thisSequence = request.getSequence();
int priorityDiff = thisPriority.compareTo(mLastPriority);
// Should never experience a higher priority after a lower priority
assertFalse(priorityDiff > 0);
// If we're not transitioning to a new priority block, check sequence numbers
if (priorityDiff == 0) {
assertTrue(thisSequence > mLastSequence);
}
mLastSequence = thisSequence;
mLastPriority = thisPriority;
mSemaphore.release();
return new NetworkResponse(new byte[16]);
}
}
private class DelayedRequest extends Request<Object> {
private final long mDelayMillis;
private final AtomicInteger mParsedCount;
private final AtomicInteger mDeliveredCount;
public DelayedRequest(long delayMillis, AtomicInteger parsed, AtomicInteger delivered) {
super("http://buganizer/", null);
mDelayMillis = delayMillis;
mParsedCount = parsed;
mDeliveredCount = delivered;
}
@Override
protected Response<Object> parseNetworkResponse(NetworkResponse response) {
mParsedCount.incrementAndGet();
SystemClock.sleep(mDelayMillis);
return Response.success(new Object(), CacheTestUtils.makeRandomCacheEntry(null));
}
@Override
protected void deliverResponse(Object response) {
mDeliveredCount.incrementAndGet();
}
}
}