@@ -0,0 +1,2763 @@
+package com.groupon.lex.metrics.resolver;%0A%0Aimport java.util.ArrayList;%0Aimport java.util.Collection;%0Aimport java.util.List;%0Aimport java.util.concurrent.CompletableFuture;%0Aimport org.joda.time.Duration;%0Aimport static org.junit.Assert.assertEquals;%0Aimport static org.junit.Assert.assertSame;%0Aimport org.junit.Before;%0Aimport org.junit.Test;%0Aimport org.junit.runner.RunWith;%0Aimport org.mockito.Mock;%0Aimport static org.mockito.Mockito.atLeast;%0Aimport static org.mockito.Mockito.times;%0Aimport static org.mockito.Mockito.verify;%0Aimport static org.mockito.Mockito.verifyNoMoreInteractions;%0Aimport static org.mockito.Mockito.when;%0Aimport org.mockito.runners.MockitoJUnitRunner;%0A%0A@RunWith(MockitoJUnitRunner.class)%0Apublic class CachingResolverTest %7B%0A    @Mock%0A    private AsyncResolver mockedAsyncResolver;%0A%0A    @Before%0A    public void setup() %7B%0A        when(mockedAsyncResolver.getTupleWidth()).thenReturn(2);%0A    %7D%0A%0A    @Test%0A    public void getTupleWidthTest() throws Exception %7B%0A        try (CachingResolver cr = new CachingResolver(mockedAsyncResolver, Duration.standardMinutes(10), Duration.standardMinutes(60))) %7B%0A            assertEquals(2, cr.getTupleWidth());%0A        %7D%0A%0A        verify(mockedAsyncResolver, times(1)).getTupleWidth();%0A        verify(mockedAsyncResolver, atLeast(0)).getTuples();%0A        verifyNoMoreInteractions(mockedAsyncResolver);%0A    %7D%0A%0A    @Test%0A    public void getTuplesTest() throws Exception %7B%0A        final CompletableFuture%3CCollection%3CResolverTuple%3E%3E fut = new CompletableFuture%3C%3E();%0A        final List%3CResolverTuple%3E RESULT = new ArrayList%3C%3E();%0A%0A        when(mockedAsyncResolver.getTuples()).thenReturn((CompletableFuture) fut);%0A%0A        final Collection%3CResolverTuple%3E entries;%0A        try (CachingResolver cr = new CachingResolver(mockedAsyncResolver, Duration.standardMinutes(10), Duration.standardMinutes(60))) %7B%0A            fut.complete(RESULT);%0A            Thread.sleep(5000);  // Racy test, but this should work in most cases to allow callbacks to propagate.%0A            entries = cr.getTuples();%0A        %7D%0A%0A        assertSame(RESULT, entries);%0A    %7D%0A%0A    @Test(expected = CachingResolver.StaleResolverException.class)%0A    public void getTuplesExceptionalTest() throws Exception %7B%0A        final CompletableFuture%3CCollection%3CResolverTuple%3E%3E fut = new CompletableFuture%3C%3E();%0A        final List%3CResolverTuple%3E RESULT = new ArrayList%3C%3E();%0A%0A        when(mockedAsyncResolver.getTuples()).thenReturn((CompletableFuture) fut);%0A%0A        try (CachingResolver cr = new CachingResolver(mockedAsyncResolver, Duration.standardMinutes(10), Duration.standardMinutes(60))) %7B%0A            fut.completeExceptionally(new TestException());%0A            cr.getTuples();%0A        %7D%0A    %7D%0A%0A    private static class TestException extends Exception %7B%0A    %7D%0A%7D%0A

Add tests for caching resolver.