blob: 8864fb8cfa3464a1b7cb1a9f74c8a42ce5b50489 [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 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.mock;
import static org.mockito.Mockito.when;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
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.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.resource.Resource;
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.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.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;
private Map<String, Map<String, String>> aliasMap;
@SuppressWarnings({ "unchecked" })
@Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
final List<VanityPathConfig> configs = new ArrayList<>();
configs.add(new VanityPathConfig("/libs/", false));
configs.add(new VanityPathConfig("/libs/denied", true));
configs.add(new VanityPathConfig("/foo/", false));
configs.add(new VanityPathConfig("/baa/", false));
configs.add(new VanityPathConfig("/justVanityPath", false));
configs.add(new VanityPathConfig("/justVanityPath2", false));
configs.add(new VanityPathConfig("/badVanityPath", false));
configs.add(new VanityPathConfig("/redirectingVanityPath", false));
configs.add(new VanityPathConfig("/redirectingVanityPath301", false));
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.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);
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();
}
@Test
public void test_simple_alias_support() {
Resource parent = mock(Resource.class);
when(parent.getPath()).thenReturn("/parent");
final Resource result = mock(Resource.class);
when(result.getParent()).thenReturn(parent);
when(result.getPath()).thenReturn("/parent/child");
when(result.getName()).thenReturn("child");
when(result.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "alias"));
when(resourceResolver.findResources(anyString(), eq("sql"))).thenAnswer(new Answer<Iterator<Resource>>() {
@Override
public Iterator<Resource> answer(InvocationOnMock invocation) throws Throwable {
if (invocation.getArguments()[0].toString().contains(ResourceResolverImpl.PROP_ALIAS)) {
return Collections.singleton(result).iterator();
} else {
return Collections.<Resource> emptySet().iterator();
}
}
});
mapEntries.doInit();
Map<String, String> aliasMap = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMap);
assertTrue(aliasMap.containsKey("alias"));
assertEquals("child", aliasMap.get("alias"));
}
@Test
public void test_that_duplicate_alias_doesnt_replace_first_alias() {
Resource parent = mock(Resource.class);
when(parent.getPath()).thenReturn("/parent");
final Resource result = mock(Resource.class);
when(result.getParent()).thenReturn(parent);
when(result.getPath()).thenReturn("/parent/child");
when(result.getName()).thenReturn("child");
when(result.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "alias"));
final Resource secondResult = mock(Resource.class);
when(secondResult.getParent()).thenReturn(parent);
when(secondResult.getPath()).thenReturn("/parent/child2");
when(secondResult.getName()).thenReturn("child2");
when(secondResult.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "alias"));
when(resourceResolver.findResources(anyString(), eq("sql"))).thenAnswer(new Answer<Iterator<Resource>>() {
@Override
public Iterator<Resource> answer(InvocationOnMock invocation) throws Throwable {
if (invocation.getArguments()[0].toString().contains(ResourceResolverImpl.PROP_ALIAS)) {
return Arrays.asList(result, secondResult).iterator();
} else {
return Collections.<Resource> emptySet().iterator();
}
}
});
mapEntries.doInit();
Map<String, String> aliasMap = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMap);
assertTrue(aliasMap.containsKey("alias"));
assertEquals("child", aliasMap.get("alias"));
}
@Test
public void test_vanity_path_registration() throws Exception {
// specifically making this a weird value because we want to verify that
// the configuration value is being used
int DEFAULT_VANITY_STATUS = 333333;
when(resourceResolverFactory.getDefaultVanityPathRedirectStatus()).thenReturn(DEFAULT_VANITY_STATUS);
final List<Resource> resources = new ArrayList<>();
Resource justVanityPath = mock(Resource.class, "justVanityPath");
when(justVanityPath.getPath()).thenReturn("/justVanityPath");
when(justVanityPath.getName()).thenReturn("justVanityPath");
when(justVanityPath.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/justVanityPath"));
resources.add(justVanityPath);
Resource badVanityPath = mock(Resource.class, "badVanityPath");
when(badVanityPath.getPath()).thenReturn("/badVanityPath");
when(badVanityPath.getName()).thenReturn("badVanityPath");
when(badVanityPath.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/content/mypage/en-us-{132"));
resources.add(badVanityPath);
Resource redirectingVanityPath = mock(Resource.class, "redirectingVanityPath");
when(redirectingVanityPath.getPath()).thenReturn("/redirectingVanityPath");
when(redirectingVanityPath.getName()).thenReturn("redirectingVanityPath");
when(redirectingVanityPath.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/redirectingVanityPath", "sling:redirect", true));
resources.add(redirectingVanityPath);
Resource redirectingVanityPath301 = mock(Resource.class, "redirectingVanityPath301");
when(redirectingVanityPath301.getPath()).thenReturn("/redirectingVanityPath301");
when(redirectingVanityPath301.getName()).thenReturn("redirectingVanityPath301");
when(redirectingVanityPath301.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/redirectingVanityPath301", "sling:redirect", true, "sling:redirectStatus", 301));
resources.add(redirectingVanityPath301);
Resource vanityPathOnJcrContentParent = mock(Resource.class, "vanityPathOnJcrContentParent");
when(vanityPathOnJcrContentParent.getPath()).thenReturn("/vanityPathOnJcrContent");
when(vanityPathOnJcrContentParent.getName()).thenReturn("vanityPathOnJcrContent");
Resource vanityPathOnJcrContent = mock(Resource.class, "vanityPathOnJcrContent");
when(vanityPathOnJcrContent.getPath()).thenReturn("/vanityPathOnJcrContent/jcr:content");
when(vanityPathOnJcrContent.getName()).thenReturn("jcr:content");
when(vanityPathOnJcrContent.getParent()).thenReturn(vanityPathOnJcrContentParent);
when(vanityPathOnJcrContent.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/vanityPathOnJcrContent"));
resources.add(vanityPathOnJcrContent);
when(resourceResolver.findResources(anyString(), eq("sql"))).thenAnswer(new Answer<Iterator<Resource>>() {
@Override
public Iterator<Resource> answer(InvocationOnMock invocation) throws Throwable {
if (invocation.getArguments()[0].toString().contains("sling:vanityPath")) {
return resources.iterator();
} else {
return Collections.<Resource> emptySet().iterator();
}
}
});
mapEntries.doInit();
mapEntries.initializeVanityPaths();
List<MapEntry> entries = mapEntries.getResolveMaps();
assertEquals(8, entries.size());
for (MapEntry entry : entries) {
if (entry.getPattern().contains("/target/redirectingVanityPath301")) {
assertEquals(301, entry.getStatus());
assertFalse(entry.isInternal());
} else if (entry.getPattern().contains("/target/redirectingVanityPath")) {
assertEquals(DEFAULT_VANITY_STATUS, entry.getStatus());
assertFalse(entry.isInternal());
} else if (entry.getPattern().contains("/target/justVanityPath")) {
assertTrue(entry.isInternal());
} else if (entry.getPattern().contains("/target/vanityPathOnJcrContent")) {
for (String redirect : entry.getRedirect()) {
assertFalse(redirect.contains("jcr:content"));
}
}
}
Field field = MapEntries.class.getDeclaredField("vanityTargets");
field.setAccessible(true);
@SuppressWarnings("unchecked")
Map<String, List<String>> vanityTargets = (Map<String, List<String>>) field.get(mapEntries);
assertEquals(4, vanityTargets.size());
}
@Test
public void test_vanity_path_updates() throws Exception {
Resource parent = mock(Resource.class, "parent");
when(parent.getPath()).thenReturn("/foo/parent");
when(parent.getName()).thenReturn("parent");
when(parent.getValueMap()).thenReturn(new ValueMapDecorator(Collections.<String, Object>emptyMap()));
when(resourceResolver.getResource(parent.getPath())).thenReturn(parent);
Resource child = mock(Resource.class, "jcrcontent");
when(child.getPath()).thenReturn("/foo/parent/jcr:content");
when(child.getName()).thenReturn("jcr:content");
when(child.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/found"));
when(child.getParent()).thenReturn(parent);
when(parent.getChild(child.getName())).thenReturn(child);
when(resourceResolver.getResource(child.getPath())).thenReturn(child);
when(resourceResolver.findResources(anyString(), eq("sql"))).thenAnswer(new Answer<Iterator<Resource>>() {
@Override
public Iterator<Resource> answer(InvocationOnMock invocation) throws Throwable {
return Collections.<Resource> emptySet().iterator();
}
});
mapEntries.doInit();
mapEntries.initializeVanityPaths();
// map entries should have no alias atm
assertTrue( mapEntries.getResolveMaps().isEmpty());
// add parent
mapEntries.onChange(Arrays.asList(new ResourceChange(ChangeType.ADDED, parent.getPath(), false)));
assertTrue( mapEntries.getResolveMaps().isEmpty());
// add child
mapEntries.onChange(Arrays.asList(new ResourceChange(ChangeType.ADDED, child.getPath(), false)));
// two entries for the vanity path
List<MapEntry> entries = mapEntries.getResolveMaps();
assertEquals(2, entries.size());
for (MapEntry entry : entries) {
assertTrue(entry.getPattern().contains("/target/found"));
}
// update parent - no change
mapEntries.onChange(Arrays.asList(new ResourceChange(ChangeType.CHANGED, parent.getPath(), false)));
entries = mapEntries.getResolveMaps();
assertEquals(2, entries.size());
for (MapEntry entry : entries) {
assertTrue(entry.getPattern().contains("/target/found"));
}
// update child - no change
mapEntries.onChange(Arrays.asList(new ResourceChange(ChangeType.CHANGED, child.getPath(), false)));
entries = mapEntries.getResolveMaps();
assertEquals(2, entries.size());
for (MapEntry entry : entries) {
assertTrue(entry.getPattern().contains("/target/found"));
}
// remove child - empty again
when(resourceResolver.getResource(child.getPath())).thenReturn(null);
when(parent.getChild(child.getName())).thenReturn(null);
mapEntries.onChange(Arrays.asList(new ResourceChange(ChangeType.REMOVED, child.getPath(), false)));
assertTrue( mapEntries.getResolveMaps().isEmpty());
// remove parent - still empty
when(resourceResolver.getResource(parent.getPath())).thenReturn(null);
mapEntries.onChange(Arrays.asList(new ResourceChange(ChangeType.REMOVED, parent.getPath(), false)));
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"};
final String[] invalidPaths = {"/libs/denied/a", "/libs/denied/b/c", "/nowhere"};
final List<Resource> resources = new ArrayList<>();
for(final String val : validPaths) {
resources.add(getVanityPathResource(val));
}
for(final String val : invalidPaths) {
resources.add(getVanityPathResource(val));
}
when(resourceResolver.findResources(anyString(), eq("sql"))).thenAnswer(new Answer<Iterator<Resource>>() {
@Override
public Iterator<Resource> answer(InvocationOnMock invocation) throws Throwable {
if (invocation.getArguments()[0].toString().contains("sling:vanityPath")) {
return resources.iterator();
} else {
return Collections.<Resource> emptySet().iterator();
}
}
});
mapEntries.doInit();
mapEntries.initializeVanityPaths();
List<MapEntry> entries = mapEntries.getResolveMaps();
// each valid resource results in 2 entries
assertEquals(validPaths.length * 2, entries.size());
final Set<String> resultSet = new HashSet<>();
for(final String p : validPaths) {
resultSet.add(p + "$1");
resultSet.add(p + ".html");
}
for (final MapEntry entry : entries) {
assertTrue(resultSet.remove(entry.getRedirect()[0]));
}
}
@Test
public void test_getActualContentPath() throws Exception {
Method method = MapEntries.class.getDeclaredMethod("getActualContentPath", String.class);
method.setAccessible(true);
String actualContent = (String) method.invoke(mapEntries, "/content");
assertEquals("/content", actualContent);
actualContent = (String) method.invoke(mapEntries, "/content/jcr:content");
assertEquals("/content", actualContent);
}
@Test
public void test_getMapEntryRedirect() throws Exception {
Method method = MapEntries.class.getDeclaredMethod("getMapEntryRedirect", MapEntry.class);
method.setAccessible(true);
MapEntry mapEntry = new MapEntry("/content", -1, false, 0, "/content");
String actualContent = (String) method.invoke(mapEntries, mapEntry);
assertEquals("/content", actualContent);
mapEntry = new MapEntry("/content", -1, false, 0, "/content$1");
actualContent = (String) method.invoke(mapEntries, mapEntry);
assertEquals("/content", actualContent);
mapEntry = new MapEntry("/content", -1, false, 0, "/content.html");
actualContent = (String) method.invoke(mapEntries, mapEntry);
assertEquals("/content", actualContent);
}
@SuppressWarnings("unchecked")
@Test
public void test_doAddVanity() throws Exception {
List<MapEntry> entries = mapEntries.getResolveMaps();
assertEquals(0, entries.size());
Field field = MapEntries.class.getDeclaredField("vanityTargets");
field.setAccessible(true);
Map<String, List<String>> vanityTargets = (Map<String, List<String>>) field.get(mapEntries);
assertEquals(0, vanityTargets.size());
final Method addResource = MapEntries.class.getDeclaredMethod("addResource", String.class, AtomicBoolean.class);
addResource.setAccessible(true);
Resource justVanityPath = mock(Resource.class, "justVanityPath");
when(resourceResolver.getResource("/justVanityPath")).thenReturn(justVanityPath);
when(justVanityPath.getPath()).thenReturn("/justVanityPath");
when(justVanityPath.getName()).thenReturn("justVanityPath");
when(justVanityPath.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/justVanityPath"));
addResource.invoke(mapEntries, "/justVanityPath", new AtomicBoolean());
entries = mapEntries.getResolveMaps();
assertEquals(2, entries.size());
Field vanityCounter = MapEntries.class.getDeclaredField("vanityCounter");
vanityCounter.setAccessible(true);
AtomicLong counter = (AtomicLong) vanityCounter.get(mapEntries);
assertEquals(2, counter.longValue());
//bad vanity
Resource badVanityPath = mock(Resource.class, "badVanityPath");
when(resourceResolver.getResource("/badVanityPath")).thenReturn(badVanityPath);
when(badVanityPath.getPath()).thenReturn("/badVanityPath");
when(badVanityPath.getName()).thenReturn("badVanityPath");
when(badVanityPath.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/content/mypage/en-us-{132"));
addResource.invoke(mapEntries, "/badVanityPath", new AtomicBoolean());
assertEquals(2, entries.size());
vanityTargets = (Map<String, List<String>>) field.get(mapEntries);
assertEquals(1, vanityTargets.size());
//vanity under jcr:content
Resource vanityPathOnJcrContentParent = mock(Resource.class, "vanityPathOnJcrContentParent");
when(vanityPathOnJcrContentParent.getPath()).thenReturn("/vanityPathOnJcrContent");
when(vanityPathOnJcrContentParent.getName()).thenReturn("vanityPathOnJcrContent");
Resource vanityPathOnJcrContent = mock(Resource.class, "vanityPathOnJcrContent");
when(resourceResolver.getResource("/vanityPathOnJcrContent/jcr:content")).thenReturn(vanityPathOnJcrContent);
when(vanityPathOnJcrContent.getPath()).thenReturn("/vanityPathOnJcrContent/jcr:content");
when(vanityPathOnJcrContent.getName()).thenReturn("jcr:content");
when(vanityPathOnJcrContent.getParent()).thenReturn(vanityPathOnJcrContentParent);
when(vanityPathOnJcrContent.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/vanityPathOnJcrContent"));
addResource.invoke(mapEntries, "/vanityPathOnJcrContent/jcr:content", new AtomicBoolean());
entries = mapEntries.getResolveMaps();
assertEquals(4, entries.size());
counter = (AtomicLong) vanityCounter.get(mapEntries);
assertEquals(4, counter.longValue());
vanityTargets = (Map<String, List<String>>) field.get(mapEntries);
assertEquals(2, vanityTargets.size());
assertNull(vanityTargets.get("/vanityPathOnJcrContent/jcr:content"));
assertNotNull(vanityTargets.get("/vanityPathOnJcrContent"));
}
@SuppressWarnings("unchecked")
@Test
public void test_doAddVanity_1() throws Exception {
when(this.resourceResolverFactory.getMaxCachedVanityPathEntries()).thenReturn(10L);
List<MapEntry> entries = mapEntries.getResolveMaps();
assertEquals(0, entries.size());
Field field = MapEntries.class.getDeclaredField("vanityTargets");
field.setAccessible(true);
Map<String, List<String>> vanityTargets = (Map<String, List<String>>) field.get(mapEntries);
assertEquals(0, vanityTargets.size());
final Method addResource = MapEntries.class.getDeclaredMethod("addResource", String.class, AtomicBoolean.class);
addResource.setAccessible(true);
Resource justVanityPath = mock(Resource.class, "justVanityPath");
when(resourceResolver.getResource("/justVanityPath")).thenReturn(justVanityPath);
when(justVanityPath.getPath()).thenReturn("/justVanityPath");
when(justVanityPath.getName()).thenReturn("justVanityPath");
when(justVanityPath.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/justVanityPath"));
addResource.invoke(mapEntries, "/justVanityPath", new AtomicBoolean());
entries = mapEntries.getResolveMaps();
assertEquals(2, entries.size());
Field vanityCounter = MapEntries.class.getDeclaredField("vanityCounter");
vanityCounter.setAccessible(true);
AtomicLong counter = (AtomicLong) vanityCounter.get(mapEntries);
assertEquals(2, counter.longValue());
//bad vanity
Resource badVanityPath = mock(Resource.class, "badVanityPath");
when(resourceResolver.getResource("/badVanityPath")).thenReturn(badVanityPath);
when(badVanityPath.getPath()).thenReturn("/badVanityPath");
when(badVanityPath.getName()).thenReturn("badVanityPath");
when(badVanityPath.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/content/mypage/en-us-{132"));
addResource.invoke(mapEntries, "/badVanityPath", new AtomicBoolean());
assertEquals(2, entries.size());
vanityTargets = (Map<String, List<String>>) field.get(mapEntries);
assertEquals(1, vanityTargets.size());
//vanity under jcr:content
Resource vanityPathOnJcrContentParent = mock(Resource.class, "vanityPathOnJcrContentParent");
when(vanityPathOnJcrContentParent.getPath()).thenReturn("/vanityPathOnJcrContent");
when(vanityPathOnJcrContentParent.getName()).thenReturn("vanityPathOnJcrContent");
Resource vanityPathOnJcrContent = mock(Resource.class, "vanityPathOnJcrContent");
when(resourceResolver.getResource("/vanityPathOnJcrContent/jcr:content")).thenReturn(vanityPathOnJcrContent);
when(vanityPathOnJcrContent.getPath()).thenReturn("/vanityPathOnJcrContent/jcr:content");
when(vanityPathOnJcrContent.getName()).thenReturn("jcr:content");
when(vanityPathOnJcrContent.getParent()).thenReturn(vanityPathOnJcrContentParent);
when(vanityPathOnJcrContent.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/vanityPathOnJcrContent"));
addResource.invoke(mapEntries, "/vanityPathOnJcrContent/jcr:content", new AtomicBoolean());
entries = mapEntries.getResolveMaps();
assertEquals(4, entries.size());
counter = (AtomicLong) vanityCounter.get(mapEntries);
assertEquals(4, counter.longValue());
vanityTargets = (Map<String, List<String>>) field.get(mapEntries);
assertEquals(2, vanityTargets.size());
assertNull(vanityTargets.get("/vanityPathOnJcrContent/jcr:content"));
assertNotNull(vanityTargets.get("/vanityPathOnJcrContent"));
}
@SuppressWarnings("unchecked")
@Test
public void test_doUpdateVanity() throws Exception {
Field field0 = MapEntries.class.getDeclaredField("resolveMapsMap");
field0.setAccessible(true);
Map<String, List<MapEntry>> resolveMapsMap = (Map<String, List<MapEntry>>) field0.get(mapEntries);
assertEquals(1, resolveMapsMap.size());
Field field = MapEntries.class.getDeclaredField("vanityTargets");
field.setAccessible(true);
Map<String, List<String>> vanityTargets = (Map<String, List<String>>) field.get(mapEntries);
assertEquals(0, vanityTargets.size());
final Method addResource = MapEntries.class.getDeclaredMethod("addResource", String.class, AtomicBoolean.class);
addResource.setAccessible(true);
final Method updateResource = MapEntries.class.getDeclaredMethod("updateResource", String.class, AtomicBoolean.class);
updateResource.setAccessible(true);
Resource justVanityPath = mock(Resource.class, "justVanityPath");
when(resourceResolver.getResource("/justVanityPath")).thenReturn(justVanityPath);
when(justVanityPath.getPath()).thenReturn("/justVanityPath");
when(justVanityPath.getName()).thenReturn("justVanityPath");
when(justVanityPath.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/justVanityPath"));
addResource.invoke(mapEntries, "/justVanityPath", new AtomicBoolean());
assertEquals(2, resolveMapsMap.size());
assertEquals(1, vanityTargets.size());
assertNotNull(resolveMapsMap.get("/target/justVanityPath"));
assertNull(resolveMapsMap.get("/target/justVanityPathUpdated"));
assertEquals(1, vanityTargets.get("/justVanityPath").size());
assertEquals("/target/justVanityPath", vanityTargets.get("/justVanityPath").get(0));
//update vanity path
when(justVanityPath.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/justVanityPathUpdated"));
updateResource.invoke(mapEntries, "/justVanityPath", new AtomicBoolean());
assertEquals(2, resolveMapsMap.size());
assertEquals(1, vanityTargets.size());
assertNull(resolveMapsMap.get("/target/justVanityPath"));
assertNotNull(resolveMapsMap.get("/target/justVanityPathUpdated"));
assertEquals(1, vanityTargets.get("/justVanityPath").size());
assertEquals("/target/justVanityPathUpdated", vanityTargets.get("/justVanityPath").get(0));
//vanity under jcr:content
Resource vanityPathOnJcrContentParent = mock(Resource.class, "vanityPathOnJcrContentParent");
when(vanityPathOnJcrContentParent.getPath()).thenReturn("/vanityPathOnJcrContent");
when(vanityPathOnJcrContentParent.getName()).thenReturn("vanityPathOnJcrContent");
when(vanityPathOnJcrContentParent.getValueMap()).thenReturn(buildValueMap());
Resource vanityPathOnJcrContent = mock(Resource.class, "vanityPathOnJcrContent");
when(resourceResolver.getResource("/vanityPathOnJcrContent/jcr:content")).thenReturn(vanityPathOnJcrContent);
when(vanityPathOnJcrContent.getPath()).thenReturn("/vanityPathOnJcrContent/jcr:content");
when(vanityPathOnJcrContent.getName()).thenReturn("jcr:content");
when(vanityPathOnJcrContent.getParent()).thenReturn(vanityPathOnJcrContentParent);
when(vanityPathOnJcrContent.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/vanityPathOnJcrContent"));
addResource.invoke(mapEntries, "/vanityPathOnJcrContent/jcr:content", new AtomicBoolean());
assertEquals(3, resolveMapsMap.size());
assertEquals(2, vanityTargets.size());
assertNotNull(resolveMapsMap.get("/target/vanityPathOnJcrContent"));
assertNull(resolveMapsMap.get("/target/vanityPathOnJcrContentUpdated"));
assertEquals(1, vanityTargets.get("/vanityPathOnJcrContent").size());
assertEquals("/target/vanityPathOnJcrContent", vanityTargets.get("/vanityPathOnJcrContent").get(0));
//update vanity path
when(vanityPathOnJcrContent.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/vanityPathOnJcrContentUpdated"));
updateResource.invoke(mapEntries, "/vanityPathOnJcrContent/jcr:content", new AtomicBoolean());
assertEquals(3, resolveMapsMap.size());
assertEquals(2, vanityTargets.size());
assertNull(resolveMapsMap.get("/target/vanityPathOnJcrContent"));
assertNotNull(resolveMapsMap.get("/target/vanityPathOnJcrContentUpdated"));
assertEquals(1, vanityTargets.get("/vanityPathOnJcrContent").size());
assertEquals("/target/vanityPathOnJcrContentUpdated", vanityTargets.get("/vanityPathOnJcrContent").get(0));
}
@SuppressWarnings("unchecked")
@Test
public void test_doRemoveVanity() throws Exception {
Field field0 = MapEntries.class.getDeclaredField("resolveMapsMap");
field0.setAccessible(true);
Map<String, List<MapEntry>> resolveMapsMap = (Map<String, List<MapEntry>>) field0.get(mapEntries);
assertEquals(1, resolveMapsMap.size());
Field field = MapEntries.class.getDeclaredField("vanityTargets");
field.setAccessible(true);
Map<String, List<String>> vanityTargets = (Map<String, List<String>>) field.get(mapEntries);
assertEquals(0, vanityTargets.size());
final Method addResource = MapEntries.class.getDeclaredMethod("addResource", String.class, AtomicBoolean.class);
addResource.setAccessible(true);
Method method1 = MapEntries.class.getDeclaredMethod("doRemoveVanity", String.class);
method1.setAccessible(true);
Resource justVanityPath = mock(Resource.class, "justVanityPath");
when(resourceResolver.getResource("/justVanityPath")).thenReturn(justVanityPath);
when(justVanityPath.getPath()).thenReturn("/justVanityPath");
when(justVanityPath.getName()).thenReturn("justVanityPath");
when(justVanityPath.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/justVanityPath"));
addResource.invoke(mapEntries, "/justVanityPath", new AtomicBoolean());
Field vanityCounter = MapEntries.class.getDeclaredField("vanityCounter");
vanityCounter.setAccessible(true);
AtomicLong counter = (AtomicLong) vanityCounter.get(mapEntries);
assertEquals(2, counter.longValue());
assertEquals(2, resolveMapsMap.size());
assertEquals(1, vanityTargets.size());
assertNotNull(resolveMapsMap.get("/target/justVanityPath"));
assertEquals(1, vanityTargets.get("/justVanityPath").size());
assertEquals("/target/justVanityPath", vanityTargets.get("/justVanityPath").get(0));
//remove vanity path
method1.invoke(mapEntries, "/justVanityPath");
counter = (AtomicLong) vanityCounter.get(mapEntries);
assertEquals(0, counter.longValue());
assertEquals(1, resolveMapsMap.size());
assertEquals(0, vanityTargets.size());
assertNull(resolveMapsMap.get("/target/justVanityPath"));
//vanity under jcr:content
Resource vanityPathOnJcrContentParent = mock(Resource.class, "vanityPathOnJcrContentParent");
when(vanityPathOnJcrContentParent.getPath()).thenReturn("/vanityPathOnJcrContent");
when(vanityPathOnJcrContentParent.getName()).thenReturn("vanityPathOnJcrContent");
Resource vanityPathOnJcrContent = mock(Resource.class, "vanityPathOnJcrContent");
when(resourceResolver.getResource("/vanityPathOnJcrContent/jcr:content")).thenReturn(vanityPathOnJcrContent);
when(vanityPathOnJcrContent.getPath()).thenReturn("/vanityPathOnJcrContent/jcr:content");
when(vanityPathOnJcrContent.getName()).thenReturn("jcr:content");
when(vanityPathOnJcrContent.getParent()).thenReturn(vanityPathOnJcrContentParent);
when(vanityPathOnJcrContent.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/vanityPathOnJcrContent"));
addResource.invoke(mapEntries, "/vanityPathOnJcrContent/jcr:content", new AtomicBoolean());
assertEquals(2, resolveMapsMap.size());
assertEquals(1, vanityTargets.size());
assertNotNull(resolveMapsMap.get("/target/vanityPathOnJcrContent"));
assertEquals(1,vanityTargets.get("/vanityPathOnJcrContent").size());
assertEquals("/target/vanityPathOnJcrContent", vanityTargets.get("/vanityPathOnJcrContent").get(0));
//remove vanity path
method1.invoke(mapEntries, "/vanityPathOnJcrContent/jcr:content");
assertEquals(1, resolveMapsMap.size());
assertEquals(0, vanityTargets.size());
assertNull(resolveMapsMap.get("/target/vanityPathOnJcrContent"));
}
/*
@SuppressWarnings("unchecked")
@Test
public void test_doUpdateVanityOrder() throws Exception {
Field field0 = MapEntries.class.getDeclaredField("resolveMapsMap");
field0.setAccessible(true);
Map<String, List<MapEntry>> resolveMapsMap = (Map<String, List<MapEntry>>) field0.get(mapEntries);
assertEquals(1, resolveMapsMap.size());
Field field = MapEntries.class.getDeclaredField("vanityTargets");
field.setAccessible(true);
Map<String, List<String>> vanityTargets = (Map<String, List<String>>) field.get(mapEntries);
assertEquals(0, vanityTargets.size());
Method method = MapEntries.class.getDeclaredMethod("doAddVanity", String.class);
method.setAccessible(true);
Method method1 = MapEntries.class.getDeclaredMethod("doUpdateVanityOrder", String.class, boolean.class);
method1.setAccessible(true);
Resource justVanityPath = mock(Resource.class, "justVanityPath");
when(resourceResolver.getResource("/justVanityPath")).thenReturn(justVanityPath);
when(justVanityPath.getPath()).thenReturn("/justVanityPath");
when(justVanityPath.getName()).thenReturn("justVanityPath");
when(justVanityPath.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/justVanityPath"));
method.invoke(mapEntries, "/justVanityPath");
Resource justVanityPath2 = mock(Resource.class, "justVanityPath2");
when(resourceResolver.getResource("/justVanityPath2")).thenReturn(justVanityPath2);
when(justVanityPath2.getPath()).thenReturn("/justVanityPath2");
when(justVanityPath2.getName()).thenReturn("justVanityPath2");
when(justVanityPath2.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/justVanityPath","sling:vanityOrder", 100));
method.invoke(mapEntries, "/justVanityPath2");
assertEquals(2, resolveMapsMap.size());
assertEquals(2, vanityTargets.size());
assertNotNull(resolveMapsMap.get("/target/justVanityPath"));
Iterator <MapEntry> iterator = resolveMapsMap.get("/target/justVanityPath").iterator();
assertEquals("/justVanityPath2$1", iterator.next().getRedirect()[0]);
assertEquals("/justVanityPath$1", iterator.next().getRedirect()[0]);
assertEquals("/justVanityPath2.html", iterator.next().getRedirect()[0]);
assertEquals("/justVanityPath.html", iterator.next().getRedirect()[0]);
assertFalse(iterator.hasNext());
when(justVanityPath.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/justVanityPath","sling:vanityOrder", 1000));
method1.invoke(mapEntries, "/justVanityPath",false);
iterator = resolveMapsMap.get("/target/justVanityPath").iterator();
assertEquals("/justVanityPath$1", iterator.next().getRedirect()[0]);
assertEquals("/justVanityPath2$1", iterator.next().getRedirect()[0]);
assertEquals("/justVanityPath.html", iterator.next().getRedirect()[0]);
assertEquals("/justVanityPath2.html", iterator.next().getRedirect()[0]);
assertFalse(iterator.hasNext());
when(justVanityPath.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/justVanityPath"));
method1.invoke(mapEntries, "/justVanityPath",true);
iterator = resolveMapsMap.get("/target/justVanityPath").iterator();
assertEquals("/justVanityPath2$1", iterator.next().getRedirect()[0]);
assertEquals("/justVanityPath$1", iterator.next().getRedirect()[0]);
assertEquals("/justVanityPath2.html", iterator.next().getRedirect()[0]);
assertEquals("/justVanityPath.html", iterator.next().getRedirect()[0]);
assertFalse(iterator.hasNext());
}
*/
//SLING-3727
@Test
public void test_doAddAliasAttributesWithDisableAliasOptimization() throws Exception {
final Method addResource = MapEntries.class.getDeclaredMethod("addResource", String.class, AtomicBoolean.class);
addResource.setAccessible(true);
when(resourceResolverFactory.isOptimizeAliasResolutionEnabled()).thenReturn(false);
mapEntries = new MapEntries(resourceResolverFactory, bundleContext, eventAdmin);
Resource parent = mock(Resource.class);
when(parent.getPath()).thenReturn("/parent");
final Resource result = mock(Resource.class);
when(resourceResolver.getResource("/parent/child")).thenReturn(result);
when(result.getParent()).thenReturn(parent);
when(result.getPath()).thenReturn("/parent/child");
when(result.getName()).thenReturn("child");
when(result.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "alias"));
addResource.invoke(mapEntries, "/parent/child", new AtomicBoolean());
Map<String, String> aliasMap = mapEntries.getAliasMap("/parent");
assertNull(aliasMap);
}
//SLING-3727
@Test
public void test_doUpdateAttributesWithDisableAliasOptimization() throws Exception {
final Method addResource = MapEntries.class.getDeclaredMethod("addResource", String.class, AtomicBoolean.class);
addResource.setAccessible(true);
when(resourceResolverFactory.isOptimizeAliasResolutionEnabled()).thenReturn(false);
mapEntries = new MapEntries(resourceResolverFactory, bundleContext, eventAdmin);
Resource parent = mock(Resource.class);
when(parent.getPath()).thenReturn("/parent");
final Resource result = mock(Resource.class);
when(resourceResolver.getResource("/parent/child")).thenReturn(result);
when(result.getParent()).thenReturn(parent);
when(result.getPath()).thenReturn("/parent/child");
when(result.getName()).thenReturn("child");
when(result.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "alias"));
addResource.invoke(mapEntries, "/parent/child", new AtomicBoolean());
Map<String, String> aliasMap = mapEntries.getAliasMap("/parent");
assertNull(aliasMap);
}
//SLING-3727
@Test
public void test_doRemoveAttributessWithDisableAliasOptimization() throws Exception {
final Method removeAlias = MapEntries.class.getDeclaredMethod("removeAlias", String.class, String.class, AtomicBoolean.class);
removeAlias.setAccessible(true);
when(resourceResolverFactory.isOptimizeAliasResolutionEnabled()).thenReturn(false);
mapEntries = new MapEntries(resourceResolverFactory, bundleContext, eventAdmin);
Resource parent = mock(Resource.class);
when(parent.getPath()).thenReturn("/parent");
final Resource result = mock(Resource.class);
when(resourceResolver.getResource("/parent/child")).thenReturn(result);
when(result.getParent()).thenReturn(parent);
when(result.getPath()).thenReturn("/parent/child");
when(result.getName()).thenReturn("child");
when(result.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "alias"));
removeAlias.invoke(mapEntries, "/parent", "/parent/child", new AtomicBoolean());
Map<String, String> aliasMap = mapEntries.getAliasMap("/parent");
assertNull(aliasMap);
}
@Test
public void test_doAddAlias() throws Exception {
final Method addResource = MapEntries.class.getDeclaredMethod("addResource", String.class, AtomicBoolean.class);
addResource.setAccessible(true);
assertEquals(0, aliasMap.size());
Resource parent = mock(Resource.class);
when(parent.getPath()).thenReturn("/parent");
final Resource result = mock(Resource.class);
when(resourceResolver.getResource("/parent/child")).thenReturn(result);
when(result.getParent()).thenReturn(parent);
when(result.getPath()).thenReturn("/parent/child");
when(result.getName()).thenReturn("child");
when(result.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "alias"));
addResource.invoke(mapEntries, "/parent/child", new AtomicBoolean());
Map<String, String> aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertTrue(aliasMapEntry.containsKey("alias"));
assertEquals("child", aliasMapEntry.get("alias"));
assertEquals(1, aliasMap.size());
//test_that_duplicate_alias_doesnt_replace_first_alias
final Resource secondResult = mock(Resource.class);
when(resourceResolver.getResource("/parent/child2")).thenReturn(secondResult);
when(secondResult.getParent()).thenReturn(parent);
when(secondResult.getPath()).thenReturn("/parent/child2");
when(secondResult.getName()).thenReturn("child2");
when(secondResult.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "alias"));
addResource.invoke(mapEntries, "/parent/child2", new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertTrue(aliasMapEntry.containsKey("alias"));
assertEquals("child", aliasMapEntry.get("alias"));
assertEquals(1, aliasMap.size());
//testing jcr:content node
final Resource jcrContentResult = mock(Resource.class);
when(resourceResolver.getResource("/parent/child/jcr:content")).thenReturn(jcrContentResult);
when(jcrContentResult.getParent()).thenReturn(result);
when(jcrContentResult.getPath()).thenReturn("/parent/child/jcr:content");
when(jcrContentResult.getName()).thenReturn("jcr:content");
when(jcrContentResult.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "aliasJcrContent"));
addResource.invoke(mapEntries, "/parent/child/jcr:content", new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertEquals(2, aliasMapEntry.size());
assertTrue(aliasMapEntry.containsKey("aliasJcrContent"));
assertEquals("child", aliasMapEntry.get("aliasJcrContent"));
assertEquals(1, aliasMap.size());
}
@Test
public void test_doAddAlias2() throws Exception {
final Method addResource = MapEntries.class.getDeclaredMethod("addResource", String.class, AtomicBoolean.class);
addResource.setAccessible(true);
assertEquals(0, aliasMap.size());
Resource parent = mock(Resource.class);
when(parent.getPath()).thenReturn("/");
final Resource result = mock(Resource.class);
when(resourceResolver.getResource("/parent")).thenReturn(result);
when(result.getParent()).thenReturn(parent);
when(result.getPath()).thenReturn("/parent");
when(result.getName()).thenReturn("parent");
when(result.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "alias"));
addResource.invoke(mapEntries, "/parent", new AtomicBoolean());
Map<String, String> aliasMapEntry = mapEntries.getAliasMap("/");
assertNotNull(aliasMapEntry);
assertTrue(aliasMapEntry.containsKey("alias"));
assertEquals("parent", aliasMapEntry.get("alias"));
assertEquals(1, aliasMap.size());
//test_that_duplicate_alias_doesnt_replace_first_alias
final Resource secondResult = mock(Resource.class);
when(resourceResolver.getResource("/parent2")).thenReturn(secondResult);
when(secondResult.getParent()).thenReturn(parent);
when(secondResult.getPath()).thenReturn("/parent2");
when(secondResult.getName()).thenReturn("parent2");
when(secondResult.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "alias"));
addResource.invoke(mapEntries, "/parent2", new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/");
assertNotNull(aliasMapEntry);
assertTrue(aliasMapEntry.containsKey("alias"));
assertEquals("parent", aliasMapEntry.get("alias"));
assertEquals(1, aliasMap.size());
//testing jcr:content node
final Resource jcrContentResult = mock(Resource.class);
when(resourceResolver.getResource("/parent/jcr:content")).thenReturn(jcrContentResult);
when(jcrContentResult.getParent()).thenReturn(result);
when(jcrContentResult.getPath()).thenReturn("/parent/jcr:content");
when(jcrContentResult.getName()).thenReturn("jcr:content");
when(jcrContentResult.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "aliasJcrContent"));
addResource.invoke(mapEntries, "/parent/jcr:content", new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/");
assertNotNull(aliasMapEntry);
assertEquals(2, aliasMapEntry.size());
assertTrue(aliasMapEntry.containsKey("aliasJcrContent"));
assertEquals("parent", aliasMapEntry.get("aliasJcrContent"));
assertEquals(1, aliasMap.size());
}
@Test
public void test_doUpdateAlias() throws Exception {
final Method updateResource = MapEntries.class.getDeclaredMethod("updateResource", String.class, AtomicBoolean.class);
updateResource.setAccessible(true);
assertEquals(0, aliasMap.size());
Resource parent = mock(Resource.class);
when(parent.getPath()).thenReturn("/parent");
final Resource result = mock(Resource.class);
when(resourceResolver.getResource("/parent/child")).thenReturn(result);
when(result.getParent()).thenReturn(parent);
when(result.getPath()).thenReturn("/parent/child");
when(result.getName()).thenReturn("child");
when(result.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "alias"));
updateResource.invoke(mapEntries, "/parent/child", new AtomicBoolean());
Map<String, String> aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertTrue(aliasMapEntry.containsKey("alias"));
assertFalse(aliasMapEntry.containsKey("aliasUpdated"));
assertEquals("child", aliasMapEntry.get("alias"));
assertEquals(1, aliasMap.size());
when(result.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "aliasUpdated"));
updateResource.invoke(mapEntries, "/parent/child", new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertFalse(aliasMapEntry.containsKey("alias"));
assertTrue(aliasMapEntry.containsKey("aliasUpdated"));
assertEquals("child", aliasMapEntry.get("aliasUpdated"));
assertEquals(1, aliasMap.size());
//testing jcr:content node update
final Resource jcrContentResult = mock(Resource.class);
when(resourceResolver.getResource("/parent/child/jcr:content")).thenReturn(jcrContentResult);
when(jcrContentResult.getParent()).thenReturn(result);
when(jcrContentResult.getPath()).thenReturn("/parent/child/jcr:content");
when(jcrContentResult.getName()).thenReturn("jcr:content");
when(jcrContentResult.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "aliasJcrContent"));
when(result.getChild("jcr:content")).thenReturn(jcrContentResult);
updateResource.invoke(mapEntries, "/parent/child/jcr:content", new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertEquals(2, aliasMapEntry.size());
assertTrue(aliasMapEntry.containsKey("aliasJcrContent"));
assertFalse(aliasMapEntry.containsKey("aliasJcrContentUpdated"));
assertEquals("child", aliasMapEntry.get("aliasJcrContent"));
assertEquals(1, aliasMap.size());
when(jcrContentResult.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "aliasJcrContentUpdated"));
updateResource.invoke(mapEntries, "/parent/child/jcr:content", new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertEquals(2, aliasMapEntry.size());
assertFalse(aliasMapEntry.containsKey("aliasJcrContent"));
assertTrue(aliasMapEntry.containsKey("aliasJcrContentUpdated"));
assertEquals("child", aliasMapEntry.get("aliasJcrContentUpdated"));
assertEquals(1, aliasMap.size());
//re-update alias
updateResource.invoke(mapEntries, "/parent/child", new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertEquals(2, aliasMapEntry.size());
assertFalse(aliasMapEntry.containsKey("alias"));
assertTrue(aliasMapEntry.containsKey("aliasUpdated"));
assertEquals("child", aliasMapEntry.get("aliasUpdated"));
//add another node with different alias and check that the update doesn't break anything (see also SLING-3728)
final Resource secondResult = mock(Resource.class);
when(resourceResolver.getResource("/parent/child2")).thenReturn(secondResult);
when(secondResult.getParent()).thenReturn(parent);
when(secondResult.getPath()).thenReturn("/parent/child2");
when(secondResult.getName()).thenReturn("child2");
when(secondResult.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "alias2"));
updateResource.invoke(mapEntries, "/parent/child2", new AtomicBoolean());
assertEquals(1, aliasMap.size());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertEquals(3, aliasMapEntry.size());
when(jcrContentResult.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "aliasJcrContentUpdated"));
updateResource.invoke(mapEntries, "/parent/child/jcr:content", new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertEquals(3, aliasMapEntry.size());
assertFalse(aliasMapEntry.containsKey("aliasJcrContent"));
assertTrue(aliasMapEntry.containsKey("aliasJcrContentUpdated"));
assertEquals("child", aliasMapEntry.get("aliasJcrContentUpdated"));
assertEquals(1, aliasMap.size());
when(result.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, null));
when(jcrContentResult.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "aliasJcrContentUpdated"));
updateResource.invoke(mapEntries, "/parent/child/jcr:content", new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertEquals(2, aliasMapEntry.size());
assertFalse(aliasMapEntry.containsKey("aliasJcrContent"));
assertTrue(aliasMapEntry.containsKey("aliasJcrContentUpdated"));
assertEquals("child", aliasMapEntry.get("aliasJcrContentUpdated"));
assertEquals(1, aliasMap.size());
}
@Test
public void test_doRemoveAlias() throws Exception {
final Method addResource = MapEntries.class.getDeclaredMethod("addResource", String.class, AtomicBoolean.class);
addResource.setAccessible(true);
final Method removeAlias = MapEntries.class.getDeclaredMethod("removeAlias", String.class, String.class, AtomicBoolean.class);
removeAlias.setAccessible(true);
// check that alias map is empty
assertEquals(0, aliasMap.size());
final Resource parent = mock(Resource.class);
when(parent.getPath()).thenReturn("/parent");
final Resource child = mock(Resource.class);
when(resourceResolver.getResource("/parent/child")).thenReturn(child);
when(child.getParent()).thenReturn(parent);
when(child.getPath()).thenReturn("/parent/child");
when(child.getName()).thenReturn("child");
when(child.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "alias"));
addResource.invoke(mapEntries, "/parent/child", new AtomicBoolean());
Map<String, String> aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertTrue(aliasMapEntry.containsKey("alias"));
assertEquals("child", aliasMapEntry.get("alias"));
assertEquals(1, aliasMap.size());
when(resourceResolver.getResource("/parent/child")).thenReturn(null);
removeAlias.invoke(mapEntries, "/parent", "/parent/child", new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNull(aliasMapEntry);
assertEquals(0, aliasMap.size());
//re-add node and test nodeDeletion true
when(resourceResolver.getResource("/parent/child")).thenReturn(child);
addResource.invoke(mapEntries, "/parent/child", new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertTrue(aliasMapEntry.containsKey("alias"));
assertEquals("child", aliasMapEntry.get("alias"));
assertEquals(1, aliasMap.size());
when(resourceResolver.getResource("/parent/child")).thenReturn(null);
removeAlias.invoke(mapEntries, "/parent", "/parent/child", new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNull(aliasMapEntry);
assertEquals(0, aliasMap.size());
}
@Test
public void test_doRemoveAlias2() throws Exception {
final Method addResource = MapEntries.class.getDeclaredMethod("addResource", String.class, AtomicBoolean.class);
addResource.setAccessible(true);
final Method removeAlias = MapEntries.class.getDeclaredMethod("removeAlias", String.class, String.class, AtomicBoolean.class);
removeAlias.setAccessible(true);
assertEquals(0, aliasMap.size());
Resource parent = mock(Resource.class);
when(parent.getPath()).thenReturn("/parent");
final Resource result = mock(Resource.class);
when(resourceResolver.getResource("/parent/child")).thenReturn(result);
when(result.getParent()).thenReturn(parent);
when(result.getPath()).thenReturn("/parent/child");
when(result.getName()).thenReturn("child");
when(result.getValueMap()).thenReturn(buildValueMap());
//testing jcr:content node removal
final Resource jcrContentResult = mock(Resource.class);
when(resourceResolver.getResource("/parent/child/jcr:content")).thenReturn(jcrContentResult);
when(jcrContentResult.getParent()).thenReturn(result);
when(jcrContentResult.getPath()).thenReturn("/parent/child/jcr:content");
when(jcrContentResult.getName()).thenReturn("jcr:content");
when(jcrContentResult.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "aliasJcrContent"));
when(result.getChild("jcr:content")).thenReturn(jcrContentResult);
addResource.invoke(mapEntries, "/parent/child/jcr:content", new AtomicBoolean());
Map<String, String> aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertTrue(aliasMapEntry.containsKey("aliasJcrContent"));
assertEquals("child", aliasMapEntry.get("aliasJcrContent"));
assertEquals(1, aliasMap.size());
when(resourceResolver.getResource("/parent/child/jcr:content")).thenReturn(null);
when(result.getChild("jcr:content")).thenReturn(null);
removeAlias.invoke(mapEntries, "/parent", "/parent/child/jcr:content", new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNull(aliasMapEntry);
assertEquals(0, aliasMap.size());
//re-add node and test nodeDeletion true
when(resourceResolver.getResource("/parent/child/jcr:content")).thenReturn(jcrContentResult);
when(result.getChild("jcr:content")).thenReturn(jcrContentResult);
addResource.invoke(mapEntries, "/parent/child/jcr:content", new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertTrue(aliasMapEntry.containsKey("aliasJcrContent"));
assertEquals("child", aliasMapEntry.get("aliasJcrContent"));
assertEquals(1, aliasMap.size());
when(resourceResolver.getResource("/parent/child/jcr:content")).thenReturn(null);
when(result.getChild("jcr:content")).thenReturn(null);
removeAlias.invoke(mapEntries, "/parent", "/parent/child/jcr:content", new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNull(aliasMapEntry);
assertEquals(0, aliasMap.size());
}
@Test
public void test_doRemoveAlias3() throws Exception {
final Method addResource = MapEntries.class.getDeclaredMethod("addResource", String.class, AtomicBoolean.class);
addResource.setAccessible(true);
final Method removeAlias = MapEntries.class.getDeclaredMethod("removeAlias", String.class, String.class, AtomicBoolean.class);
removeAlias.setAccessible(true);
assertEquals(0, aliasMap.size());
final Resource parentRsrc = mock(Resource.class);
when(parentRsrc.getPath()).thenReturn("/parent");
final Resource childRsrc = mock(Resource.class);
when(resourceResolver.getResource("/parent/child")).thenReturn(childRsrc);
when(childRsrc.getParent()).thenReturn(parentRsrc);
when(childRsrc.getPath()).thenReturn("/parent/child");
when(childRsrc.getName()).thenReturn("child");
when(childRsrc.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "alias"));
addResource.invoke(mapEntries, "/parent/child", new AtomicBoolean());
final Resource jcrContentResult = mock(Resource.class);
when(resourceResolver.getResource("/parent/child/jcr:content")).thenReturn(jcrContentResult);
when(jcrContentResult.getParent()).thenReturn(childRsrc);
when(jcrContentResult.getPath()).thenReturn("/parent/child/jcr:content");
when(jcrContentResult.getName()).thenReturn("jcr:content");
when(jcrContentResult.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "aliasJcrContent"));
when(childRsrc.getChild("jcr:content")).thenReturn(jcrContentResult);
addResource.invoke(mapEntries, "/parent/child/jcr:content", new AtomicBoolean());
// test with two nodes
assertEquals(1, aliasMap.size());
Map<String, String> aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertEquals(2, aliasMapEntry.size());
assertEquals("child", aliasMapEntry.get("aliasJcrContent"));
assertEquals("child", aliasMapEntry.get("alias"));
// remove child jcr:content node
when(resourceResolver.getResource("/parent/child/jcr:content")).thenReturn(null);
when(childRsrc.getChild("jcr:content")).thenReturn(null);
removeAlias.invoke(mapEntries, "/parent", "/parent/child/jcr:content", new AtomicBoolean());
// test with one node
assertEquals(1, aliasMap.size());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertEquals(1, aliasMapEntry.size());
assertEquals("child", aliasMapEntry.get("alias"));
// re-add the node and test /parent/child
when(resourceResolver.getResource("/parent/child/jcr:content")).thenReturn(jcrContentResult);
when(childRsrc.getChild("jcr:content")).thenReturn(jcrContentResult);
addResource.invoke(mapEntries, "/parent/child/jcr:content", new AtomicBoolean());
// STOP
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertEquals(2, aliasMapEntry.size());
assertEquals("child", aliasMapEntry.get("aliasJcrContent"));
assertEquals("child", aliasMapEntry.get("alias"));
when(resourceResolver.getResource("/parent/child")).thenReturn(null);
removeAlias.invoke(mapEntries, "/parent", "/parent/child", new AtomicBoolean());
when(resourceResolver.getResource("/parent/child")).thenReturn(childRsrc);
addResource.invoke(mapEntries, "/parent/child/jcr:content", new AtomicBoolean());
assertEquals(1, aliasMap.size());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertEquals(1, aliasMapEntry.size());
assertEquals("child", aliasMapEntry.get("aliasJcrContent"));
// re-add the node and test node removal
addResource.invoke(mapEntries, "/parent/child", new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertTrue(aliasMapEntry.containsKey("aliasJcrContent"));
assertEquals("child", aliasMapEntry.get("aliasJcrContent"));
assertEquals(2, aliasMapEntry.size());
when(resourceResolver.getResource("/parent/child/jcr:content")).thenReturn(null);
when(childRsrc.getChild("jcr:content")).thenReturn(null);
removeAlias.invoke(mapEntries, "/parent", "/parent/child/jcr:content", new AtomicBoolean());
assertEquals(1, aliasMap.size());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertEquals(1, aliasMapEntry.size());
// re-add the node and test node removal for /parent/child
when(resourceResolver.getResource("/parent/child/jcr:content")).thenReturn(jcrContentResult);
when(childRsrc.getChild("jcr:content")).thenReturn(jcrContentResult);
addResource.invoke(mapEntries, "/parent/child/jcr:content", new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertTrue(aliasMapEntry.containsKey("aliasJcrContent"));
assertEquals("child", aliasMapEntry.get("aliasJcrContent"));
assertEquals(2, aliasMapEntry.size());
when(resourceResolver.getResource("/parent/child")).thenReturn( null);
removeAlias.invoke(mapEntries, "/parent", "/parent/child", new AtomicBoolean());
assertEquals(0, aliasMap.size());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNull(aliasMapEntry);
}
@Test
public void test_doRemoveAlias4() throws Exception {
final Method addResource = MapEntries.class.getDeclaredMethod("addResource", String.class, AtomicBoolean.class);
addResource.setAccessible(true);
final Method removeAlias = MapEntries.class.getDeclaredMethod("removeAlias", String.class, String.class, AtomicBoolean.class);
removeAlias.setAccessible(true);
assertEquals(0, aliasMap.size());
Resource parent = mock(Resource.class);
when(parent.getPath()).thenReturn("/");
final Resource result = mock(Resource.class);
when(resourceResolver.getResource("/parent")).thenReturn(result);
when(result.getParent()).thenReturn(parent);
when(result.getPath()).thenReturn("/parent");
when(result.getName()).thenReturn("parent");
when(result.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "alias"));
addResource.invoke(mapEntries, "/parent", new AtomicBoolean());
Map<String, String> aliasMapEntry = mapEntries.getAliasMap("/");
assertNotNull(aliasMapEntry);
assertTrue(aliasMapEntry.containsKey("alias"));
assertEquals("parent", aliasMapEntry.get("alias"));
assertEquals(1, aliasMap.size());
when(resourceResolver.getResource("/parent")).thenReturn(null);
removeAlias.invoke(mapEntries, "/", "/parent", new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/");
assertNull(aliasMapEntry);
assertEquals(0, aliasMap.size());
//re-add node and test nodeDeletion true
when(resourceResolver.getResource("/parent")).thenReturn(result);
addResource.invoke(mapEntries, "/parent", new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/");
assertNotNull(aliasMapEntry);
assertTrue(aliasMapEntry.containsKey("alias"));
assertEquals("parent", aliasMapEntry.get("alias"));
assertEquals(1, aliasMap.size());
when(resourceResolver.getResource("/parent")).thenReturn(null);
removeAlias.invoke(mapEntries, "/", "/parent", new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/");
assertNull(aliasMapEntry);
assertEquals(0, aliasMap.size());
}
@Test
public void test_doRemoveAlias5() throws Exception {
final Method addResource = MapEntries.class.getDeclaredMethod("addResource", String.class, AtomicBoolean.class);
addResource.setAccessible(true);
final Method removeAlias = MapEntries.class.getDeclaredMethod("removeAlias", String.class, String.class, AtomicBoolean.class);
removeAlias.setAccessible(true);
assertEquals(0, aliasMap.size());
Resource parent = mock(Resource.class);
when(parent.getPath()).thenReturn("/");
final Resource result = mock(Resource.class);
when(resourceResolver.getResource("/parent")).thenReturn(result);
when(result.getParent()).thenReturn(parent);
when(result.getPath()).thenReturn("/parent");
when(result.getName()).thenReturn("parent");
when(result.getValueMap()).thenReturn(buildValueMap());
//testing jcr:content node removal
final Resource jcrContentResult = mock(Resource.class);
when(resourceResolver.getResource("/parent/jcr:content")).thenReturn(jcrContentResult);
when(jcrContentResult.getParent()).thenReturn(result);
when(jcrContentResult.getPath()).thenReturn("/parent/jcr:content");
when(jcrContentResult.getName()).thenReturn("jcr:content");
when(jcrContentResult.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "aliasJcrContent"));
when(result.getChild("jcr:content")).thenReturn(jcrContentResult);
addResource.invoke(mapEntries, "/parent/jcr:content", new AtomicBoolean());
Map<String, String> aliasMapEntry = mapEntries.getAliasMap("/");
assertNotNull(aliasMapEntry);
assertTrue(aliasMapEntry.containsKey("aliasJcrContent"));
assertEquals("parent", aliasMapEntry.get("aliasJcrContent"));
assertEquals(1, aliasMap.size());
when(resourceResolver.getResource("/parent/jcr:content")).thenReturn(null);
when(result.getChild("jcr:content")).thenReturn(null);
removeAlias.invoke(mapEntries, "/", "/parent/jcr:content", new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/");
assertNull(aliasMapEntry);
assertEquals(0, aliasMap.size());
}
@Test
public void test_doRemoveAliasFromSibling() throws Exception {
final Method addResource = MapEntries.class.getDeclaredMethod("addResource", String.class, AtomicBoolean.class);
addResource.setAccessible(true);
final Method removeResource = MapEntries.class.getDeclaredMethod("removeResource", String.class, AtomicBoolean.class);
removeResource.setAccessible(true);
assertEquals(0, aliasMap.size());
Resource parent = mock(Resource.class);
when(parent.getPath()).thenReturn("/parent");
when(resourceResolver.getResource("/parent")).thenReturn(parent);
when(parent.getParent()).thenReturn(parent);
when(parent.getPath()).thenReturn("/parent");
when(parent.getName()).thenReturn("parent");
when(parent.getValueMap()).thenReturn(buildValueMap());
final Resource child1 = mock(Resource.class);
when(resourceResolver.getResource("/parent/child1")).thenReturn(child1);
when(child1.getParent()).thenReturn(parent);
when(child1.getPath()).thenReturn("/parent/child1");
when(child1.getName()).thenReturn("child1");
when(child1.getValueMap()).thenReturn(buildValueMap());
final Resource child1JcrContent = mock(Resource.class);
when(resourceResolver.getResource("/parent/child1/jcr:content")).thenReturn(child1JcrContent);
when(child1JcrContent.getParent()).thenReturn(child1);
when(child1JcrContent.getPath()).thenReturn("/parent/child1/jcr:content");
when(child1JcrContent.getName()).thenReturn("jcr:content");
when(child1JcrContent.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "test1"));
when(child1.getChild("jcr:content")).thenReturn(child1JcrContent);
when(parent.getChild("child1")).thenReturn(child1);
addResource.invoke(mapEntries, child1JcrContent.getPath(), new AtomicBoolean());
Map<String, String> aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertTrue(aliasMapEntry.containsKey("test1"));
assertEquals("child1", aliasMapEntry.get("test1"));
assertEquals(1, aliasMap.size());
final Resource child2 = mock(Resource.class);
when(resourceResolver.getResource("/parent/child2")).thenReturn(child2);
when(child2.getParent()).thenReturn(parent);
when(child2.getPath()).thenReturn("/parent/child2");
when(child2.getName()).thenReturn("child2");
when(child2.getValueMap()).thenReturn(buildValueMap());
final Resource child2JcrContent = mock(Resource.class);
when(resourceResolver.getResource("/parent/child2/jcr:content")).thenReturn(child2JcrContent);
when(child2JcrContent.getParent()).thenReturn(child2);
when(child2JcrContent.getPath()).thenReturn("/parent/child2/jcr:content");
when(child2JcrContent.getName()).thenReturn("jcr:content");
when(child2JcrContent.getValueMap()).thenReturn(buildValueMap(ResourceResolverImpl.PROP_ALIAS, "test2"));
when(child2.getChild("jcr:content")).thenReturn(child2JcrContent);
when(parent.getChild("child2")).thenReturn(child2);
addResource.invoke(mapEntries, child2JcrContent.getPath(), new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertTrue(aliasMapEntry.containsKey("test1"));
assertTrue(aliasMapEntry.containsKey("test2"));
assertEquals("child1", aliasMapEntry.get("test1"));
assertEquals("child2", aliasMapEntry.get("test2"));
assertEquals(1, aliasMap.size());
assertEquals(2, mapEntries.getAliasMap("/parent").size());
final Resource child2JcrContentChild = mock(Resource.class);
when(resourceResolver.getResource("/parent/child2/jcr:content/test")).thenReturn(child2JcrContentChild);
when(child2JcrContentChild.getParent()).thenReturn(child2);
when(child2JcrContentChild.getPath()).thenReturn("/parent/child2/jcr:content/test");
when(child2JcrContentChild.getName()).thenReturn("test");
when(child2JcrContent.getChild("test")).thenReturn(child2JcrContentChild);
removeResource.invoke(mapEntries, child2JcrContentChild.getPath(), new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertTrue(aliasMapEntry.containsKey("test1"));
assertTrue(aliasMapEntry.containsKey("test2"));
assertEquals("child1", aliasMapEntry.get("test1"));
assertEquals("child2", aliasMapEntry.get("test2"));
assertEquals(1, aliasMap.size());
assertEquals(2, mapEntries.getAliasMap("/parent").size());
when(child2.getChild("jcr:content")).thenReturn(null);
removeResource.invoke(mapEntries, child2JcrContent.getPath(), new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertTrue(aliasMapEntry.containsKey("test1"));
assertEquals("child1", aliasMapEntry.get("test1"));
assertEquals(1, aliasMap.size());
assertEquals(1, mapEntries.getAliasMap("/parent").size());
when(child1.getChild("jcr:content")).thenReturn(null);
removeResource.invoke(mapEntries, child1JcrContent.getPath(), new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNull(aliasMapEntry);
when(child1.getChild("jcr:content")).thenReturn(child1JcrContent);
addResource.invoke(mapEntries, child1JcrContent.getPath(), new AtomicBoolean());
when(child2.getChild("jcr:content")).thenReturn(child2JcrContent);
addResource.invoke(mapEntries, child2JcrContent.getPath(), new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNotNull(aliasMapEntry);
assertTrue(aliasMapEntry.containsKey("test1"));
assertTrue(aliasMapEntry.containsKey("test2"));
assertEquals("child1", aliasMapEntry.get("test1"));
assertEquals("child2", aliasMapEntry.get("test2"));
assertEquals(1, aliasMap.size());
assertEquals(2, mapEntries.getAliasMap("/parent").size());
removeResource.invoke(mapEntries, parent.getPath(), new AtomicBoolean());
aliasMapEntry = mapEntries.getAliasMap("/parent");
assertNull(aliasMapEntry);
}
@Test
public void test_isValidVanityPath() throws Exception {
Method method = MapEntries.class.getDeclaredMethod("isValidVanityPath", String.class);
method.setAccessible(true);
assertFalse((Boolean)method.invoke(mapEntries, "/jcr:system/node"));
assertTrue((Boolean)method.invoke(mapEntries, "/justVanityPath"));
}
@Test
//SLING-4847
public void test_doNodeAdded1() throws Exception {
final Method addResource = MapEntries.class.getDeclaredMethod("addResource", String.class, AtomicBoolean.class);
addResource.setAccessible(true);
final AtomicBoolean refreshed = new AtomicBoolean(false);
addResource.invoke(mapEntries, "/node", refreshed);
assertTrue(refreshed.get());
}
@Test
//SLING-4891
public void test_getVanityPaths_1() throws Exception {
when(this.resourceResolverFactory.getMaxCachedVanityPathEntries()).thenReturn(0L);
Method method = MapEntries.class.getDeclaredMethod("getVanityPaths", String.class);
method.setAccessible(true);
method.invoke(mapEntries, "/notExisting");
Field vanityCounter = MapEntries.class.getDeclaredField("vanityCounter");
vanityCounter.setAccessible(true);
AtomicLong counter = (AtomicLong) vanityCounter.get(mapEntries);
assertEquals(0, counter.longValue());
}
@Test
//SLING-4891
public void test_getVanityPaths_2() throws Exception {
final Resource justVanityPath = mock(Resource.class, "justVanityPath");
when(resourceResolver.getResource("/justVanityPath")).thenReturn(justVanityPath);
when(justVanityPath.getPath()).thenReturn("/justVanityPath");
when(justVanityPath.getName()).thenReturn("justVanityPath");
when(justVanityPath.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/justVanityPath"));
when(resourceResolver.findResources(anyString(), eq("sql"))).thenAnswer(new Answer<Iterator<Resource>>() {
@Override
public Iterator<Resource> answer(InvocationOnMock invocation) throws Throwable {
if (invocation.getArguments()[0].toString().contains("sling:vanityPath")) {
return Collections.singleton(justVanityPath).iterator();
} else {
return Collections.<Resource> emptySet().iterator();
}
}
});
when(this.resourceResolverFactory.getMaxCachedVanityPathEntries()).thenReturn(0L);
Method method = MapEntries.class.getDeclaredMethod("getVanityPaths", String.class);
method.setAccessible(true);
method.invoke(mapEntries, "/target/justVanityPath");
Field vanityCounter = MapEntries.class.getDeclaredField("vanityCounter");
vanityCounter.setAccessible(true);
AtomicLong counter = (AtomicLong) vanityCounter.get(mapEntries);
assertEquals(2, counter.longValue());
final Resource justVanityPath2 = mock(Resource.class, "justVanityPath2");
when(resourceResolver.getResource("/justVanityPath2")).thenReturn(justVanityPath2);
when(justVanityPath2.getPath()).thenReturn("/justVanityPath2");
when(justVanityPath2.getName()).thenReturn("justVanityPath2");
when(justVanityPath2.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/justVanityPath","sling:vanityOrder", 100));
when(resourceResolver.findResources(anyString(), eq("sql"))).thenAnswer(new Answer<Iterator<Resource>>() {
@Override
public Iterator<Resource> answer(InvocationOnMock invocation) throws Throwable {
if (invocation.getArguments()[0].toString().contains("sling:vanityPath")) {
return Collections.singleton(justVanityPath).iterator();
} else {
return Collections.<Resource> emptySet().iterator();
}
}
});
method.invoke(mapEntries, "/target/justVanityPath");
counter = (AtomicLong) vanityCounter.get(mapEntries);
assertEquals(4, counter.longValue());
}
@Test
//SLING-4891
public void test_getVanityPaths_3() throws Exception {
final Resource justVanityPath = mock(Resource.class, "justVanityPath");
when(resourceResolver.getResource("/justVanityPath")).thenReturn(justVanityPath);
when(justVanityPath.getPath()).thenReturn("/justVanityPath");
when(justVanityPath.getName()).thenReturn("justVanityPath");
when(justVanityPath.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/justVanityPath"));
when(resourceResolver.findResources(anyString(), eq("sql"))).thenAnswer(new Answer<Iterator<Resource>>() {
@Override
public Iterator<Resource> answer(InvocationOnMock invocation) throws Throwable {
if (invocation.getArguments()[0].toString().contains("sling:vanityPath")) {
return Collections.singleton(justVanityPath).iterator();
} else {
return Collections.<Resource> emptySet().iterator();
}
}
});
when(this.resourceResolverFactory.getMaxCachedVanityPathEntries()).thenReturn(0L);
when(this.resourceResolverFactory.isMaxCachedVanityPathEntriesStartup()).thenReturn(false);
Method method = MapEntries.class.getDeclaredMethod("getVanityPaths", String.class);
method.setAccessible(true);
method.invoke(mapEntries, "/target/justVanityPath");
Field vanityCounter = MapEntries.class.getDeclaredField("vanityCounter");
vanityCounter.setAccessible(true);
AtomicLong counter = (AtomicLong) vanityCounter.get(mapEntries);
assertEquals(0, counter.longValue());
}
@Test
//SLING-4891
public void test_getVanityPaths_4() throws Exception {
final Resource badVanityPath = mock(Resource.class, "badVanityPath");
when(badVanityPath.getPath()).thenReturn("/badVanityPath");
when(badVanityPath.getName()).thenReturn("badVanityPath");
when(badVanityPath.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/content/mypage/en-us-{132"));
when(resourceResolver.findResources(anyString(), eq("sql"))).thenAnswer(new Answer<Iterator<Resource>>() {
@Override
public Iterator<Resource> answer(InvocationOnMock invocation) throws Throwable {
if (invocation.getArguments()[0].toString().contains("sling:vanityPath")) {
return Collections.singleton(badVanityPath).iterator();
} else {
return Collections.<Resource> emptySet().iterator();
}
}
});
when(this.resourceResolverFactory.getMaxCachedVanityPathEntries()).thenReturn(0L);
when(this.resourceResolverFactory.isMaxCachedVanityPathEntriesStartup()).thenReturn(true);
Method method = MapEntries.class.getDeclaredMethod("getVanityPaths", String.class);
method.setAccessible(true);
method.invoke(mapEntries, "/content/mypage/en-us-{132");
Field vanityCounter = MapEntries.class.getDeclaredField("vanityCounter");
vanityCounter.setAccessible(true);
AtomicLong counter = (AtomicLong) vanityCounter.get(mapEntries);
assertEquals(0, counter.longValue());
}
@Test
//SLING-4891
public void test_getVanityPaths_5() throws Exception {
final Resource justVanityPath = mock(Resource.class, "justVanityPath");
when(resourceResolver.getResource("/justVanityPath")).thenReturn(justVanityPath);
when(justVanityPath.getPath()).thenReturn("/justVanityPath");
when(justVanityPath.getName()).thenReturn("justVanityPath");
when(justVanityPath.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/justVanityPath"));
when(resourceResolver.findResources(anyString(), eq("sql"))).thenAnswer(new Answer<Iterator<Resource>>() {
@Override
public Iterator<Resource> answer(InvocationOnMock invocation) throws Throwable {
if (invocation.getArguments()[0].toString().contains("sling:vanityPath")) {
return Collections.singleton(justVanityPath).iterator();
} else {
return Collections.<Resource> emptySet().iterator();
}
}
});
when(this.resourceResolverFactory.getMaxCachedVanityPathEntries()).thenReturn(2L);
when(this.resourceResolverFactory.isMaxCachedVanityPathEntriesStartup()).thenReturn(false);
Method method = MapEntries.class.getDeclaredMethod("getVanityPaths", String.class);
method.setAccessible(true);
method.invoke(mapEntries, "/target/justVanityPath");
Field vanityCounter = MapEntries.class.getDeclaredField("vanityCounter");
vanityCounter.setAccessible(true);
AtomicLong counter = (AtomicLong) vanityCounter.get(mapEntries);
assertEquals(2, counter.longValue());
final Resource justVanityPath2 = mock(Resource.class, "justVanityPath2");
when(resourceResolver.getResource("/justVanityPath2")).thenReturn(justVanityPath2);
when(justVanityPath2.getPath()).thenReturn("/justVanityPath2");
when(justVanityPath2.getName()).thenReturn("justVanityPath2");
when(justVanityPath2.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/justVanityPath","sling:vanityOrder", 100));
when(resourceResolver.findResources(anyString(), eq("sql"))).thenAnswer(new Answer<Iterator<Resource>>() {
@Override
public Iterator<Resource> answer(InvocationOnMock invocation) throws Throwable {
if (invocation.getArguments()[0].toString().contains("sling:vanityPath")) {
return Collections.singleton(justVanityPath).iterator();
} else {
return Collections.<Resource> emptySet().iterator();
}
}
});
method.invoke(mapEntries, "/target/justVanityPath");
counter = (AtomicLong) vanityCounter.get(mapEntries);
assertEquals(2, counter.longValue());
}
@Test
//SLING-4891
public void test_loadVanityPaths() throws Exception {
when(this.resourceResolverFactory.getMaxCachedVanityPathEntries()).thenReturn(2L);
final Resource justVanityPath = mock(Resource.class, "justVanityPath");
when(resourceResolver.getResource("/justVanityPath")).thenReturn(justVanityPath);
when(justVanityPath.getPath()).thenReturn("/justVanityPath");
when(justVanityPath.getName()).thenReturn("justVanityPath");
when(justVanityPath.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/justVanityPath"));
when(resourceResolver.findResources(anyString(), eq("sql"))).thenAnswer(new Answer<Iterator<Resource>>() {
@Override
public Iterator<Resource> answer(InvocationOnMock invocation) throws Throwable {
if (invocation.getArguments()[0].toString().contains("sling:vanityPath")) {
return Collections.singleton(justVanityPath).iterator();
} else {
return Collections.<Resource> emptySet().iterator();
}
}
});
Method method = MapEntries.class.getDeclaredMethod("loadVanityPaths", boolean.class);
method.setAccessible(true);
method.invoke(mapEntries, false);
Field vanityCounter = MapEntries.class.getDeclaredField("vanityCounter");
vanityCounter.setAccessible(true);
AtomicLong counter = (AtomicLong) vanityCounter.get(mapEntries);
assertEquals(2, counter.longValue());
}
@Test
//SLING-4891
public void test_loadVanityPaths_1() throws Exception {
final Resource justVanityPath = mock(Resource.class, "justVanityPath");
when(resourceResolver.getResource("/justVanityPath")).thenReturn(justVanityPath);
when(justVanityPath.getPath()).thenReturn("/justVanityPath");
when(justVanityPath.getName()).thenReturn("justVanityPath");
when(justVanityPath.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/justVanityPath"));
when(resourceResolver.findResources(anyString(), eq("sql"))).thenAnswer(new Answer<Iterator<Resource>>() {
@Override
public Iterator<Resource> answer(InvocationOnMock invocation) throws Throwable {
if (invocation.getArguments()[0].toString().contains("sling:vanityPath")) {
return Collections.singleton(justVanityPath).iterator();
} else {
return Collections.<Resource> emptySet().iterator();
}
}
});
Method method = MapEntries.class.getDeclaredMethod("loadVanityPaths", boolean.class);
method.setAccessible(true);
method.invoke(mapEntries, false);
Field vanityCounter = MapEntries.class.getDeclaredField("vanityCounter");
vanityCounter.setAccessible(true);
AtomicLong counter = (AtomicLong) vanityCounter.get(mapEntries);
assertEquals(2, counter.longValue());
}
@Test
//SLING-4891
public void test_getMapEntryList() throws Exception {
List<MapEntry> entries = mapEntries.getResolveMaps();
assertEquals(0, entries.size());
final Resource justVanityPath = mock(Resource.class,
"justVanityPath");
when(resourceResolver.getResource("/justVanityPath")).thenReturn(justVanityPath);
when(justVanityPath.getPath()).thenReturn("/justVanityPath");
when(justVanityPath.getName()).thenReturn("justVanityPath");
when(justVanityPath.getValueMap()).thenReturn(buildValueMap("sling:vanityPath",
"/target/justVanityPath"));
when(resourceResolver.findResources(anyString(),
eq("sql"))).thenAnswer(new Answer<Iterator<Resource>>() {
@Override
public Iterator<Resource> answer(InvocationOnMock invocation)
throws Throwable {
if
(invocation.getArguments()[0].toString().contains("sling:vanityPath")) {
return Collections.singleton(justVanityPath).iterator();
} else {
return Collections.<Resource> emptySet().iterator();
}
}
});
Method method =
MapEntries.class.getDeclaredMethod("getMapEntryList",String.class);
method.setAccessible(true);
method.invoke(mapEntries, "/target/justVanityPath");
entries = mapEntries.getResolveMaps();
assertEquals(2, entries.size());
Field vanityCounter =
MapEntries.class.getDeclaredField("vanityCounter");
vanityCounter.setAccessible(true);
AtomicLong counter = (AtomicLong) vanityCounter.get(mapEntries);
assertEquals(2, counter.longValue());
method.invoke(mapEntries, "/target/justVanityPath");
entries = mapEntries.getResolveMaps();
assertEquals(2, entries.size());
counter = (AtomicLong) vanityCounter.get(mapEntries);
assertEquals(2, counter.longValue());
}
@Test
//SLING-4883
public void test_concutrrent_getResolveMapsIterator() throws Exception {
ExecutorService pool = Executors.newFixedThreadPool(10);
final Resource justVanityPath = mock(Resource.class, "justVanityPath");
when(resourceResolver.getResource("/justVanityPath")).thenReturn(justVanityPath);
when(justVanityPath.getPath()).thenReturn("/justVanityPath");
when(justVanityPath.getName()).thenReturn("justVanityPath");
when(justVanityPath.getValueMap()).thenReturn(buildValueMap("sling:vanityPath", "/target/justVanityPath"));
when(resourceResolver.findResources(anyString(), eq("sql"))).thenAnswer(new Answer<Iterator<Resource>>() {
@Override
public Iterator<Resource> answer(InvocationOnMock invocation) throws Throwable {
if (invocation.getArguments()[0].toString().contains("sling:vanityPath")) {
return Collections.singleton(justVanityPath).iterator();
} else {
return Collections.<Resource> emptySet().iterator();
}
}
});
when(this.resourceResolverFactory.getMaxCachedVanityPathEntries()).thenReturn(2L);
ArrayList<DataFuture> list = new ArrayList<>();
for (int i =0;i<10;i++) {
list.add(createDataFuture(pool, mapEntries));
}
for (DataFuture df : list) {
df.future.get();
}
}
// tests SLING-6542
@Test
public void sessionConcurrency() throws Exception {
final Method addResource = MapEntries.class.getDeclaredMethod("addResource", String.class, AtomicBoolean.class);
addResource.setAccessible(true);
final Method updateResource = MapEntries.class.getDeclaredMethod("updateResource", String.class, AtomicBoolean.class);
updateResource.setAccessible(true);
final Method handleConfigurationUpdate = MapEntries.class.getDeclaredMethod("handleConfigurationUpdate",
String.class, AtomicBoolean.class, AtomicBoolean.class, boolean.class);
handleConfigurationUpdate.setAccessible(true);
final Semaphore sessionLock = new Semaphore(1);
// simulate somewhat slow (1ms) session operations that use locking
// to determine that they are using the session exclusively.
// if that lock mechanism detects concurrent access we fail
Mockito.doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
simulateSomewhatSlowSessionOperation(sessionLock);
return null;
}
}).when(resourceResolver).refresh();
Mockito.doAnswer(new Answer<Resource>() {
@Override
public Resource answer(InvocationOnMock invocation) throws Throwable {
simulateSomewhatSlowSessionOperation(sessionLock);
return null;
}
}).when(resourceResolver).getResource(any(String.class));
when(resourceResolverFactory.isMapConfiguration(any(String.class))).thenReturn(true);
final AtomicInteger failureCnt = new AtomicInteger(0);
final List<Exception> exceptions = new LinkedList<>();
final Semaphore done = new Semaphore(0);
final int NUM_THREADS = 30;
final Random random = new Random(12321);
for(int i=0; i<NUM_THREADS; i++) {
final int randomWait = random.nextInt(10);
Runnable r = new Runnable() {
@Override
public void run() {
try{
Thread.sleep(randomWait);
for(int i=0; i<3; i++) {
addResource.invoke(mapEntries, "/node", new AtomicBoolean());
updateResource.invoke(mapEntries, "/node", new AtomicBoolean());
handleConfigurationUpdate.invoke(mapEntries, "/node", new AtomicBoolean(), new AtomicBoolean(), false);
}
} catch(Exception e) {
e.printStackTrace();
synchronized(exceptions) {
exceptions.add(e);
}
failureCnt.incrementAndGet();
} finally {
done.release();
}
}
};
Thread th = new Thread(r);
th.setDaemon(true);
th.start();
}
assertTrue("threads did not finish in time", done.tryAcquire(NUM_THREADS, 30, TimeUnit.SECONDS));
if (failureCnt.get() != 0) {
synchronized(exceptions) {
throw new AssertionError("exceptions encountered (" + failureCnt.get() + "). First exception: ", exceptions.get(0));
}
}
}
// -------------------------- 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;
}
}
}