This is an automated email from the ASF dual-hosted git repository.

andysch pushed a commit to branch feature/SLING-7768
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-resourceresolver.git

commit 7e03737261186acd3d5b381d44543f249ef4af26
Author: Andreas Schaefer <[email protected]>
AuthorDate: Fri Jul 27 11:55:51 2018 -0700

    Adding Resource Resolver based path resolution tests and revamping some of 
the unit tests to consolidate them
---
 .../impl/MockedResourceResolverImplTest.java       |  21 +-
 .../mapping/AbstractMappingMapEntriesTest.java     | 315 +++++++++++++++++++++
 .../impl/mapping/EtcMappingMapEntriesTest.java     | 252 +++++++++++++++++
 .../impl/mapping/MapEntriesTest.java               | 177 ++----------
 .../mapping/StringInterpolationMapEntriesTest.java | 173 ++---------
 .../sling/resourceresolver/util/MockTestUtil.java  | 124 ++++++++
 6 files changed, 754 insertions(+), 308 deletions(-)

diff --git 
a/src/test/java/org/apache/sling/resourceresolver/impl/MockedResourceResolverImplTest.java
 
b/src/test/java/org/apache/sling/resourceresolver/impl/MockedResourceResolverImplTest.java
index 330b103..d84b714 100644
--- 
a/src/test/java/org/apache/sling/resourceresolver/impl/MockedResourceResolverImplTest.java
+++ 
b/src/test/java/org/apache/sling/resourceresolver/impl/MockedResourceResolverImplTest.java
@@ -17,6 +17,7 @@
  */
 package org.apache.sling.resourceresolver.impl;
 
+import static 
org.apache.sling.resourceresolver.util.MockTestUtil.getResourceName;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -405,7 +406,7 @@ public class MockedResourceResolverImplTest {
     @SuppressWarnings("unchecked")
     private Resource buildResource(String fullpath, Iterable<Resource> 
children, ResourceResolver resourceResolver, ResourceProvider<?> provider, 
String ... properties) {
         Resource resource = Mockito.mock(Resource.class);
-        Mockito.when(resource.getName()).thenReturn(getName(fullpath));
+        Mockito.when(resource.getName()).thenReturn(getResourceName(fullpath));
         Mockito.when(resource.getPath()).thenReturn(fullpath);
         ResourceMetadata resourceMetadata = new ResourceMetadata();
         
Mockito.when(resource.getResourceMetadata()).thenReturn(resourceMetadata);
@@ -434,15 +435,15 @@ public class MockedResourceResolverImplTest {
     }
 
 
-    /**
-     * extract the name from a path.
-     * @param fullpath
-     * @return
-     */
-    private String getName(String fullpath) {
-        int n = fullpath.lastIndexOf("/");
-        return fullpath.substring(n+1);
-    }
+//    /**
+//     * extract the name from a path.
+//     * @param fullpath
+//     * @return
+//     */
+//    private String getName(String fullpath) {
+//        int n = fullpath.lastIndexOf("/");
+//        return fullpath.substring(n+1);
+//    }
 
     /**
      * Test getting a resolver.
diff --git 
a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/AbstractMappingMapEntriesTest.java
 
b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/AbstractMappingMapEntriesTest.java
new file mode 100644
index 0000000..0f462e0
--- /dev/null
+++ 
b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/AbstractMappingMapEntriesTest.java
@@ -0,0 +1,315 @@
+/*
+ * 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.resourceresolver.impl.mapping;
+
+import junit.framework.TestCase;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceMetadata;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.api.resource.path.Path;
+import org.apache.sling.api.wrappers.ValueMapDecorator;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.event.EventAdmin;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.Semaphore;
+
+import static 
org.apache.sling.resourceresolver.impl.mapping.MapEntries.PROP_REDIRECT_EXTERNAL;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyMap;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.withSettings;
+
+/**
+ * These are tests that are testing the Sling Interpolation Feature 
(SLING-7768)
+ * on the MapEntries level
+ */
+public abstract class AbstractMappingMapEntriesTest {
+    static final String PROP_REG_EXP = "sling:match";
+
+    @Mock
+    MapConfigurationProvider resourceResolverFactory;
+
+    @Mock
+    BundleContext bundleContext;
+
+    @Mock
+    Bundle bundle;
+
+    @Mock
+    EventAdmin eventAdmin;
+
+    @Mock
+    ResourceResolver resourceResolver;
+
+    @Mock
+    StringInterpolationProviderConfiguration 
stringInterpolationProviderConfiguration;
+
+    StringInterpolationProviderImpl stringInterpolationProvider = new 
StringInterpolationProviderImpl();
+    MapEntries mapEntries;
+
+    File vanityBloomFilterFile;
+
+    Resource map;
+    Resource http;
+
+    Map<String, Map<String, String>> aliasMap;
+
+    @SuppressWarnings({"unchecked"})
+    @Before
+    public void setup() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        List<MapConfigurationProvider.VanityPathConfig> configs = 
getVanityPathConfigs();
+        vanityBloomFilterFile = new 
File("target/test-classes/resourcesvanityBloomFilter.txt");
+        when(bundle.getSymbolicName()).thenReturn("TESTBUNDLE");
+        when(bundleContext.getBundle()).thenReturn(bundle);
+        
when(bundleContext.getDataFile("vanityBloomFilter.txt")).thenReturn(vanityBloomFilterFile);
+        
when(resourceResolverFactory.getServiceResourceResolver(any(Map.class))).thenReturn(resourceResolver);
+        when(resourceResolverFactory.isVanityPathEnabled()).thenReturn(true);
+        
when(resourceResolverFactory.getVanityPathConfig()).thenReturn(configs);
+        
when(resourceResolverFactory.isOptimizeAliasResolutionEnabled()).thenReturn(true);
+        
when(resourceResolverFactory.isForceNoAliasTraversal()).thenReturn(true);
+        when(resourceResolverFactory.getObservationPaths()).thenReturn(new 
Path[] {new Path("/")});
+        
when(resourceResolverFactory.getMapRoot()).thenReturn(MapEntries.DEFAULT_MAP_ROOT);
+        
when(resourceResolverFactory.getMaxCachedVanityPathEntries()).thenReturn(-1L);
+        
when(resourceResolverFactory.isMaxCachedVanityPathEntriesStartup()).thenReturn(true);
+        when(resourceResolver.findResources(anyString(), 
eq("sql"))).thenReturn(
+            Collections.<Resource> emptySet().iterator());
+
+        map = setupEtcMapResource("/etc", "map");
+        http = setupEtcMapResource("http", map);
+
+        setupStringInterpolationProvider(new String[] {});
+        mapEntries = new MapEntries(resourceResolverFactory, bundleContext, 
eventAdmin, stringInterpolationProvider);
+
+        final Field aliasMapField = 
MapEntries.class.getDeclaredField("aliasMap");
+        aliasMapField.setAccessible(true);
+        this.aliasMap = ( Map<String, Map<String, String>>) 
aliasMapField.get(mapEntries);
+    }
+
+    List<MapConfigurationProvider.VanityPathConfig> getVanityPathConfigs() {
+        return new ArrayList<>();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        vanityBloomFilterFile.delete();
+    }
+
+
+    // -------------------------- private methods ----------
+
+    ValueMap buildValueMap(Object... string) {
+        final Map<String, Object> data = new HashMap<>();
+        for (int i = 0; i < string.length; i = i + 2) {
+            data.put((String) string[i], string[i+1]);
+        }
+        return new ValueMapDecorator(data);
+    }
+
+    Resource getVanityPathResource(final String path) {
+        Resource rsrc = mock(Resource.class);
+        when(rsrc.getPath()).thenReturn(path);
+        when(rsrc.getName()).thenReturn(ResourceUtil.getName(path));
+        when(rsrc.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", 
"/vanity" + path));
+        return rsrc;
+    }
+
+    Resource setupEtcMapResource(String parentPath, String name, 
String...valueMapPairs) {
+        return setupEtcMapResource0(parentPath, name, null, valueMapPairs);
+    }
+    Resource setupEtcMapResource(String name, Resource parent, 
String...valueMapPairs) {
+        return setupEtcMapResource0(null, name, parent, valueMapPairs);
+    }
+    private Resource setupEtcMapResource0(String parentPath, String name, 
Resource parent, String...valueMapPairs) {
+        Resource resource = mock(Resource.class, 
withSettings().name(name).extraInterfaces(ResourceDecorator.class));
+        String path = (parent == null ? parentPath : parent.getPath()) + "/" + 
name;
+        when(resource.getPath()).thenReturn(path);
+        when(resource.getName()).thenReturn(name);
+        ValueMap valueMap = buildValueMap(valueMapPairs);
+        when(resource.getValueMap()).thenReturn(valueMap);
+        when(resource.adaptTo(ValueMap.class)).thenReturn(valueMap);
+        
when(resourceResolver.getResource(resource.getPath())).thenReturn(resource);
+        if(parent != null) {
+            List<Resource> childList = ((ResourceDecorator) 
parent).getChildrenList();
+            childList.add(resource);
+        }
+        final List<Resource> childrenList = new ArrayList<>();
+        when(((ResourceDecorator) 
resource).getChildrenList()).thenReturn(childrenList);
+        // Delay the children list iterator to make sure all children are 
added beforehand
+        // Iterators have a modCount that is set when created. Any changes to 
the underlying list will
+        // change that modCount and the usage of the iterator will fail due to 
Concurrent Modification Exception
+        when(resource.listChildren()).thenAnswer(new 
Answer<Iterator<Resource>>() {
+            @Override
+            public Iterator<Resource> answer(InvocationOnMock invocation) 
throws Throwable {
+                return childrenList.iterator();
+            }
+        });
+        ResourceMetadata resourceMetadata = mock(ResourceMetadata.class);
+        when(resource.getResourceMetadata()).thenReturn(resourceMetadata);
+        doNothing().when(resourceMetadata).setResolutionPath(anyString());
+        doNothing().when(resourceMetadata).setParameterMap(anyMap());
+
+        return resource;
+    }
+
+    void setupStringInterpolationProvider(final String[] placeholderValues) {
+        
when(stringInterpolationProviderConfiguration.place_holder_key_value_pairs()).thenReturn(placeholderValues);
+        stringInterpolationProvider.activate(bundleContext, 
stringInterpolationProviderConfiguration);
+    }
+
+    MapEntriesTest.DataFuture createDataFuture(ExecutorService pool, final 
MapEntries mapEntries) {
+
+        Future<Iterator<?>> future = pool.submit(new Callable<Iterator<?>>() {
+            @Override
+            public Iterator<MapEntry> call() throws Exception {
+                return 
mapEntries.getResolveMapsIterator("http/localhost.8080/target/justVanityPath");
+            }
+        });
+        return new MapEntriesTest.DataFuture(future);
+    }
+
+    void simulateSomewhatSlowSessionOperation(final Semaphore sessionLock) 
throws InterruptedException {
+        if (!sessionLock.tryAcquire()) {
+            fail("concurrent session access detected");
+        }
+        try{
+            Thread.sleep(1);
+        } finally {
+            sessionLock.release();
+        }
+    }
+
+    static class ExpectedEtcMapping {
+        List<ExpectedEtcMapEntry> expectedEtcMapEntries = new ArrayList<>();
+
+        public ExpectedEtcMapping() {}
+
+        public ExpectedEtcMapping(String...expectedMapping) {
+            if(expectedMapping.length % 2 != 0) {
+                throw new IllegalArgumentException("Expect an even number of 
strings with pattern / redirect");
+            }
+            int size = expectedMapping.length / 2;
+            for(int i = 0; i < size; i++ ) {
+                expectedEtcMapEntries.add(new 
ExpectedEtcMapEntry(expectedMapping[2 * i], expectedMapping[2 * i + 1]));
+            }
+        }
+
+        public ExpectedEtcMapping addEtcMapEntry(String pattern, String 
redirect) {
+            addEtcMapEntry(pattern, false, redirect);
+            return this;
+        }
+        public ExpectedEtcMapping addEtcMapEntry(String pattern, boolean 
internal, String redirect) {
+            expectedEtcMapEntries.add(new ExpectedEtcMapEntry(pattern, 
internal, redirect));
+            return this;
+        }
+
+        public void assertEtcMap(String title, List<MapEntry> mapEntries) {
+            assertEquals("Wrong Number of Mappings for: " + title, 
expectedEtcMapEntries.size(), mapEntries.size());
+            ArrayList<MapEntry> actual = new ArrayList<>(mapEntries);
+            ArrayList<ExpectedEtcMapEntry> expected = new 
ArrayList<>(expectedEtcMapEntries);
+            for(MapEntry actualMapEntry: actual) {
+                ExpectedEtcMapEntry expectedFound = null;
+                for(ExpectedEtcMapEntry expectedEtcMapEntry: expected) {
+                    
if(expectedEtcMapEntry.pattern.equals(actualMapEntry.getPattern())) {
+                        expectedFound = expectedEtcMapEntry;
+                        break;
+                    }
+                }
+                if(expectedFound == null) {
+                    TestCase.fail("This pattern (" + 
actualMapEntry.getPattern() + ") is not expected for: " + title);
+                }
+                expectedFound.assertEtcMap(title, actualMapEntry);
+                expected.remove(expectedFound);
+            }
+            for(ExpectedEtcMapEntry expectedEtcMapEntry: expected) {
+                TestCase.fail("Expected Map Entry (" + 
expectedEtcMapEntry.pattern + ") not provided for: " + title);
+            }
+        }
+    }
+
+    static class ExpectedEtcMapEntry {
+        private String pattern;
+        private boolean internal;
+        private String redirect;
+
+        public ExpectedEtcMapEntry(String pattern, String redirect) {
+            this(pattern, false, redirect);
+        }
+
+        public ExpectedEtcMapEntry(String pattern, boolean internal, String 
redirect) {
+            this.pattern = pattern;
+            this.internal = internal;
+            this.redirect = redirect;
+        }
+
+        public void assertEtcMap(String title, MapEntry mapEntry) {
+            assertEquals("Wrong Pattern for " + title, pattern, 
mapEntry.getPattern());
+            List<String> givenRedirects = new 
ArrayList<>(Arrays.asList(mapEntry.getRedirect()));
+            assertEquals("Wrong Number of Redirects for: " + title, 1, 
givenRedirects.size());
+            assertEquals("Wrong Redirect for: " + title, this.redirect, 
givenRedirects.get(0));
+            assertEquals("Wrong Redirect Type (ext/int) for: " + title, 
this.internal, mapEntry.isInternal());
+        }
+    }
+
+    /**
+     * Iterator to piggyback the list of Resources onto a Resource Mock
+     * so that we can add children to them and create the iterators after
+     * everything is setup
+     */
+    static interface ResourceDecorator {
+        public List<Resource> getChildrenList();
+    }
+
+    static class DataFuture {
+        public Future<Iterator<?>> future;
+
+        public DataFuture(Future<Iterator<?>> future) {
+            super();
+            this.future = future;
+        }
+    }
+
+}
diff --git 
a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/EtcMappingMapEntriesTest.java
 
b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/EtcMappingMapEntriesTest.java
new file mode 100644
index 0000000..5526ea0
--- /dev/null
+++ 
b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/EtcMappingMapEntriesTest.java
@@ -0,0 +1,252 @@
+/*
+ * 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.resourceresolver.impl.mapping;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceMetadata;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.path.Path;
+import 
org.apache.sling.resourceresolver.impl.CommonResourceResolverFactoryImpl;
+import org.apache.sling.resourceresolver.impl.ResourceAccessSecurityTracker;
+import org.apache.sling.resourceresolver.impl.ResourceResolverFactoryActivator;
+import org.apache.sling.resourceresolver.impl.ResourceResolverFactoryImpl;
+import 
org.apache.sling.resourceresolver.impl.providers.ResourceProviderHandler;
+import 
org.apache.sling.resourceresolver.impl.providers.ResourceProviderStorage;
+import 
org.apache.sling.resourceresolver.impl.providers.ResourceProviderTracker;
+import org.apache.sling.serviceusermapping.ServiceUserMapper;
+import org.apache.sling.spi.resource.provider.ResolveContext;
+import org.apache.sling.spi.resource.provider.ResourceContext;
+import org.apache.sling.spi.resource.provider.ResourceProvider;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+import javax.servlet.http.HttpServletRequest;
+import java.lang.reflect.Method;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import static java.util.Arrays.asList;
+import static 
org.apache.sling.resourceresolver.impl.MockedResourceResolverImplTest.createRPHandler;
+import static 
org.apache.sling.resourceresolver.impl.ResourceResolverImpl.PROP_REDIRECT_INTERNAL;
+import static 
org.apache.sling.resourceresolver.impl.mapping.MapEntries.PROP_REDIRECT_EXTERNAL;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyMap;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+public class EtcMappingMapEntriesTest extends AbstractMappingMapEntriesTest {
+
+    @Test
+    public void root_node_to_content_mapping() throws Exception {
+        setupEtcMapResource("localhost.8080", http,PROP_REDIRECT_EXTERNAL, 
"/content/simple-node");
+
+        mapEntries.doInit();
+        ExpectedEtcMapping expectedEtcMapping = new 
ExpectedEtcMapping("^http/localhost.8080/", "/content/simple-node/");
+        expectedEtcMapping.assertEtcMap("Etc Mapping for simple node", 
mapEntries.getResolveMaps());
+    }
+
+    @Test
+    public void match_to_content_mapping() throws Exception {
+        setupEtcMapResource("test-node", http,
+            PROP_REG_EXP, "localhost.8080/",
+            PROP_REDIRECT_EXTERNAL, "/content/simple-match/"
+        );
+
+        mapEntries.doInit();
+        ExpectedEtcMapping expectedEtcMapping = new 
ExpectedEtcMapping("^http/localhost.8080/", "/content/simple-match/");
+        expectedEtcMapping.assertEtcMap("Etc Mapping for simple match", 
mapEntries.getResolveMaps());
+    }
+
+    // The following tests are based on the example from the 
https://sling.apache.org/documentation/the-sling-engine/mappings-for-resource-resolution.html
 page
+
+    @Test
+    public void internal_to_external_node_mapping() throws Exception {
+        setupEtcMapResource("example.com.80", http,PROP_REDIRECT_EXTERNAL, 
"http://www.example.com/";);
+
+        mapEntries.doInit();
+        ExpectedEtcMapping expectedEtcMapping = new 
ExpectedEtcMapping("^http/example.com.80/", "http://www.example.com/";);
+        expectedEtcMapping.assertEtcMap("Etc Mapping for internal to external 
based on node", mapEntries.getResolveMaps());
+    }
+
+    @Test
+    public void internal_root_to_content_node_mapping() throws Exception {
+        setupEtcMapResource("www.example.com.80", http,PROP_REDIRECT_INTERNAL, 
"/example");
+
+        mapEntries.doInit();
+        ExpectedEtcMapping expectedEtcMapping = new 
ExpectedEtcMapping().addEtcMapEntry("^http/www.example.com.80/", true, 
"/example/");
+        expectedEtcMapping.assertEtcMap("Etc Mapping for internal root to 
content", mapEntries.getResolveMaps());
+    }
+
+    @Test
+    public void host_redirect_match_mapping() throws Exception {
+        setupEtcMapResource("any_example.com.80", http,
+            PROP_REG_EXP, ".+\\.example\\.com\\.80",
+            PROP_REDIRECT_EXTERNAL, "http://www.example.com/";
+        );
+
+        mapEntries.doInit();
+        ExpectedEtcMapping expectedEtcMapping = new 
ExpectedEtcMapping().addEtcMapEntry("^http/.+\\.example\\.com\\.80", false, 
"http://www.example.com/";);
+        expectedEtcMapping.assertEtcMap("Etc Mapping for host redirect match 
mapping", mapEntries.getResolveMaps());
+    }
+
+    @Test
+    public void nested_internal_mixed_mapping() throws Exception {
+        Resource localhost = setupEtcMapResource("localhost_any", http,
+            PROP_REG_EXP, "localhost\\.\\d*",
+            PROP_REDIRECT_INTERNAL, "/content"
+        );
+        setupEtcMapResource("cgi-bin", localhost, PROP_REDIRECT_INTERNAL, 
"/scripts");
+        setupEtcMapResource("gateway", localhost, PROP_REDIRECT_INTERNAL, 
"http://gbiv.com";);
+        setupEtcMapResource("(stories)", localhost, PROP_REDIRECT_INTERNAL, 
"/anecdotes/$1");
+
+        mapEntries.doInit();
+        ExpectedEtcMapping expectedEtcMapping = new ExpectedEtcMapping()
+            .addEtcMapEntry("^http/localhost\\.\\d*", true, "/content")
+            .addEtcMapEntry("^http/localhost\\.\\d*/cgi-bin/", true, 
"/scripts/")
+            .addEtcMapEntry("^http/localhost\\.\\d*/gateway/", true, 
"http://gbiv.com/";)
+            .addEtcMapEntry("^http/localhost\\.\\d*/(stories)/", true, 
"/anecdotes/$1/");
+        expectedEtcMapping.assertEtcMap("Etc Mapping for nested internal mixed 
mapping", mapEntries.getResolveMaps());
+
+        // Not really an etc-map resource but it is good for now
+        final Resource test = setupEtcMapResource("/scripts", "test");
+        ResourceProvider<?> rp = new ResourceProvider<Object>() {
+            @Override
+            public Resource getResource(ResolveContext<Object> ctx, String 
path, ResourceContext rCtx, Resource parent) {
+                if(path.equals("/scripts/test")) {
+                    return test;
+                }
+                if(path.startsWith(map.getPath())) {
+                    return findMapping(map, path);
+                }
+                return null;
+            }
+
+            private Resource findMapping(Resource parent, String path) {
+                if(parent.getPath().equals(path)) {
+                    return parent;
+                }
+                Iterator<Resource> i = parent.listChildren();
+                while(i.hasNext()) {
+                    Resource child = i.next();
+                    if(path.equals(child.getPath())) {
+                        return child;
+                    } else {
+                        return findMapping(child, path);
+                    }
+                }
+                return null;
+            }
+
+            @Override
+            public Iterator<Resource> listChildren(ResolveContext<Object> ctx, 
Resource parent) {
+                if(parent.getPath().startsWith(map.getPath())) {
+                    return parent.listChildren();
+                }
+                return null;
+            }
+        };
+
+        List<ResourceProviderHandler> handlers = asList(createRPHandler(rp, 
"rp1", 0, "/"));
+        ResourceProviderTracker resourceProviderTracker = 
mock(ResourceProviderTracker.class);
+        ResourceProviderStorage storage = new 
ResourceProviderStorage(handlers);
+        
when(resourceProviderTracker.getResourceProviderStorage()).thenReturn(storage);
+        ResourceResolverFactoryActivator activator = spy(new 
ResourceResolverFactoryActivator());
+        // Both 'resourceProviderTracker' and 'resourceAccessSecurityTracker' 
are package private and so we cannot
+        // set them here. Intercept the call to obtain them and provide the 
desired value
+        
when(activator.getResourceProviderTracker()).thenReturn(resourceProviderTracker);
+        when(activator.getResourceAccessSecurityTracker()).thenReturn(new 
ResourceAccessSecurityTracker());
+        when(activator.getBundleContext()).thenReturn(bundleContext);
+        
when(activator.getStringInterpolationProvider()).thenReturn(stringInterpolationProvider);
+        when(activator.getMapRoot()).thenReturn("/etc/map");
+        when(activator.getObservationPaths()).thenReturn(new Path[] {new 
Path("/")});
+        CommonResourceResolverFactoryImpl commonFactory = spy(new 
CommonResourceResolverFactoryImpl(activator));
+        when(bundleContext.getBundle()).thenReturn(bundle);
+        ServiceUserMapper serviceUserMapper = mock(ServiceUserMapper.class);
+        when(activator.getServiceUserMapper()).thenReturn(serviceUserMapper);
+        
when(serviceUserMapper.getServiceUserID(any(Bundle.class),anyString())).thenReturn("mapping");
+        Method method = 
CommonResourceResolverFactoryImpl.class.getDeclaredMethod("activate", 
BundleContext.class);
+        method.setAccessible(true);
+        method.invoke(commonFactory, bundleContext);
+        final Bundle usingBundle = mock(Bundle.class);
+        ResourceResolverFactoryImpl resFac = new 
ResourceResolverFactoryImpl(commonFactory, usingBundle, null);
+        ResourceResolver resResolver = 
resFac.getAdministrativeResourceResolver(null);
+
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        when(request.getScheme()).thenReturn("http");
+        when(request.getServerName()).thenReturn("localhost");
+        when(request.getServerPort()).thenReturn(80);
+        Resource mappedResource = resResolver.resolve(request, 
"/cgi-bin/test.html");
+        String path = mappedResource.getPath();
+        assertEquals("Wrong Resolved Path", "/scripts/test", path);
+    }
+
+//    @Test
+//    public void regex_map_internal_mapping() throws Exception {
+//        setupEtcMapResource("regexmap", http,
+//            PROP_REG_EXP, "$1.example.com/$2",
+//            PROP_REDIRECT_INTERNAL, "/content/([^/]+)/(.*)"
+//        );
+//
+//        mapEntries.doInit();
+//        // Regex Mappings are ignored for the Resolve Map
+//        ExpectedEtcMapping expectedEtcMapping = new ExpectedEtcMapping();
+////            .addEtcMapEntry("^http/$1.example.com/$2", true, 
"/content/([^/]+)/(.*)");
+//        expectedEtcMapping.assertEtcMap("Etc Mapping for regex map internal 
mapping", mapEntries.getResolveMaps());
+//
+//        ResourceProvider<?> rp = new ResourceProvider<Object>() {
+//
+//            @Override
+//            public Resource getResource(ResolveContext<Object> ctx, String 
path, ResourceContext rCtx, Resource parent) {
+//                return null;
+//            }
+//
+//            @Override
+//            public Iterator<Resource> listChildren(ResolveContext<Object> 
ctx, Resource parent) {
+//                return null;
+//            }
+//        };
+//
+//        List<ResourceProviderHandler> handlers = asList(createRPHandler(rp, 
"rp1", 0, "/"));
+//        ResourceProviderTracker resourceProviderTracker = 
mock(ResourceProviderTracker.class);
+//        ResourceProviderStorage storage = new 
ResourceProviderStorage(handlers);
+//        
when(resourceProviderTracker.getResourceProviderStorage()).thenReturn(storage);
+//        ResourceResolverFactoryActivator activator = spy(new 
ResourceResolverFactoryActivator());
+//        
when(activator.getResourceProviderTracker()).thenReturn(resourceProviderTracker);
+////        activator.resourceProviderTracker = resourceProviderTracker;
+//        when(activator.getResourceAccessSecurityTracker()).thenReturn(new 
ResourceAccessSecurityTracker());
+////        activator.resourceAccessSecurityTracker = new 
ResourceAccessSecurityTracker();
+//        CommonResourceResolverFactoryImpl commonFactory = new 
CommonResourceResolverFactoryImpl(activator);
+//        final Bundle usingBundle = mock(Bundle.class);
+//        ResourceResolverFactoryImpl resFac = new 
ResourceResolverFactoryImpl(commonFactory, usingBundle, null);
+//        ResourceResolver resResolver = 
resFac.getAdministrativeResourceResolver(null);
+//
+//        HttpServletRequest request = mock(HttpServletRequest.class);
+//        when(request.getScheme()).thenReturn("http");
+//        when(request.getServerName()).thenReturn("a.example.com");
+//        when(request.getServerPort()).thenReturn(80);
+//        Resource mappedResource = resResolver.resolve(request, "/b.html");
+//        String path = mappedResource.getPath();
+//    }
+}
diff --git 
a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/MapEntriesTest.java
 
b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/MapEntriesTest.java
index 682dacf..b61ac20 100644
--- 
a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/MapEntriesTest.java
+++ 
b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/MapEntriesTest.java
@@ -16,32 +16,26 @@
  */
 package org.apache.sling.resourceresolver.impl.mapping;
 
-import static 
org.apache.sling.resourceresolver.impl.mapping.MapEntries.PROP_REDIRECT_EXTERNAL;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import org.apache.sling.api.SlingException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.observation.ResourceChange;
+import org.apache.sling.api.resource.observation.ResourceChange.ChangeType;
+import org.apache.sling.api.wrappers.ValueMapDecorator;
+import org.apache.sling.resourceresolver.impl.ResourceResolverImpl;
+import 
org.apache.sling.resourceresolver.impl.mapping.MapConfigurationProvider.VanityPathConfig;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
 
-import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.Field;
-import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
 import java.text.ParseException;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedList;
@@ -49,73 +43,30 @@ import java.util.List;
 import java.util.Map;
 import java.util.Random;
 import java.util.Set;
-import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 
-import org.apache.sling.api.SlingException;
-import org.apache.sling.api.resource.Resource;
-import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.api.resource.ResourceResolverFactory;
-import org.apache.sling.api.resource.ResourceUtil;
-import org.apache.sling.api.resource.ValueMap;
-import org.apache.sling.api.resource.observation.ResourceChange;
-import org.apache.sling.api.resource.observation.ResourceChange.ChangeType;
-import org.apache.sling.api.resource.path.Path;
-import org.apache.sling.api.wrappers.ValueMapDecorator;
-import org.apache.sling.resourceresolver.impl.ResourceResolverImpl;
-import 
org.apache.sling.resourceresolver.impl.mapping.MapConfigurationProvider.VanityPathConfig;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.service.event.EventAdmin;
-
-public class MapEntriesTest {
-
-    private MapEntries mapEntries;
-
-    File vanityBloomFilterFile;
-
-    @Mock
-    private MapConfigurationProvider resourceResolverFactory;
-
-    @Mock
-    private BundleContext bundleContext;
-
-    @Mock
-    private Bundle bundle;
-
-    @Mock
-    private ResourceResolver resourceResolver;
-
-    @Mock
-    private EventAdmin eventAdmin;
-
-    @Mock
-    private StringInterpolationProvider stringInterpolationProvider;
-
-    private Map<String, Map<String, String>> aliasMap;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
-    @SuppressWarnings({ "unchecked" })
-    @Before
-    public void setup() throws Exception {
-        MockitoAnnotations.initMocks(this);
+public class MapEntriesTest extends AbstractMappingMapEntriesTest {
 
+    List<MapConfigurationProvider.VanityPathConfig> getVanityPathConfigs() {
         final List<VanityPathConfig> configs = new ArrayList<>();
         configs.add(new VanityPathConfig("/libs/", false));
         configs.add(new VanityPathConfig("/libs/denied", true));
@@ -129,35 +80,10 @@ public class MapEntriesTest {
         configs.add(new VanityPathConfig("/vanityPathOnJcrContent", false));
 
         Collections.sort(configs);
-        vanityBloomFilterFile = new 
File("src/main/resourcesvanityBloomFilter.txt");
-        when(bundle.getSymbolicName()).thenReturn("TESTBUNDLE");
-        when(bundleContext.getBundle()).thenReturn(bundle);
-        
when(bundleContext.getDataFile("vanityBloomFilter.txt")).thenReturn(vanityBloomFilterFile);
-        
when(resourceResolverFactory.getServiceResourceResolver(any(Map.class))).thenReturn(resourceResolver);
-        when(resourceResolverFactory.isVanityPathEnabled()).thenReturn(true);
-        
when(resourceResolverFactory.getVanityPathConfig()).thenReturn(configs);
-        
when(resourceResolverFactory.isOptimizeAliasResolutionEnabled()).thenReturn(true);
-        
when(resourceResolverFactory.isForceNoAliasTraversal()).thenReturn(true);
-        when(resourceResolverFactory.getObservationPaths()).thenReturn(new 
Path[] {new Path("/")});
-        
when(resourceResolverFactory.getMapRoot()).thenReturn(MapEntries.DEFAULT_MAP_ROOT);
-        
when(resourceResolverFactory.getMaxCachedVanityPathEntries()).thenReturn(-1L);
-        
when(resourceResolverFactory.isMaxCachedVanityPathEntriesStartup()).thenReturn(true);
-        when(resourceResolver.findResources(anyString(), 
eq("sql"))).thenReturn(
-                Collections.<Resource> emptySet().iterator());
-
-        mapEntries = new MapEntries(resourceResolverFactory, bundleContext, 
eventAdmin, stringInterpolationProvider);
-        final Field aliasMapField = 
MapEntries.class.getDeclaredField("aliasMap");
-        aliasMapField.setAccessible(true);
-
-        this.aliasMap = ( Map<String, Map<String, String>>) 
aliasMapField.get(mapEntries);
-    }
 
-    @After
-    public void tearDown() throws Exception {
-        vanityBloomFilterFile.delete();
+        return configs;
     }
 
-
     @Test(timeout = 1000)
     public void test_simple_alias_support() throws InterruptedException {
         Resource parent = mock(Resource.class);
@@ -395,22 +321,6 @@ public class MapEntriesTest {
         assertTrue( mapEntries.getResolveMaps().isEmpty());
     }
 
-    private ValueMap buildValueMap(Object... string) {
-        final Map<String, Object> data = new HashMap<>();
-        for (int i = 0; i < string.length; i = i + 2) {
-            data.put((String) string[i], string[i+1]);
-        }
-        return new ValueMapDecorator(data);
-    }
-
-    private Resource getVanityPathResource(final String path) {
-        Resource rsrc = mock(Resource.class);
-        when(rsrc.getPath()).thenReturn(path);
-        when(rsrc.getName()).thenReturn(ResourceUtil.getName(path));
-        when(rsrc.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", 
"/vanity" + path));
-        return rsrc;
-    }
-
     @Test
     public void test_vanity_path_registration_include_exclude() throws 
IOException {
         final String[] validPaths = {"/libs/somewhere", "/libs/a/b", "/foo/a", 
"/baa/a"};
@@ -2280,39 +2190,4 @@ public class MapEntriesTest {
             }
         }
     }
-
-    // -------------------------- private methods ----------
-    private DataFuture createDataFuture(ExecutorService pool, final MapEntries 
mapEntries) {
-
-        Future<Iterator<?>> future = pool.submit(new Callable<Iterator<?>>() {
-            @Override
-            public Iterator<MapEntry> call() throws Exception {
-                return 
mapEntries.getResolveMapsIterator("http/localhost.8080/target/justVanityPath");
-            }
-        });
-        return new DataFuture(future);
-    }
-
-    private void simulateSomewhatSlowSessionOperation(final Semaphore 
sessionLock) throws InterruptedException {
-        if (!sessionLock.tryAcquire()) {
-            fail("concurrent session access detected");
-        }
-        try{
-            Thread.sleep(1);
-        } finally {
-            sessionLock.release();
-        }
-    }
-
-    // -------------------------- inner classes ------------
-
-    private static class DataFuture {
-        public Future<Iterator<?>> future;
-
-        public DataFuture(Future<Iterator<?>> future) {
-            super();
-            this.future = future;
-        }
-    }
-
 }
\ No newline at end of file
diff --git 
a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/StringInterpolationMapEntriesTest.java
 
b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/StringInterpolationMapEntriesTest.java
index 8392637..f1635a0 100644
--- 
a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/StringInterpolationMapEntriesTest.java
+++ 
b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/StringInterpolationMapEntriesTest.java
@@ -17,101 +17,31 @@
 package org.apache.sling.resourceresolver.impl.mapping;
 
 import org.apache.sling.api.resource.Resource;
-import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.api.resource.ValueMap;
-import org.apache.sling.api.resource.path.Path;
-import org.apache.sling.api.wrappers.ValueMapDecorator;
-import org.junit.Before;
 import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-import org.osgi.framework.BundleContext;
-import org.osgi.service.event.EventAdmin;
 
-import java.io.File;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
+import java.util.Arrays;
 import java.util.List;
-import java.util.Map;
 
+import static junit.framework.TestCase.fail;
 import static 
org.apache.sling.resourceresolver.impl.mapping.MapEntries.PROP_REDIRECT_EXTERNAL;
 import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.withSettings;
 
 /**
  * These are tests that are testing the Sling Interpolation Feature 
(SLING-7768)
  * on the MapEntries level
  */
-public class StringInterpolationMapEntriesTest {
-    private static final String PROP_REG_EXP = "sling:match";
-
-    @Mock
-    private MapConfigurationProvider resourceResolverFactory;
-
-    @Mock
-    private BundleContext bundleContext;
-
-    @Mock
-    private EventAdmin eventAdmin;
-
-    @Mock
-    private ResourceResolver resourceResolver;
-
-    @Mock
-    private StringInterpolationProviderConfiguration 
stringInterpolationProviderConfiguration;
-
-    File vanityBloomFilterFile;
-
-    private Resource map;
-    private Resource http;
-
-    @SuppressWarnings({"unchecked"})
-    @Before
-    public void setup() throws Exception {
-        MockitoAnnotations.initMocks(this);
-
-        
when(resourceResolverFactory.getServiceResourceResolver(any(Map.class))).thenReturn(resourceResolver);
-        when(resourceResolverFactory.isVanityPathEnabled()).thenReturn(true);
-        final List<MapConfigurationProvider.VanityPathConfig> configs = new 
ArrayList<>();
-        
when(resourceResolverFactory.getVanityPathConfig()).thenReturn(configs);
-        
when(resourceResolverFactory.isOptimizeAliasResolutionEnabled()).thenReturn(true);
-        
when(resourceResolverFactory.isForceNoAliasTraversal()).thenReturn(true);
-        when(resourceResolverFactory.getObservationPaths()).thenReturn(new 
Path[] {new Path("/")});
-        
when(resourceResolverFactory.getMapRoot()).thenReturn(MapEntries.DEFAULT_MAP_ROOT);
-        
when(resourceResolverFactory.getMaxCachedVanityPathEntries()).thenReturn(-1L);
-        
when(resourceResolverFactory.isMaxCachedVanityPathEntriesStartup()).thenReturn(true);
-        when(resourceResolver.findResources(anyString(), 
eq("sql"))).thenReturn(
-            Collections.<Resource> emptySet().iterator());
-        vanityBloomFilterFile = new 
File("target/test-classes/resourcesvanityBloomFilter.txt");
-        
when(bundleContext.getDataFile("vanityBloomFilter.txt")).thenReturn(vanityBloomFilterFile);
-
-        map = setupEtcMapResource("/etc", "map");
-        http = setupEtcMapResource("http", map);
-    }
+public class StringInterpolationMapEntriesTest extends 
AbstractMappingMapEntriesTest {
 
     @Test
     public void simple_node_string_interpolation() throws Exception {
         // To avoid side effects the String Interpolation uses its own 
Resource Resolver
-        Resource sivOne = setupEtcMapResource("${siv.one}", 
http,PROP_REDIRECT_EXTERNAL, "/content/test-me");
-        StringInterpolationProvider stringInterpolationProvider = 
setupStringInterpolationProvider(new String[] {"siv.one=test-value"});
+        Resource sivOne = setupEtcMapResource("${siv.one}", 
http,PROP_REDIRECT_EXTERNAL, "/content/simple-node");
+        setupStringInterpolationProvider(new String[] 
{"siv.one=test-simple-node"});
 
-        MapEntries mapEntries = new MapEntries(resourceResolverFactory, 
bundleContext, eventAdmin, stringInterpolationProvider);
-        List<MapEntry> mapMaps = mapEntries.getResolveMaps();
-        assertEquals("Expected one mapping", 1, mapMaps.size());
-        MapEntry mapEntry = mapMaps.get(0);
-        assertEquals("Wrong String Interpolation for siv.one", 
"^http/test-value/", mapEntry.getPattern());
-        String[] redirects = mapEntry.getRedirect();
-        assertEquals("Expected one redirect", 1, redirects.length);
-        assertEquals("Wrong Mapping found for siv.one", "/content/test-me/", 
redirects[0]);
+        mapEntries.doInit();
+        ExpectedEtcMapping expectedEtcMapping = new 
ExpectedEtcMapping("^http/test-simple-node/", "/content/simple-node/");
+        expectedEtcMapping.assertEtcMap("String Interpolation for simple 
match", mapEntries.getResolveMaps());
     }
 
     @Test
@@ -119,77 +49,26 @@ public class StringInterpolationMapEntriesTest {
         // To avoid side effects the String Interpolation uses its own 
Resource Resolver
         Resource sivOne = setupEtcMapResource("test-node", http,
             PROP_REG_EXP, "${siv.one}/",
-            PROP_REDIRECT_EXTERNAL, "/content/test-me/"
+            PROP_REDIRECT_EXTERNAL, "/content/simple-match/"
         );
-        StringInterpolationProvider stringInterpolationProvider = 
setupStringInterpolationProvider(new String[] {"siv.one=test-value"});
+        setupStringInterpolationProvider(new String[] 
{"siv.one=test-simple-match"});
 
-        MapEntries mapEntries = new MapEntries(resourceResolverFactory, 
bundleContext, eventAdmin, stringInterpolationProvider);
-        List<MapEntry> mapMaps = mapEntries.getResolveMaps();
-        assertEquals("Expected one mapping", 1, mapMaps.size());
-        MapEntry mapEntry = mapMaps.get(0);
-        assertEquals("Wrong String Interpolation for siv.one", 
"^http/test-value/", mapEntry.getPattern());
-        String[] redirects = mapEntry.getRedirect();
-        assertEquals("Expected one redirect", 1, redirects.length);
-        assertEquals("Wrong Mapping found for siv.one", "/content/test-me/", 
redirects[0]);
+        mapEntries.doInit();
+        ExpectedEtcMapping expectedEtcMapping = new 
ExpectedEtcMapping("^http/test-simple-match/", "/content/simple-match/");
+        expectedEtcMapping.assertEtcMap("String Interpolation for simple 
match", mapEntries.getResolveMaps());
     }
 
-    // -------------------------- private methods ----------
-
-    private ValueMap buildValueMap(Object... string) {
-        final Map<String, Object> data = new HashMap<>();
-        for (int i = 0; i < string.length; i = i + 2) {
-            data.put((String) string[i], string[i+1]);
-        }
-        return new ValueMapDecorator(data);
-    }
-
-    private Resource setupEtcMapResource(String parentPath, String name, 
String...valueMapPairs) {
-        return setupEtcMapResource0(parentPath, name, null, valueMapPairs);
-    }
-    private Resource setupEtcMapResource(String name, Resource parent, 
String...valueMapPairs) {
-        return setupEtcMapResource0(null, name, parent, valueMapPairs);
-    }
-    private Resource setupEtcMapResource0(String parentPath, String name, 
Resource parent, String...valueMapPairs) {
-        Resource resource = mock(Resource.class, 
withSettings().name(name).extraInterfaces(ResourceDecorator.class));
-        String path = (parent == null ? parentPath : parent.getPath()) + "/" + 
name;
-        when(resource.getPath()).thenReturn(path);
-        when(resource.getName()).thenReturn(name);
-        ValueMap valueMap = buildValueMap(valueMapPairs);
-        when(resource.getValueMap()).thenReturn(valueMap);
-        when(resource.adaptTo(ValueMap.class)).thenReturn(valueMap);
-        
when(resourceResolver.getResource(resource.getPath())).thenReturn(resource);
-        if(parent != null) {
-            List<Resource> childList = ((ResourceDecorator) 
parent).getChildrenList();
-            childList.add(resource);
-        }
-        final List<Resource> childrenList = new ArrayList<>();
-        when(((ResourceDecorator) 
resource).getChildrenList()).thenReturn(childrenList);
-        // Delay the children list iterator to make sure all children are 
added beforehand
-        // Iterators have a modCount that is set when created. Any changes to 
the underlying list will
-        // change that modCount and the usage of the iterator will fail due to 
Concurrent Modification Exception
-        when(resource.listChildren()).thenAnswer(new 
Answer<Iterator<Resource>>() {
-            @Override
-            public Iterator<Resource> answer(InvocationOnMock invocation) 
throws Throwable {
-                return childrenList.iterator();
-            }
-        });
-
-        return resource;
-    }
-
-    private StringInterpolationProvider setupStringInterpolationProvider(final 
String[] placeholderValues) {
-        
when(stringInterpolationProviderConfiguration.place_holder_key_value_pairs()).thenReturn(placeholderValues);
-        StringInterpolationProviderImpl stringInterpolationProvider = new 
StringInterpolationProviderImpl();
-        stringInterpolationProvider.activate(bundleContext, 
stringInterpolationProviderConfiguration);
-        return stringInterpolationProvider;
-    }
-
-    /**
-     * Iterator to piggyback the list of Resources onto a Resource Mock
-     * so that we can add children to them and create the iterators after
-     * everything is setup
-     */
-    private static interface ResourceDecorator {
-        public List<Resource> getChildrenList();
-    }
+//    @Test
+//    public void simple_nested_match_string_interpolation() throws Exception {
+//        // To avoid side effects the String Interpolation uses its own 
Resource Resolver
+//        Resource sivOne = setupEtcMapResource("test-node", http,
+//            PROP_REG_EXP, "${siv.one}/",
+//            PROP_REDIRECT_EXTERNAL, "/content/simple-match/"
+//        );
+//        setupStringInterpolationProvider(new String[] 
{"siv.one=test-simple-match"});
+//
+//        mapEntries.doInit();
+//        ExpectedEtcMapping expectedEtcMapping = new 
ExpectedEtcMapping("^http/test-simple-match/", "/content/simple-match/");
+//        expectedEtcMapping.assertEtcMap("String Interpolation for simple 
match", mapEntries.getResolveMaps());
+//    }
 }
diff --git 
a/src/test/java/org/apache/sling/resourceresolver/util/MockTestUtil.java 
b/src/test/java/org/apache/sling/resourceresolver/util/MockTestUtil.java
new file mode 100644
index 0000000..7db3831
--- /dev/null
+++ b/src/test/java/org/apache/sling/resourceresolver/util/MockTestUtil.java
@@ -0,0 +1,124 @@
+/*
+ * 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.resourceresolver.util;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceMetadata;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.api.wrappers.ValueMapDecorator;
+import org.apache.sling.resourceresolver.impl.SimpleValueMapImpl;
+import 
org.apache.sling.resourceresolver.impl.mapping.AbstractMappingMapEntriesTest;
+import org.apache.sling.spi.resource.provider.ResolveContext;
+import org.apache.sling.spi.resource.provider.ResourceContext;
+import org.apache.sling.spi.resource.provider.ResourceProvider;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import static java.util.Arrays.asList;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.withSettings;
+
+public class MockTestUtil {
+
+    /**
+     * Extract the name from a resource path
+     * @param fullPath Full / Aboslute path to the resource
+     * @return Name of the resource
+     */
+    public static String getResourceName(String fullPath) {
+        int n = fullPath.lastIndexOf("/");
+        return fullPath.substring(n+1);
+    }
+
+    /**
+     * Build a resource with path, parent, provider and resource resolver.
+     * @param fullPath Full Path of the Resource
+     * @param parent Parent of this resource but it can be null
+     * @param resourceResolver Resource Resolver of this resource
+     * @param provider Resource Provider Instance
+     * @param properties Key / Value pair for resource properties (the number 
of strings must be even)
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    private Resource buildResource(String fullPath, Resource parent, 
ResourceResolver resourceResolver, ResourceProvider<?> provider, String ... 
properties) {
+        if(properties != null && properties.length % 2 != 0) { throw new 
IllegalArgumentException("List of Resource Properties must be an even number: " 
+ asList(properties)); }
+        Resource resource = mock(Resource.class, 
withSettings().name(getResourceName(fullPath)).extraInterfaces(ResourceChildrenAccessor.class));
+        when(resource.getName()).thenReturn(getResourceName(fullPath));
+        when(resource.getPath()).thenReturn(fullPath);
+        ResourceMetadata resourceMetadata = new ResourceMetadata();
+        when(resource.getResourceMetadata()).thenReturn(resourceMetadata);
+        when(resource.getResourceResolver()).thenReturn(resourceResolver);
+
+        if(parent != null) {
+            List<Resource> childList = ((ResourceChildrenAccessor) 
parent).getChildrenList();
+            childList.add(resource);
+        }
+        final List<Resource> childrenList = new ArrayList<>();
+        when(((ResourceChildrenAccessor) 
resource).getChildrenList()).thenReturn(childrenList);
+        // Delay the children list iterator to make sure all children are 
added beforehand
+        // Iterators have a modCount that is set when created. Any changes to 
the underlying list will
+        // change that modCount and the usage of the iterator will fail due to 
Concurrent Modification Exception
+        when(resource.listChildren()).thenAnswer(new 
Answer<Iterator<Resource>>() {
+            @Override
+            public Iterator<Resource> answer(InvocationOnMock invocation) 
throws Throwable {
+                return childrenList.iterator();
+            }
+        });
+
+        // register the resource with the provider
+        if ( provider != null ) {
+            when(provider.listChildren(Mockito.any(ResolveContext.class), 
Mockito.eq(resource))).thenAnswer(new Answer<Iterator<Resource>>() {
+                @Override
+                public Iterator<Resource> answer(InvocationOnMock invocation) 
throws Throwable {
+                    return childrenList.iterator();
+                }
+            });
+            when(provider.getResource(Mockito.any(ResolveContext.class), 
Mockito.eq(fullPath), Mockito.any(ResourceContext.class), 
Mockito.any(Resource.class))).thenReturn(resource);
+        }
+        if ( properties != null ) {
+            ValueMap vm = new SimpleValueMapImpl();
+            for ( int i=0; i < properties.length; i+=2) {
+                resourceMetadata.put(properties[i], properties[i+1]);
+                vm.put(properties[i], properties[i+1]);
+            }
+            when(resource.getValueMap()).thenReturn(vm);
+            when(resource.adaptTo(Mockito.eq(ValueMap.class))).thenReturn(vm);
+        } else {
+            when(resource.getValueMap()).thenReturn(ValueMapDecorator.EMPTY);
+            
when(resource.adaptTo(Mockito.eq(ValueMap.class))).thenReturn(ValueMapDecorator.EMPTY);
+        }
+
+        return resource;
+    }
+
+    /**
+     * Iterator to piggyback the list of Resources onto a Resource Mock
+     * so that we can add children to them and create the iterators after
+     * everything is setup
+     */
+    static interface ResourceChildrenAccessor {
+        public List<Resource> getChildrenList();
+    }
+
+}

Reply via email to