You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by di...@apache.org on 2021/11/12 10:33:54 UTC
[sling-org-apache-sling-i18n] branch master updated: SLING-10912:
fix flaky ConcurrentJcrResourceBundleLoadingTest (#8)
This is an automated email from the ASF dual-hosted git repository.
diru pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-i18n.git
The following commit(s) were added to refs/heads/master by this push:
new c61f0e8 SLING-10912: fix flaky ConcurrentJcrResourceBundleLoadingTest (#8)
c61f0e8 is described below
commit c61f0e8d85da4bf85b42212e88862db28b17bb05
Author: Dirk Rudolph <di...@gmail.com>
AuthorDate: Fri Nov 12 11:32:05 2021 +0100
SLING-10912: fix flaky ConcurrentJcrResourceBundleLoadingTest (#8)
---
.../ConcurrentJcrResourceBundleLoadingTest.java | 65 ++++++++++++----------
1 file changed, 37 insertions(+), 28 deletions(-)
diff --git a/src/test/java/org/apache/sling/i18n/impl/ConcurrentJcrResourceBundleLoadingTest.java b/src/test/java/org/apache/sling/i18n/impl/ConcurrentJcrResourceBundleLoadingTest.java
index d0d5249..a8784af 100644
--- a/src/test/java/org/apache/sling/i18n/impl/ConcurrentJcrResourceBundleLoadingTest.java
+++ b/src/test/java/org/apache/sling/i18n/impl/ConcurrentJcrResourceBundleLoadingTest.java
@@ -19,7 +19,7 @@
package org.apache.sling.i18n.impl;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
import static org.mockito.AdditionalMatchers.or;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -36,10 +36,11 @@ import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Locale;
import java.util.ResourceBundle;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.i18n.impl.JcrResourceBundleProvider.Key;
@@ -50,8 +51,6 @@ import org.junit.runners.Parameterized;
import org.mockito.ArgumentMatchers;
import org.mockito.Mock;
import org.mockito.Mockito;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
import org.mockito.verification.VerificationMode;
import org.osgi.framework.BundleContext;
import org.powermock.api.mockito.PowerMockito;
@@ -104,7 +103,7 @@ public class ConcurrentJcrResourceBundleLoadingTest {
public long invalidation_delay() {
return 5000;
}
-
+
@Override
public String[] excluded_paths() {
return new String[] {"/var/eventing"};
@@ -194,39 +193,49 @@ public class ConcurrentJcrResourceBundleLoadingTest {
public void newBundleReplacesOldBundleAfterReload() throws Exception {
final ResourceBundle oldBundle = provider.getResourceBundle(Locale.ENGLISH);
final ResourceBundle newBundle = mock(JcrResourceBundle.class);
- final AtomicBoolean newBundleReady = new AtomicBoolean(false);
+ final CountDownLatch newBundleReturned = new CountDownLatch(1);
- doAnswer(new Answer<ResourceBundle>() {
- @Override public ResourceBundle answer(InvocationOnMock invocationOnMock) throws Throwable {
- Thread.sleep(1000);
- newBundleReady.set(true);
- return newBundle;
- }
+ doAnswer(invocationOnMock -> {
+ Thread.sleep(1000);
+ return newBundle;
}).when(provider, "createResourceBundle", or(ArgumentMatchers.isNull(), any(ResourceResolver.class)), eq(null), eq(Locale.ENGLISH));
- Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
- @Override
- public void run() {
- ResourceBundle expected = newBundleReady.get() ? newBundle : oldBundle;
- assertSame(expected, provider.getResourceBundle(Locale.ENGLISH));
- }
- }, 0, 200, TimeUnit.MILLISECONDS);
+ ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
+ executorService.scheduleAtFixedRate(
+ () -> {
+ ResourceBundle currentBundle = provider.getResourceBundle(Locale.ENGLISH);
+ if (currentBundle == newBundle) {
+ // Shutdown the executor once we got the new ResourceBundle. This will cancel the future and opens the gate below.
+ // Do not assert the returned bundle directly here, as this may become flaky when the bundle returned by the
+ // mock above was returned but not yet put into the cache.
+ executorService.shutdownNow();
+ newBundleReturned.countDown();
+ }
+ },
+ // start with an initial delay to not call getResourceBundle again before we call reloadBundle below
+ 200,
+ 200,
+ TimeUnit.MILLISECONDS);
provider.reloadBundle(new Key(null, Locale.ENGLISH));
+ // wait until the scheduled future gets canceled by shutting down the executor service
+ // this means the new bundle got returned and is in the cache
+ if (!newBundleReturned.await(5000, TimeUnit.MILLISECONDS)) {
+ fail("expected cancellation");
+ }
+ // CancellationException expected
+
// we expect getResourceBundleInternal() called once in the beginning of the test and once again after reloading the bundle.
final int expectedGetResourceBundleInternal = 2;
- VerificationMode verificationMode;
-
- if (preload) {
+ VerificationMode verificationMode = preload
// when preloading the calls to getResourceBundleInternal are non-blocking and so more calls will happen while reloading.
// assuming at least one more
- verificationMode = atLeast(expectedGetResourceBundleInternal + 1);
- } else {
- verificationMode = times(expectedGetResourceBundleInternal);
- }
+ ? atLeast(expectedGetResourceBundleInternal + 1)
+ : times(expectedGetResourceBundleInternal);
+
+ verifyPrivate(provider, verificationMode).invoke("getResourceBundleInternal",
+ or(ArgumentMatchers.isNull(), any(ResourceResolver.class)), eq(null), eq(Locale.ENGLISH), anyBoolean());
- verifyPrivate(provider, verificationMode)
- .invoke("getResourceBundleInternal", or(ArgumentMatchers.isNull(), any(ResourceResolver.class)), eq(null), eq(Locale.ENGLISH), anyBoolean());
}
}
\ No newline at end of file