blob: 17c66509409655c7667bfb6cf237c63f21953c67 [file] [log] [blame]
package com.bumptech.glide.load.engine;
import com.bumptech.glide.Priority;
import com.bumptech.glide.load.Encoder;
import com.bumptech.glide.load.Key;
import com.bumptech.glide.load.ResourceDecoder;
import com.bumptech.glide.load.ResourceEncoder;
import com.bumptech.glide.load.Transformation;
import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.load.engine.cache.DiskCache;
import com.bumptech.glide.load.engine.cache.MemoryCache;
import com.bumptech.glide.load.resource.transcode.ResourceTranscoder;
import com.bumptech.glide.request.ResourceCallback;
import com.bumptech.glide.tests.GlideShadowLooper;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = { GlideShadowLooper.class })
public class EngineTest {
private static final String ID = "asdf";
private EngineTestHarness harness;
@Before
public void setUp() {
harness = new EngineTestHarness();
}
@Test
public void testNewRunnerIsCreatedAndPostedWithNoExistingLoad() {
harness.doLoad();
verify(harness.runner).queue();
}
@Test
public void testCallbackIsAddedToNewEngineJobWithNoExistingLoad() {
harness.doLoad();
verify(harness.job).addCallback(eq(harness.cb));
}
@Test
public void testLoadStatusIsReturnedForNewLoad() {
assertNotNull(harness.doLoad());
}
@Test
public void testEngineJobReceivesRemoveCallbackFromLoadStatus() {
Engine.LoadStatus loadStatus = harness.doLoad();
loadStatus.cancel();
verify(harness.job).removeCallback(eq(harness.cb));
}
@Test
public void testNewRunnerIsAddedToRunnersMap() {
harness.doLoad();
assertTrue(harness.runners.containsKey(harness.cacheKey));
}
@Test
public void testNewRunnerIsNotCreatedAndPostedWithExistingLoad() {
harness.doLoad();
harness.doLoad();
verify(harness.runner, times(1)).queue();
}
@Test
@SuppressWarnings("unchecked")
public void testCallbackIsAddedToExistingRunnerWithExistingLoad() {
harness.doLoad();
ResourceCallback newCallback = mock(ResourceCallback.class);
harness.cb = newCallback;
harness.doLoad();
verify(harness.job).addCallback(eq(newCallback));
}
@Test
public void testLoadStatusIsReturnedForExistingJob() {
harness.doLoad();
Engine.LoadStatus loadStatus = harness.doLoad();
assertNotNull(loadStatus);
}
@Test
public void testResourceIsReturnedFromActiveResourcesIfPresent() {
harness.activeResources.put(harness.cacheKey, new WeakReference<Resource>(harness.resource));
harness.doLoad();
verify(harness.cb).onResourceReady(eq(harness.resource));
}
@Test
public void testResourceIsNotReturnedFromActiveResourcesIfRefIsCleared() {
harness.activeResources.put(harness.cacheKey, new WeakReference<Resource>(null));
harness.doLoad();
verify(harness.cb, never()).onResourceReady((Resource) isNull());
}
@Test
public void testKeyIsRemovedFromActiveResourcesIfRefIsCleared() {
harness.activeResources.put(harness.cacheKey, new WeakReference<Resource>(null));
harness.doLoad();
assertFalse(harness.activeResources.containsKey(harness.cacheKey));
}
@Test
public void testResourceIsAcquiredIfReturnedFromActiveResources() {
harness.activeResources.put(harness.cacheKey, new WeakReference<Resource>(harness.resource));
harness.doLoad();
verify(harness.resource).acquire(eq(1));
}
@Test
public void testNewLoadIsNotStartedIfResourceIsActive() {
harness.activeResources.put(harness.cacheKey, new WeakReference<Resource>(harness.resource));
harness.doLoad();
verify(harness.runner, never()).queue();
}
@Test
public void testNullLoadStatusIsReturnedIfResourceIsActive() {
harness.activeResources.put(harness.cacheKey, new WeakReference<Resource>(harness.resource));
assertNull(harness.doLoad());
}
@Test
public void testActiveResourcesIsNotCheckedIfReturnedFromCache() {
when(harness.cache.remove(eq(harness.cacheKey))).thenReturn(harness.resource);
Resource other = mock(Resource.class);
harness.activeResources.put(harness.cacheKey, new WeakReference<Resource>(other));
harness.doLoad();
verify(harness.cb).onResourceReady(eq(harness.resource));
verify(harness.cb, never()).onResourceReady(eq(other));
}
@Test
public void testCacheIsChecked() {
when(harness.cache.remove(eq(harness.cacheKey))).thenReturn(harness.resource);
harness.doLoad();
verify(harness.cb).onResourceReady(eq(harness.resource));
}
@Test
public void testResourceIsReturnedFromCacheIfPresent() {
when(harness.cache.remove(eq(harness.cacheKey))).thenReturn(harness.resource);
harness.doLoad();
verify(harness.cb).onResourceReady(eq(harness.resource));
}
@Test
public void testResourceIsAddedToActiveResourceIfReturnedFromCache() {
when(harness.cache.remove(eq(harness.cacheKey))).thenReturn(harness.resource);
harness.doLoad();
assertEquals(harness.resource, harness.activeResources.get(harness.cacheKey)
.get());
}
@Test
public void testResourceIsAcquiredIfReturnedFromCache() {
when(harness.cache.remove(eq(harness.cacheKey))).thenReturn(harness.resource);
harness.doLoad();
verify(harness.resource).acquire(1);
}
@Test
public void testNewLoadIsNotStartedIfResourceIsCached() {
when(harness.cache.remove(eq(harness.cacheKey))).thenReturn(mock(Resource.class));
harness.doLoad();
verify(harness.runner, never()).queue();
}
@Test
public void testNullLoadStatusIsReturnedForCachedResource() {
when(harness.cache.remove(eq(harness.cacheKey))).thenReturn(mock(Resource.class));
Engine.LoadStatus loadStatus = harness.doLoad();
assertNull(loadStatus);
}
@Test
public void testRunnerIsRemovedFromRunnersOnEngineNotifiedJobComplete() {
harness.doLoad();
harness.engine.onEngineJobComplete(harness.cacheKey, harness.resource);
assertFalse(harness.runners.containsKey(harness.cacheKey));
}
@Test
public void testRunnerIsNotCancelledOnEngineNotifiedJobComplete() {
harness.doLoad();
harness.engine.onEngineJobComplete(harness.cacheKey, harness.resource);
verify(harness.runner, never()).cancel();
}
@Test
public void testEngineIsSetAsResourceListenerOnJobComplete() {
harness.doLoad();
harness.engine.onEngineJobComplete(harness.cacheKey, harness.resource);
verify(harness.resource).setResourceListener(eq(harness.cacheKey), eq(harness.engine));
}
@Test
public void testEngineIsNotSetAsResourceListenerIfResourceIsNullOnJobComplete() {
harness.doLoad();
harness.engine.onEngineJobComplete(harness.cacheKey, null);
}
@Test
public void testResourceIsAddedToActiveResourcesOnEngineComplete() {
harness.engine.onEngineJobComplete(harness.cacheKey, harness.resource);
WeakReference<Resource> resourceRef = harness.activeResources.get(harness.cacheKey);
assertEquals(harness.resource, resourceRef.get());
}
@Test
public void testDoesNotPutNullResourceInActiveResourcesOnEngineComplete() {
harness.engine.onEngineJobComplete(harness.cacheKey, null);
assertFalse(harness.activeResources.containsKey(harness.cacheKey));
}
@Test
public void testRunnerIsRemovedFromRunnersOnEngineNotifiedJobCancel() {
harness.doLoad();
harness.engine.onEngineJobCancelled(harness.cacheKey);
assertFalse(harness.runners.containsKey(harness.cacheKey));
}
@Test
public void testRunnerIsCancelledOnEngineNotifiedJobCanceled() {
harness.doLoad();
harness.engine.onEngineJobCancelled(harness.cacheKey);
verify(harness.runner).cancel();
}
@Test
public void testResourceIsAddedToCacheOnReleased() {
harness.engine.onResourceReleased(harness.cacheKey, harness.resource);
verify(harness.cache).put(eq(harness.cacheKey), eq(harness.resource));
}
@Test
public void testResourceIsNotAddedToCacheOnReleasedIfNotCacheable() {
when(harness.resource.isCacheable()).thenReturn(false);
harness.engine.onResourceReleased(harness.cacheKey, harness.resource);
verify(harness.cache, never()).put(eq(harness.cacheKey), eq(harness.resource));
}
@Test
public void testResourceIsRecycledIfNotCacheableWhenReleased() {
when(harness.resource.isCacheable()).thenReturn(false);
harness.engine.onResourceReleased(harness.cacheKey, harness.resource);
verify(harness.resource).recycle();
}
@Test
public void testResourceIsRemovedFromActiveResourcesWhenReleased() {
harness.activeResources.put(harness.cacheKey, new WeakReference<Resource>(harness.resource));
harness.engine.onResourceReleased(harness.cacheKey, harness.resource);
assertFalse(harness.activeResources.containsKey(harness.cacheKey));
}
@Test
public void testEngineAddedAsListenerToMemoryCache() {
verify(harness.cache).setResourceRemovedListener(eq(harness.engine));
}
@Test
public void testResourceIsRecycledWhenRemovedFromCache() {
harness.engine.onResourceRemoved(harness.resource);
verify(harness.resource).recycle();
}
@Test
public void testRunnerIsPutInRunnersWithCacheKeyWithRelevantIds() {
harness.doLoad();
assertNotNull(harness.runners.get(harness.cacheKey));
}
@Test
public void testKeyFactoryIsGivenNecessaryArguments() {
harness.doLoad();
verify(harness.keyFactory).buildKey(eq(ID), eq(harness.width), eq(harness.height), eq(harness.cacheDecoder),
eq(harness.decoder), eq(harness.transformation), eq(harness.encoder), eq(harness.transcoder),
eq(harness.sourceEncoder));
}
@Test
public void testFactoryIsGivenCacheKeyToBuildRunner() {
harness.doLoad();
verify(harness.factory).build(eq(harness.cacheKey), anyInt(), anyInt(), any(ResourceDecoder.class),
any(DataFetcher.class), anyBoolean(), any(Encoder.class), any(ResourceDecoder.class),
any(Transformation.class), any(ResourceEncoder.class), any(ResourceTranscoder.class),
any(Priority.class), anyBoolean(), any(EngineJobListener.class));
}
@Test
public void testFactoryIsGivenNecessaryArguments() {
harness.doLoad();
verify(harness.factory).build(eq(harness.cacheKey), eq(harness.width), eq(harness.height),
eq(harness.cacheDecoder), eq(harness.fetcher), eq(harness.cacheSource), eq(harness.sourceEncoder),
eq(harness.decoder), eq(harness.transformation), eq(harness.encoder), eq(harness.transcoder),
eq(harness.priority), eq(harness.isMemoryCacheable), eq(harness.engine));
}
@SuppressWarnings("unchecked")
private static class EngineTestHarness {
EngineKey cacheKey = mock(EngineKey.class);
EngineKeyFactory keyFactory = mock(EngineKeyFactory.class);
ResourceDecoder<InputStream, Object> cacheDecoder = mock(ResourceDecoder.class);
DataFetcher<Object> fetcher = mock(DataFetcher.class);
ResourceDecoder<Object, Object> decoder = mock(ResourceDecoder.class);
ResourceEncoder<Object> encoder = mock(ResourceEncoder.class);
ResourceTranscoder<Object, Object> transcoder = mock(ResourceTranscoder.class);
Priority priority = Priority.NORMAL;
ResourceCallback cb = mock(ResourceCallback.class);
Resource<Object> resource = mock(Resource.class);
Map<Key, ResourceRunner> runners = new HashMap<Key, ResourceRunner>();
Transformation transformation = mock(Transformation.class);
ResourceRunnerFactory factory = mock(ResourceRunnerFactory.class);
Map<Key, WeakReference<Resource>> activeResources = new HashMap<Key, WeakReference<Resource>>();
boolean cacheSource = true;
Encoder<Object> sourceEncoder = mock(Encoder.class);
int width = 100;
int height = 100;
MemoryCache cache = mock(MemoryCache.class);
ResourceRunner<Object, Object> runner = mock(ResourceRunner.class);
EngineJob job;
Engine engine;
boolean isMemoryCacheable;
public EngineTestHarness() {
when(resource.isCacheable()).thenReturn(true);
when(keyFactory.buildKey(anyString(), anyInt(), anyInt(), any(ResourceDecoder.class),
any(ResourceDecoder.class), any(Transformation.class), any(ResourceEncoder.class),
any(ResourceTranscoder.class), any(Encoder.class))).thenReturn(cacheKey);
when(fetcher.getId()).thenReturn(ID);
job = mock(EngineJob.class);
when(runner.getJob()).thenReturn(job);
engine = new Engine(factory, cache, mock(DiskCache.class), mock(ExecutorService.class),
mock(ExecutorService.class), runners, keyFactory, activeResources);
when(factory.build(eq(cacheKey), eq(width), eq(height), eq(cacheDecoder), eq(fetcher), eq(cacheSource),
eq(sourceEncoder), eq(decoder), eq(transformation), eq(encoder), eq(transcoder), eq(priority),
eq(isMemoryCacheable), eq(engine))).thenReturn(runner);
}
public Engine.LoadStatus doLoad() {
return engine.load(width, height, cacheDecoder, fetcher, cacheSource, sourceEncoder, decoder,
transformation, encoder, transcoder, priority, isMemoryCacheable, cb);
}
}
}