package com.github.droidfu.http;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.whenNew;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.protocol.HttpContext;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import android.util.Log;
import com.github.droidfu.cachefu.CacheHelper;
import com.github.droidfu.cachefu.HttpResponseCache;
import com.github.droidfu.http.CachedHttpResponse.ResponseData;
import com.github.droidfu.support.StringSupport;
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Log.class, HttpResponseCache.class, CacheHelper.class, StringSupport.class })
public class HttpResponseCacheTest extends BetterHttpTestBase {
private HttpResponseCache cache;
@Mock
private File fileMock;
@SuppressWarnings("unchecked")
@Before
public void setupHttpClient() throws Exception {
super.setupHttpClient();
mockStatic(StringSupport.class);
when(StringSupport.underscore(Matchers.anyString())).thenReturn("http_resp/");
mockIOObjects();
BetterHttp.enableResponseCache(10, 60, 1);
cache = BetterHttp.getResponseCache();
when(
httpClientMock.execute(any(HttpUriRequest.class), any(ResponseHandler.class),
any(HttpContext.class))).thenAnswer(new Answer<BetterHttpResponse>() {
public BetterHttpResponse answer(InvocationOnMock invocation) throws Throwable {
HttpResponseCache cache = BetterHttp.getResponseCache();
cache.put(url, new ResponseData(200, responseBody.getBytes()));
return mockResponse;
}
});
}
@SuppressWarnings("unchecked")
@Test
public void testBasicCachingFlow() throws Exception {
when(fileMock.exists()).thenReturn(false);
// first time invocation should do an actual request
BetterHttpResponse resp = BetterHttp.get(url, true).send();
verify(httpClientMock, times(1)).execute(any(HttpUriRequest.class),
any(ResponseHandler.class), any(HttpContext.class));
assertSame(mockResponse, resp);
// any subsequent invocation should return the cached response
resp = BetterHttp.get(url, true).send();
assertNotSame(mockResponse, resp);
assertTrue(resp instanceof CachedHttpResponse);
}
@Test
public void shouldGenerateCorrectFileNamesWhenCachingToDisk() {
assertEquals("http+api+qype+com+positions+1+1+places+x+y+a+2Bc",
cache.getFileNameForKey(url));
}
@Test
public void removingByPrefixShouldWork() throws IOException {
cache.setDiskCacheEnabled("cache_root_dir");
cache.put("http://example.com/places", new ResponseData(200, responseBody.getBytes()));
cache.put("http://example.com/places/photos",
new ResponseData(200, responseBody.getBytes()));
verify(fileMock, times(2)).createNewFile();
assertEquals(2, cache.size());
cache.removeAllWithPrefix("http://example.com/places");
verify(fileMock, times(2)).delete();
assertTrue(cache.isEmpty());
}
@Test
public void removeByPrefixShouldRemoveExpiredCachedFiles() throws IOException {
cache.setDiskCacheEnabled("cache_root_dir");
File[] cachedFiles = { new File("http://example.com/users/photos"),
new File("http://example.com/users") };
when(fileMock.listFiles(Matchers.any(FilenameFilter.class))).thenReturn(cachedFiles);
cache.put("http://example.com/users", new ResponseData(200, responseBody.getBytes()));
cache.put("http://example.com/users/photos", new ResponseData(200, responseBody.getBytes()));
verify(fileMock, times(2)).createNewFile();
assertEquals(2, cache.size());
// Cache expires
cache.removeKey("http://example.com/users");
cache.removeKey("http://example.com/users/photos");
cache.removeAllWithPrefix("http://example.com/users");
verify(fileMock, times(2)).delete();
}
private void mockIOObjects() throws Exception {
whenNew(File.class).withArguments(Matchers.anyString()).thenReturn(fileMock);
when(fileMock.exists()).thenReturn(true);
when(fileMock.createNewFile()).thenReturn(true);
when(fileMock.length()).thenReturn(11111L);
mockStatic(FileInputStream.class);
FileInputStream fis = mock(FileInputStream.class);
whenNew(FileInputStream.class).withArguments(File.class).thenReturn(fis);
mockStatic(BufferedInputStream.class);
BufferedInputStream bis = mock(BufferedInputStream.class);
whenNew(BufferedInputStream.class).withArguments(FileInputStream.class).thenReturn(bis);
mockStatic(FileOutputStream.class);
FileOutputStream fos = mock(FileOutputStream.class);
whenNew(FileOutputStream.class).withArguments(File.class).thenReturn(fos);
mockStatic(BufferedOutputStream.class);
BufferedOutputStream bos = mock(BufferedOutputStream.class);
whenNew(BufferedOutputStream.class).withArguments(FileOutputStream.class).thenReturn(bos);
}
}