blob: d335724f58171116b10f07e5c118aa6ae46affe8 [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.resourcemerger.impl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.collections4.iterators.IteratorIterable;
import org.apache.sling.api.resource.ModifiableValueMap;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.hamcrest.ResourceMatchers;
import org.apache.sling.resourcemerger.impl.picker.SearchPathBasedResourcePicker;
import org.apache.sling.spi.resource.provider.ResolveContext;
import org.apache.sling.spi.resource.provider.ResourceContext;
import org.apache.sling.testing.resourceresolver.MockHelper;
import org.apache.sling.testing.resourceresolver.MockResourceResolverFactory;
import org.apache.sling.testing.resourceresolver.MockResourceResolverFactoryOptions;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class MergedResourceProviderForSearchPathBasedPickerTest {
private ResourceResolver resolver;
private CRUDMergingResourceProvider provider;
private ResolveContext<Void> ctx;
@Before public void setup() throws Exception {
final MockResourceResolverFactoryOptions options = new MockResourceResolverFactoryOptions();
options.setSearchPaths(new String[] {"/apps/", "/libs/"});
final ResourceResolverFactory factory = new MockResourceResolverFactory(options);
this.resolver = factory.getResourceResolver(null);
MockHelper.create(this.resolver).resource("/apps")
.resource("a").p(MergedResourceConstants.PN_HIDE_CHILDREN, new String[] {"Z", "x", "y"})
.resource("1").p("a", "1").p("b", "2")
.resource(".2").p(ResourceResolver.PROPERTY_RESOURCE_TYPE, "apps")
.resource(".3").p("e", "2")
.p(MergedResourceConstants.PN_HIDE_PROPERTIES, "*")
.p("b", "x")
.p("d", "1")
.resource(".4").p("e", "2")
.p(MergedResourceConstants.PN_HIDE_PROPERTIES, new String[] {"a", "c"})
.p("b", "x")
.p("d", "1")
.resource(".X")
.resource("/apps/b").resource("c").resource("d").resource("e").resource("f")
.resource("/libs")
.resource("deleteTest")
.resource(".mvmTest").p("a", "1").p("b", "2")
.resource(".a")
.resource("1").p("a", "5").p("c", "2")
.resource(".2").p(ResourceResolver.PROPERTY_RESOURCE_TYPE, "libs")
.resource(".3").p("a", "1").p("b", "2").p("c", "3")
.resource(".4").p("a", "1").p("b", "2").p("c", "3")
.resource(".Y")
.resource(".Z")
.resource("/libs/a/Y/a")
.resource("/libs/a/Y/b")
.resource("/libs/a/Y/c")
.resource("/libs/b").resource("c").resource("d").resource("e").resource("f")
.commit();
this.provider = new CRUDMergingResourceProvider("/merged", new SearchPathBasedResourcePicker(), false);
this.ctx = new BasicResolveContext(resolver);
}
@Test public void testHideChildren() {
// check preconditions in libs and apps
assertNotNull(this.resolver.getResource("/libs/a/Z"));
assertNull(this.resolver.getResource("/libs/a/X"));
assertNotNull(this.resolver.getResource("/libs/a/Y"));
assertNull(this.resolver.getResource("/libs/a/x"));
assertNull(this.resolver.getResource("/libs/a/y"));
assertNull(this.resolver.getResource("/apps/a/Z"));
assertNotNull(this.resolver.getResource("/apps/a/X"));
assertNull(this.resolver.getResource("/apps/a/Y"));
assertNull(this.resolver.getResource("/apps/a/x"));
assertNull(this.resolver.getResource("/apps/a/y"));
// now do the real checks
assertNull(this.provider.getResource(ctx, "/merged/a/Z", ResourceContext.EMPTY_CONTEXT, null));
assertNotNull(this.provider.getResource(ctx, "/merged/a/Y", ResourceContext.EMPTY_CONTEXT, null));
assertNotNull(this.provider.getResource(ctx, "/merged/a/X", ResourceContext.EMPTY_CONTEXT, null));
assertNull(this.provider.getResource(ctx, "/merged/a/x", ResourceContext.EMPTY_CONTEXT, null));
assertNull(this.provider.getResource(ctx, "/merged/a/y", ResourceContext.EMPTY_CONTEXT, null));
}
@Test public void testListChildren() {
final Resource rsrcA = this.provider.getResource(ctx, "/merged/a", ResourceContext.EMPTY_CONTEXT, null);
assertNotNull(rsrcA);
final Iterator<Resource> i = this.provider.listChildren(ctx, rsrcA);
assertNotNull(i);
final List<String> names = new ArrayList<String>();
while ( i.hasNext() ) {
names.add(i.next().getName());
}
assertEquals(6, names.size());
assertTrue(names.contains("1"));
assertTrue(names.contains("2"));
assertTrue(names.contains("3"));
assertTrue(names.contains("4"));
assertTrue(names.contains("Y"));
assertTrue(names.contains("X"));
}
@Test public void testListSubChildren() {
final Resource rsrcY = this.provider.getResource(ctx, "/merged/a/Y", ResourceContext.EMPTY_CONTEXT, null);
assertNotNull(rsrcY);
final Iterator<Resource> i = this.provider.listChildren(ctx, rsrcY);
assertNotNull(i);
final List<String> names = new ArrayList<String>();
while ( i.hasNext() ) {
names.add(i.next().getName());
}
assertEquals(3, names.size());
assertTrue(names.contains("a"));
assertTrue(names.contains("b"));
assertTrue(names.contains("c"));
}
@Test public void testProperties() {
final Resource rsrcA1 = this.provider.getResource(ctx, "/merged/a/1", ResourceContext.EMPTY_CONTEXT, null);
final ValueMap vm = rsrcA1.adaptTo(ValueMap.class);
assertNotNull(vm);
assertEquals(3, vm.size());
assertEquals("1", vm.get("a"));
assertEquals("2", vm.get("b"));
assertEquals("2", vm.get("c"));
}
@Test public void testResourceType() {
// a/2 defines the property and it's overlaid
final Resource rsrcA2 = this.provider.getResource(ctx, "/merged/a/2", ResourceContext.EMPTY_CONTEXT, null);
assertEquals("apps", rsrcA2.getResourceType());
// a/12 doesn't define the property and it's overlaid
final Resource rsrcA1 = this.provider.getResource(ctx, "/merged/a/1", ResourceContext.EMPTY_CONTEXT, null);
assertEquals("a/1", rsrcA1.getResourceType());
}
@Test public void testClearProperties() {
final Resource rsrcA3 = this.provider.getResource(ctx, "/merged/a/3", ResourceContext.EMPTY_CONTEXT, null);
final ValueMap vm = rsrcA3.adaptTo(ValueMap.class);
assertNotNull(vm);
// only the properties from the underlying resource should have been cleared (i.e. the ones from /libs)
assertEquals(3, vm.size());
assertEquals("2", vm.get("e"));
assertEquals("x", vm.get("b"));
assertEquals("1", vm.get("d"));
}
@Test public void testHideProperties() {
final Resource rsrcA4 = this.provider.getResource(ctx, "/merged/a/4", ResourceContext.EMPTY_CONTEXT, null);
final ValueMap vm = rsrcA4.adaptTo(ValueMap.class);
assertNotNull(vm);
assertEquals(3, vm.size());
assertEquals("1", vm.get("d"));
assertEquals("2", vm.get("e"));
assertEquals("x", vm.get("b"));
}
@Test public void testSimpleCreateAndDelete() throws PersistenceException {
final String path = "/merged/a/new";
try {
final Resource rsrc = this.provider.create(ctx, path, Collections.singletonMap("foo", (Object)"bla"));
assertNotNull(rsrc);
assertEquals(path, rsrc.getPath());
final ValueMap vm = ResourceUtil.getValueMap(rsrc);
assertEquals("bla", vm.get("foo"));
final Resource realResource = this.resolver.getResource("/apps/a/new");
assertNotNull(realResource);
final ValueMap vmReal = ResourceUtil.getValueMap(realResource);
assertEquals("bla", vmReal.get("foo"));
assertNull(this.resolver.getResource("/libs/a/new"));
this.provider.delete(ctx, rsrc);
assertNull(this.provider.getResource(ctx, path, ResourceContext.EMPTY_CONTEXT, null));
assertNull(this.resolver.getResource("/libs/a/new"));
assertNull(this.resolver.getResource("/apps/a/new"));
} finally {
this.resolver.revert();
}
}
@Test public void testDeleteByHiding() throws PersistenceException {
final String path = "/merged/deleteTest";
try {
assertNotNull(this.resolver.getResource("/libs/deleteTest"));
assertNull(this.resolver.getResource("/apps/deleteTest"));
final Resource rsrc = this.provider.getResource(ctx, path, ResourceContext.EMPTY_CONTEXT, null);
assertNotNull(rsrc);
assertEquals(path, rsrc.getPath());
this.provider.delete(ctx, rsrc);
assertNull(this.provider.getResource(ctx, path, ResourceContext.EMPTY_CONTEXT, null));
assertNotNull(this.resolver.getResource("/libs/deleteTest"));
final Resource hidingRsrc = this.resolver.getResource("/apps/deleteTest");
assertNotNull(hidingRsrc);
final ValueMap vm = hidingRsrc.getValueMap();
assertEquals(Boolean.TRUE, vm.get(MergedResourceConstants.PN_HIDE_RESOURCE));
} finally {
this.resolver.revert();
}
}
@Test public void testDeleteByHidingAndCreate() throws PersistenceException {
final String path = "/merged/deleteTest";
try {
assertNotNull(this.resolver.getResource("/libs/deleteTest"));
assertNull(this.resolver.getResource("/apps/deleteTest"));
final Resource rsrc = this.provider.getResource(ctx, path, ResourceContext.EMPTY_CONTEXT, null);
assertNotNull(rsrc);
assertEquals(path, rsrc.getPath());
this.provider.delete(ctx, rsrc);
this.provider.create(ctx, path, Collections.singletonMap("foo", (Object)"bla"));
assertNotNull(this.provider.getResource(ctx, path, ResourceContext.EMPTY_CONTEXT, null));
assertNotNull(this.resolver.getResource("/libs/deleteTest"));
final Resource hidingRsrc = this.resolver.getResource("/apps/deleteTest");
assertNotNull(hidingRsrc);
final ValueMap vm = hidingRsrc.getValueMap();
assertEquals("bla", vm.get("foo"));
} finally {
this.resolver.revert();
}
}
@Test public void testModifiableValueMap() throws PersistenceException {
final String path = "/merged/mvmTest";
try {
assertNotNull(this.resolver.getResource("/libs/mvmTest"));
assertNull(this.resolver.getResource("/apps/mvmTest"));
final Resource rsrc = this.provider.getResource(ctx, path, ResourceContext.EMPTY_CONTEXT, null);
assertNotNull(rsrc);
final ValueMap beforeVM = rsrc.getValueMap();
assertEquals("1", beforeVM.get("a"));
assertEquals("2", beforeVM.get("b"));
final ModifiableValueMap mvm = rsrc.adaptTo(ModifiableValueMap.class);
assertNotNull(mvm);
assertEquals("1", mvm.get("a"));
assertEquals("2", mvm.get("b"));
mvm.put("c", "3");
mvm.remove("a");
assertNotNull(this.resolver.getResource("/libs/mvmTest"));
assertNotNull(this.resolver.getResource("/apps/mvmTest"));
final Resource rsrc2 = this.provider.getResource(ctx, path, ResourceContext.EMPTY_CONTEXT, null);
assertNotNull(rsrc2);
final ValueMap afterVM = rsrc2.getValueMap();
assertNull(afterVM.get("a"));
assertEquals("2", afterVM.get("b"));
assertEquals("3", afterVM.get("c"));
final Resource rsrcL = this.resolver.getResource("/libs/mvmTest");
assertEquals("1", rsrcL.getValueMap().get("a"));
assertEquals("2", rsrcL.getValueMap().get("b"));
assertNull(rsrcL.getValueMap().get("c"));
final Resource rsrcA = this.resolver.getResource("/apps/mvmTest");
assertNull(rsrcA.getValueMap().get("a"));
assertNull(rsrcA.getValueMap().get("b"));
assertEquals("3", rsrcA.getValueMap().get("c"));
final String[] hidden = rsrcA.getValueMap().get(MergedResourceConstants.PN_HIDE_PROPERTIES, String[].class);
assertNotNull(hidden);
assertEquals(1, hidden.length);
assertEquals("a", hidden[0]);
} finally {
this.resolver.revert();
}
}
@Test public void testGetWithRelatedResource() {
final String path = "/merged/b/c/d";
String[] relatedPaths = new String[] {
null, // no related resource
"/merged/a", // not related
"/merged/b", // parent of parent
"/merged/b/c", // parent
"/merged/b/c/d", // itself
"/merged/b/c/d/e", // child
"/merged/b/c/d/e/f" // deep child
};
for (String relatedPath : relatedPaths) {
final Resource relatedResource;
if (relatedPath != null) {
relatedResource = provider.getResource(ctx, relatedPath, ResourceContext.EMPTY_CONTEXT, null);
assertNotNull("Not found: " + relatedPath, relatedResource);
} else {
relatedResource = null;
}
Resource resource = provider.getResource(ctx, path, ResourceContext.EMPTY_CONTEXT, relatedResource);
assertNotNull(resource);
assertEquals(path, resource.getPath());
assertTrue(resource instanceof MergedResource);
MergedResource mergedResource = (MergedResource) resource;
List<Resource> mappedResources = mergedResource.getMappedResources();
assertEquals(2, mappedResources.size());
assertEquals(mappedResources.get(0).getPath(), "/libs/b/c/d");
assertEquals(mappedResources.get(1).getPath(), "/apps/b/c/d");
}
}
@Test
public void testOrderBefore() throws PersistenceException {
// create new child nodes below base and overlay
MockHelper.create(this.resolver).resource("/libs/orderbeforetest").resource("/apps/orderbeforetest")
.resource("/libs/orderbeforetest/create").resource("/libs/orderbeforetest/edit")
.resource("/libs/orderbeforetest/update").resource("/libs/orderbeforetest/delete")
.resource("/libs/orderbeforetest/rollout").resource("/apps/orderbeforetest/move")
.resource("/apps/orderbeforetest/create").p(MergedResourceConstants.PN_ORDER_BEFORE, "edit").commit();
Resource mergedResource = this.provider.getResource(ctx, "/merged/orderbeforetest",
ResourceContext.EMPTY_CONTEXT, null);
// convert the iterator returned by list children into an iterable (to be able
// to perform some tests)
IteratorIterable<Resource> iterable = new IteratorIterable<Resource>(provider.listChildren(ctx, mergedResource),
true);
Assert.assertThat(iterable,
Matchers.contains(ResourceMatchers.name("create"), ResourceMatchers.name("edit"),
ResourceMatchers.name("update"), ResourceMatchers.name("delete"),
ResourceMatchers.name("rollout"), ResourceMatchers.name("move")));
}
}