diff --git a/.github/workflows/analysis.yml b/.github/workflows/analysis.yml index ef301327d7..d5fff4c78f 100644 --- a/.github/workflows/analysis.yml +++ b/.github/workflows/analysis.yml @@ -2,7 +2,7 @@ name: analysis on: [ push, pull_request ] env: - ORG_GRADLE_PROJECT_checksumFailOn: build_finish + ORG_GRADLE_PROJECT_checksumFailOn: never ORG_GRADLE_PROJECT_checksumIgnore: false ORG_GRADLE_PROJECT_checksumPrint: true diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 561e117e56..8aad2687df 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,7 +2,7 @@ name: build on: [ push, pull_request ] env: - ORG_GRADLE_PROJECT_checksumFailOn: build_finish + ORG_GRADLE_PROJECT_checksumFailOn: never ORG_GRADLE_PROJECT_checksumIgnore: false ORG_GRADLE_PROJECT_checksumPrint: true MIN_JVM: 11 diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 4303c5d5a4..487e70b5e0 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -2,7 +2,7 @@ name: examples on: [ push, pull_request ] env: - ORG_GRADLE_PROJECT_checksumFailOn: build_finish + ORG_GRADLE_PROJECT_checksumFailOn: never ORG_GRADLE_PROJECT_checksumIgnore: false ORG_GRADLE_PROJECT_checksumPrint: true diff --git a/.github/workflows/lincheck.yml b/.github/workflows/lincheck.yml index 80ced625f2..abd3f025d2 100644 --- a/.github/workflows/lincheck.yml +++ b/.github/workflows/lincheck.yml @@ -2,7 +2,7 @@ name: lincheck on: [ push, pull_request ] env: - ORG_GRADLE_PROJECT_checksumFailOn: build_finish + ORG_GRADLE_PROJECT_checksumFailOn: never ORG_GRADLE_PROJECT_checksumIgnore: false ORG_GRADLE_PROJECT_checksumPrint: true JAVA_VERSION: 17 diff --git a/.github/workflows/qodana.yml b/.github/workflows/qodana.yml index 333e336fc3..5e5d7599e6 100644 --- a/.github/workflows/qodana.yml +++ b/.github/workflows/qodana.yml @@ -2,7 +2,7 @@ name: Qodana on: [ push, pull_request ] env: - ORG_GRADLE_PROJECT_checksumFailOn: build_finish + ORG_GRADLE_PROJECT_checksumFailOn: never ORG_GRADLE_PROJECT_checksumIgnore: false ORG_GRADLE_PROJECT_checksumPrint: true JAVA_VERSION: 11 diff --git a/build.gradle b/build.gradle index 057b5152d5..7d036d1b87 100644 --- a/build.gradle +++ b/build.gradle @@ -67,10 +67,10 @@ subprojects { dependencies { testImplementation libraries.guava - testImplementation libraries.slf4jNop testImplementation testLibraries.truth testImplementation testLibraries.mockito testImplementation testLibraries.hamcrest + testImplementation testLibraries.slf4jTest testImplementation testLibraries.awaitility testImplementation testLibraries.osgiCompile diff --git a/caffeine/src/main/java/com/github/benmanes/caffeine/cache/BoundedLocalCache.java b/caffeine/src/main/java/com/github/benmanes/caffeine/cache/BoundedLocalCache.java index 1de415d344..7bd4fb8441 100644 --- a/caffeine/src/main/java/com/github/benmanes/caffeine/cache/BoundedLocalCache.java +++ b/caffeine/src/main/java/com/github/benmanes/caffeine/cache/BoundedLocalCache.java @@ -52,6 +52,7 @@ import java.util.OptionalLong; import java.util.Set; import java.util.Spliterator; +import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -60,6 +61,7 @@ import java.util.concurrent.ForkJoinTask; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.concurrent.locks.ReentrantLock; import java.util.function.BiFunction; import java.util.function.Consumer; @@ -1290,7 +1292,9 @@ void refreshIfNeeded(Node node, long now) { refreshFuture[0].whenComplete((newValue, error) -> { long loadTime = statsTicker().read() - startTime[0]; if (error != null) { - logger.log(Level.WARNING, "Exception thrown during refresh", error); + if (!(error instanceof CancellationException) && !(error instanceof TimeoutException)) { + logger.log(Level.WARNING, "Exception thrown during refresh", error); + } refreshes().remove(keyReference, refreshFuture[0]); statsCounter().recordLoadFailure(loadTime); return; diff --git a/caffeine/src/main/java/com/github/benmanes/caffeine/cache/LocalAsyncCache.java b/caffeine/src/main/java/com/github/benmanes/caffeine/cache/LocalAsyncCache.java index 33926167ca..ccd8ea1d56 100644 --- a/caffeine/src/main/java/com/github/benmanes/caffeine/cache/LocalAsyncCache.java +++ b/caffeine/src/main/java/com/github/benmanes/caffeine/cache/LocalAsyncCache.java @@ -31,11 +31,13 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; +import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.BiConsumer; import java.util.function.BiFunction; @@ -197,7 +199,8 @@ default void handleCompletion(K key, CompletableFuture valueFuture, } long loadTime = cache().statsTicker().read() - startTime; if (value == null) { - if (error != null) { + if ((error != null) && !(error instanceof CancellationException) + && !(error instanceof TimeoutException)) { logger.log(Level.WARNING, "Exception thrown during asynchronous load", error); } cache().remove(key, valueFuture); @@ -240,10 +243,12 @@ public void accept(@Nullable Map result, @Nullable Thr } for (var entry : proxies.entrySet()) { cache.remove(entry.getKey(), entry.getValue()); - entry.getValue().obtrudeException(error); + entry.getValue().completeExceptionally(error); } cache.statsCounter().recordLoadFailure(loadTime); - logger.log(Level.WARNING, "Exception thrown during asynchronous load", error); + if (!(error instanceof CancellationException) && !(error instanceof TimeoutException)) { + logger.log(Level.WARNING, "Exception thrown during asynchronous load", error); + } } else { fillProxies(result); addNewEntries(result); @@ -255,7 +260,7 @@ public void accept(@Nullable Map result, @Nullable Thr private void fillProxies(Map result) { proxies.forEach((key, future) -> { V value = result.get(key); - future.obtrudeValue(value); + future.complete(value); if (value == null) { cache.remove(key, future); } else { diff --git a/caffeine/src/main/java/com/github/benmanes/caffeine/cache/LocalAsyncLoadingCache.java b/caffeine/src/main/java/com/github/benmanes/caffeine/cache/LocalAsyncLoadingCache.java index 8792c6485c..e5276b0d0f 100644 --- a/caffeine/src/main/java/com/github/benmanes/caffeine/cache/LocalAsyncLoadingCache.java +++ b/caffeine/src/main/java/com/github/benmanes/caffeine/cache/LocalAsyncLoadingCache.java @@ -24,9 +24,11 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; +import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.Executor; +import java.util.concurrent.TimeoutException; import java.util.function.BiFunction; import java.util.function.Function; @@ -281,7 +283,9 @@ public CompletableFuture> refreshAll(Iterable keys) { asyncCache.cache().refreshes().remove(keyReference, castedFuture); long loadTime = asyncCache.cache().statsTicker().read() - startTime[0]; if (error != null) { - logger.log(Level.WARNING, "Exception thrown during refresh", error); + if (!(error instanceof CancellationException) && !(error instanceof TimeoutException)) { + logger.log(Level.WARNING, "Exception thrown during refresh", error); + } asyncCache.cache().statsCounter().recordLoadFailure(loadTime); return; } diff --git a/caffeine/src/main/java/com/github/benmanes/caffeine/cache/LocalLoadingCache.java b/caffeine/src/main/java/com/github/benmanes/caffeine/cache/LocalLoadingCache.java index bdd9e6f2fc..ec63de7327 100644 --- a/caffeine/src/main/java/com/github/benmanes/caffeine/cache/LocalLoadingCache.java +++ b/caffeine/src/main/java/com/github/benmanes/caffeine/cache/LocalLoadingCache.java @@ -25,8 +25,10 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; +import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; +import java.util.concurrent.TimeoutException; import java.util.function.Function; import org.checkerframework.checker.nullness.qual.Nullable; @@ -131,7 +133,9 @@ default CompletableFuture refresh(K key) { boolean removed = cache().refreshes().remove(keyReference, reloading[0]); long loadTime = cache().statsTicker().read() - startTime[0]; if (error != null) { - logger.log(Level.WARNING, "Exception thrown during refresh", error); + if (!(error instanceof CancellationException) && !(error instanceof TimeoutException)) { + logger.log(Level.WARNING, "Exception thrown during refresh", error); + } cache().statsCounter().recordLoadFailure(loadTime); return; } diff --git a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/AsyncTest.java b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/AsyncTest.java index 3018e3cf62..d4edbe276c 100644 --- a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/AsyncTest.java +++ b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/AsyncTest.java @@ -85,7 +85,7 @@ public void getWhenSuccessful_success_async() { result.set(Async.getWhenSuccessful(future)); }); await().untilAtomic(result, is(1)); - future.obtrudeValue(2); + future.complete(2); await().untilAtomic(result, is(2)); } diff --git a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/LoadingCacheTest.java b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/LoadingCacheTest.java index bfc8fbcfd3..734cf5530c 100644 --- a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/LoadingCacheTest.java +++ b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/LoadingCacheTest.java @@ -29,6 +29,8 @@ import static com.google.common.truth.Truth.assertThat; import static java.util.function.Function.identity; import static java.util.stream.Collectors.toMap; +import static uk.org.lidalia.slf4jext.ConventionalLevelHierarchy.INFO_LEVELS; +import static uk.org.lidalia.slf4jext.Level.WARN; import java.util.ArrayList; import java.util.Collections; @@ -36,7 +38,9 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; +import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -56,6 +60,7 @@ import com.github.benmanes.caffeine.cache.testing.CacheSpec.Population; import com.github.benmanes.caffeine.cache.testing.CacheValidationListener; import com.github.benmanes.caffeine.testing.Int; +import com.github.valfirst.slf4jtest.TestLoggerFactory; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.primitives.Ints; @@ -658,6 +663,70 @@ public void refresh_evicted(CacheContext context) { assertThat(context).stats().success(1).failures(0); } + @Test(dataProvider = "caches") + @CacheSpec(implementation = Implementation.Caffeine, population = Population.EMPTY) + public void refresh_cancel_noLog(CacheContext context) { + var cacheLoader = new CacheLoader() { + @Override public Int load(Int key) { + throw new AssertionError(); + } + @Override public CompletableFuture asyncLoad(Int key, Executor executor) { + var future = new CompletableFuture(); + future.cancel(false); + return future; + } + }; + LoadingCache cache = context.isAsync() + ? context.buildAsync(cacheLoader).synchronous() + : context.build(cacheLoader); + TestLoggerFactory.getAllTestLoggers().values().stream() + .forEach(logger -> logger.setEnabledLevels(INFO_LEVELS)); + + cache.refresh(context.absentKey()); + assertThat(TestLoggerFactory.getLoggingEvents()).isEmpty(); + } + + @Test(dataProvider = "caches") + @CacheSpec(implementation = Implementation.Caffeine, population = Population.EMPTY) + public void refresh_timeout_noLog(CacheContext context) { + var cacheLoader = new CacheLoader() { + @Override public Int load(Int key) { + throw new AssertionError(); + } + @Override public CompletableFuture asyncLoad(Int key, Executor executor) { + var future = new CompletableFuture(); + future.orTimeout(0, TimeUnit.SECONDS); + await().until(() -> future.isDone()); + return future; + } + }; + LoadingCache cache = context.isAsync() + ? context.buildAsync(cacheLoader).synchronous() + : context.build(cacheLoader); + TestLoggerFactory.getAllTestLoggers().values().stream() + .forEach(logger -> logger.setEnabledLevels(INFO_LEVELS)); + + cache.refresh(context.absentKey()); + assertThat(TestLoggerFactory.getLoggingEvents()).isEmpty(); + } + + @Test(dataProvider = "caches") + @CacheSpec(implementation = Implementation.Caffeine, population = Population.EMPTY) + public void refresh_error_log(CacheContext context) throws Exception { + var expected = new RuntimeException(); + CacheLoader cacheLoader = key -> { throw expected; }; + LoadingCache cache = context.isAsync() + ? context.buildAsync(cacheLoader).synchronous() + : context.build(cacheLoader); + TestLoggerFactory.getAllTestLoggers().values().stream() + .forEach(logger -> logger.setEnabledLevels(INFO_LEVELS)); + + cache.refresh(context.absentKey()); + var event = Iterables.getOnlyElement(TestLoggerFactory.getLoggingEvents()); + assertThat(event.getThrowable().orElseThrow()).hasCauseThat().isSameInstanceAs(expected); + assertThat(event.getLevel()).isEqualTo(WARN); + } + /* --------------- refreshAll --------------- */ @CacheSpec(removalListener = { Listener.DEFAULT, Listener.REJECTING }) diff --git a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/RefreshAfterWriteTest.java b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/RefreshAfterWriteTest.java index 7bc718c891..3de9f1e8d1 100644 --- a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/RefreshAfterWriteTest.java +++ b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/RefreshAfterWriteTest.java @@ -30,6 +30,8 @@ import static com.google.common.truth.Truth8.assertThat; import static java.util.Map.entry; import static org.hamcrest.Matchers.is; +import static uk.org.lidalia.slf4jext.ConventionalLevelHierarchy.INFO_LEVELS; +import static uk.org.lidalia.slf4jext.Level.WARN; import java.time.Duration; import java.util.List; @@ -59,6 +61,8 @@ import com.github.benmanes.caffeine.cache.testing.TrackingExecutor; import com.github.benmanes.caffeine.testing.ConcurrentTestHarness; import com.github.benmanes.caffeine.testing.Int; +import com.github.valfirst.slf4jtest.TestLoggerFactory; +import com.google.common.collect.Iterables; /** * The test cases for caches that support the refresh after write policy. @@ -246,6 +250,81 @@ public void refreshIfNeeded_absent_nullValue(LoadingCache cache, Cache assertThat(cache).doesNotContainKey(context.firstKey()); } + @Test(dataProvider = "caches") + @CacheSpec(implementation = Implementation.Caffeine, + population = Population.EMPTY, refreshAfterWrite = Expire.ONE_MINUTE) + public void refreshIfNeeded_cancel_noLog(CacheContext context) { + var cacheLoader = new CacheLoader() { + @Override public Int load(Int key) { + throw new AssertionError(); + } + @Override public CompletableFuture asyncReload( + Int key, Int oldValue, Executor executor) { + var future = new CompletableFuture(); + future.cancel(false); + return future; + } + }; + LoadingCache cache = context.isAsync() + ? context.buildAsync(cacheLoader).synchronous() + : context.build(cacheLoader); + cache.put(context.absentKey(), context.absentValue()); + TestLoggerFactory.getAllTestLoggers().values().stream() + .forEach(logger -> logger.setEnabledLevels(INFO_LEVELS)); + context.ticker().advance(2, TimeUnit.MINUTES); + + cache.get(context.absentKey()); + assertThat(TestLoggerFactory.getLoggingEvents()).isEmpty(); + } + + @Test(dataProvider = "caches") + @CacheSpec(implementation = Implementation.Caffeine, + population = Population.EMPTY, refreshAfterWrite = Expire.ONE_MINUTE) + public void refreshIfNeeded_timeout_noLog(CacheContext context) { + var cacheLoader = new CacheLoader() { + @Override public Int load(Int key) { + throw new AssertionError(); + } + @Override public CompletableFuture asyncReload( + Int key, Int oldValue, Executor executor) { + var future = new CompletableFuture(); + future.orTimeout(0, TimeUnit.SECONDS); + await().until(() -> future.isDone()); + return future; + } + }; + LoadingCache cache = context.isAsync() + ? context.buildAsync(cacheLoader).synchronous() + : context.build(cacheLoader); + cache.put(context.absentKey(), context.absentValue()); + TestLoggerFactory.getAllTestLoggers().values().stream() + .forEach(logger -> logger.setEnabledLevels(INFO_LEVELS)); + context.ticker().advance(2, TimeUnit.MINUTES); + + cache.get(context.absentKey()); + assertThat(TestLoggerFactory.getLoggingEvents()).isEmpty(); + } + + @Test(dataProvider = "caches") + @CacheSpec(implementation = Implementation.Caffeine, + population = Population.EMPTY, refreshAfterWrite = Expire.ONE_MINUTE) + public void refreshIfNeeded_error_log(CacheContext context) { + var expected = new RuntimeException(); + CacheLoader cacheLoader = key -> { throw expected; }; + LoadingCache cache = context.isAsync() + ? context.buildAsync(cacheLoader).synchronous() + : context.build(cacheLoader); + cache.put(context.absentKey(), context.absentValue()); + TestLoggerFactory.getAllTestLoggers().values().stream() + .forEach(logger -> logger.setEnabledLevels(INFO_LEVELS)); + context.ticker().advance(2, TimeUnit.MINUTES); + + cache.get(context.absentKey()); + var event = Iterables.getOnlyElement(TestLoggerFactory.getLoggingEvents()); + assertThat(event.getThrowable().orElseThrow()).hasCauseThat().isSameInstanceAs(expected); + assertThat(event.getLevel()).isEqualTo(WARN); + } + /* --------------- getIfPresent --------------- */ @Test(dataProvider = "caches") diff --git a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/testing/CacheValidationListener.java b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/testing/CacheValidationListener.java index 2d1642df78..0d95edd72e 100644 --- a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/testing/CacheValidationListener.java +++ b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/testing/CacheValidationListener.java @@ -24,6 +24,7 @@ import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static org.testng.ITestResult.FAILURE; +import static uk.org.lidalia.slf4jext.ConventionalLevelHierarchy.OFF_LEVELS; import java.util.Arrays; import java.util.Collection; @@ -58,6 +59,7 @@ import com.github.benmanes.caffeine.cache.testing.CacheSpec.CacheExpiry; import com.github.benmanes.caffeine.cache.testing.CacheSpec.CacheScheduler; import com.github.benmanes.caffeine.cache.testing.CacheSpec.ExecutorFailure; +import com.github.valfirst.slf4jtest.TestLoggerFactory; /** * A listener that validates the internal structure after a successful test execution. @@ -81,10 +83,15 @@ public void onStart(ISuite suite) { resultQueues.add(invokedMethods.get()); } } + disableLoggers(); } @Override public void beforeInvocation(IInvokedMethod method, ITestResult testResult) { + TestLoggerFactory.getAllTestLoggers().values().stream() + .forEach(logger -> logger.setEnabledLevels(OFF_LEVELS)); + TestLoggerFactory.clear(); + if (beforeCleanup.get() || !beforeCleanup.compareAndSet(false, true)) { return; } @@ -227,6 +234,7 @@ private static void checkNoStats(ITestResult testResult, CacheContext context) { /** Free memory by clearing unused resources after test execution. */ private void cleanUp(ITestResult testResult) { resultQueues.forEach(Collection::clear); + TestLoggerFactory.clear(); resetMocks(testResult); resetCache(testResult); @@ -295,4 +303,16 @@ private void stringifyParams(ITestResult testResult, boolean briefParams) { } } } + + private void disableLoggers() { + String packageName = Caffeine.class.getPackageName(); + String[] classes = {"Caffeine", "LocalCache", "LocalManualCache", "LocalLoadingCache", + "LocalAsyncCache", "BoundedLocalCache", "UnboundedLocalCache", + "ExecutorServiceScheduler", "GuardedScheduler"}; + for (var className : classes) { + System.getLogger(packageName + "." + className); + } + TestLoggerFactory.getAllTestLoggers().values().stream() + .forEach(logger -> logger.setEnabledLevelsForAllThreads(OFF_LEVELS)); + } } diff --git a/checksum.xml b/checksum.xml index 4cbf26590b..3da94a3c18 100644 --- a/checksum.xml +++ b/checksum.xml @@ -37,6 +37,7 @@ + @@ -257,6 +258,7 @@ + @@ -273,6 +275,9 @@ B683854D72E20AB8BE7AEBB41212A559D1B984560675D38423A6603C2F0B71578502431B0BBF7F94EB8833E66017B7237B0966DCF7165349B05A6385C595DA7B + + 46B0259FEC934F044B0B2120F5C63EF57F3A98CC227E46F2651B700DA936475FFA3546EB0DECB35B40D2EBA1DFF67A53E977F412F54C9A49DD18AE17E6F28051 + 4C5619A1191B8450FCC10AFD613F38B286B95EA28C4F20150AE388569ED7BDC6D963C042233A5FD45A8933DF86CD4DDCABDFFBD855181578289D1E0A5CD3E981 diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index 7cbc3760e0..f4b92ee820 100644 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -44,7 +44,7 @@ ext { fastutil: '8.5.6', flipTables: '1.1.0', googleJavaFormat: '1.11.0', - guava: '31.0-jre', + guava: '31.0.1-jre', jackrabbit: '1.40.0', jamm: '0.3.3', javaObjectLayout: '0.16', @@ -75,6 +75,7 @@ ext { lincheck: '2.14.1', mockito: '3.12.4', paxExam: '4.13.4', + slf4jTest: '2.4.0', testng: '7.4.0', truth: '1.1.3', felix: '7.0.1', @@ -177,6 +178,10 @@ ext { "org.ops4j.pax.exam:pax-exam-link-mvn:${testVersions.paxExam}", "org.ops4j.pax.url:pax-url-aether:2.6.7", ], + slf4jTest: [ + "com.github.valfirst:slf4j-test:${testVersions.slf4jTest}", + "org.slf4j:slf4j-jdk-platform-logging:${versions.slf4j}", + ], testng: [ "org.testng:testng:${testVersions.testng}", "com.google.inject:guice:${testVersions.guice}", diff --git a/gradle/jmh.gradle b/gradle/jmh.gradle index b751d68b4f..407c7d4942 100644 --- a/gradle/jmh.gradle +++ b/gradle/jmh.gradle @@ -13,6 +13,12 @@ eclipse.classpath.file.whenMerged { entries.find { it.path == 'src/jmh/java' }.entryAttributes['test'] = 'true' } +configurations { + jmh { + exclude module: 'slf4j-test' + } +} + dependencies { afterEvaluate { jmh configurations.testImplementation.allDependencies