This is an automated email from the ASF dual-hosted git repository. reschke pushed a commit to branch SLING-12900 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-resourceresolver.git
commit 3b01927fd8b8771c1b3c6ba4d4e6d98f02cf5a22 Author: Julian Reschke <[email protected]> AuthorDate: Thu Aug 21 13:04:08 2025 +0100 SLING-12900: improve test coverage for VP bg init vs events, minor refactoring --- .../resourceresolver/impl/mapping/MapEntries.java | 27 ++++++++------- .../impl/mapping/VanityPathMapEntriesTest.java | 40 ++++++++++++++++++++++ 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntries.java b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntries.java index c8e47673..e0fd3a38 100644 --- a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntries.java +++ b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntries.java @@ -35,6 +35,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; +import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import java.util.TreeSet; @@ -426,8 +427,11 @@ public class MapEntries implements MapEntriesHandler, ResourceChangeListener, Ex // ---------- ResourceChangeListener interface + private final Set<ResourceChange.ChangeType> RELEVANT_CHANGE_TYPES = Set.of( + ResourceChange.ChangeType.ADDED, ResourceChange.ChangeType.CHANGED, ResourceChange.ChangeType.REMOVED); + /** - * Handles the change to any of the node properties relevant for vanity URL + * Handles the change to any of the node properties relevant for vanity paths * mappings. The {@link #MapEntries(MapConfigurationProvider, BundleContext, EventAdmin, StringInterpolationProvider, Optional)} * constructor makes sure the event listener is registered to only get * appropriate events. @@ -450,28 +454,27 @@ public class MapEntries implements MapEntriesHandler, ResourceChangeListener, Ex final ResourceChange.ChangeType type = rc.getType(); final String path = rc.getPath(); - log.debug("onChange, type={}, path={}", rc.getType(), path); + log.debug("onChange, type={}, path={}", type, path); // don't care for system area if (path.startsWith(JCR_SYSTEM_PREFIX)) { continue; } - // during startup: just enqueue the events - if (inStartup) { - if (type == ResourceChange.ChangeType.REMOVED - || type == ResourceChange.ChangeType.ADDED - || type == ResourceChange.ChangeType.CHANGED) { + boolean queued = false; + + if (RELEVANT_CHANGE_TYPES.contains(type)) { + // during startup: just enqueue the events + if (inStartup) { Map.Entry<String, ResourceChange.ChangeType> entry = new SimpleEntry<>(path, type); log.trace("enqueue: {}", entry); resourceChangeQueue.add(entry); + queued = true; } - } else { - boolean changed = handleResourceChange(type, path, resolverRefreshed, hasReloadedConfig); + } - if (changed) { - sendEvent = true; - } + if (!queued) { + sendEvent |= handleResourceChange(type, path, resolverRefreshed, hasReloadedConfig); } } diff --git a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/VanityPathMapEntriesTest.java b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/VanityPathMapEntriesTest.java index d8a97a73..d5b04a90 100644 --- a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/VanityPathMapEntriesTest.java +++ b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/VanityPathMapEntriesTest.java @@ -32,6 +32,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; @@ -52,6 +53,7 @@ import org.apache.sling.api.wrappers.ValueMapDecorator; import org.apache.sling.resourceresolver.impl.ResourceResolverMetrics; import org.apache.sling.resourceresolver.impl.mapping.MapConfigurationProvider.VanityPathConfig; import org.junit.After; +import org.junit.Assume; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -1273,6 +1275,44 @@ public class VanityPathMapEntriesTest extends AbstractMappingMapEntriesTest { assertTrue(finalVanityMap.get("/eventTest").contains("/baa")); } + @Test + public void test_remove_vanity_path_during_bg_init() { + Assume.assumeTrue( + "simulation of resource removal during bg init only meaningful in 'bg init' case", + resourceResolverFactory.isVanityPathCacheInitInBackground()); + + Resource root = createMockedResource("/"); + Resource foo = createMockedResource(root, "foo"); + Resource leaf = createMockedResource(foo, "leaf"); + + when(leaf.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/bar")); + + CountDownLatch greenLight = new CountDownLatch(1); + + when(resourceResolver.findResources(anyString(), eq("JCR-SQL2"))) + .thenAnswer((Answer<Iterator<Resource>>) invocation -> { + greenLight.await(); + return Set.of(leaf).iterator(); + }); + + VanityPathHandler vph = mapEntries.vph; + vph.initializeVanityPaths(); + assertFalse(vph.isReady()); + + // bg init will wait until we give green light + mapEntries.onChange(List.of(new ResourceChange(ResourceChange.ChangeType.REMOVED, leaf.getPath(), false))); + + greenLight.countDown(); + waitForBgInit(); + + assertTrue(vph.isReady()); + + Map<String, List<String>> vanityPathMappings = mapEntries.getVanityPathMappings(); + List<String> mappings = vanityPathMappings.get("/foo/leaf"); + + assertNull("expected no (null) mapping for /foo/leaf", mappings); + } + // checks for the expected list of queries and the cache statistics private void checkCounters( String testName,
