aboutsummaryrefslogtreecommitdiff
path: root/src/test/java/com
diff options
context:
space:
mode:
authorFicus Kirkpatrick <ficus@android.com>2014-11-29 09:32:54 -0800
committerFicus Kirkpatrick <ficus@android.com>2014-12-05 15:46:44 -0800
commitb9b8dc3d98fb1a8c3f02c2c2fcc18cbd344c05cb (patch)
tree1f4a33c24f608d79781de54e5d1ff5f3072fa261 /src/test/java/com
parent008e0cc8e51ef9e91110d91d4d662d0d86b252a1 (diff)
downloadvolley-b9b8dc3d98fb1a8c3f02c2c2fcc18cbd344c05cb.tar.gz
Migrate from Gradle to Maven.
- Restructure source to src/{main,test} style - Add pom.xml and update Android.mk - Migrate all tests to JUnit4 and Robolectric - RequestQueueTest is currently @Ignored as fixing it will involve more extensive refactoring. - Main library still builds in Gradle; tests do not Change-Id: I1edc53bb1a54f64d3e806e4572901295ef63e2ca
Diffstat (limited to 'src/test/java/com')
-rw-r--r--src/test/java/com/android/volley/CacheDispatcherTest.java115
-rw-r--r--src/test/java/com/android/volley/NetworkDispatcherTest.java100
-rw-r--r--src/test/java/com/android/volley/RequestQueueTest.java205
-rw-r--r--src/test/java/com/android/volley/RequestTest.java97
-rw-r--r--src/test/java/com/android/volley/ResponseDeliveryTest.java68
-rw-r--r--src/test/java/com/android/volley/mock/MockCache.java65
-rw-r--r--src/test/java/com/android/volley/mock/MockHttpClient.java114
-rw-r--r--src/test/java/com/android/volley/mock/MockHttpStack.java72
-rw-r--r--src/test/java/com/android/volley/mock/MockHttpURLConnection.java77
-rw-r--r--src/test/java/com/android/volley/mock/MockNetwork.java58
-rw-r--r--src/test/java/com/android/volley/mock/MockRequest.java101
-rw-r--r--src/test/java/com/android/volley/mock/MockResponseDelivery.java51
-rw-r--r--src/test/java/com/android/volley/mock/TestRequest.java179
-rw-r--r--src/test/java/com/android/volley/mock/WaitableQueue.java72
-rw-r--r--src/test/java/com/android/volley/toolbox/BasicNetworkTest.java78
-rw-r--r--src/test/java/com/android/volley/toolbox/ByteArrayPoolTest.java76
-rw-r--r--src/test/java/com/android/volley/toolbox/DiskBasedCacheTest.java124
-rw-r--r--src/test/java/com/android/volley/toolbox/HttpClientStackTest.java144
-rw-r--r--src/test/java/com/android/volley/toolbox/HttpHeaderParserTest.java226
-rw-r--r--src/test/java/com/android/volley/toolbox/HurlStackTest.java155
-rw-r--r--src/test/java/com/android/volley/toolbox/ImageRequestTest.java107
-rw-r--r--src/test/java/com/android/volley/toolbox/NetworkImageViewTest.java53
-rw-r--r--src/test/java/com/android/volley/toolbox/PoolingByteArrayOutputStreamTest.java78
-rw-r--r--src/test/java/com/android/volley/utils/CacheTestUtils.java40
-rw-r--r--src/test/java/com/android/volley/utils/ImmediateResponseDelivery.java23
25 files changed, 2478 insertions, 0 deletions
diff --git a/src/test/java/com/android/volley/CacheDispatcherTest.java b/src/test/java/com/android/volley/CacheDispatcherTest.java
new file mode 100644
index 0000000..42bdda0
--- /dev/null
+++ b/src/test/java/com/android/volley/CacheDispatcherTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.mock.MockCache;
+import com.android.volley.mock.MockRequest;
+import com.android.volley.mock.MockResponseDelivery;
+import com.android.volley.mock.WaitableQueue;
+import com.android.volley.utils.CacheTestUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import static org.junit.Assert.*;
+
+@RunWith(RobolectricTestRunner.class)
+@SuppressWarnings("rawtypes")
+public class CacheDispatcherTest {
+ private CacheDispatcher mDispatcher;
+ private WaitableQueue mCacheQueue;
+ private WaitableQueue mNetworkQueue;
+ private MockCache mCache;
+ private MockResponseDelivery mDelivery;
+ private MockRequest mRequest;
+
+ private static final long TIMEOUT_MILLIS = 5000;
+
+ @Before public void setUp() throws Exception {
+ mCacheQueue = new WaitableQueue();
+ mNetworkQueue = new WaitableQueue();
+ mCache = new MockCache();
+ mDelivery = new MockResponseDelivery();
+
+ mRequest = new MockRequest();
+
+ mDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
+ mDispatcher.start();
+ }
+
+ @After public void tearDown() throws Exception {
+ mDispatcher.quit();
+ mDispatcher.join();
+ }
+
+ // A cancelled request should not be processed at all.
+ @Test public void cancelledRequest() throws Exception {
+ mRequest.cancel();
+ mCacheQueue.add(mRequest);
+ mCacheQueue.waitUntilEmpty(TIMEOUT_MILLIS);
+ assertFalse(mCache.getCalled);
+ assertFalse(mDelivery.wasEitherResponseCalled());
+ }
+
+ // A cache miss does not post a response and puts the request on the network queue.
+ @Test public void cacheMiss() throws Exception {
+ mCacheQueue.add(mRequest);
+ mCacheQueue.waitUntilEmpty(TIMEOUT_MILLIS);
+ assertFalse(mDelivery.wasEitherResponseCalled());
+ assertTrue(mNetworkQueue.size() > 0);
+ Request request = mNetworkQueue.take();
+ assertNull(request.getCacheEntry());
+ }
+
+ // A non-expired cache hit posts a response and does not queue to the network.
+ @Test public void nonExpiredCacheHit() throws Exception {
+ Cache.Entry entry = CacheTestUtils.makeRandomCacheEntry(null, false, false);
+ mCache.setEntryToReturn(entry);
+ mCacheQueue.add(mRequest);
+ mCacheQueue.waitUntilEmpty(TIMEOUT_MILLIS);
+ assertTrue(mDelivery.postResponse_called);
+ assertFalse(mDelivery.postError_called);
+ }
+
+ // A soft-expired cache hit posts a response and queues to the network.
+ @Test public void softExpiredCacheHit() throws Exception {
+ Cache.Entry entry = CacheTestUtils.makeRandomCacheEntry(null, false, true);
+ mCache.setEntryToReturn(entry);
+ mCacheQueue.add(mRequest);
+ mCacheQueue.waitUntilEmpty(TIMEOUT_MILLIS);
+ assertTrue(mDelivery.postResponse_called);
+ assertFalse(mDelivery.postError_called);
+ assertTrue(mNetworkQueue.size() > 0);
+ Request request = mNetworkQueue.take();
+ assertSame(entry, request.getCacheEntry());
+ }
+
+ // An expired cache hit does not post a response and queues to the network.
+ @Test public void expiredCacheHit() throws Exception {
+ Cache.Entry entry = CacheTestUtils.makeRandomCacheEntry(null, true, true);
+ mCache.setEntryToReturn(entry);
+ mCacheQueue.add(mRequest);
+ mCacheQueue.waitUntilEmpty(TIMEOUT_MILLIS);
+ assertFalse(mDelivery.wasEitherResponseCalled());
+ assertTrue(mNetworkQueue.size() > 0);
+ Request request = mNetworkQueue.take();
+ assertSame(entry, request.getCacheEntry());
+ }
+}
diff --git a/src/test/java/com/android/volley/NetworkDispatcherTest.java b/src/test/java/com/android/volley/NetworkDispatcherTest.java
new file mode 100644
index 0000000..c5763bd
--- /dev/null
+++ b/src/test/java/com/android/volley/NetworkDispatcherTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.mock.MockCache;
+import com.android.volley.mock.MockNetwork;
+import com.android.volley.mock.MockRequest;
+import com.android.volley.mock.MockResponseDelivery;
+import com.android.volley.mock.WaitableQueue;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import java.util.Arrays;
+
+import static org.junit.Assert.*;
+
+@RunWith(RobolectricTestRunner.class)
+public class NetworkDispatcherTest {
+ private NetworkDispatcher mDispatcher;
+ private MockResponseDelivery mDelivery;
+ private WaitableQueue mNetworkQueue;
+ private MockNetwork mNetwork;
+ private MockCache mCache;
+ private MockRequest mRequest;
+
+ private static final byte[] CANNED_DATA = "Ceci n'est pas une vraie reponse".getBytes();
+ private static final long TIMEOUT_MILLIS = 5000;
+
+ @Before public void setUp() throws Exception {
+ mDelivery = new MockResponseDelivery();
+ mNetworkQueue = new WaitableQueue();
+ mNetwork = new MockNetwork();
+ mCache = new MockCache();
+ mRequest = new MockRequest();
+ mDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery);
+ mDispatcher.start();
+ }
+
+ @After public void tearDown() throws Exception {
+ mDispatcher.quit();
+ mDispatcher.join();
+ }
+
+ @Test public void successPostsResponse() throws Exception {
+ mNetwork.setDataToReturn(CANNED_DATA);
+ mNetwork.setNumExceptionsToThrow(0);
+ mNetworkQueue.add(mRequest);
+ mNetworkQueue.waitUntilEmpty(TIMEOUT_MILLIS);
+ assertFalse(mDelivery.postError_called);
+ assertTrue(mDelivery.postResponse_called);
+ Response<?> response = mDelivery.responsePosted;
+ assertNotNull(response);
+ assertTrue(response.isSuccess());
+ assertTrue(Arrays.equals((byte[])response.result, CANNED_DATA));
+ }
+
+ @Test public void exceptionPostsError() throws Exception {
+ mNetwork.setNumExceptionsToThrow(MockNetwork.ALWAYS_THROW_EXCEPTIONS);
+ mNetworkQueue.add(mRequest);
+ mNetworkQueue.waitUntilEmpty(TIMEOUT_MILLIS);
+ assertFalse(mDelivery.postResponse_called);
+ assertTrue(mDelivery.postError_called);
+ }
+
+ @Test public void shouldCacheFalse() throws Exception {
+ mRequest.setShouldCache(false);
+ mNetworkQueue.add(mRequest);
+ mNetworkQueue.waitUntilEmpty(TIMEOUT_MILLIS);
+ assertFalse(mCache.putCalled);
+ }
+
+ @Test public void shouldCacheTrue() throws Exception {
+ mNetwork.setDataToReturn(CANNED_DATA);
+ mRequest.setShouldCache(true);
+ mRequest.setCacheKey("bananaphone");
+ mNetworkQueue.add(mRequest);
+ mNetworkQueue.waitUntilEmpty(TIMEOUT_MILLIS);
+ assertTrue(mCache.putCalled);
+ assertNotNull(mCache.entryPut);
+ assertTrue(Arrays.equals(mCache.entryPut.data, CANNED_DATA));
+ assertEquals("bananaphone", mCache.keyPut);
+ }
+}
diff --git a/src/test/java/com/android/volley/RequestQueueTest.java b/src/test/java/com/android/volley/RequestQueueTest.java
new file mode 100644
index 0000000..cc88d3b
--- /dev/null
+++ b/src/test/java/com/android/volley/RequestQueueTest.java
@@ -0,0 +1,205 @@
+/*
+ * 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 org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implements;
+
+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;
+
+import static org.junit.Assert.*;
+
+// TODO: Resurrect these tests when we have something like a finish() observer.
+// They are really gross as-is and depend on a bunch of sleeping and whatnot.
+@Ignore
+@RunWith(RobolectricTestRunner.class)
+public class RequestQueueTest {
+ private ResponseDelivery mDelivery;
+
+ @Before public void setUp() throws Exception {
+ 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;
+ }
+
+ @Test public void add_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();
+ }
+
+ @Test public void add_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();
+ }
+
+ @Test public void cancelAll_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(Request.Method.GET, "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();
+ }
+ }
+
+}
diff --git a/src/test/java/com/android/volley/RequestTest.java b/src/test/java/com/android/volley/RequestTest.java
new file mode 100644
index 0000000..d5beca5
--- /dev/null
+++ b/src/test/java/com/android/volley/RequestTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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 org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import static org.junit.Assert.*;
+
+@RunWith(RobolectricTestRunner.class)
+public class RequestTest {
+
+ @Test public void compareTo() {
+ int sequence = 0;
+ TestRequest low = new TestRequest(Priority.LOW);
+ low.setSequence(sequence++);
+ TestRequest low2 = new TestRequest(Priority.LOW);
+ low2.setSequence(sequence++);
+ TestRequest high = new TestRequest(Priority.HIGH);
+ high.setSequence(sequence++);
+ TestRequest immediate = new TestRequest(Priority.IMMEDIATE);
+ immediate.setSequence(sequence++);
+
+ // "Low" should sort higher because it's really processing order.
+ assertTrue(low.compareTo(high) > 0);
+ assertTrue(high.compareTo(low) < 0);
+ assertTrue(low.compareTo(low2) < 0);
+ assertTrue(low.compareTo(immediate) > 0);
+ assertTrue(immediate.compareTo(high) < 0);
+ }
+
+ private class TestRequest extends Request<Object> {
+ private Priority mPriority = Priority.NORMAL;
+ public TestRequest(Priority priority) {
+ super(Request.Method.GET, "", null);
+ mPriority = priority;
+ }
+
+ @Override
+ public Priority getPriority() {
+ return mPriority;
+ }
+
+ @Override
+ protected void deliverResponse(Object response) {
+ }
+
+ @Override
+ protected Response<Object> parseNetworkResponse(NetworkResponse response) {
+ return null;
+ }
+ }
+
+ @Test public void urlParsing() {
+ UrlParseRequest nullUrl = new UrlParseRequest(null);
+ assertEquals(0, nullUrl.getTrafficStatsTag());
+ UrlParseRequest emptyUrl = new UrlParseRequest("");
+ assertEquals(0, emptyUrl.getTrafficStatsTag());
+ UrlParseRequest noHost = new UrlParseRequest("http:///");
+ assertEquals(0, noHost.getTrafficStatsTag());
+ UrlParseRequest badProtocol = new UrlParseRequest("bad:http://foo");
+ assertEquals(0, badProtocol.getTrafficStatsTag());
+ UrlParseRequest goodProtocol = new UrlParseRequest("http://foo");
+ assertFalse(0 == goodProtocol.getTrafficStatsTag());
+ }
+
+ private class UrlParseRequest extends Request<Object> {
+ public UrlParseRequest(String url) {
+ super(Request.Method.GET, url, null);
+ }
+
+ @Override
+ protected void deliverResponse(Object response) {
+ }
+
+ @Override
+ protected Response<Object> parseNetworkResponse(NetworkResponse response) {
+ return null;
+ }
+ }
+}
diff --git a/src/test/java/com/android/volley/ResponseDeliveryTest.java b/src/test/java/com/android/volley/ResponseDeliveryTest.java
new file mode 100644
index 0000000..9fadfc3
--- /dev/null
+++ b/src/test/java/com/android/volley/ResponseDeliveryTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.mock.MockRequest;
+import com.android.volley.utils.CacheTestUtils;
+import com.android.volley.utils.ImmediateResponseDelivery;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import static org.junit.Assert.*;
+
+@RunWith(RobolectricTestRunner.class)
+public class ResponseDeliveryTest {
+
+ private ExecutorDelivery mDelivery;
+ private MockRequest mRequest;
+ private Response<byte[]> mSuccessResponse;
+
+ @Before public void setUp() throws Exception {
+ // Make the delivery just run its posted responses immediately.
+ mDelivery = new ImmediateResponseDelivery();
+ mRequest = new MockRequest();
+ mRequest.setSequence(1);
+ byte[] data = new byte[16];
+ Cache.Entry cacheEntry = CacheTestUtils.makeRandomCacheEntry(data);
+ mSuccessResponse = Response.success(data, cacheEntry);
+ }
+
+ @Test public void postResponseCallsDeliverResponse() {
+ mDelivery.postResponse(mRequest, mSuccessResponse);
+ assertTrue(mRequest.deliverResponse_called);
+ assertFalse(mRequest.deliverError_called);
+ }
+
+ @Test public void postResponseSuppressesCanceled() {
+ mRequest.cancel();
+ mDelivery.postResponse(mRequest, mSuccessResponse);
+ assertFalse(mRequest.deliverResponse_called);
+ assertFalse(mRequest.deliverError_called);
+ }
+
+ @Test public void postErrorCallsDeliverError() {
+ Response<byte[]> errorResponse = Response.error(new ServerError());
+
+ mDelivery.postResponse(mRequest, errorResponse);
+ assertTrue(mRequest.deliverError_called);
+ assertFalse(mRequest.deliverResponse_called);
+ }
+}
diff --git a/src/test/java/com/android/volley/mock/MockCache.java b/src/test/java/com/android/volley/mock/MockCache.java
new file mode 100644
index 0000000..85a4607
--- /dev/null
+++ b/src/test/java/com/android/volley/mock/MockCache.java
@@ -0,0 +1,65 @@
+/*
+ * 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.mock;
+
+import com.android.volley.Cache;
+
+public class MockCache implements Cache {
+
+ public boolean clearCalled = false;
+ @Override
+ public void clear() {
+ clearCalled = true;
+ }
+
+ public boolean getCalled = false;
+ private Entry mFakeEntry = null;
+
+ public void setEntryToReturn(Entry entry) {
+ mFakeEntry = entry;
+ }
+
+ @Override
+ public Entry get(String key) {
+ getCalled = true;
+ return mFakeEntry;
+ }
+
+ public boolean putCalled = false;
+ public String keyPut = null;
+ public Entry entryPut = null;
+
+ @Override
+ public void put(String key, Entry entry) {
+ putCalled = true;
+ keyPut = key;
+ entryPut = entry;
+ }
+
+ @Override
+ public void invalidate(String key, boolean fullExpire) {
+ }
+
+ @Override
+ public void remove(String key) {
+ }
+
+ @Override
+ public void initialize() {
+ }
+
+}
diff --git a/src/test/java/com/android/volley/mock/MockHttpClient.java b/src/test/java/com/android/volley/mock/MockHttpClient.java
new file mode 100644
index 0000000..c2a36bc
--- /dev/null
+++ b/src/test/java/com/android/volley/mock/MockHttpClient.java
@@ -0,0 +1,114 @@
+/*
+ * 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.mock;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.StatusLine;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.message.BasicHttpResponse;
+import org.apache.http.message.BasicStatusLine;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.HttpContext;
+
+
+public class MockHttpClient implements HttpClient {
+ private int mStatusCode = HttpStatus.SC_OK;
+ private HttpEntity mResponseEntity = null;
+
+ public void setResponseData(HttpEntity entity) {
+ mStatusCode = HttpStatus.SC_OK;
+ mResponseEntity = entity;
+ }
+
+ public void setErrorCode(int statusCode) {
+ if (statusCode == HttpStatus.SC_OK) {
+ throw new IllegalArgumentException("statusCode cannot be 200 for an error");
+ }
+ mStatusCode = statusCode;
+ }
+
+ public HttpUriRequest requestExecuted = null;
+
+ // This is the only one we actually use.
+ @Override
+ public HttpResponse execute(HttpUriRequest request, HttpContext context) {
+ requestExecuted = request;
+ StatusLine statusLine = new BasicStatusLine(
+ new ProtocolVersion("HTTP", 1, 1), mStatusCode, "");
+ HttpResponse response = new BasicHttpResponse(statusLine);
+ response.setEntity(mResponseEntity);
+
+ return response;
+ }
+
+
+ // Unimplemented methods ahoy
+
+ @Override
+ public HttpResponse execute(HttpUriRequest request) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public HttpResponse execute(HttpHost target, HttpRequest request) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T> T execute(HttpUriRequest arg0, ResponseHandler<? extends T> arg1) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public HttpResponse execute(HttpHost target, HttpRequest request, HttpContext context) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T> T execute(HttpUriRequest arg0, ResponseHandler<? extends T> arg1, HttpContext arg2) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T> T execute(HttpHost arg0, HttpRequest arg1, ResponseHandler<? extends T> arg2) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T> T execute(HttpHost arg0, HttpRequest arg1, ResponseHandler<? extends T> arg2,
+ HttpContext arg3) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ClientConnectionManager getConnectionManager() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public HttpParams getParams() {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/src/test/java/com/android/volley/mock/MockHttpStack.java b/src/test/java/com/android/volley/mock/MockHttpStack.java
new file mode 100644
index 0000000..9594fde
--- /dev/null
+++ b/src/test/java/com/android/volley/mock/MockHttpStack.java
@@ -0,0 +1,72 @@
+/*
+ * 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.mock;
+
+import com.android.volley.AuthFailureError;
+import com.android.volley.Request;
+import com.android.volley.toolbox.HttpStack;
+
+import org.apache.http.HttpResponse;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class MockHttpStack implements HttpStack {
+
+ private HttpResponse mResponseToReturn;
+
+ private String mLastUrl;
+
+ private Map<String, String> mLastHeaders;
+
+ private byte[] mLastPostBody;
+
+ public String getLastUrl() {
+ return mLastUrl;
+ }
+
+ public Map<String, String> getLastHeaders() {
+ return mLastHeaders;
+ }
+
+ public byte[] getLastPostBody() {
+ return mLastPostBody;
+ }
+
+ public void setResponseToReturn(HttpResponse response) {
+ mResponseToReturn = response;
+ }
+
+ @Override
+ public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
+ throws AuthFailureError {
+ mLastUrl = request.getUrl();
+ mLastHeaders = new HashMap<String, String>();
+ if (request.getHeaders() != null) {
+ mLastHeaders.putAll(request.getHeaders());
+ }
+ if (additionalHeaders != null) {
+ mLastHeaders.putAll(additionalHeaders);
+ }
+ try {
+ mLastPostBody = request.getBody();
+ } catch (AuthFailureError e) {
+ mLastPostBody = null;
+ }
+ return mResponseToReturn;
+ }
+}
diff --git a/src/test/java/com/android/volley/mock/MockHttpURLConnection.java b/src/test/java/com/android/volley/mock/MockHttpURLConnection.java
new file mode 100644
index 0000000..efa3a21
--- /dev/null
+++ b/src/test/java/com/android/volley/mock/MockHttpURLConnection.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2012 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.mock;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+public class MockHttpURLConnection extends HttpURLConnection {
+
+ private boolean mDoOutput;
+ private String mRequestMethod;
+ private OutputStream mOutputStream;
+
+ public MockHttpURLConnection() throws MalformedURLException {
+ super(new URL("http://foo.com"));
+ mDoOutput = false;
+ mRequestMethod = "GET";
+ mOutputStream = new ByteArrayOutputStream();
+ }
+
+ @Override
+ public void setDoOutput(boolean flag) {
+ mDoOutput = flag;
+ }
+
+ @Override
+ public boolean getDoOutput() {
+ return mDoOutput;
+ }
+
+ @Override
+ public void setRequestMethod(String method) {
+ mRequestMethod = method;
+ }
+
+ @Override
+ public String getRequestMethod() {
+ return mRequestMethod;
+ }
+
+ @Override
+ public OutputStream getOutputStream() {
+ return mOutputStream;
+ }
+
+ @Override
+ public void disconnect() {
+ }
+
+ @Override
+ public boolean usingProxy() {
+ return false;
+ }
+
+ @Override
+ public void connect() throws IOException {
+ }
+
+}
diff --git a/src/test/java/com/android/volley/mock/MockNetwork.java b/src/test/java/com/android/volley/mock/MockNetwork.java
new file mode 100644
index 0000000..207ec63
--- /dev/null
+++ b/src/test/java/com/android/volley/mock/MockNetwork.java
@@ -0,0 +1,58 @@
+/*
+ * 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.mock;
+
+import com.android.volley.Network;
+import com.android.volley.NetworkResponse;
+import com.android.volley.Request;
+import com.android.volley.ServerError;
+import com.android.volley.VolleyError;
+
+public class MockNetwork implements Network {
+ public final static int ALWAYS_THROW_EXCEPTIONS = -1;
+
+ private int mNumExceptionsToThrow = 0;
+ private byte[] mDataToReturn = null;
+
+ /**
+ * @param numExceptionsToThrow number of times to throw an exception or
+ * {@link #ALWAYS_THROW_EXCEPTIONS}
+ */
+ public void setNumExceptionsToThrow(int numExceptionsToThrow) {
+ mNumExceptionsToThrow = numExceptionsToThrow;
+ }
+
+ public void setDataToReturn(byte[] data) {
+ mDataToReturn = data;
+ }
+
+ public Request<?> requestHandled = null;
+
+ @Override
+ public NetworkResponse performRequest(Request<?> request) throws VolleyError {
+ if (mNumExceptionsToThrow > 0 || mNumExceptionsToThrow == ALWAYS_THROW_EXCEPTIONS) {
+ if (mNumExceptionsToThrow != ALWAYS_THROW_EXCEPTIONS) {
+ mNumExceptionsToThrow--;
+ }
+ throw new ServerError();
+ }
+
+ requestHandled = request;
+ return new NetworkResponse(mDataToReturn);
+ }
+
+}
diff --git a/src/test/java/com/android/volley/mock/MockRequest.java b/src/test/java/com/android/volley/mock/MockRequest.java
new file mode 100644
index 0000000..9815ea8
--- /dev/null
+++ b/src/test/java/com/android/volley/mock/MockRequest.java
@@ -0,0 +1,101 @@
+/*
+ * 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.mock;
+
+import com.android.volley.NetworkResponse;
+import com.android.volley.Request;
+import com.android.volley.Response;
+import com.android.volley.Response.ErrorListener;
+import com.android.volley.VolleyError;
+import com.android.volley.utils.CacheTestUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class MockRequest extends Request<byte[]> {
+ public MockRequest() {
+ super(Request.Method.GET, "http://foo.com", null);
+ }
+
+ public MockRequest(String url, ErrorListener listener) {
+ super(Request.Method.GET, url, listener);
+ }
+
+ private Map<String, String> mPostParams = new HashMap<String, String>();
+
+ public void setPostParams(Map<String, String> postParams) {
+ mPostParams = postParams;
+ }
+
+ @Override
+ public Map<String, String> getPostParams() {
+ return mPostParams;
+ }
+
+ private String mCacheKey = super.getCacheKey();
+
+ public void setCacheKey(String cacheKey) {
+ mCacheKey = cacheKey;
+ }
+
+ @Override
+ public String getCacheKey() {
+ return mCacheKey;
+ }
+
+ public boolean deliverResponse_called = false;
+ public boolean parseResponse_called = false;
+
+ @Override
+ protected void deliverResponse(byte[] response) {
+ deliverResponse_called = true;
+ }
+
+ public boolean deliverError_called = false;
+
+ @Override
+ public void deliverError(VolleyError error) {
+ super.deliverError(error);
+ deliverError_called = true;
+ }
+
+ public boolean cancel_called = false;
+
+ @Override
+ public void cancel() {
+ cancel_called = true;
+ super.cancel();
+ }
+
+ private Priority mPriority = super.getPriority();
+
+ public void setPriority(Priority priority) {
+ mPriority = priority;
+ }
+
+ @Override
+ public Priority getPriority() {
+ return mPriority;
+ }
+
+ @Override
+ protected Response<byte[]> parseNetworkResponse(NetworkResponse response) {
+ parseResponse_called = true;
+ return Response.success(response.data, CacheTestUtils.makeRandomCacheEntry(response.data));
+ }
+
+}
diff --git a/src/test/java/com/android/volley/mock/MockResponseDelivery.java b/src/test/java/com/android/volley/mock/MockResponseDelivery.java
new file mode 100644
index 0000000..4dbfd5c
--- /dev/null
+++ b/src/test/java/com/android/volley/mock/MockResponseDelivery.java
@@ -0,0 +1,51 @@
+/*
+ * 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.mock;
+
+import com.android.volley.Request;
+import com.android.volley.Response;
+import com.android.volley.ResponseDelivery;
+import com.android.volley.VolleyError;
+
+public class MockResponseDelivery implements ResponseDelivery {
+
+ public boolean postResponse_called = false;
+ public boolean postError_called = false;
+
+ public boolean wasEitherResponseCalled() {
+ return postResponse_called || postError_called;
+ }
+
+ public Response<?> responsePosted = null;
+ @Override
+ public void postResponse(Request<?> request, Response<?> response) {
+ postResponse_called = true;
+ responsePosted = response;
+ }
+
+ @Override
+ public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
+ postResponse_called = true;
+ responsePosted = response;
+ runnable.run();
+ }
+
+ @Override
+ public void postError(Request<?> request, VolleyError error) {
+ postError_called = true;
+ }
+}
diff --git a/src/test/java/com/android/volley/mock/TestRequest.java b/src/test/java/com/android/volley/mock/TestRequest.java
new file mode 100644
index 0000000..dfc4dc1
--- /dev/null
+++ b/src/test/java/com/android/volley/mock/TestRequest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2012 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.mock;
+
+import com.android.volley.NetworkResponse;
+import com.android.volley.Request;
+import com.android.volley.Response;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class TestRequest {
+ private static final String TEST_URL = "http://foo.com";
+
+ /** Base Request class for testing allowing both the deprecated and new constructor. */
+ private static class Base extends Request<byte[]> {
+ @SuppressWarnings("deprecation")
+ public Base(String url, Response.ErrorListener listener) {
+ super(url, listener);
+ }
+
+ public Base(int method, String url, Response.ErrorListener listener) {
+ super(method, url, listener);
+ }
+
+ @Override
+ protected Response<byte[]> parseNetworkResponse(NetworkResponse response) {
+ return null;
+ }
+
+ @Override
+ protected void deliverResponse(byte[] response) {
+ }
+ }
+
+ /** Test example of a GET request in the deprecated style. */
+ public static class DeprecatedGet extends Base {
+ public DeprecatedGet() {
+ super(TEST_URL, null);
+ }
+ }
+
+ /** Test example of a POST request in the deprecated style. */
+ public static class DeprecatedPost extends Base {
+ private Map<String, String> mPostParams;
+
+ public DeprecatedPost() {
+ super(TEST_URL, null);
+ mPostParams = new HashMap<String, String>();
+ mPostParams.put("requestpost", "foo");
+ }
+
+ @Override
+ protected Map<String, String> getPostParams() {
+ return mPostParams;
+ }
+ }
+
+ /** Test example of a GET request in the new style. */
+ public static class Get extends Base {
+ public Get() {
+ super(Method.GET, TEST_URL, null);
+ }
+ }
+
+ /**
+ * Test example of a POST request in the new style. In the new style, it is possible
+ * to have a POST with no body.
+ */
+ public static class Post extends Base {
+ public Post() {
+ super(Method.POST, TEST_URL, null);
+ }
+ }
+
+ /** Test example of a POST request in the new style with a body. */
+ public static class PostWithBody extends Post {
+ private Map<String, String> mParams;
+
+ public PostWithBody() {
+ mParams = new HashMap<String, String>();
+ mParams.put("testKey", "testValue");
+ }
+
+ @Override
+ public Map<String, String> getParams() {
+ return mParams;
+ }
+ }
+
+ /**
+ * Test example of a PUT request in the new style. In the new style, it is possible to have a
+ * PUT with no body.
+ */
+ public static class Put extends Base {
+ public Put() {
+ super(Method.PUT, TEST_URL, null);
+ }
+ }
+
+ /** Test example of a PUT request in the new style with a body. */
+ public static class PutWithBody extends Put {
+ private Map<String, String> mParams = new HashMap<String, String>();
+
+ public PutWithBody() {
+ mParams = new HashMap<String, String>();
+ mParams.put("testKey", "testValue");
+ }
+
+ @Override
+ public Map<String, String> getParams() {
+ return mParams;
+ }
+ }
+
+ /** Test example of a DELETE request in the new style. */
+ public static class Delete extends Base {
+ public Delete() {
+ super(Method.DELETE, TEST_URL, null);
+ }
+ }
+
+ /** Test example of a HEAD request in the new style. */
+ public static class Head extends Base {
+ public Head() {
+ super(Method.HEAD, TEST_URL, null);
+ }
+ }
+
+ /** Test example of a OPTIONS request in the new style. */
+ public static class Options extends Base {
+ public Options() {
+ super(Method.OPTIONS, TEST_URL, null);
+ }
+ }
+
+ /** Test example of a TRACE request in the new style. */
+ public static class Trace extends Base {
+ public Trace() {
+ super(Method.TRACE, TEST_URL, null);
+ }
+ }
+
+ /** Test example of a PATCH request in the new style. */
+ public static class Patch extends Base {
+ public Patch() {
+ super(Method.PATCH, TEST_URL, null);
+ }
+ }
+
+ /** Test example of a PATCH request in the new style with a body. */
+ public static class PatchWithBody extends Patch {
+ private Map<String, String> mParams = new HashMap<String, String>();
+
+ public PatchWithBody() {
+ mParams = new HashMap<String, String>();
+ mParams.put("testKey", "testValue");
+ }
+
+ @Override
+ public Map<String, String> getParams() {
+ return mParams;
+ }
+ }
+}
diff --git a/src/test/java/com/android/volley/mock/WaitableQueue.java b/src/test/java/com/android/volley/mock/WaitableQueue.java
new file mode 100644
index 0000000..079bbf5
--- /dev/null
+++ b/src/test/java/com/android/volley/mock/WaitableQueue.java
@@ -0,0 +1,72 @@
+/*
+ * 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.mock;
+
+import com.android.volley.NetworkResponse;
+import com.android.volley.Request;
+import com.android.volley.Response;
+
+import java.util.concurrent.PriorityBlockingQueue;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+// TODO: the name of this class sucks
+@SuppressWarnings("serial")
+public class WaitableQueue extends PriorityBlockingQueue<Request<?>> {
+ private final Request<?> mStopRequest = new MagicStopRequest();
+ private final Semaphore mStopEvent = new Semaphore(0);
+
+ // TODO: this isn't really "until empty" it's "until next call to take() after empty"
+ public void waitUntilEmpty(long timeoutMillis)
+ throws TimeoutException, InterruptedException {
+ add(mStopRequest);
+ if (!mStopEvent.tryAcquire(timeoutMillis, TimeUnit.MILLISECONDS)) {
+ throw new TimeoutException();
+ }
+ }
+
+ @Override
+ public Request<?> take() throws InterruptedException {
+ Request<?> item = super.take();
+ if (item == mStopRequest) {
+ mStopEvent.release();
+ return take();
+ }
+ return item;
+ }
+
+ private static class MagicStopRequest extends Request<Object> {
+ public MagicStopRequest() {
+ super(Request.Method.GET, "", null);
+ }
+
+ @Override
+ public Priority getPriority() {
+ return Priority.LOW;
+ }
+
+ @Override
+ protected Response<Object> parseNetworkResponse(NetworkResponse response) {
+ return null;
+ }
+
+ @Override
+ protected void deliverResponse(Object response) {
+ }
+ }
+}
diff --git a/src/test/java/com/android/volley/toolbox/BasicNetworkTest.java b/src/test/java/com/android/volley/toolbox/BasicNetworkTest.java
new file mode 100644
index 0000000..89718b1
--- /dev/null
+++ b/src/test/java/com/android/volley/toolbox/BasicNetworkTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.toolbox;
+
+import com.android.volley.NetworkResponse;
+import com.android.volley.Request;
+import com.android.volley.Response;
+import com.android.volley.mock.MockHttpStack;
+
+import org.apache.http.ProtocolVersion;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.message.BasicHttpResponse;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import static org.junit.Assert.*;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@RunWith(RobolectricTestRunner.class)
+public class BasicNetworkTest {
+
+ @Test public void headersAndPostParams() throws Exception {
+ MockHttpStack mockHttpStack = new MockHttpStack();
+ BasicHttpResponse fakeResponse = new BasicHttpResponse(new ProtocolVersion("HTTP", 1, 1),
+ 200, "OK");
+ fakeResponse.setEntity(new StringEntity("foobar"));
+ mockHttpStack.setResponseToReturn(fakeResponse);
+ BasicNetwork httpNetwork = new BasicNetwork(mockHttpStack);
+ Request<String> request = new Request<String>(Request.Method.GET, "http://foo", null) {
+
+ @Override
+ protected Response<String> parseNetworkResponse(NetworkResponse response) {
+ return null;
+ }
+
+ @Override
+ protected void deliverResponse(String response) {
+ }
+
+ @Override
+ public Map<String, String> getHeaders() {
+ Map<String, String> result = new HashMap<String, String>();
+ result.put("requestheader", "foo");
+ return result;
+ }
+
+ @Override
+ public Map<String, String> getParams() {
+ Map<String, String> result = new HashMap<String, String>();
+ result.put("requestpost", "foo");
+ return result;
+ }
+ };
+ httpNetwork.performRequest(request);
+ assertEquals("foo", mockHttpStack.getLastHeaders().get("requestheader"));
+ assertEquals("requestpost=foo&", new String(mockHttpStack.getLastPostBody()));
+ }
+}
diff --git a/src/test/java/com/android/volley/toolbox/ByteArrayPoolTest.java b/src/test/java/com/android/volley/toolbox/ByteArrayPoolTest.java
new file mode 100644
index 0000000..661e994
--- /dev/null
+++ b/src/test/java/com/android/volley/toolbox/ByteArrayPoolTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2012 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.toolbox;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+public class ByteArrayPoolTest {
+ @Test public void reusesBuffer() {
+ ByteArrayPool pool = new ByteArrayPool(32);
+
+ byte[] buf1 = pool.getBuf(16);
+ byte[] buf2 = pool.getBuf(16);
+
+ pool.returnBuf(buf1);
+ pool.returnBuf(buf2);
+
+ byte[] buf3 = pool.getBuf(16);
+ byte[] buf4 = pool.getBuf(16);
+ assertTrue(buf3 == buf1 || buf3 == buf2);
+ assertTrue(buf4 == buf1 || buf4 == buf2);
+ assertTrue(buf3 != buf4);
+ }
+
+ @Test public void obeysSizeLimit() {
+ ByteArrayPool pool = new ByteArrayPool(32);
+
+ byte[] buf1 = pool.getBuf(16);
+ byte[] buf2 = pool.getBuf(16);
+ byte[] buf3 = pool.getBuf(16);
+
+ pool.returnBuf(buf1);
+ pool.returnBuf(buf2);
+ pool.returnBuf(buf3);
+
+ byte[] buf4 = pool.getBuf(16);
+ byte[] buf5 = pool.getBuf(16);
+ byte[] buf6 = pool.getBuf(16);
+
+ assertTrue(buf4 == buf2 || buf4 == buf3);
+ assertTrue(buf5 == buf2 || buf5 == buf3);
+ assertTrue(buf4 != buf5);
+ assertTrue(buf6 != buf1 && buf6 != buf2 && buf6 != buf3);
+ }
+
+ @Test public void returnsBufferWithRightSize() {
+ ByteArrayPool pool = new ByteArrayPool(32);
+
+ byte[] buf1 = pool.getBuf(16);
+ pool.returnBuf(buf1);
+
+ byte[] buf2 = pool.getBuf(17);
+ assertNotSame(buf2, buf1);
+
+ byte[] buf3 = pool.getBuf(15);
+ assertSame(buf3, buf1);
+ }
+}
diff --git a/src/test/java/com/android/volley/toolbox/DiskBasedCacheTest.java b/src/test/java/com/android/volley/toolbox/DiskBasedCacheTest.java
new file mode 100644
index 0000000..4b2955d
--- /dev/null
+++ b/src/test/java/com/android/volley/toolbox/DiskBasedCacheTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2013 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.toolbox;
+
+import com.android.volley.Cache;
+import com.android.volley.toolbox.DiskBasedCache.CacheHeader;
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.*;
+
+public class DiskBasedCacheTest {
+
+ // Simple end-to-end serialize/deserialize test.
+ @Test public void cacheHeaderSerialization() throws Exception {
+ Cache.Entry e = new Cache.Entry();
+ e.data = new byte[8];
+ e.serverDate = 1234567L;
+ e.ttl = 9876543L;
+ e.softTtl = 8765432L;
+ e.etag = "etag";
+ e.responseHeaders = new HashMap<String, String>();
+ e.responseHeaders.put("fruit", "banana");
+
+ CacheHeader first = new CacheHeader("my-magical-key", e);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ first.writeHeader(baos);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ CacheHeader second = CacheHeader.readHeader(bais);
+
+ assertEquals(first.key, second.key);
+ assertEquals(first.serverDate, second.serverDate);
+ assertEquals(first.ttl, second.ttl);
+ assertEquals(first.softTtl, second.softTtl);
+ assertEquals(first.etag, second.etag);
+ assertEquals(first.responseHeaders, second.responseHeaders);
+ }
+
+ @Test public void serializeInt() throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DiskBasedCache.writeInt(baos, 0);
+ DiskBasedCache.writeInt(baos, 19791214);
+ DiskBasedCache.writeInt(baos, -20050711);
+ DiskBasedCache.writeInt(baos, Integer.MIN_VALUE);
+ DiskBasedCache.writeInt(baos, Integer.MAX_VALUE);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ assertEquals(DiskBasedCache.readInt(bais), 0);
+ assertEquals(DiskBasedCache.readInt(bais), 19791214);
+ assertEquals(DiskBasedCache.readInt(bais), -20050711);
+ assertEquals(DiskBasedCache.readInt(bais), Integer.MIN_VALUE);
+ assertEquals(DiskBasedCache.readInt(bais), Integer.MAX_VALUE);
+ }
+
+ @Test public void serializeLong() throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DiskBasedCache.writeLong(baos, 0);
+ DiskBasedCache.writeLong(baos, 31337);
+ DiskBasedCache.writeLong(baos, -4160);
+ DiskBasedCache.writeLong(baos, 4295032832L);
+ DiskBasedCache.writeLong(baos, -4314824046L);
+ DiskBasedCache.writeLong(baos, Long.MIN_VALUE);
+ DiskBasedCache.writeLong(baos, Long.MAX_VALUE);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ assertEquals(DiskBasedCache.readLong(bais), 0);
+ assertEquals(DiskBasedCache.readLong(bais), 31337);
+ assertEquals(DiskBasedCache.readLong(bais), -4160);
+ assertEquals(DiskBasedCache.readLong(bais), 4295032832L);
+ assertEquals(DiskBasedCache.readLong(bais), -4314824046L);
+ assertEquals(DiskBasedCache.readLong(bais), Long.MIN_VALUE);
+ assertEquals(DiskBasedCache.readLong(bais), Long.MAX_VALUE);
+ }
+
+ @Test public void serializeString() throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DiskBasedCache.writeString(baos, "");
+ DiskBasedCache.writeString(baos, "This is a string.");
+ DiskBasedCache.writeString(baos, "ファイカス");
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ assertEquals(DiskBasedCache.readString(bais), "");
+ assertEquals(DiskBasedCache.readString(bais), "This is a string.");
+ assertEquals(DiskBasedCache.readString(bais), "ファイカス");
+ }
+
+ @Test public void serializeMap() throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ Map<String, String> empty = new HashMap<String, String>();
+ DiskBasedCache.writeStringStringMap(empty, baos);
+ DiskBasedCache.writeStringStringMap(null, baos);
+ Map<String, String> twoThings = new HashMap<String, String>();
+ twoThings.put("first", "thing");
+ twoThings.put("second", "item");
+ DiskBasedCache.writeStringStringMap(twoThings, baos);
+ Map<String, String> emptyKey = new HashMap<String, String>();
+ emptyKey.put("", "value");
+ DiskBasedCache.writeStringStringMap(emptyKey, baos);
+ Map<String, String> emptyValue = new HashMap<String, String>();
+ emptyValue.put("key", "");
+ DiskBasedCache.writeStringStringMap(emptyValue, baos);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ assertEquals(DiskBasedCache.readStringStringMap(bais), empty);
+ assertEquals(DiskBasedCache.readStringStringMap(bais), empty); // null reads back empty
+ assertEquals(DiskBasedCache.readStringStringMap(bais), twoThings);
+ assertEquals(DiskBasedCache.readStringStringMap(bais), emptyKey);
+ assertEquals(DiskBasedCache.readStringStringMap(bais), emptyValue);
+ }
+}
diff --git a/src/test/java/com/android/volley/toolbox/HttpClientStackTest.java b/src/test/java/com/android/volley/toolbox/HttpClientStackTest.java
new file mode 100644
index 0000000..0c417d4
--- /dev/null
+++ b/src/test/java/com/android/volley/toolbox/HttpClientStackTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2012 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.toolbox;
+
+import com.android.volley.Request.Method;
+import com.android.volley.mock.TestRequest;
+import com.android.volley.toolbox.HttpClientStack.HttpPatch;
+
+import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpHead;
+import org.apache.http.client.methods.HttpOptions;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.client.methods.HttpTrace;
+import org.apache.http.client.methods.HttpUriRequest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import static org.junit.Assert.*;
+
+@RunWith(RobolectricTestRunner.class)
+public class HttpClientStackTest {
+
+ @Test public void createDeprecatedGetRequest() throws Exception {
+ TestRequest.DeprecatedGet request = new TestRequest.DeprecatedGet();
+ assertEquals(request.getMethod(), Method.DEPRECATED_GET_OR_POST);
+
+ HttpUriRequest httpRequest = HttpClientStack.createHttpRequest(request, null);
+ assertTrue(httpRequest instanceof HttpGet);
+ }
+
+ @Test public void createDeprecatedPostRequest() throws Exception {
+ TestRequest.DeprecatedPost request = new TestRequest.DeprecatedPost();
+ assertEquals(request.getMethod(), Method.DEPRECATED_GET_OR_POST);
+
+ HttpUriRequest httpRequest = HttpClientStack.createHttpRequest(request, null);
+ assertTrue(httpRequest instanceof HttpPost);
+ }
+
+ @Test public void createGetRequest() throws Exception {
+ TestRequest.Get request = new TestRequest.Get();
+ assertEquals(request.getMethod(), Method.GET);
+
+ HttpUriRequest httpRequest = HttpClientStack.createHttpRequest(request, null);
+ assertTrue(httpRequest instanceof HttpGet);
+ }
+
+ @Test public void createPostRequest() throws Exception {
+ TestRequest.Post request = new TestRequest.Post();
+ assertEquals(request.getMethod(), Method.POST);
+
+ HttpUriRequest httpRequest = HttpClientStack.createHttpRequest(request, null);
+ assertTrue(httpRequest instanceof HttpPost);
+ }
+
+ @Test public void createPostRequestWithBody() throws Exception {
+ TestRequest.PostWithBody request = new TestRequest.PostWithBody();
+ assertEquals(request.getMethod(), Method.POST);
+
+ HttpUriRequest httpRequest = HttpClientStack.createHttpRequest(request, null);
+ assertTrue(httpRequest instanceof HttpPost);
+ }
+
+ @Test public void createPutRequest() throws Exception {
+ TestRequest.Put request = new TestRequest.Put();
+ assertEquals(request.getMethod(), Method.PUT);
+
+ HttpUriRequest httpRequest = HttpClientStack.createHttpRequest(request, null);
+ assertTrue(httpRequest instanceof HttpPut);
+ }
+
+ @Test public void createPutRequestWithBody() throws Exception {
+ TestRequest.PutWithBody request = new TestRequest.PutWithBody();
+ assertEquals(request.getMethod(), Method.PUT);
+
+ HttpUriRequest httpRequest = HttpClientStack.createHttpRequest(request, null);
+ assertTrue(httpRequest instanceof HttpPut);
+ }
+
+ @Test public void createDeleteRequest() throws Exception {
+ TestRequest.Delete request = new TestRequest.Delete();
+ assertEquals(request.getMethod(), Method.DELETE);
+
+ HttpUriRequest httpRequest = HttpClientStack.createHttpRequest(request, null);
+ assertTrue(httpRequest instanceof HttpDelete);
+ }
+
+ @Test public void createHeadRequest() throws Exception {
+ TestRequest.Head request = new TestRequest.Head();
+ assertEquals(request.getMethod(), Method.HEAD);
+
+ HttpUriRequest httpRequest = HttpClientStack.createHttpRequest(request, null);
+ assertTrue(httpRequest instanceof HttpHead);
+ }
+
+ @Test public void createOptionsRequest() throws Exception {
+ TestRequest.Options request = new TestRequest.Options();
+ assertEquals(request.getMethod(), Method.OPTIONS);
+
+ HttpUriRequest httpRequest = HttpClientStack.createHttpRequest(request, null);
+ assertTrue(httpRequest instanceof HttpOptions);
+ }
+
+ @Test public void createTraceRequest() throws Exception {
+ TestRequest.Trace request = new TestRequest.Trace();
+ assertEquals(request.getMethod(), Method.TRACE);
+
+ HttpUriRequest httpRequest = HttpClientStack.createHttpRequest(request, null);
+ assertTrue(httpRequest instanceof HttpTrace);
+ }
+
+ @Test public void createPatchRequest() throws Exception {
+ TestRequest.Patch request = new TestRequest.Patch();
+ assertEquals(request.getMethod(), Method.PATCH);
+
+ HttpUriRequest httpRequest = HttpClientStack.createHttpRequest(request, null);
+ assertTrue(httpRequest instanceof HttpPatch);
+ }
+
+ @Test public void createPatchRequestWithBody() throws Exception {
+ TestRequest.PatchWithBody request = new TestRequest.PatchWithBody();
+ assertEquals(request.getMethod(), Method.PATCH);
+
+ HttpUriRequest httpRequest = HttpClientStack.createHttpRequest(request, null);
+ assertTrue(httpRequest instanceof HttpPatch);
+ }
+}
diff --git a/src/test/java/com/android/volley/toolbox/HttpHeaderParserTest.java b/src/test/java/com/android/volley/toolbox/HttpHeaderParserTest.java
new file mode 100644
index 0000000..b8c4847
--- /dev/null
+++ b/src/test/java/com/android/volley/toolbox/HttpHeaderParserTest.java
@@ -0,0 +1,226 @@
+/*
+ * 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.toolbox;
+
+import com.android.volley.Cache;
+import com.android.volley.NetworkResponse;
+
+import org.apache.http.Header;
+import org.apache.http.message.BasicHeader;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import static org.junit.Assert.*;
+
+@RunWith(RobolectricTestRunner.class)
+public class HttpHeaderParserTest {
+
+ private static long ONE_MINUTE_MILLIS = 1000L * 60;
+ private static long ONE_HOUR_MILLIS = 1000L * 60 * 60;
+
+ private NetworkResponse response;
+ private Map<String, String> headers;
+
+ @Before public void setUp() throws Exception {
+ headers = new HashMap<String, String>();
+ response = new NetworkResponse(0, null, headers, false);
+ }
+
+ @Test public void parseCacheHeaders_noHeaders() {
+ Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
+
+ assertNotNull(entry);
+ assertNull(entry.etag);
+ assertEquals(0, entry.serverDate);
+ assertEquals(0, entry.ttl);
+ assertEquals(0, entry.softTtl);
+ }
+
+ @Test public void parseCacheHeaders_headersSet() {
+ headers.put("MyCustomHeader", "42");
+
+ Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
+
+ assertNotNull(entry);
+ assertNotNull(entry.responseHeaders);
+ assertEquals(1, entry.responseHeaders.size());
+ assertEquals("42", entry.responseHeaders.get("MyCustomHeader"));
+ }
+
+ @Test public void parseCacheHeaders_etag() {
+ headers.put("ETag", "Yow!");
+
+ Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
+
+ assertNotNull(entry);
+ assertEquals("Yow!", entry.etag);
+ }
+
+ @Test public void parseCacheHeaders_normalExpire() {
+ long now = System.currentTimeMillis();
+ headers.put("Date", rfc1123Date(now));
+ headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
+
+ Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
+
+ assertNotNull(entry);
+ assertNull(entry.etag);
+ assertEqualsWithin(entry.serverDate, now, ONE_MINUTE_MILLIS);
+ assertTrue(entry.softTtl >= (now + ONE_HOUR_MILLIS));
+ assertTrue(entry.ttl == entry.softTtl);
+ }
+
+ @Test public void parseCacheHeaders_expiresInPast() {
+ long now = System.currentTimeMillis();
+ headers.put("Date", rfc1123Date(now));
+ headers.put("Expires", rfc1123Date(now - ONE_HOUR_MILLIS));
+
+ Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
+
+ assertNotNull(entry);
+ assertNull(entry.etag);
+ assertEqualsWithin(entry.serverDate, now, ONE_MINUTE_MILLIS);
+ assertEquals(0, entry.ttl);
+ assertEquals(0, entry.softTtl);
+ }
+
+ @Test public void parseCacheHeaders_serverRelative() {
+
+ long now = System.currentTimeMillis();
+ // Set "current" date as one hour in the future
+ headers.put("Date", rfc1123Date(now + ONE_HOUR_MILLIS));
+ // TTL four hours in the future, so should be three hours from now
+ headers.put("Expires", rfc1123Date(now + 4 * ONE_HOUR_MILLIS));
+
+ Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
+
+ assertEqualsWithin(now + 3 * ONE_HOUR_MILLIS, entry.ttl, ONE_MINUTE_MILLIS);
+ assertEquals(entry.softTtl, entry.ttl);
+ }
+
+ @Test public void parseCacheHeaders_cacheControlOverridesExpires() {
+ long now = System.currentTimeMillis();
+ headers.put("Date", rfc1123Date(now));
+ headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
+ headers.put("Cache-Control", "public, max-age=86400");
+
+ Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
+
+ assertNotNull(entry);
+ assertNull(entry.etag);
+ assertEqualsWithin(now + 24 * ONE_HOUR_MILLIS, entry.ttl, ONE_MINUTE_MILLIS);
+ assertEquals(entry.softTtl, entry.ttl);
+ }
+
+ @Test public void parseCacheHeaders_cacheControlNoCache() {
+ long now = System.currentTimeMillis();
+ headers.put("Date", rfc1123Date(now));
+ headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
+ headers.put("Cache-Control", "no-cache");
+
+ Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
+
+ assertNull(entry);
+ }
+
+ @Test public void parseCacheHeaders_cacheControlMustRevalidate() {
+ long now = System.currentTimeMillis();
+ headers.put("Date", rfc1123Date(now));
+ headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
+ headers.put("Cache-Control", "must-revalidate");
+
+ Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
+
+ assertNotNull(entry);
+ assertNull(entry.etag);
+ assertEqualsWithin(now, entry.ttl, ONE_MINUTE_MILLIS);
+ assertEquals(entry.softTtl, entry.ttl);
+ }
+
+ private void assertEqualsWithin(long expected, long value, long fudgeFactor) {
+ long diff = Math.abs(expected - value);
+ assertTrue(diff < fudgeFactor);
+ }
+
+ private static String rfc1123Date(long millis) {
+ DateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.ENGLISH);
+ return df.format(new Date(millis));
+ }
+
+ // --------------------------
+
+ @Test public void parseCharset() {
+ // Like the ones we usually see
+ headers.put("Content-Type", "text/plain; charset=utf-8");
+ assertEquals("utf-8", HttpHeaderParser.parseCharset(headers));
+
+ // Extra whitespace
+ headers.put("Content-Type", "text/plain; charset=utf-8 ");
+ assertEquals("utf-8", HttpHeaderParser.parseCharset(headers));
+
+ // Extra parameters
+ headers.put("Content-Type", "text/plain; charset=utf-8; frozzle=bar");
+ assertEquals("utf-8", HttpHeaderParser.parseCharset(headers));
+
+ // No Content-Type header
+ headers.clear();
+ assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers));
+
+ // Empty value
+ headers.put("Content-Type", "text/plain; charset=");
+ assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers));
+
+ // None specified
+ headers.put("Content-Type", "text/plain");
+ assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers));
+
+ // None specified, extra semicolon
+ headers.put("Content-Type", "text/plain;");
+ assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers));
+ }
+
+ @Test public void parseCaseInsensitive() {
+
+ long now = System.currentTimeMillis();
+
+ Header[] headersArray = new Header[5];
+ headersArray[0] = new BasicHeader("eTAG", "Yow!");
+ headersArray[1] = new BasicHeader("DATE", rfc1123Date(now));
+ headersArray[2] = new BasicHeader("expires", rfc1123Date(now + ONE_HOUR_MILLIS));
+ headersArray[3] = new BasicHeader("cache-control", "public, max-age=86400");
+ headersArray[4] = new BasicHeader("content-type", "text/plain");
+
+ Map<String, String> headers = BasicNetwork.convertHeaders(headersArray);
+ NetworkResponse response = new NetworkResponse(0, null, headers, false);
+ Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
+
+ assertNotNull(entry);
+ assertEquals("Yow!", entry.etag);
+ assertEqualsWithin(now + 24 * ONE_HOUR_MILLIS, entry.ttl, ONE_MINUTE_MILLIS);
+ assertEquals(entry.softTtl, entry.ttl);
+ assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers));
+ }
+}
diff --git a/src/test/java/com/android/volley/toolbox/HurlStackTest.java b/src/test/java/com/android/volley/toolbox/HurlStackTest.java
new file mode 100644
index 0000000..42aeea8
--- /dev/null
+++ b/src/test/java/com/android/volley/toolbox/HurlStackTest.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2012 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.toolbox;
+
+import com.android.volley.Request.Method;
+import com.android.volley.mock.MockHttpURLConnection;
+import com.android.volley.mock.TestRequest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import static org.junit.Assert.*;
+
+@RunWith(RobolectricTestRunner.class)
+public class HurlStackTest {
+
+ private MockHttpURLConnection mMockConnection;
+
+ @Before public void setUp() throws Exception {
+ mMockConnection = new MockHttpURLConnection();
+ }
+
+ @Test public void connectionForDeprecatedGetRequest() throws Exception {
+ TestRequest.DeprecatedGet request = new TestRequest.DeprecatedGet();
+ assertEquals(request.getMethod(), Method.DEPRECATED_GET_OR_POST);
+
+ HurlStack.setConnectionParametersForRequest(mMockConnection, request);
+ assertEquals("GET", mMockConnection.getRequestMethod());
+ assertFalse(mMockConnection.getDoOutput());
+ }
+
+ @Test public void connectionForDeprecatedPostRequest() throws Exception {
+ TestRequest.DeprecatedPost request = new TestRequest.DeprecatedPost();
+ assertEquals(request.getMethod(), Method.DEPRECATED_GET_OR_POST);
+
+ HurlStack.setConnectionParametersForRequest(mMockConnection, request);
+ assertEquals("POST", mMockConnection.getRequestMethod());
+ assertTrue(mMockConnection.getDoOutput());
+ }
+
+ @Test public void connectionForGetRequest() throws Exception {
+ TestRequest.Get request = new TestRequest.Get();
+ assertEquals(request.getMethod(), Method.GET);
+
+ HurlStack.setConnectionParametersForRequest(mMockConnection, request);
+ assertEquals("GET", mMockConnection.getRequestMethod());
+ assertFalse(mMockConnection.getDoOutput());
+ }
+
+ @Test public void connectionForPostRequest() throws Exception {
+ TestRequest.Post request = new TestRequest.Post();
+ assertEquals(request.getMethod(), Method.POST);
+
+ HurlStack.setConnectionParametersForRequest(mMockConnection, request);
+ assertEquals("POST", mMockConnection.getRequestMethod());
+ assertFalse(mMockConnection.getDoOutput());
+ }
+
+ @Test public void connectionForPostWithBodyRequest() throws Exception {
+ TestRequest.PostWithBody request = new TestRequest.PostWithBody();
+ assertEquals(request.getMethod(), Method.POST);
+
+ HurlStack.setConnectionParametersForRequest(mMockConnection, request);
+ assertEquals("POST", mMockConnection.getRequestMethod());
+ assertTrue(mMockConnection.getDoOutput());
+ }
+
+ @Test public void connectionForPutRequest() throws Exception {
+ TestRequest.Put request = new TestRequest.Put();
+ assertEquals(request.getMethod(), Method.PUT);
+
+ HurlStack.setConnectionParametersForRequest(mMockConnection, request);
+ assertEquals("PUT", mMockConnection.getRequestMethod());
+ assertFalse(mMockConnection.getDoOutput());
+ }
+
+ @Test public void connectionForPutWithBodyRequest() throws Exception {
+ TestRequest.PutWithBody request = new TestRequest.PutWithBody();
+ assertEquals(request.getMethod(), Method.PUT);
+
+ HurlStack.setConnectionParametersForRequest(mMockConnection, request);
+ assertEquals("PUT", mMockConnection.getRequestMethod());
+ assertTrue(mMockConnection.getDoOutput());
+ }
+
+ @Test public void connectionForDeleteRequest() throws Exception {
+ TestRequest.Delete request = new TestRequest.Delete();
+ assertEquals(request.getMethod(), Method.DELETE);
+
+ HurlStack.setConnectionParametersForRequest(mMockConnection, request);
+ assertEquals("DELETE", mMockConnection.getRequestMethod());
+ assertFalse(mMockConnection.getDoOutput());
+ }
+
+ @Test public void connectionForHeadRequest() throws Exception {
+ TestRequest.Head request = new TestRequest.Head();
+ assertEquals(request.getMethod(), Method.HEAD);
+
+ HurlStack.setConnectionParametersForRequest(mMockConnection, request);
+ assertEquals("HEAD", mMockConnection.getRequestMethod());
+ assertFalse(mMockConnection.getDoOutput());
+ }
+
+ @Test public void connectionForOptionsRequest() throws Exception {
+ TestRequest.Options request = new TestRequest.Options();
+ assertEquals(request.getMethod(), Method.OPTIONS);
+
+ HurlStack.setConnectionParametersForRequest(mMockConnection, request);
+ assertEquals("OPTIONS", mMockConnection.getRequestMethod());
+ assertFalse(mMockConnection.getDoOutput());
+ }
+
+ @Test public void connectionForTraceRequest() throws Exception {
+ TestRequest.Trace request = new TestRequest.Trace();
+ assertEquals(request.getMethod(), Method.TRACE);
+
+ HurlStack.setConnectionParametersForRequest(mMockConnection, request);
+ assertEquals("TRACE", mMockConnection.getRequestMethod());
+ assertFalse(mMockConnection.getDoOutput());
+ }
+
+ @Test public void connectionForPatchRequest() throws Exception {
+ TestRequest.Patch request = new TestRequest.Patch();
+ assertEquals(request.getMethod(), Method.PATCH);
+
+ HurlStack.setConnectionParametersForRequest(mMockConnection, request);
+ assertEquals("PATCH", mMockConnection.getRequestMethod());
+ assertFalse(mMockConnection.getDoOutput());
+ }
+
+ @Test public void connectionForPatchWithBodyRequest() throws Exception {
+ TestRequest.PatchWithBody request = new TestRequest.PatchWithBody();
+ assertEquals(request.getMethod(), Method.PATCH);
+
+ HurlStack.setConnectionParametersForRequest(mMockConnection, request);
+ assertEquals("PATCH", mMockConnection.getRequestMethod());
+ assertTrue(mMockConnection.getDoOutput());
+ }
+}
diff --git a/src/test/java/com/android/volley/toolbox/ImageRequestTest.java b/src/test/java/com/android/volley/toolbox/ImageRequestTest.java
new file mode 100644
index 0000000..2f4495a
--- /dev/null
+++ b/src/test/java/com/android/volley/toolbox/ImageRequestTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.toolbox;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+
+import com.android.volley.NetworkResponse;
+import com.android.volley.Response;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.shadows.ShadowBitmapFactory;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.junit.Assert.*;
+
+@RunWith(RobolectricTestRunner.class)
+public class ImageRequestTest {
+
+ @Test public void parseNetworkResponse_resizing() throws Exception {
+ // This is a horrible hack but Robolectric doesn't have a way to provide
+ // width and height hints for decodeByteArray. It works because the byte array
+ // "file:fake" is ASCII encodable and thus the name in Robolectric's fake
+ // bitmap creator survives as-is, and provideWidthAndHeightHints puts
+ // "file:" + name in its lookaside map. I write all this because it will
+ // probably break mysteriously at some point and I feel terrible about your
+ // having to debug it.
+ byte[] jpegBytes = "file:fake".getBytes();
+ ShadowBitmapFactory.provideWidthAndHeightHints("fake", 1024, 500);
+ NetworkResponse jpeg = new NetworkResponse(jpegBytes);
+
+ // No resize
+ verifyResize(jpeg, 0, 0, 1024, 500);
+
+ // Exact sizes
+ verifyResize(jpeg, 512, 250, 512, 250); // exactly half
+ verifyResize(jpeg, 511, 249, 509, 249); // just under half
+ verifyResize(jpeg, 1080, 500, 1024, 500); // larger
+ verifyResize(jpeg, 500, 500, 500, 244); // keep same ratio
+
+ // Specify only width, preserve aspect ratio
+ verifyResize(jpeg, 512, 0, 512, 250);
+ verifyResize(jpeg, 800, 0, 800, 390);
+ verifyResize(jpeg, 1024, 0, 1024, 500);
+
+ // Specify only height, preserve aspect ratio
+ verifyResize(jpeg, 0, 250, 512, 250);
+ verifyResize(jpeg, 0, 391, 800, 391);
+ verifyResize(jpeg, 0, 500, 1024, 500);
+ }
+
+ private void verifyResize(NetworkResponse networkResponse, int maxWidth, int maxHeight,
+ int expectedWidth, int expectedHeight) {
+ ImageRequest request = new ImageRequest(
+ "", null, maxWidth, maxHeight, Config.RGB_565, null);
+ Response<Bitmap> response = request.parseNetworkResponse(networkResponse);
+ assertNotNull(response);
+ assertTrue(response.isSuccess());
+ Bitmap bitmap = response.result;
+ assertNotNull(bitmap);
+ assertEquals(expectedWidth, bitmap.getWidth());
+ assertEquals(expectedHeight, bitmap.getHeight());
+ }
+
+ @Test public void findBestSampleSize() {
+ // desired == actual == 1
+ assertEquals(1, ImageRequest.findBestSampleSize(100, 150, 100, 150));
+
+ // exactly half == 2
+ assertEquals(2, ImageRequest.findBestSampleSize(280, 160, 140, 80));
+
+ // just over half == 1
+ assertEquals(1, ImageRequest.findBestSampleSize(1000, 800, 501, 401));
+
+ // just under 1/4 == 4
+ assertEquals(4, ImageRequest.findBestSampleSize(100, 200, 24, 50));
+ }
+
+ private static byte[] readInputStream(InputStream in) throws IOException {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int count;
+ while ((count = in.read(buffer)) != -1) {
+ bytes.write(buffer, 0, count);
+ }
+ in.close();
+ return bytes.toByteArray();
+ }
+}
diff --git a/src/test/java/com/android/volley/toolbox/NetworkImageViewTest.java b/src/test/java/com/android/volley/toolbox/NetworkImageViewTest.java
new file mode 100644
index 0000000..48c81b6
--- /dev/null
+++ b/src/test/java/com/android/volley/toolbox/NetworkImageViewTest.java
@@ -0,0 +1,53 @@
+package com.android.volley.toolbox;
+
+import android.view.ViewGroup.LayoutParams;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+
+import static org.junit.Assert.*;
+
+@RunWith(RobolectricTestRunner.class)
+public class NetworkImageViewTest {
+ private NetworkImageView mNIV;
+ private MockImageLoader mMockImageLoader;
+
+ @Before public void setUp() throws Exception {
+ mMockImageLoader = new MockImageLoader();
+ mNIV = new NetworkImageView(Robolectric.application);
+ }
+
+ @Test public void setImageUrl_requestsImage() {
+ mNIV.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+ mNIV.setImageUrl("http://foo", mMockImageLoader);
+ assertEquals("http://foo", mMockImageLoader.lastRequestUrl);
+ assertEquals(0, mMockImageLoader.lastMaxWidth);
+ assertEquals(0, mMockImageLoader.lastMaxHeight);
+ }
+
+ // public void testSetImageUrl_setsMaxSize() {
+ // // TODO: Not sure how to make getWidth() return something from an
+ // // instrumentation test. Write this test once it's figured out.
+ // }
+
+ private class MockImageLoader extends ImageLoader {
+ public MockImageLoader() {
+ super(null, null);
+ }
+
+ public String lastRequestUrl;
+ public int lastMaxWidth;
+ public int lastMaxHeight;
+
+ public ImageContainer get(String requestUrl, ImageListener imageListener, int maxWidth,
+ int maxHeight) {
+ lastRequestUrl = requestUrl;
+ lastMaxWidth = maxWidth;
+ lastMaxHeight = maxHeight;
+ return null;
+ }
+ }
+}
diff --git a/src/test/java/com/android/volley/toolbox/PoolingByteArrayOutputStreamTest.java b/src/test/java/com/android/volley/toolbox/PoolingByteArrayOutputStreamTest.java
new file mode 100644
index 0000000..c3bfac7
--- /dev/null
+++ b/src/test/java/com/android/volley/toolbox/PoolingByteArrayOutputStreamTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.toolbox;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class PoolingByteArrayOutputStreamTest {
+ @Test public void pooledOneBuffer() throws IOException {
+ ByteArrayPool pool = new ByteArrayPool(32768);
+ writeOneBuffer(pool);
+ writeOneBuffer(pool);
+ writeOneBuffer(pool);
+ }
+
+ @Test public void pooledIndividualWrites() throws IOException {
+ ByteArrayPool pool = new ByteArrayPool(32768);
+ writeBytesIndividually(pool);
+ writeBytesIndividually(pool);
+ writeBytesIndividually(pool);
+ }
+
+ @Test public void unpooled() throws IOException {
+ ByteArrayPool pool = new ByteArrayPool(0);
+ writeOneBuffer(pool);
+ writeOneBuffer(pool);
+ writeOneBuffer(pool);
+ }
+
+ @Test public void unpooledIndividualWrites() throws IOException {
+ ByteArrayPool pool = new ByteArrayPool(0);
+ writeBytesIndividually(pool);
+ writeBytesIndividually(pool);
+ writeBytesIndividually(pool);
+ }
+
+ private void writeOneBuffer(ByteArrayPool pool) throws IOException {
+ byte[] data = new byte[16384];
+ for (int i = 0; i < data.length; i++) {
+ data[i] = (byte) (i & 0xff);
+ }
+ PoolingByteArrayOutputStream os = new PoolingByteArrayOutputStream(pool);
+ os.write(data);
+
+ assertTrue(Arrays.equals(data, os.toByteArray()));
+ }
+
+ private void writeBytesIndividually(ByteArrayPool pool) {
+ byte[] data = new byte[16384];
+ for (int i = 0; i < data.length; i++) {
+ data[i] = (byte) (i & 0xff);
+ }
+ PoolingByteArrayOutputStream os = new PoolingByteArrayOutputStream(pool);
+ for (int i = 0; i < data.length; i++) {
+ os.write(data[i]);
+ }
+
+ assertTrue(Arrays.equals(data, os.toByteArray()));
+ }
+}
diff --git a/src/test/java/com/android/volley/utils/CacheTestUtils.java b/src/test/java/com/android/volley/utils/CacheTestUtils.java
new file mode 100644
index 0000000..cd2b8e7
--- /dev/null
+++ b/src/test/java/com/android/volley/utils/CacheTestUtils.java
@@ -0,0 +1,40 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+package com.android.volley.utils;
+
+import com.android.volley.Cache;
+
+import java.util.Random;
+
+public class CacheTestUtils {
+
+ /**
+ * Makes a random cache entry.
+ * @param data Data to use, or null to use random data
+ * @param isExpired Whether the TTLs should be set such that this entry is expired
+ * @param needsRefresh Whether the TTLs should be set such that this entry needs refresh
+ */
+ public static Cache.Entry makeRandomCacheEntry(
+ byte[] data, boolean isExpired, boolean needsRefresh) {
+ Random random = new Random();
+ Cache.Entry entry = new Cache.Entry();
+ if (data != null) {
+ entry.data = data;
+ } else {
+ entry.data = new byte[random.nextInt(1024)];
+ }
+ entry.etag = String.valueOf(random.nextLong());
+ entry.serverDate = random.nextLong();
+ entry.ttl = isExpired ? 0 : Long.MAX_VALUE;
+ entry.softTtl = needsRefresh ? 0 : Long.MAX_VALUE;
+ return entry;
+ }
+
+ /**
+ * Like {@link #makeRandomCacheEntry(byte[], boolean, boolean)} but
+ * defaults to an unexpired entry.
+ */
+ public static Cache.Entry makeRandomCacheEntry(byte[] data) {
+ return makeRandomCacheEntry(data, false, false);
+ }
+}
diff --git a/src/test/java/com/android/volley/utils/ImmediateResponseDelivery.java b/src/test/java/com/android/volley/utils/ImmediateResponseDelivery.java
new file mode 100644
index 0000000..666e0d0
--- /dev/null
+++ b/src/test/java/com/android/volley/utils/ImmediateResponseDelivery.java
@@ -0,0 +1,23 @@
+// Copyright 2011 Google Inc. All rights reserved.
+
+package com.android.volley.utils;
+
+import com.android.volley.ExecutorDelivery;
+
+import java.util.concurrent.Executor;
+
+/**
+ * A ResponseDelivery for testing that immediately delivers responses
+ * instead of posting back to the main thread.
+ */
+public class ImmediateResponseDelivery extends ExecutorDelivery {
+
+ public ImmediateResponseDelivery() {
+ super(new Executor() {
+ @Override
+ public void execute(Runnable command) {
+ command.run();
+ }
+ });
+ }
+}