From 1e52b10d9d6b02b054fed0aef78d76cb6fcb6b71 Mon Sep 17 00:00:00 2001 From: Ben Manes Date: Tue, 28 Sep 2021 15:34:49 -0700 Subject: [PATCH] Suppress log warning if a future is cancelled or times out (fixes #597) Caffeine logs a warning with the exception when an asynchronous load or refresh fails. This is to assist in debugging due to a common mistake of not handling errors, e.g. chaining `thenApply` without an exception handler in a fire-and-forget fashion. It is expected that if this aid is an annoyance that application can simply disable this in their logging configuration. This logging is not helpful when the future fails due to calling the future's cancel() method or using orTimeout(duration). In those cases the cause is expected and desired, so we can assume that the application is handling the failure appropriately. Therefore the logging of these causes should be skipped. --- .github/workflows/analysis.yml | 2 +- .github/workflows/build.yml | 2 +- .github/workflows/examples.yml | 2 +- .github/workflows/lincheck.yml | 2 +- .github/workflows/qodana.yml | 2 +- build.gradle | 2 +- .../caffeine/cache/BoundedLocalCache.java | 6 +- .../caffeine/cache/LocalAsyncCache.java | 13 ++- .../cache/LocalAsyncLoadingCache.java | 6 +- .../caffeine/cache/LocalLoadingCache.java | 6 +- .../benmanes/caffeine/cache/AsyncTest.java | 2 +- .../caffeine/cache/LoadingCacheTest.java | 69 ++++++++++++++++ .../caffeine/cache/RefreshAfterWriteTest.java | 79 +++++++++++++++++++ .../testing/CacheValidationListener.java | 20 +++++ checksum.xml | 5 ++ gradle/dependencies.gradle | 7 +- gradle/jmh.gradle | 6 ++ 17 files changed, 216 insertions(+), 15 deletions(-) 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