Skip to content

Commit

Permalink
Fix unit tests for redis implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
marcosbarbero committed May 28, 2020
1 parent b7ec11d commit ca8b042
Showing 1 changed file with 31 additions and 64 deletions.
Original file line number Diff line number Diff line change
@@ -1,22 +1,9 @@
package com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.repository;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.matches;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
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;

import com.google.common.collect.Maps;
import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.properties.RateLimitProperties.Policy;
import java.time.Duration;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
Expand All @@ -25,6 +12,12 @@
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

import java.time.Duration;
import java.util.Map;

import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;

@SuppressWarnings("unchecked")
public class RedisRateLimiterTest extends BaseRateLimiterTest {

Expand All @@ -36,102 +29,76 @@ public class RedisRateLimiterTest extends BaseRateLimiterTest {
@BeforeEach
public void setUp() {
MockitoAnnotations.initMocks(this);
Map<String, BoundValueOperations<String, String>> map = Maps.newHashMap();
Map<String, Long> longMap = Maps.newHashMap();

when(this.redisTemplate.boundValueOps(any())).thenAnswer(invocation -> {
String key = invocation.getArgument(0);
BoundValueOperations<String, String> mock = map.computeIfAbsent(key, k -> Mockito.mock(BoundValueOperations.class));
when(mock.increment(anyLong())).thenAnswer(invocationOnMock -> {
long value = invocationOnMock.getArgument(0);
return longMap.compute(key, (k, v) -> ((v != null) ? v : 0L) + value);
});
return mock;
});
when(this.redisTemplate.opsForValue()).thenAnswer(invocation -> {
ValueOperations<String, String> mock = mock(ValueOperations.class);
when(mock.increment(any(), anyLong())).thenAnswer(invocationOnMock -> {
String key = invocationOnMock.getArgument(0);
long value = invocationOnMock.getArgument(1);
return longMap.compute(key, (k, v) -> ((v != null) ? v : 0L) + value);
});
return mock;
});
doReturn(1L, 2L)
.when(redisTemplate).execute(any(), anyList(), anyString(), anyString());

this.target = new RedisRateLimiter(this.rateLimiterErrorHandler, this.redisTemplate);
}

@Test
@Disabled
public void testConsumeOnlyQuota() {
// disabling in favor of integration tests
}

@Test
@Disabled
public void testConsume() {
// disabling in favor of integration tests
}

@Test
public void testConsumeRemainingLimitException() {
ValueOperations<String, String> ops = mock(ValueOperations.class);
when(ops.setIfAbsent(anyString(), anyString(), anyLong(), any())).thenReturn(false);
doReturn(ops).when(redisTemplate).opsForValue();
doThrow(new RuntimeException()).when(ops).increment(anyString(), anyLong());
doThrow(new RuntimeException()).when(redisTemplate).execute(any(), anyList(), anyString(), anyString());

Policy policy = new Policy();
policy.setLimit(100L);
target.consume(policy, "key", 0L);
verify(redisTemplate.opsForValue()).setIfAbsent(anyString(), anyString(), anyLong(), any());
verify(redisTemplate.opsForValue()).increment(anyString(), anyLong());
verify(rateLimiterErrorHandler).handleError(matches(".* key, .*"), any());
}

@Test
public void testConsumeRemainingQuotaLimitException() {
ValueOperations<String, String> ops = mock(ValueOperations.class);
when(ops.setIfAbsent(anyString(), anyString(), anyLong(), any())).thenReturn(false);
doReturn(ops).when(redisTemplate).opsForValue();
doThrow(new RuntimeException()).when(ops).increment(anyString(), anyLong());
doThrow(new RuntimeException()).when(redisTemplate).execute(any(), anyList(), anyString(), anyString());

Policy policy = new Policy();
policy.setQuota(Duration.ofSeconds(100));
target.consume(policy, "key", 0L);
verify(redisTemplate.opsForValue()).setIfAbsent(anyString(), anyString(), anyLong(), any());
verify(redisTemplate.opsForValue()).increment(anyString(), anyLong());
verify(rateLimiterErrorHandler).handleError(matches(".* key-quota, .*"), any());
}

@Test
public void testConsumeGetExpireException() {
ValueOperations<String, String> ops = mock(ValueOperations.class);
when(ops.setIfAbsent(anyString(), anyString(), anyLong(), any())).thenReturn(false);
doReturn(ops).when(redisTemplate).opsForValue();
doThrow(new RuntimeException()).when(ops).increment(anyString(), anyLong());
doThrow(new RuntimeException()).when(redisTemplate).execute(any(), anyList(), anyString(), anyString());

Policy policy = new Policy();
policy.setLimit(100L);
policy.setQuota(Duration.ofSeconds(50));
target.consume(policy, "key", 0L);
verify(redisTemplate.opsForValue(), times(2)).setIfAbsent(anyString(), anyString(), anyLong(), any());
verify(redisTemplate.opsForValue(), times(2)).increment(anyString(), anyLong());
verify(rateLimiterErrorHandler).handleError(matches(".* key, .*"), any());
verify(rateLimiterErrorHandler).handleError(matches(".* key-quota, .*"), any());
}

@Test
public void testConsumeExpireException() {
ValueOperations<String, String> ops = mock(ValueOperations.class);
doThrow(new RuntimeException()).when(ops).setIfAbsent(anyString(), anyString(), anyLong(), any());
when(ops.increment(anyString(), anyLong())).thenReturn(0L);
doReturn(ops).when(redisTemplate).opsForValue();
doThrow(new RuntimeException()).when(redisTemplate).execute(any(), anyList(), anyString(), anyString());

Policy policy = new Policy();
policy.setLimit(100L);
target.consume(policy, "key", 0L);
verify(redisTemplate.opsForValue()).setIfAbsent(anyString(), anyString(), anyLong(), any());
verify(redisTemplate.opsForValue(), never()).increment(any(), anyLong());
verify(rateLimiterErrorHandler).handleError(matches(".* key, .*"), any());
}

@Test
public void testConsumeSetKey() {
ValueOperations<String, String> ops = mock(ValueOperations.class);
when(ops.setIfAbsent(anyString(), anyString(), anyLong(), any())).thenReturn(true);
doReturn(ops).when(redisTemplate).opsForValue();
doReturn(1L, 2L)
.when(redisTemplate).execute(any(), anyList(), anyString(), anyString());

Policy policy = new Policy();
policy.setLimit(20L);
target.consume(policy, "key", 0L);
verify(redisTemplate.opsForValue()).setIfAbsent(anyString(), anyString(), anyLong(), any());
verify(redisTemplate.opsForValue(), never()).increment(any(), anyLong());

verify(redisTemplate).execute(any(), anyList(), anyString(), anyString());
verify(rateLimiterErrorHandler, never()).handleError(any(), any());
}
}

0 comments on commit ca8b042

Please sign in to comment.