package io.dropwizard.auth;
import com.codahale.metrics.MetricRegistry;
import com.google.common.cache.CacheBuilderSpec;
import com.google.common.collect.ImmutableSet;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.InOrder;
import java.security.Principal;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class CachingAuthenticatorTest {
@SuppressWarnings("unchecked")
private final Authenticator<String, Principal> underlying = mock(Authenticator.class);
private final CachingAuthenticator<String, Principal> cached =
new CachingAuthenticator<>(new MetricRegistry(), underlying, CacheBuilderSpec.parse("maximumSize=1"));
@Rule
public ExpectedException expected = ExpectedException.none();
@Before
public void setUp() throws Exception {
when(underlying.authenticate(anyString())).thenReturn(Optional.of(new PrincipalImpl("principal")));
}
@Test
public void cachesTheFirstReturnedPrincipal() throws Exception {
assertThat(cached.authenticate("credentials")).isEqualTo(Optional.<Principal>of(new PrincipalImpl("principal")));
assertThat(cached.authenticate("credentials")).isEqualTo(Optional.<Principal>of(new PrincipalImpl("principal")));
verify(underlying, times(1)).authenticate("credentials");
}
@Test
public void respectsTheCacheConfiguration() throws Exception {
cached.authenticate("credentials1");
cached.authenticate("credentials2");
cached.authenticate("credentials1");
final InOrder inOrder = inOrder(underlying);
inOrder.verify(underlying, times(1)).authenticate("credentials1");
inOrder.verify(underlying, times(1)).authenticate("credentials2");
inOrder.verify(underlying, times(1)).authenticate("credentials1");
}
@Test
public void invalidatesSingleCredentials() throws Exception {
cached.authenticate("credentials");
cached.invalidate("credentials");
cached.authenticate("credentials");
verify(underlying, times(2)).authenticate("credentials");
}
@Test
public void invalidatesSetsOfCredentials() throws Exception {
cached.authenticate("credentials");
cached.invalidateAll(ImmutableSet.of("credentials"));
cached.authenticate("credentials");
verify(underlying, times(2)).authenticate("credentials");
}
@Test
public void invalidatesCredentialsMatchingGivenPredicate() throws Exception {
cached.authenticate("credentials");
cached.invalidateAll("credentials"::equals);
cached.authenticate("credentials");
verify(underlying, times(2)).authenticate("credentials");
}
@Test
public void invalidatesAllCredentials() throws Exception {
cached.authenticate("credentials");
cached.invalidateAll();
cached.authenticate("credentials");
verify(underlying, times(2)).authenticate("credentials");
}
@Test
public void calculatesTheSizeOfTheCache() throws Exception {
cached.authenticate("credentials1");
assertThat(cached.size()).isEqualTo(1);
}
@Test
public void calculatesCacheStats() throws Exception {
cached.authenticate("credentials1");
assertThat(cached.stats().loadCount()).isEqualTo(1);
assertThat(cached.size()).isEqualTo(1);
}
@Test
public void shouldNotCacheAbsentPrincipals() throws Exception {
when(underlying.authenticate(anyString())).thenReturn(Optional.empty());
assertThat(cached.authenticate("credentials")).isEqualTo(Optional.empty());
verify(underlying).authenticate("credentials");
assertThat(cached.size()).isEqualTo(0);
}
@Test
public void shouldPropagateAuthenticationException() throws AuthenticationException {
final AuthenticationException e = new AuthenticationException("Auth failed");
when(underlying.authenticate(anyString())).thenThrow(e);
expected.expect(CoreMatchers.sameInstance(e));
cached.authenticate("credentials");
}
@Test
public void shouldPropagateRuntimeException() throws AuthenticationException {
final RuntimeException e = new NullPointerException();
when(underlying.authenticate(anyString())).thenThrow(e);
expected.expect(CoreMatchers.sameInstance(e));
cached.authenticate("credentials");
}
}