SLING-11776 - Sling ResourceMerger may cause high cpu utilization - Add test cases
diff --git a/pom.xml b/pom.xml
index b650054..7bd269a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -137,5 +137,11 @@
             <artifactId>slf4j-simple</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <version>4.6.1</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>
diff --git a/src/test/java/org/apache/sling/resourcemerger/impl/MergingResourceProviderTest.java b/src/test/java/org/apache/sling/resourcemerger/impl/MergingResourceProviderTest.java
new file mode 100644
index 0000000..29325bf
--- /dev/null
+++ b/src/test/java/org/apache/sling/resourcemerger/impl/MergingResourceProviderTest.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.resourcemerger.impl;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.resourcemerger.spi.MergedResourcePicker2;
+import org.apache.sling.spi.resource.provider.ResolveContext;
+import org.apache.sling.spi.resource.provider.ResourceContext;
+import org.apache.sling.testing.resourceresolver.MockResource;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+public class MergingResourceProviderTest {
+
+    private MergingResourceProvider mergingResourceProvider;
+
+    private MergedResourcePicker2 picker;
+    @Mock
+    private ResolveContext<Void> resolveContext;
+    @Mock
+    private ResourceContext resourceContext;
+    @Mock
+    private ResourceResolver resourceResolver;
+    private MockResource resource;
+
+    private static final String MERGE_ROOT = "/mnt/override";
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        picker = new MockPicker();
+
+        Mockito.when(resolveContext.getResourceResolver()).thenReturn(resourceResolver);
+
+        // Act like a resource provider is registered at MergingResourceProviderTest.MERGE_ROOT
+        Mockito.when(resourceResolver.getResource(Mockito.startsWith(MergingResourceProviderTest.MERGE_ROOT)))
+                .thenAnswer(new Answer() {
+                    public Object answer(InvocationOnMock invocation) {
+                        Object[] args = invocation.getArguments();
+                        return mergingResourceProvider.getResource(resolveContext, args[0].toString(), resourceContext, null);
+                    }
+                });
+
+        resource = new MockResource("/apps", null, resourceResolver);
+        Mockito.when(resourceResolver.getResource("/apps"))
+                .thenReturn(resource);
+
+        mergingResourceProvider = new MergingResourceProvider(MergingResourceProviderTest.MERGE_ROOT,
+                picker,false, true);
+    }
+
+    @Test
+    public void testGetResource() {
+        String path = MergingResourceProviderTest.MERGE_ROOT + "/apps";
+
+        Resource rsc = mergingResourceProvider.getResource(resolveContext, path, resourceContext, null);
+        Mockito.verify(resourceResolver, Mockito.times(1)).getResource("/apps");
+        assertTrue(rsc instanceof MergedResource);
+        assertTrue(rsc.getPath().equals(path));
+    }
+
+    @Test
+    public void testGetResourceWithMultipleMergedRoots() {
+        String path = MergingResourceProviderTest.MERGE_ROOT + MergingResourceProviderTest.MERGE_ROOT
+                + MergingResourceProviderTest.MERGE_ROOT + MergingResourceProviderTest.MERGE_ROOT
+                + "/apps";
+
+        Resource rsc = mergingResourceProvider.getResource(resolveContext, path, resourceContext, null);
+        Mockito.verify(resourceResolver, Mockito.times(0)).getResource(Mockito.startsWith(MergingResourceProviderTest.MERGE_ROOT));
+        Mockito.verify(resourceResolver, Mockito.times(0)).getResource(Mockito.startsWith("/apps"));
+        assertNull(rsc);
+    }
+
+    class MockPicker implements MergedResourcePicker2 {
+
+        public List<Resource> pickResources(ResourceResolver resolver, String relativePath, Resource relatedResource) {
+
+            String absPath = "/" + relativePath;
+            final List<Resource> resources = new ArrayList<Resource>();
+            final Set<String> roots = new HashSet<String>();
+
+            Resource currentTarget = resolver.getResource(absPath);
+
+            if (currentTarget == null) {
+                currentTarget = new StubResource(resolver, absPath);
+            }
+            resources.add(currentTarget);
+            return resources;
+        }
+    }
+
+}