1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.volley; 18 19 import com.android.volley.mock.MockCache; 20 import com.android.volley.mock.MockRequest; 21 import com.android.volley.mock.MockResponseDelivery; 22 import com.android.volley.mock.WaitableQueue; 23 import com.android.volley.utils.CacheTestUtils; 24 25 import org.junit.After; 26 import org.junit.Before; 27 import org.junit.Test; 28 import org.junit.runner.RunWith; 29 import org.robolectric.RobolectricTestRunner; 30 31 import static org.junit.Assert.*; 32 33 @RunWith(RobolectricTestRunner.class) 34 @SuppressWarnings("rawtypes") 35 public class CacheDispatcherTest { 36 private CacheDispatcher mDispatcher; 37 private WaitableQueue mCacheQueue; 38 private WaitableQueue mNetworkQueue; 39 private MockCache mCache; 40 private MockResponseDelivery mDelivery; 41 private MockRequest mRequest; 42 43 private static final long TIMEOUT_MILLIS = 5000; 44 45 @Before public void setUp() throws Exception { 46 mCacheQueue = new WaitableQueue(); 47 mNetworkQueue = new WaitableQueue(); 48 mCache = new MockCache(); 49 mDelivery = new MockResponseDelivery(); 50 51 mRequest = new MockRequest(); 52 53 mDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); 54 mDispatcher.start(); 55 } 56 57 @After public void tearDown() throws Exception { 58 mDispatcher.quit(); 59 mDispatcher.join(); 60 } 61 62 // A cancelled request should not be processed at all. 63 @Test public void cancelledRequest() throws Exception { 64 mRequest.cancel(); 65 mCacheQueue.add(mRequest); 66 mCacheQueue.waitUntilEmpty(TIMEOUT_MILLIS); 67 assertFalse(mCache.getCalled); 68 assertFalse(mDelivery.wasEitherResponseCalled()); 69 } 70 71 // A cache miss does not post a response and puts the request on the network queue. 72 @Test public void cacheMiss() throws Exception { 73 mCacheQueue.add(mRequest); 74 mCacheQueue.waitUntilEmpty(TIMEOUT_MILLIS); 75 assertFalse(mDelivery.wasEitherResponseCalled()); 76 assertTrue(mNetworkQueue.size() > 0); 77 Request request = mNetworkQueue.take(); 78 assertNull(request.getCacheEntry()); 79 } 80 81 // A non-expired cache hit posts a response and does not queue to the network. 82 @Test public void nonExpiredCacheHit() throws Exception { 83 Cache.Entry entry = CacheTestUtils.makeRandomCacheEntry(null, false, false); 84 mCache.setEntryToReturn(entry); 85 mCacheQueue.add(mRequest); 86 mCacheQueue.waitUntilEmpty(TIMEOUT_MILLIS); 87 assertTrue(mDelivery.postResponse_called); 88 assertFalse(mDelivery.postError_called); 89 } 90 91 // A soft-expired cache hit posts a response and queues to the network. 92 @Test public void softExpiredCacheHit() throws Exception { 93 Cache.Entry entry = CacheTestUtils.makeRandomCacheEntry(null, false, true); 94 mCache.setEntryToReturn(entry); 95 mCacheQueue.add(mRequest); 96 mCacheQueue.waitUntilEmpty(TIMEOUT_MILLIS); 97 assertTrue(mDelivery.postResponse_called); 98 assertFalse(mDelivery.postError_called); 99 assertTrue(mNetworkQueue.size() > 0); 100 Request request = mNetworkQueue.take(); 101 assertSame(entry, request.getCacheEntry()); 102 } 103 104 // An expired cache hit does not post a response and queues to the network. 105 @Test public void expiredCacheHit() throws Exception { 106 Cache.Entry entry = CacheTestUtils.makeRandomCacheEntry(null, true, true); 107 mCache.setEntryToReturn(entry); 108 mCacheQueue.add(mRequest); 109 mCacheQueue.waitUntilEmpty(TIMEOUT_MILLIS); 110 assertFalse(mDelivery.wasEitherResponseCalled()); 111 assertTrue(mNetworkQueue.size() > 0); 112 Request request = mNetworkQueue.take(); 113 assertSame(entry, request.getCacheEntry()); 114 } 115 116 @Test public void duplicateCacheMiss() throws Exception { 117 MockRequest secondRequest = new MockRequest(); 118 mRequest.setSequence(1); 119 secondRequest.setSequence(2); 120 mCacheQueue.add(mRequest); 121 mCacheQueue.add(secondRequest); 122 mCacheQueue.waitUntilEmpty(TIMEOUT_MILLIS); 123 assertTrue(mNetworkQueue.size() == 1); 124 assertFalse(mDelivery.postResponse_called); 125 } 126 127 @Test public void tripleCacheMiss_networkErrorOnFirst() throws Exception { 128 MockRequest secondRequest = new MockRequest(); 129 MockRequest thirdRequest = new MockRequest(); 130 mRequest.setSequence(1); 131 secondRequest.setSequence(2); 132 thirdRequest.setSequence(3); 133 mCacheQueue.add(mRequest); 134 mCacheQueue.add(secondRequest); 135 mCacheQueue.add(thirdRequest); 136 mCacheQueue.waitUntilEmpty(TIMEOUT_MILLIS); 137 138 assertTrue(mNetworkQueue.size() == 1); 139 assertFalse(mDelivery.postResponse_called); 140 141 Request request = mNetworkQueue.take(); 142 request.notifyListenerResponseNotUsable(); 143 // Second request should now be in network queue. 144 assertTrue(mNetworkQueue.size() == 1); 145 request = mNetworkQueue.take(); 146 assertTrue(request.equals(secondRequest)); 147 // Another unusable response, third request should now be added. 148 request.notifyListenerResponseNotUsable(); 149 assertTrue(mNetworkQueue.size() == 1); 150 request = mNetworkQueue.take(); 151 assertTrue(request.equals(thirdRequest)); 152 } 153 154 @Test public void duplicateSoftExpiredCacheHit_failedRequest() throws Exception { 155 Cache.Entry entry = CacheTestUtils.makeRandomCacheEntry(null, false, true); 156 mCache.setEntryToReturn(entry); 157 158 MockRequest secondRequest = new MockRequest(); 159 mRequest.setSequence(1); 160 secondRequest.setSequence(2); 161 162 mCacheQueue.add(mRequest); 163 mCacheQueue.add(secondRequest); 164 mCacheQueue.waitUntilEmpty(TIMEOUT_MILLIS); 165 166 assertTrue(mNetworkQueue.size() == 1); 167 assertTrue(mDelivery.postResponse_calledNtimes == 2); 168 169 Request request = mNetworkQueue.take(); 170 request.notifyListenerResponseNotUsable(); 171 // Second request should now be in network queue. 172 assertTrue(mNetworkQueue.size() == 1); 173 request = mNetworkQueue.take(); 174 assertTrue(request.equals(secondRequest)); 175 } 176 177 @Test public void duplicateSoftExpiredCacheHit_successfulRequest() throws Exception { 178 Cache.Entry entry = CacheTestUtils.makeRandomCacheEntry(null, false, true); 179 mCache.setEntryToReturn(entry); 180 181 MockRequest secondRequest = new MockRequest(); 182 mRequest.setSequence(1); 183 secondRequest.setSequence(2); 184 185 mCacheQueue.add(mRequest); 186 mCacheQueue.add(secondRequest); 187 mCacheQueue.waitUntilEmpty(TIMEOUT_MILLIS); 188 189 assertTrue(mNetworkQueue.size() == 1); 190 assertTrue(mDelivery.postResponse_calledNtimes == 2); 191 192 Request request = mNetworkQueue.take(); 193 request.notifyListenerResponseReceived(Response.success(null, entry)); 194 // Second request should have delivered response. 195 assertTrue(mNetworkQueue.size() == 0); 196 assertTrue(mDelivery.postResponse_calledNtimes == 3); 197 } 198 } 199