From 7ef4aa38ddaa2bba0ee9a3ff80e2dfd44dd267c7 Mon Sep 17 00:00:00 2001 From: Jacques-Etienne Beaudet Date: Wed, 30 Oct 2024 21:44:21 -0400 Subject: [PATCH] breaking-feat: Update jedis --- .github/workflows/main-ci.yml | 21 +++ .travis.yml | 10 - pom.xml | 142 ++++++++++---- .../coveo/spillway/storage/RedisStorage.java | 2 +- .../java/com/coveo/spillway/SpillwayTest.java | 174 ++++++++---------- .../SpillwayTryUpdateAndVerifyLimitTest.java | 163 ++++++++-------- .../functional/SpillwayFunctionalTests.java | 42 ++--- .../spillway/limit/LimitDefinitionTest.java | 3 +- .../com/coveo/spillway/limit/LimitTest.java | 3 +- .../AsyncBatchLimitUsageStorageTest.java | 24 ++- .../storage/AsyncLimitUsageStorageTest.java | 18 +- .../spillway/storage/InMemoryStorageTest.java | 12 +- .../spillway/storage/RedisStorageTest.java | 37 ++-- .../utils/CacheSynchronizationTest.java | 16 +- .../trigger/AbstractLimitTriggerTest.java | 14 +- .../PercentageThresholdTriggerTest.java | 22 +-- .../trigger/ValueThresholdTriggerTest.java | 15 +- 17 files changed, 370 insertions(+), 348 deletions(-) create mode 100644 .github/workflows/main-ci.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml new file mode 100644 index 0000000..4fcd238 --- /dev/null +++ b/.github/workflows/main-ci.yml @@ -0,0 +1,21 @@ +name: Java CI with Maven + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + cache: maven + - name: Maven build&tests + run: mvn -ntp clean verify --file pom.xml \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 53e7228..0000000 --- a/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -language: java - -jdk: - - oraclejdk8 - -cache: - directories: - - "$HOME/.m2/repository" - -dist: trusty diff --git a/pom.xml b/pom.xml index f844d7f..9e36d13 100644 --- a/pom.xml +++ b/pom.xml @@ -5,13 +5,13 @@ com.coveo spillway - 2.2.0-SNAPSHOT + 3.0.0 jar ${project.artifactId} Simple, flexible, distributable rate limiting for your application - http://github.com/coveo/spillway + https://github.com/coveooss/spillway @@ -24,25 +24,25 @@ Guillaume Simard Coveo - http://github.com/coveo + https://github.com/coveo Emile Fugulin Coveo - http://github.com/coveo + https://github.com/coveo Pierre-Alexandre St-Jean http://github.com/pastjean Coveo - http://github.com/coveo + https://github.com/coveo - scm:git:git@github.com:coveo/spillway.git - scm:git:git@github.com:coveo/spillway.git - http://github.com/coveo/spillway + scm:git:git@github.com:coveooss/spillway.git + scm:git:git@github.com:coveooss/spillway.git + https://github.com/coveooss/spillway @@ -59,49 +59,96 @@ UTF-8 - 1.8 - 1.8 + 17 + + 3.17.0 + + 5.0.2 + + 5.14.2 + + 5.11.3 + + 2.0.12 + + 1.4.4 + + 1.4.3 + + + + org.mockito + mockito-bom + ${mockito.version} + pom + import + + + org.junit + junit-bom + ${junit.version} + pom + import + + + + org.slf4j slf4j-api - 1.7.30 + ${slf4j.version} org.apache.commons commons-lang3 - 3.10 + ${commons-lang3.version} redis.clients jedis - 4.2.1 + ${jedis.version} - junit - junit - 4.12 + org.slf4j + slf4j-simple + ${slf4j.version} + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.mockito + mockito-core test org.mockito - mockito-all - 1.10.19 + mockito-junit-jupiter test com.google.truth truth - 0.28 + ${truth.version} test + + + junit + junit + + - com.github.kstyrc + com.github.codemonstur embedded-redis - 0.6 + ${embedded-redis.version} test @@ -110,26 +157,32 @@ org.apache.maven.plugins - maven-source-plugin - 3.0.0 + maven-compiler-plugin + 3.13.0 + full + true + lines,vars,source + false - - - attach-sources - - jar - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.10.3 + maven-surefire-plugin + 3.5.1 + + false + + + + org.apache.maven.plugins + maven-source-plugin + 3.3.1 + + - attach-javadocs + attach-sources jar @@ -183,6 +236,19 @@ release + + org.apache.maven.plugins + maven-javadoc-plugin + 3.10.1 + + + attach-javadocs + + jar + + + + org.sonatype.plugins nexus-staging-maven-plugin @@ -197,7 +263,7 @@ org.apache.maven.plugins maven-gpg-plugin - 1.6 + 3.2.7 sign-artifacts @@ -205,6 +271,12 @@ sign + + + --pinentry-mode + loopback + + diff --git a/src/main/java/com/coveo/spillway/storage/RedisStorage.java b/src/main/java/com/coveo/spillway/storage/RedisStorage.java index 2ef0589..2ace2ed 100644 --- a/src/main/java/com/coveo/spillway/storage/RedisStorage.java +++ b/src/main/java/com/coveo/spillway/storage/RedisStorage.java @@ -114,7 +114,7 @@ public Map addAndGet(Collection requests) { pipeline.sync(); } catch (Throwable e) { - logger.error("An exception occured while publishing limits to Redis.", e); + logger.error("An exception occurred while publishing limits to Redis.", e); } } diff --git a/src/test/java/com/coveo/spillway/SpillwayTest.java b/src/test/java/com/coveo/spillway/SpillwayTest.java index c22ca27..8972d59 100644 --- a/src/test/java/com/coveo/spillway/SpillwayTest.java +++ b/src/test/java/com/coveo/spillway/SpillwayTest.java @@ -10,13 +10,12 @@ import com.coveo.spillway.limit.override.LimitOverrideBuilder; import com.coveo.spillway.storage.InMemoryStorage; import com.coveo.spillway.storage.LimitUsageStorage; -import com.coveo.spillway.storage.utils.AddAndGetRequest; import com.coveo.spillway.trigger.LimitTriggerCallback; import com.coveo.spillway.trigger.ValueThresholdTrigger; import com.google.common.collect.ImmutableMap; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import java.time.Clock; @@ -26,16 +25,15 @@ import java.util.Optional; import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyListOf; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.ArgumentMatchers.*; 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 static org.mockito.Matchers.eq; public class SpillwayTest { @@ -47,27 +45,10 @@ public class SpillwayTest { private static final String JOHN = "john"; private static final String A_LIMIT_NAME = "perUser"; - private class User { + private record User(String name, String ip) {} - private String name; - private String ip; - - User(String name, String ip) { - this.name = name; - this.ip = ip; - } - - String getName() { - return name; - } - - String getIp() { - return ip; - } - } - - private User john = new User(JOHN, "127.0.0.1"); - private User gina = new User("gina", "127.0.0.1"); + private final User john = new User(JOHN, "127.0.0.1"); + private final User gina = new User("gina", "127.0.0.1"); private LimitUsageStorage mockedStorage; private LimitUsageStorage inMemoryStorage; @@ -76,7 +57,7 @@ String getIp() { private SpillwayFactory inMemoryFactory; private SpillwayFactory mockedFactory; - @Before + @BeforeEach public void setup() { clock = mock(Clock.class); inMemoryStorage = new InMemoryStorage(); @@ -89,9 +70,9 @@ public void setup() { } @Test - public void simpleLimit() throws Exception { + public void simpleLimit() { Limit limit1 = - LimitBuilder.of("perUser", User::getName).to(2).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(2).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", limit1); assertThat(spillway.tryCall(john)).isTrue(); @@ -99,21 +80,23 @@ public void simpleLimit() throws Exception { assertThat(spillway.tryCall(john)).isFalse(); // Third tryCall fails } - @Test(expected = SpillwayLimitsWithSameNameException.class) - public void multipleLimitsWithOverlap() throws Exception { + @Test + public void multipleLimitsWithOverlap() { Limit limit1 = - LimitBuilder.of("perUser", User::getName).to(5).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(5).per(Duration.ofHours(1)).build(); Limit limit2 = - LimitBuilder.of("perUser", User::getName).to(1).per(Duration.ofSeconds(1)).build(); - inMemoryFactory.enforce("testResource", limit1, limit2); + LimitBuilder.of("perUser", User::name).to(1).per(Duration.ofSeconds(1)).build(); + + assertThrows( + SpillwayLimitsWithSameNameException.class, + () -> inMemoryFactory.enforce("testResource", limit1, limit2)); } @Test - public void multipleLimitsNoOverlap() throws Exception { - Limit ipLimit = - LimitBuilder.of("perIp", User::getIp).to(1).per(Duration.ofHours(1)).build(); + public void multipleLimitsNoOverlap() { + Limit ipLimit = LimitBuilder.of("perIp", User::ip).to(1).per(Duration.ofHours(1)).build(); Limit userLimit = - LimitBuilder.of("perUser", User::getName).to(1).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(1).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", ipLimit, userLimit); assertThat(spillway.tryCall(john)).isTrue(); @@ -121,9 +104,9 @@ public void multipleLimitsNoOverlap() throws Exception { } @Test - public void multipleResourcesEachHaveTheirOwnLimit() throws Exception { + public void multipleResourcesEachHaveTheirOwnLimit() { Limit userLimit = - LimitBuilder.of("perUser", User::getName).to(1).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(1).per(Duration.ofHours(1)).build(); Spillway spillway1 = inMemoryFactory.enforce("testResource1", userLimit); Spillway spillway2 = inMemoryFactory.enforce("testResource2", userLimit); @@ -134,19 +117,19 @@ public void multipleResourcesEachHaveTheirOwnLimit() throws Exception { } @Test - public void canUseDefaultPropertyExtractor() throws Exception { + public void canUseDefaultPropertyExtractor() { Limit userLimit = LimitBuilder.of("perUser").to(1).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", userLimit); - assertThat(spillway.tryCall(john.getName())).isTrue(); - assertThat(spillway.tryCall(john.getName())).isFalse(); + assertThat(spillway.tryCall(john.name())).isTrue(); + assertThat(spillway.tryCall(john.name())).isFalse(); } @Test - public void canBeNotifiedWhenLimitIsExceeded() throws Exception { + public void canBeNotifiedWhenLimitIsExceeded() { LimitTriggerCallback callback = mock(LimitTriggerCallback.class); Limit userLimit = - LimitBuilder.of("perUser", User::getName) + LimitBuilder.of("perUser", User::name) .to(1) .per(Duration.ofHours(1)) .withExceededCallback(callback) @@ -162,7 +145,7 @@ public void canBeNotifiedWhenLimitIsExceeded() throws Exception { @Test public void callThrowsAnExceptionWhichContainsAllTheDetails() throws Exception { Limit userLimit = - LimitBuilder.of("perUser", User::getName).to(1).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(1).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", userLimit); spillway.call(john); @@ -179,9 +162,8 @@ public void callThrowsAnExceptionWhichContainsAllTheDetails() throws Exception { @Test public void callThrowsForMultipleBreachedLimits() throws Exception { Limit userLimit = - LimitBuilder.of("perUser", User::getName).to(1).per(Duration.ofHours(1)).build(); - Limit ipLimit = - LimitBuilder.of("perIp", User::getIp).to(1).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(1).per(Duration.ofHours(1)).build(); + Limit ipLimit = LimitBuilder.of("perIp", User::ip).to(1).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", userLimit, ipLimit); @@ -198,9 +180,9 @@ public void callThrowsForMultipleBreachedLimits() throws Exception { } @Test - public void bucketChangesWhenTimePasses() throws Exception { + public void bucketChangesWhenTimePasses() { Limit userLimit = - LimitBuilder.of("perUser", User::getName).to(1).per(Duration.ofSeconds(1)).build(); + LimitBuilder.of("perUser", User::name).to(1).per(Duration.ofSeconds(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", userLimit); assertThat(spillway.tryCall(john)).isTrue(); @@ -213,9 +195,9 @@ public void bucketChangesWhenTimePasses() throws Exception { } @Test - public void capacityNotIncrementedIfLimitTriggered() throws Exception { + public void capacityNotIncrementedIfLimitTriggered() { Limit limit1 = - LimitBuilder.of("perUser", User::getName).to(0).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(0).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", limit1); assertThat(spillway.tryCall(john)).isFalse(); @@ -228,7 +210,7 @@ public void capacityNotIncrementedIfLimitTriggered() throws Exception { @Test public void canGetCurrentLimitStatus() throws Exception { Limit userLimit = - LimitBuilder.of("perUser", User::getName).to(2).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(2).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", userLimit); spillway.call(john); @@ -243,7 +225,7 @@ public void canGetCurrentLimitStatus() throws Exception { limitStatuses .keySet() .stream() - .filter(key -> key.getProperty().equals(john.getName())) + .filter(key -> key.getProperty().equals(john.name())) .findFirst(); assertThat(johnKey.isPresent()).isTrue(); assertThat(limitStatuses.get(johnKey.get())).isEqualTo(2); @@ -252,33 +234,33 @@ public void canGetCurrentLimitStatus() throws Exception { limitStatuses .keySet() .stream() - .filter(key -> key.getProperty().equals(gina.getName())) + .filter(key -> key.getProperty().equals(gina.name())) .findFirst(); assertThat(ginaKey.isPresent()).isTrue(); assertThat(limitStatuses.get(ginaKey.get())).isEqualTo(1); } @Test - public void ifCallbackThrowsWeIgnoreThatCallbackAndContinue() throws Exception { + public void ifCallbackThrowsWeIgnoreThatCallbackAndContinue() { LimitTriggerCallback callbackThatIsOkay = mock(LimitTriggerCallback.class); LimitTriggerCallback callbackThatThrows = mock(LimitTriggerCallback.class); doThrow(RuntimeException.class) .when(callbackThatThrows) .trigger(any(LimitDefinition.class), any(Object.class)); Limit ipLimit1 = - LimitBuilder.of("perIp1", User::getIp) + LimitBuilder.of("perIp1", User::ip) .to(1) .per(Duration.ofHours(1)) .withExceededCallback(callbackThatThrows) .build(); Limit userLimit = - LimitBuilder.of("perUser", User::getName) + LimitBuilder.of("perUser", User::name) .to(1) .per(Duration.ofHours(1)) .withExceededCallback(callbackThatIsOkay) .build(); Limit ipLimit2 = - LimitBuilder.of("perIp2", User::getIp) + LimitBuilder.of("perIp2", User::ip) .to(1) .per(Duration.ofHours(1)) .withExceededCallback(callbackThatThrows) @@ -295,9 +277,9 @@ public void ifCallbackThrowsWeIgnoreThatCallbackAndContinue() throws Exception { } @Test - public void canExceedLimitByDoingALargeIncrement() throws Exception { + public void canExceedLimitByDoingALargeIncrement() { Limit userLimit = - LimitBuilder.of("perUser", User::getName).to(2).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(2).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", userLimit); try { @@ -310,9 +292,9 @@ public void canExceedLimitByDoingALargeIncrement() throws Exception { } @Test - public void costCanBeALargeNumber() throws Exception { + public void costCanBeALargeNumber() { Limit userLimit = - LimitBuilder.of("perUser", User::getName).to(4).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(4).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", userLimit); assertThat(spillway.tryCall(john, 4)).isTrue(); @@ -320,12 +302,12 @@ public void costCanBeALargeNumber() throws Exception { } @Test - public void canAddLimitTriggers() throws Exception { + public void canAddLimitTriggers() { LimitTriggerCallback callback = mock(LimitTriggerCallback.class); ValueThresholdTrigger trigger = new ValueThresholdTrigger(5, callback); Limit userLimit = - LimitBuilder.of("perUser", User::getName) + LimitBuilder.of("perUser", User::name) .to(15) .per(Duration.ofHours(1)) .withLimitTrigger(trigger) @@ -342,8 +324,8 @@ public void canAddLimitTriggers() throws Exception { } @Test - public void triggersAreIgnoreIfTheStorageReturnsAnIncoherentResponse() throws Exception { - when(mockedStorage.addAndGet(anyListOf(AddAndGetRequest.class))) + public void triggersAreIgnoreIfTheStorageReturnsAnIncoherentResponse() { + when(mockedStorage.addAndGet(anyCollection())) .thenReturn( ImmutableMap.of( mock(LimitKey.class), 1, mock(LimitKey.class), 2, mock(LimitKey.class), 3)); @@ -351,7 +333,7 @@ public void triggersAreIgnoreIfTheStorageReturnsAnIncoherentResponse() throws Ex LimitTriggerCallback callback = mock(LimitTriggerCallback.class); ValueThresholdTrigger trigger = new ValueThresholdTrigger(5, callback); Limit userLimit = - LimitBuilder.of("perUser", User::getName) + LimitBuilder.of("perUser", User::name) .to(15) .per(Duration.ofHours(1)) .withLimitTrigger(trigger) @@ -364,11 +346,11 @@ public void triggersAreIgnoreIfTheStorageReturnsAnIncoherentResponse() throws Ex } @Test - public void canAddCapacityLimitOverride() throws Exception { + public void canAddCapacityLimitOverride() { LimitOverride override = LimitOverrideBuilder.of(JOHN).to(A_CAPACITY).per(A_DURATION).build(); Limit userLimit = - LimitBuilder.of("perUser", User::getName) + LimitBuilder.of("perUser", User::name) .to(A_HIGHER_CAPACITY) .per(A_DURATION) .withLimitOverride(override) @@ -379,12 +361,12 @@ public void canAddCapacityLimitOverride() throws Exception { } @Test - public void canAddExpirationLimitOverride() throws Exception { + public void canAddExpirationLimitOverride() { LimitOverride override = LimitOverrideBuilder.of(JOHN).to(A_CAPACITY).per(A_SHORT_DURATION).build(); Limit userLimit = - LimitBuilder.of("perUser", User::getName) + LimitBuilder.of("perUser", User::name) .to(A_CAPACITY) .per(A_DURATION) .withLimitOverride(override) @@ -401,7 +383,7 @@ public void canAddExpirationLimitOverride() throws Exception { } @Test - public void canAddTriggersLimitOverride() throws Exception { + public void canAddTriggersLimitOverride() { ArgumentCaptor definitionCaptor = ArgumentCaptor.forClass(LimitDefinition.class); @@ -416,7 +398,7 @@ public void canAddTriggersLimitOverride() throws Exception { .build(); Limit userLimit = - LimitBuilder.of(A_LIMIT_NAME, User::getName) + LimitBuilder.of(A_LIMIT_NAME, User::name) .to(A_CAPACITY) .per(A_DURATION) .withExceededCallback(limitCallback) @@ -435,13 +417,13 @@ public void canAddTriggersLimitOverride() throws Exception { } @Test - public void testAddMultipleLimitOverridesForSameProperty() throws Exception { + public void testAddMultipleLimitOverridesForSameProperty() { LimitOverride override = LimitOverrideBuilder.of(JOHN).to(A_CAPACITY).per(A_DURATION).build(); LimitOverride anotherOverride = LimitOverrideBuilder.of(JOHN).to(A_SMALLER_CAPACITY).per(A_DURATION).build(); Limit userLimit = - LimitBuilder.of("perUser", User::getName) + LimitBuilder.of("perUser", User::name) .to(A_HIGHER_CAPACITY) .per(A_DURATION) .withLimitOverride(override) @@ -452,37 +434,37 @@ public void testAddMultipleLimitOverridesForSameProperty() throws Exception { assertThat(spillway.tryCall(john, A_SMALLER_CAPACITY + 10)).isFalse(); } - @Test(expected = IllegalArgumentException.class) - public void positiveCostOnlyCall() throws Exception { + @Test + public void positiveCostOnlyCall() { Limit limit1 = - LimitBuilder.of("perUser", User::getName).to(2).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(2).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", limit1); - spillway.call(john, 0); + assertThrows(IllegalArgumentException.class, () -> spillway.call(john, 0)); } - @Test(expected = IllegalArgumentException.class) - public void positiveCostOnlyTryCall() throws Exception { + @Test + public void positiveCostOnlyTryCall() { Limit limit1 = - LimitBuilder.of("perUser", User::getName).to(2).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(2).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", limit1); - spillway.tryCall(john, 0); + assertThrows(IllegalArgumentException.class, () -> spillway.tryCall(john, 0)); } - @Test(expected = IllegalArgumentException.class) - public void positiveCostOnlyCheckLimit() throws Exception { + @Test + public void positiveCostOnlyCheckLimit() { Limit limit1 = - LimitBuilder.of("perUser", User::getName).to(2).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(2).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", limit1); - spillway.checkLimit(john, 0); + assertThrows(IllegalArgumentException.class, () -> spillway.checkLimit(john, 0)); } @Test public void checkLimit() throws Exception { Limit limit1 = - LimitBuilder.of("perUser", User::getName).to(3).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(3).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", limit1); assertThat(spillway.checkLimit(john)).isTrue(); @@ -494,9 +476,9 @@ public void checkLimit() throws Exception { } @Test - public void checkLimitDoesNotAffectStorage() throws Exception { + public void checkLimitDoesNotAffectStorage() { Limit limit1 = - LimitBuilder.of("perUser", User::getName).to(1).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(1).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", limit1); spillway.checkLimit(john); @@ -506,17 +488,17 @@ public void checkLimitDoesNotAffectStorage() throws Exception { currentCounts .keySet() .stream() - .filter(key -> key.getProperty().equals(john.getName())) + .filter(key -> key.getProperty().equals(john.name())) .findFirst(); assertThat(johnKey.isPresent()).isTrue(); assertThat(currentCounts.get(johnKey.get())).isEqualTo(0); } @Test - public void checkLimitDoesNotFireTriggers() throws Exception { + public void checkLimitDoesNotFireTriggers() { LimitTriggerCallback callback = mock(LimitTriggerCallback.class); Limit userLimit = - LimitBuilder.of("perUser", User::getName) + LimitBuilder.of("perUser", User::name) .to(1) .per(Duration.ofHours(1)) .withExceededCallback(callback) diff --git a/src/test/java/com/coveo/spillway/SpillwayTryUpdateAndVerifyLimitTest.java b/src/test/java/com/coveo/spillway/SpillwayTryUpdateAndVerifyLimitTest.java index 12fab7b..6d85915 100644 --- a/src/test/java/com/coveo/spillway/SpillwayTryUpdateAndVerifyLimitTest.java +++ b/src/test/java/com/coveo/spillway/SpillwayTryUpdateAndVerifyLimitTest.java @@ -1,10 +1,9 @@ package com.coveo.spillway; import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyListOf; -import static org.mockito.Matchers.eq; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -22,7 +21,6 @@ import com.coveo.spillway.limit.override.LimitOverrideBuilder; import com.coveo.spillway.storage.InMemoryStorage; import com.coveo.spillway.storage.LimitUsageStorage; -import com.coveo.spillway.storage.utils.AddAndGetRequest; import com.coveo.spillway.trigger.LimitTriggerCallback; import com.coveo.spillway.trigger.ValueThresholdTrigger; import com.google.common.collect.ImmutableMap; @@ -32,9 +30,10 @@ import java.util.Map; import java.util.Optional; import java.util.stream.IntStream; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; + +import com.google.common.truth.Truth; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; public class SpillwayTryUpdateAndVerifyLimitTest { @@ -47,27 +46,10 @@ public class SpillwayTryUpdateAndVerifyLimitTest { private static final String JOHN = "john"; private static final String A_LIMIT_NAME = "perUser"; - private class User { - - private String name; - private String ip; + private record User(String name, String ip) {} - User(String name, String ip) { - this.name = name; - this.ip = ip; - } - - String getName() { - return name; - } - - String getIp() { - return ip; - } - } - - private User john = new User(JOHN, "127.0.0.1"); - private User gina = new User("gina", "127.0.0.1"); + private final User john = new User(JOHN, "127.0.0.1"); + private final User gina = new User("gina", "127.0.0.1"); private LimitUsageStorage mockedStorage; private LimitUsageStorage inMemoryStorage; @@ -76,7 +58,7 @@ String getIp() { private SpillwayFactory inMemoryFactory; private SpillwayFactory mockedFactory; - @Before + @BeforeEach public void setup() { clock = mock(Clock.class); inMemoryStorage = new InMemoryStorage(); @@ -89,9 +71,9 @@ public void setup() { } @Test - public void simpleLimit() throws Exception { + public void simpleLimit() { Limit limit1 = - LimitBuilder.of("perUser", User::getName).to(2).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(2).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", limit1); assertThat(spillway.tryUpdateAndVerifyLimit(john)).isTrue(); @@ -100,21 +82,23 @@ public void simpleLimit() throws Exception { .isFalse(); // Third tryUpdateAndVerifyLimit fails } - @Test(expected = SpillwayLimitsWithSameNameException.class) - public void multipleLimitsWithOverlap() throws Exception { + @Test + public void multipleLimitsWithOverlap() { Limit limit1 = - LimitBuilder.of("perUser", User::getName).to(5).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(5).per(Duration.ofHours(1)).build(); Limit limit2 = - LimitBuilder.of("perUser", User::getName).to(1).per(Duration.ofSeconds(1)).build(); - inMemoryFactory.enforce("testResource", limit1, limit2); + LimitBuilder.of("perUser", User::name).to(1).per(Duration.ofSeconds(1)).build(); + + assertThrows( + SpillwayLimitsWithSameNameException.class, + () -> inMemoryFactory.enforce("testResource", limit1, limit2)); } @Test - public void multipleLimitsNoOverlap() throws Exception { - Limit ipLimit = - LimitBuilder.of("perIp", User::getIp).to(1).per(Duration.ofHours(1)).build(); + public void multipleLimitsNoOverlap() { + Limit ipLimit = LimitBuilder.of("perIp", User::ip).to(1).per(Duration.ofHours(1)).build(); Limit userLimit = - LimitBuilder.of("perUser", User::getName).to(1).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(1).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", ipLimit, userLimit); assertThat(spillway.tryUpdateAndVerifyLimit(john)).isTrue(); @@ -122,9 +106,9 @@ public void multipleLimitsNoOverlap() throws Exception { } @Test - public void multipleResourcesEachHaveTheirOwnLimit() throws Exception { + public void multipleResourcesEachHaveTheirOwnLimit() { Limit userLimit = - LimitBuilder.of("perUser", User::getName).to(1).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(1).per(Duration.ofHours(1)).build(); Spillway spillway1 = inMemoryFactory.enforce("testResource1", userLimit); Spillway spillway2 = inMemoryFactory.enforce("testResource2", userLimit); @@ -135,19 +119,19 @@ public void multipleResourcesEachHaveTheirOwnLimit() throws Exception { } @Test - public void canUseDefaultPropertyExtractor() throws Exception { + public void canUseDefaultPropertyExtractor() { Limit userLimit = LimitBuilder.of("perUser").to(1).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", userLimit); - assertThat(spillway.tryUpdateAndVerifyLimit(john.getName())).isTrue(); - assertThat(spillway.tryUpdateAndVerifyLimit(john.getName())).isFalse(); + assertThat(spillway.tryUpdateAndVerifyLimit(john.name())).isTrue(); + assertThat(spillway.tryUpdateAndVerifyLimit(john.name())).isFalse(); } @Test - public void canBeNotifiedWhenLimitIsExceeded() throws Exception { + public void canBeNotifiedWhenLimitIsExceeded() { LimitTriggerCallback callback = mock(LimitTriggerCallback.class); Limit userLimit = - LimitBuilder.of("perUser", User::getName) + LimitBuilder.of("perUser", User::name) .to(1) .per(Duration.ofHours(1)) .withExceededCallback(callback) @@ -163,7 +147,7 @@ public void canBeNotifiedWhenLimitIsExceeded() throws Exception { @Test public void callThrowsAnExceptionWhichContainsAllTheDetails() throws Exception { Limit userLimit = - LimitBuilder.of("perUser", User::getName).to(1).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(1).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", userLimit); spillway.updateAndVerifyLimit(john); @@ -180,9 +164,8 @@ public void callThrowsAnExceptionWhichContainsAllTheDetails() throws Exception { @Test public void callThrowsForMultipleBreachedLimits() throws Exception { Limit userLimit = - LimitBuilder.of("perUser", User::getName).to(1).per(Duration.ofHours(1)).build(); - Limit ipLimit = - LimitBuilder.of("perIp", User::getIp).to(1).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(1).per(Duration.ofHours(1)).build(); + Limit ipLimit = LimitBuilder.of("perIp", User::ip).to(1).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", userLimit, ipLimit); @@ -199,9 +182,9 @@ public void callThrowsForMultipleBreachedLimits() throws Exception { } @Test - public void bucketChangesWhenTimePasses() throws Exception { + public void bucketChangesWhenTimePasses() { Limit userLimit = - LimitBuilder.of("perUser", User::getName).to(1).per(Duration.ofSeconds(1)).build(); + LimitBuilder.of("perUser", User::name).to(1).per(Duration.ofSeconds(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", userLimit); assertThat(spillway.tryUpdateAndVerifyLimit(john)).isTrue(); @@ -214,9 +197,9 @@ public void bucketChangesWhenTimePasses() throws Exception { } @Test - public void capacityNotIncrementedIfLimitTriggered() throws Exception { + public void capacityNotIncrementedIfLimitTriggered() { Limit limit1 = - LimitBuilder.of("perUser", User::getName).to(0).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(0).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", limit1); assertThat(spillway.tryUpdateAndVerifyLimit(john)).isFalse(); @@ -229,7 +212,7 @@ public void capacityNotIncrementedIfLimitTriggered() throws Exception { @Test public void canGetCurrentLimitStatus() throws Exception { Limit userLimit = - LimitBuilder.of("perUser", User::getName).to(2).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(2).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", userLimit); spillway.updateAndVerifyLimit(john); @@ -244,7 +227,7 @@ public void canGetCurrentLimitStatus() throws Exception { limitStatuses .keySet() .stream() - .filter(key -> key.getProperty().equals(john.getName())) + .filter(key -> key.getProperty().equals(john.name())) .findFirst(); assertThat(johnKey.isPresent()).isTrue(); assertThat(limitStatuses.get(johnKey.get())).isEqualTo(2); @@ -253,33 +236,33 @@ public void canGetCurrentLimitStatus() throws Exception { limitStatuses .keySet() .stream() - .filter(key -> key.getProperty().equals(gina.getName())) + .filter(key -> key.getProperty().equals(gina.name())) .findFirst(); assertThat(ginaKey.isPresent()).isTrue(); assertThat(limitStatuses.get(ginaKey.get())).isEqualTo(1); } @Test - public void ifCallbackThrowsWeIgnoreThatCallbackAndContinue() throws Exception { + public void ifCallbackThrowsWeIgnoreThatCallbackAndContinue() { LimitTriggerCallback callbackThatIsOkay = mock(LimitTriggerCallback.class); LimitTriggerCallback callbackThatThrows = mock(LimitTriggerCallback.class); doThrow(RuntimeException.class) .when(callbackThatThrows) .trigger(any(LimitDefinition.class), any(Object.class)); Limit ipLimit1 = - LimitBuilder.of("perIp1", User::getIp) + LimitBuilder.of("perIp1", User::ip) .to(1) .per(Duration.ofHours(1)) .withExceededCallback(callbackThatThrows) .build(); Limit userLimit = - LimitBuilder.of("perUser", User::getName) + LimitBuilder.of("perUser", User::name) .to(1) .per(Duration.ofHours(1)) .withExceededCallback(callbackThatIsOkay) .build(); Limit ipLimit2 = - LimitBuilder.of("perIp2", User::getIp) + LimitBuilder.of("perIp2", User::ip) .to(1) .per(Duration.ofHours(1)) .withExceededCallback(callbackThatThrows) @@ -296,9 +279,9 @@ public void ifCallbackThrowsWeIgnoreThatCallbackAndContinue() throws Exception { } @Test - public void canExceedLimitByDoingALargeIncrement() throws Exception { + public void canExceedLimitByDoingALargeIncrement() { Limit userLimit = - LimitBuilder.of("perUser", User::getName).to(2).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(2).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", userLimit); try { @@ -311,9 +294,9 @@ public void canExceedLimitByDoingALargeIncrement() throws Exception { } @Test - public void costCanBeALargeNumber() throws Exception { + public void costCanBeALargeNumber() { Limit userLimit = - LimitBuilder.of("perUser", User::getName).to(4).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(4).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", userLimit); assertThat(spillway.tryUpdateAndVerifyLimit(john, 4)).isTrue(); @@ -321,12 +304,12 @@ public void costCanBeALargeNumber() throws Exception { } @Test - public void canAddLimitTriggers() throws Exception { + public void canAddLimitTriggers() { LimitTriggerCallback callback = mock(LimitTriggerCallback.class); ValueThresholdTrigger trigger = new ValueThresholdTrigger(5, callback); Limit userLimit = - LimitBuilder.of("perUser", User::getName) + LimitBuilder.of("perUser", User::name) .to(15) .per(Duration.ofHours(1)) .withLimitTrigger(trigger) @@ -343,8 +326,8 @@ public void canAddLimitTriggers() throws Exception { } @Test - public void triggersAreIgnoreIfTheStorageReturnsAnIncoherentResponse() throws Exception { - when(mockedStorage.addAndGetWithLimit(anyListOf(AddAndGetRequest.class))) + public void triggersAreIgnoreIfTheStorageReturnsAnIncoherentResponse() { + when(mockedStorage.addAndGetWithLimit(anyCollection())) .thenReturn( ImmutableMap.of( mock(LimitKey.class), 1, mock(LimitKey.class), 2, mock(LimitKey.class), 3)); @@ -352,7 +335,7 @@ public void triggersAreIgnoreIfTheStorageReturnsAnIncoherentResponse() throws Ex LimitTriggerCallback callback = mock(LimitTriggerCallback.class); ValueThresholdTrigger trigger = new ValueThresholdTrigger(5, callback); Limit userLimit = - LimitBuilder.of("perUser", User::getName) + LimitBuilder.of("perUser", User::name) .to(15) .per(Duration.ofHours(1)) .withLimitTrigger(trigger) @@ -365,11 +348,11 @@ public void triggersAreIgnoreIfTheStorageReturnsAnIncoherentResponse() throws Ex } @Test - public void canAddCapacityLimitOverride() throws Exception { + public void canAddCapacityLimitOverride() { LimitOverride override = LimitOverrideBuilder.of(JOHN).to(A_CAPACITY).per(A_DURATION).build(); Limit userLimit = - LimitBuilder.of("perUser", User::getName) + LimitBuilder.of("perUser", User::name) .to(A_HIGHER_CAPACITY) .per(A_DURATION) .withLimitOverride(override) @@ -380,12 +363,12 @@ public void canAddCapacityLimitOverride() throws Exception { } @Test - public void canAddExpirationLimitOverride() throws Exception { + public void canAddExpirationLimitOverride() { LimitOverride override = LimitOverrideBuilder.of(JOHN).to(A_CAPACITY).per(A_SHORT_DURATION).build(); Limit userLimit = - LimitBuilder.of("perUser", User::getName) + LimitBuilder.of("perUser", User::name) .to(A_CAPACITY) .per(A_DURATION) .withLimitOverride(override) @@ -402,7 +385,7 @@ public void canAddExpirationLimitOverride() throws Exception { } @Test - public void canAddTriggersLimitOverride() throws Exception { + public void canAddTriggersLimitOverride() { ArgumentCaptor definitionCaptor = ArgumentCaptor.forClass(LimitDefinition.class); @@ -417,7 +400,7 @@ public void canAddTriggersLimitOverride() throws Exception { .build(); Limit userLimit = - LimitBuilder.of(A_LIMIT_NAME, User::getName) + LimitBuilder.of(A_LIMIT_NAME, User::name) .to(A_CAPACITY) .per(A_DURATION) .withExceededCallback(limitCallback) @@ -436,13 +419,13 @@ public void canAddTriggersLimitOverride() throws Exception { } @Test - public void testAddMultipleLimitOverridesForSameProperty() throws Exception { + public void testAddMultipleLimitOverridesForSameProperty() { LimitOverride override = LimitOverrideBuilder.of(JOHN).to(A_CAPACITY).per(A_DURATION).build(); LimitOverride anotherOverride = LimitOverrideBuilder.of(JOHN).to(A_SMALLER_CAPACITY).per(A_DURATION).build(); Limit userLimit = - LimitBuilder.of("perUser", User::getName) + LimitBuilder.of("perUser", User::name) .to(A_HIGHER_CAPACITY) .per(A_DURATION) .withLimitOverride(override) @@ -453,28 +436,28 @@ public void testAddMultipleLimitOverridesForSameProperty() throws Exception { assertThat(spillway.tryUpdateAndVerifyLimit(john, A_SMALLER_CAPACITY + 10)).isFalse(); } - @Test(expected = IllegalArgumentException.class) + @Test public void positiveCostOnlyCall() throws Exception { Limit limit1 = - LimitBuilder.of("perUser", User::getName).to(2).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(2).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", limit1); - spillway.call(john, 0); + assertThrows(IllegalArgumentException.class, () -> spillway.call(john, 0)); } - @Test(expected = IllegalArgumentException.class) - public void positiveCostOnlyTryCall() throws Exception { + @Test + public void positiveCostOnlyTryCall() { Limit limit1 = - LimitBuilder.of("perUser", User::getName).to(2).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(2).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", limit1); - spillway.tryUpdateAndVerifyLimit(john, 0); + assertThrows(IllegalArgumentException.class, () -> spillway.tryUpdateAndVerifyLimit(john, 0)); } @Test public void checkLimit() throws Exception { Limit limit1 = - LimitBuilder.of("perUser", User::getName).to(3).per(Duration.ofHours(1)).build(); + LimitBuilder.of("perUser", User::name).to(3).per(Duration.ofHours(1)).build(); Spillway spillway = inMemoryFactory.enforce("testResource", limit1); assertThat(spillway.checkLimit(john)).isTrue(); @@ -486,21 +469,21 @@ public void checkLimit() throws Exception { } @Test - public void tryUpdateAndVerifyLimitMultiThread() throws Exception { + public void tryUpdateAndVerifyLimitMultiThread() { IntStream.range(0, 10) .forEach( i -> { InMemoryStorage inMemoryStorage = new InMemoryStorage(); SpillwayFactory inMemoryFactory = new SpillwayFactory(inMemoryStorage); Limit userLimit = - LimitBuilder.of("perUser", User::getName).to(100).per(A_DURATION).build(); + LimitBuilder.of("perUser", User::name).to(100).per(A_DURATION).build(); Spillway spillway = inMemoryFactory.enforce("testResource", userLimit); Optional limitReached = IntStream.range(0, 101) .parallel() .mapToObj(j -> spillway.tryUpdateAndVerifyLimit(john)) .reduce(Boolean::logicalAnd); - Assert.assertFalse(limitReached.orElse(true)); + assertThat(limitReached).hasValue(false); }); } } diff --git a/src/test/java/com/coveo/spillway/functional/SpillwayFunctionalTests.java b/src/test/java/com/coveo/spillway/functional/SpillwayFunctionalTests.java index 3db163e..d8182b0 100644 --- a/src/test/java/com/coveo/spillway/functional/SpillwayFunctionalTests.java +++ b/src/test/java/com/coveo/spillway/functional/SpillwayFunctionalTests.java @@ -14,11 +14,7 @@ import java.util.stream.IntStream; import org.apache.commons.lang3.tuple.Pair; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Test; +import org.junit.jupiter.api.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,14 +27,13 @@ import com.coveo.spillway.storage.AsyncLimitUsageStorage; import com.coveo.spillway.storage.InMemoryStorage; import com.coveo.spillway.storage.RedisStorage; -import com.coveo.spillway.storage.RedisStorageTest; import com.google.common.base.Stopwatch; import com.google.common.collect.Range; import redis.clients.jedis.JedisPool; import redis.embedded.RedisServer; -@Ignore("Functional tests, remove ignore to run them") +@Disabled("Functional tests, remove ignore to run them") public class SpillwayFunctionalTests { private static final String RESOURCE1 = "someResource"; @@ -59,8 +54,7 @@ public class SpillwayFunctionalTests { private static JedisPool jedis; private static RedisStorage storage; - @SuppressWarnings("resource") - @BeforeClass + @BeforeAll public static void startRedis() throws IOException { try { redisServer = new RedisServer(6389); @@ -73,12 +67,12 @@ public static void startRedis() throws IOException { storage = RedisStorage.builder().withJedisPool(new JedisPool("localhost", 6389)).build(); } - @AfterClass - public static void stopRedis() { + @AfterAll + public static void stopRedis() throws IOException { redisServer.stop(); } - @Before + @BeforeEach public void setup() { jedis.getResource().flushDB(); inMemoryFactory = new SpillwayFactory(new InMemoryStorage()); @@ -106,7 +100,7 @@ public void oneMillionConcurrentRequestsWith100Threads() throws Exception { threadPool.shutdown(); threadPool.awaitTermination(1, TimeUnit.MINUTES); - assertThat(counter.get()).isIn(inErrorMargin(ONE_MILLION, MARGIN_OF_ERROR)); + assertThat(counter.get()).isIn(inErrorMargin(MARGIN_OF_ERROR)); } @Test @@ -240,26 +234,16 @@ public void asyncBatchStorageTest() throws Exception { Map currentCounters = asyncStorage.getCurrentLimitCounters(); Map cacheCounters = asyncStorage.debugCacheLimitCounters(); - currentCounters - .entrySet() - .forEach( - entry -> { - assertThat(entry.getValue()).isEqualTo(numberOfCalls); - }); - - cacheCounters - .entrySet() - .forEach( - entry -> { - assertThat(entry.getValue()).isEqualTo(2 * numberOfCalls); - }); + currentCounters.forEach((key, value) -> assertThat(value).isEqualTo(numberOfCalls)); + + cacheCounters.forEach((key, value) -> assertThat(value).isEqualTo(2 * numberOfCalls)); } - private Range inErrorMargin(Integer expectedValue, double marginOfError) { + private Range inErrorMargin(double marginOfError) { marginOfError += 1; - Integer lowerBound = (int) (expectedValue / marginOfError); - Integer upperBound = (int) (expectedValue * marginOfError); + Integer lowerBound = (int) (SpillwayFunctionalTests.ONE_MILLION / marginOfError); + Integer upperBound = (int) (SpillwayFunctionalTests.ONE_MILLION * marginOfError); return Range.closed(lowerBound, upperBound); } diff --git a/src/test/java/com/coveo/spillway/limit/LimitDefinitionTest.java b/src/test/java/com/coveo/spillway/limit/LimitDefinitionTest.java index 2111379..128b206 100644 --- a/src/test/java/com/coveo/spillway/limit/LimitDefinitionTest.java +++ b/src/test/java/com/coveo/spillway/limit/LimitDefinitionTest.java @@ -22,9 +22,8 @@ */ package com.coveo.spillway.limit; -import org.junit.Test; - import com.coveo.spillway.limit.LimitDefinition; +import org.junit.jupiter.api.Test; import java.time.Duration; diff --git a/src/test/java/com/coveo/spillway/limit/LimitTest.java b/src/test/java/com/coveo/spillway/limit/LimitTest.java index 04dc176..8c05295 100644 --- a/src/test/java/com/coveo/spillway/limit/LimitTest.java +++ b/src/test/java/com/coveo/spillway/limit/LimitTest.java @@ -22,10 +22,9 @@ */ package com.coveo.spillway.limit; -import org.junit.Test; - import com.coveo.spillway.limit.Limit; import com.coveo.spillway.limit.LimitDefinition; +import org.junit.jupiter.api.Test; import java.time.Duration; import java.util.ArrayList; diff --git a/src/test/java/com/coveo/spillway/storage/AsyncBatchLimitUsageStorageTest.java b/src/test/java/com/coveo/spillway/storage/AsyncBatchLimitUsageStorageTest.java index 494f15c..30eeb19 100644 --- a/src/test/java/com/coveo/spillway/storage/AsyncBatchLimitUsageStorageTest.java +++ b/src/test/java/com/coveo/spillway/storage/AsyncBatchLimitUsageStorageTest.java @@ -1,7 +1,6 @@ package com.coveo.spillway.storage; import static com.google.common.truth.Truth.*; -import static org.mockito.Matchers.*; import static org.mockito.Mockito.*; import java.time.Duration; @@ -14,21 +13,21 @@ import java.util.Map.Entry; import org.apache.commons.lang3.tuple.ImmutablePair; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; import com.coveo.spillway.limit.LimitKey; import com.coveo.spillway.storage.utils.AddAndGetRequest; import com.coveo.spillway.storage.utils.CacheSynchronization; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class AsyncBatchLimitUsageStorageTest { private static final String RESOURCE = "TheResource"; private static final String PROPERTY = "TheProperty"; @@ -47,19 +46,19 @@ public class AsyncBatchLimitUsageStorageTest { private AsyncBatchLimitUsageStorage asyncBatchLimitUsageStorage; - @Before + @BeforeEach public void setup() { cacheSpy = Mockito.spy(new InMemoryStorage()); cacheSynchronizationSpy = Mockito.spy(new CacheSynchronization(cacheSpy, storageMock)); } - @After + @AfterEach public void tearDown() throws Exception { asyncBatchLimitUsageStorage.close(); } @Test - public void testAddWithCacheForcefullyInitialized() throws Exception { + public void testAddWithCacheForcefullyInitialized() { asyncBatchLimitUsageStorage = new AsyncBatchLimitUsageStorage( storageMock, @@ -88,7 +87,7 @@ public void testAddWithCacheForcefullyInitialized() throws Exception { } @Test - public void testAddWithCacheNotForcefullyInitialized() throws Exception { + public void testAddWithCacheNotForcefullyInitialized() { asyncBatchLimitUsageStorage = new AsyncBatchLimitUsageStorage( storageMock, @@ -125,8 +124,7 @@ public void testSynchronizeIsNotAffectingProcess() throws Exception { .then( invocation -> { Thread.sleep(MOCKED_STORAGE_SLEEP); - return ImmutablePair.of( - LimitKey.fromRequest(invocation.getArgumentAt(0, AddAndGetRequest.class)), 100); + return ImmutablePair.of(LimitKey.fromRequest(invocation.getArgument(0)), 100); }); asyncBatchLimitUsageStorage = diff --git a/src/test/java/com/coveo/spillway/storage/AsyncLimitUsageStorageTest.java b/src/test/java/com/coveo/spillway/storage/AsyncLimitUsageStorageTest.java index 2bc1675..dc9bc41 100644 --- a/src/test/java/com/coveo/spillway/storage/AsyncLimitUsageStorageTest.java +++ b/src/test/java/com/coveo/spillway/storage/AsyncLimitUsageStorageTest.java @@ -23,12 +23,12 @@ package com.coveo.spillway.storage; import com.coveo.spillway.limit.LimitKey; -import com.coveo.spillway.storage.AsyncLimitUsageStorage; import com.coveo.spillway.storage.utils.AddAndGetRequest; import com.google.common.collect.ImmutableMap; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,8 +36,7 @@ import java.time.Instant; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Matchers.anyCollectionOf; -import static org.mockito.Mockito.mock; +import static org.mockito.ArgumentMatchers.anyCollection; import static org.mockito.Mockito.when; public class AsyncLimitUsageStorageTest { @@ -53,8 +52,7 @@ public class AsyncLimitUsageStorageTest { private static final int MOCKED_STORAGE_SLEEP = 100; private AsyncLimitUsageStorage asyncStorage; - private LimitUsageStorage mockedStorage; - private AddAndGetRequest request = + private final AddAndGetRequest request = new AddAndGetRequest.Builder() .withResource(RESOURCE) .withProperty(PROPERTY) @@ -65,10 +63,10 @@ public class AsyncLimitUsageStorageTest { .withExpiration(EXPIRATION) .build(); - @Before + @BeforeEach public void setup() { - mockedStorage = mock(LimitUsageStorage.class); - when(mockedStorage.addAndGet(anyCollectionOf(AddAndGetRequest.class))) + LimitUsageStorage mockedStorage = Mockito.mock(LimitUsageStorage.class); + when(mockedStorage.addAndGet(anyCollection())) .then( invocation -> { Thread.sleep(MOCKED_STORAGE_SLEEP); diff --git a/src/test/java/com/coveo/spillway/storage/InMemoryStorageTest.java b/src/test/java/com/coveo/spillway/storage/InMemoryStorageTest.java index 481f16a..ce8bbbd 100644 --- a/src/test/java/com/coveo/spillway/storage/InMemoryStorageTest.java +++ b/src/test/java/com/coveo/spillway/storage/InMemoryStorageTest.java @@ -22,14 +22,14 @@ */ package com.coveo.spillway.storage; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; import com.coveo.spillway.limit.LimitKey; +import org.mockito.junit.jupiter.MockitoExtension; import java.time.Clock; import java.time.Duration; @@ -39,7 +39,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.*; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class InMemoryStorageTest { private static final String RESOURCE1 = "someResource"; @@ -55,7 +55,7 @@ public class InMemoryStorageTest { @InjectMocks private InMemoryStorage storage; - @Before + @BeforeEach public void setup() { when(clock.instant()).thenReturn(Instant.now()); } diff --git a/src/test/java/com/coveo/spillway/storage/RedisStorageTest.java b/src/test/java/com/coveo/spillway/storage/RedisStorageTest.java index 8ca94d9..0282b25 100644 --- a/src/test/java/com/coveo/spillway/storage/RedisStorageTest.java +++ b/src/test/java/com/coveo/spillway/storage/RedisStorageTest.java @@ -29,13 +29,8 @@ import java.time.Duration; import java.time.Instant; import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.coveo.spillway.limit.LimitKey; @@ -50,6 +45,7 @@ * The behavior of the RedisStorage class is tightly coupled with the behavior * of redis so it makes sense imho. */ +//@Disabled("Functional tests, remove ignore to run them") public class RedisStorageTest { private static final String RESOURCE1 = "someResource"; @@ -63,6 +59,7 @@ public class RedisStorageTest { private static final String KEY3 = "yetAnotherKey"; private static final Duration EXPIRATION = Duration.ofHours(1); private static final Instant TIMESTAMP = Instant.now(); + private static final int REDIS_PORT = 7893; private static final Logger logger = LoggerFactory.getLogger(RedisStorageTest.class); @@ -70,26 +67,25 @@ public class RedisStorageTest { private static JedisPool jedis; private static RedisStorage storage; - @SuppressWarnings("resource") - @BeforeClass + @BeforeAll public static void startRedis() throws IOException { try { - redisServer = new RedisServer(6389); + redisServer = new RedisServer(REDIS_PORT); } catch (IOException e) { - logger.error("Failed to start Redis server. Is port 6389 available?"); + logger.error("Failed to start Redis server. Is port {} available?", REDIS_PORT); throw e; } redisServer.start(); - jedis = new JedisPool("localhost", 6389); - storage = RedisStorage.builder().withJedisPool(new JedisPool("localhost", 6389)).build(); + jedis = new JedisPool("localhost", REDIS_PORT); + storage = RedisStorage.builder().withJedisPool(new JedisPool("localhost", REDIS_PORT)).build(); } - @AfterClass - public static void stopRedis() { + @AfterAll + public static void stopRedis() throws IOException { redisServer.stop(); } - @Before + @BeforeEach public void flushDataInRedis() { try (Jedis resource = jedis.getResource()) { resource.flushDB(); @@ -197,7 +193,7 @@ public void canAddLargeValues() { } @Test - public void canAddLargeValuesToExisitingCounters() { + public void canAddLargeValuesToExistingCounters() { storage.incrementAndGet(RESOURCE1, LIMIT1, PROPERTY1, true, EXPIRATION, TIMESTAMP); int result = storage.addAndGet(RESOURCE1, LIMIT1, PROPERTY1, true, EXPIRATION, TIMESTAMP, 5).getValue(); @@ -210,8 +206,13 @@ public void testBackwardCompatibilityWithPreviousKeys() { // Versions pre 2.0.0-alpha.3 are not storing expiration try (Jedis resource = jedis.getResource()) { resource.set( - Stream.of(RedisStorage.DEFAULT_PREFIX, RESOURCE1, LIMIT1, PROPERTY1, TIMESTAMP.toString()) - .collect(Collectors.joining(RedisStorage.KEY_SEPARATOR)), + String.join( + RedisStorage.KEY_SEPARATOR, + RedisStorage.DEFAULT_PREFIX, + RESOURCE1, + LIMIT1, + PROPERTY1, + TIMESTAMP.toString()), "1"); } diff --git a/src/test/java/com/coveo/spillway/storage/utils/CacheSynchronizationTest.java b/src/test/java/com/coveo/spillway/storage/utils/CacheSynchronizationTest.java index a0c0648..d98aa7a 100644 --- a/src/test/java/com/coveo/spillway/storage/utils/CacheSynchronizationTest.java +++ b/src/test/java/com/coveo/spillway/storage/utils/CacheSynchronizationTest.java @@ -1,7 +1,6 @@ package com.coveo.spillway.storage.utils; import static com.google.common.truth.Truth.*; -import static org.mockito.Matchers.*; import static org.mockito.Mockito.*; import java.time.Duration; @@ -12,20 +11,20 @@ import java.util.function.Consumer; import java.util.stream.Collectors; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; import com.coveo.spillway.limit.LimitKey; import com.coveo.spillway.storage.InMemoryStorage; import com.coveo.spillway.storage.LimitUsageStorage; import com.google.common.collect.ImmutableMap; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class CacheSynchronizationTest { private static final String RESOURCE = "TheResource"; private static final String LIMIT = "TheLimit"; @@ -42,7 +41,7 @@ public class CacheSynchronizationTest { private CacheSynchronization cacheSynchronization; - @Before + @BeforeEach public void setup() { cacheSynchronization = new CacheSynchronization(inMemoryStorageMock, limitUsageStorageMock); } @@ -93,8 +92,7 @@ private void givenLimitUsageStorageHasValues(Map counters) { private void givenInMemoryCacheHasValues(Map counters) { doAnswer( invocation -> { - Consumer> consumer = - (Consumer>) invocation.getArgumentAt(0, Consumer.class); + Consumer> consumer = invocation.getArgument(0); for (Entry entry : counters diff --git a/src/test/java/com/coveo/spillway/trigger/AbstractLimitTriggerTest.java b/src/test/java/com/coveo/spillway/trigger/AbstractLimitTriggerTest.java index c19186b..99f76fc 100644 --- a/src/test/java/com/coveo/spillway/trigger/AbstractLimitTriggerTest.java +++ b/src/test/java/com/coveo/spillway/trigger/AbstractLimitTriggerTest.java @@ -1,21 +1,21 @@ package com.coveo.spillway.trigger; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.*; import java.time.Duration; import java.time.Instant; -import org.junit.Before; -import org.junit.Test; - import com.coveo.spillway.limit.LimitDefinition; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class AbstractLimitTriggerTest { private static final LimitDefinition LIMIT_DEFINITION = new LimitDefinition("testLimit", 100, Duration.ofMinutes(1)); - private class SimpleThresholdTrigger extends AbstractLimitTrigger { + private static class SimpleThresholdTrigger extends AbstractLimitTrigger { public SimpleThresholdTrigger(LimitTriggerCallback callback) { super(callback); @@ -31,7 +31,7 @@ protected boolean triggered( private LimitTriggerCallback callback; private AbstractLimitTrigger abstractLimitTrigger; - @Before + @BeforeEach public void setup() { callback = mock(LimitTriggerCallback.class); abstractLimitTrigger = new SimpleThresholdTrigger(callback); @@ -44,7 +44,7 @@ public void testCallbackNotTriggeredTwiceInSameBucket() { abstractLimitTrigger.callbackIfRequired(null, 1, now.plusSeconds(10), 1, LIMIT_DEFINITION); abstractLimitTrigger.callbackIfRequired(null, 1, now.plusSeconds(20), 1, LIMIT_DEFINITION); - verify(callback).trigger(any(LimitDefinition.class), any(Object.class)); + verify(callback).trigger(any(LimitDefinition.class), isNull()); } @Test @@ -53,7 +53,7 @@ public void testCallbackTriggeredWhenBucketChange() { abstractLimitTrigger.callbackIfRequired(null, 1, now, 1, LIMIT_DEFINITION); abstractLimitTrigger.callbackIfRequired(null, 1, now.plusSeconds(70), 1, LIMIT_DEFINITION); - verify(callback, times(2)).trigger(any(LimitDefinition.class), any(Object.class)); + verify(callback, times(2)).trigger(any(LimitDefinition.class), isNull()); } private Instant givenABucketStartingInstant() { diff --git a/src/test/java/com/coveo/spillway/trigger/PercentageThresholdTriggerTest.java b/src/test/java/com/coveo/spillway/trigger/PercentageThresholdTriggerTest.java index 17272a6..d6693f0 100644 --- a/src/test/java/com/coveo/spillway/trigger/PercentageThresholdTriggerTest.java +++ b/src/test/java/com/coveo/spillway/trigger/PercentageThresholdTriggerTest.java @@ -22,39 +22,39 @@ */ package com.coveo.spillway.trigger; -import org.junit.Before; -import org.junit.Test; - import com.coveo.spillway.limit.LimitDefinition; -import com.coveo.spillway.trigger.LimitTriggerCallback; -import com.coveo.spillway.trigger.PercentageThresholdTrigger; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.time.Duration; import static com.google.common.truth.Truth.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.mock; public class PercentageThresholdTriggerTest { private LimitTriggerCallback callback; - private LimitDefinition limitDef = new LimitDefinition("testLimit", 100, Duration.ofDays(1)); + private final LimitDefinition limitDef = + new LimitDefinition("testLimit", 100, Duration.ofDays(1)); private PercentageThresholdTrigger trigger; - @Before + @BeforeEach public void setup() { callback = mock(LimitTriggerCallback.class); // Will trigger at 50% of the limit trigger = new PercentageThresholdTrigger(0.5, callback); } - @Test(expected = IllegalArgumentException.class) + @Test public void negativeThresholdThrows() { - new PercentageThresholdTrigger(-1, callback); + assertThrows( + IllegalArgumentException.class, () -> new PercentageThresholdTrigger(-1, callback)); } - @Test(expected = IllegalArgumentException.class) + @Test public void largerThanOneThresholdThrows() { - new PercentageThresholdTrigger(2, callback); + assertThrows(IllegalArgumentException.class, () -> new PercentageThresholdTrigger(2, callback)); } @Test diff --git a/src/test/java/com/coveo/spillway/trigger/ValueThresholdTriggerTest.java b/src/test/java/com/coveo/spillway/trigger/ValueThresholdTriggerTest.java index 1c5731e..3ad51dd 100644 --- a/src/test/java/com/coveo/spillway/trigger/ValueThresholdTriggerTest.java +++ b/src/test/java/com/coveo/spillway/trigger/ValueThresholdTriggerTest.java @@ -22,12 +22,9 @@ */ package com.coveo.spillway.trigger; -import org.junit.Before; -import org.junit.Test; - import com.coveo.spillway.limit.LimitDefinition; -import com.coveo.spillway.trigger.LimitTriggerCallback; -import com.coveo.spillway.trigger.ValueThresholdTrigger; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.time.Duration; @@ -35,13 +32,13 @@ import static org.mockito.Mockito.mock; public class ValueThresholdTriggerTest { - private LimitTriggerCallback callback; - private LimitDefinition limitDef = new LimitDefinition("testLimit", 100, Duration.ofDays(1)); + private final LimitDefinition limitDef = + new LimitDefinition("testLimit", 100, Duration.ofDays(1)); private ValueThresholdTrigger trigger; - @Before + @BeforeEach public void setup() { - callback = mock(LimitTriggerCallback.class); + LimitTriggerCallback callback = mock(LimitTriggerCallback.class); // Will trigger at 50% of the limit trigger = new ValueThresholdTrigger(50, callback); }