blob: 1f3fa1343d5f77b10c9c9e1bc950ecd7056d51a0 [file] [log] [blame]
/*
* 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 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.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.sling.api.resource.Resource;
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.resourceresolver.util.MockTestUtil;
import org.apache.sling.resourceresolver.util.MockTestUtil.ExpectedEtcMapping;
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;
/**
* These tests are for the /etc/map setup of the Map Entries when
* an /etc/map is present.
*/
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);
when(activator.getPathToUriMappingService()).thenReturn(MockTestUtil.createPathToUriMappingServiceMock(resResolver));
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();
// }
}