/*
* 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.validation.impl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nonnull;
import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.validation.impl.model.ResourcePropertyBuilder;
import org.apache.sling.validation.impl.model.ValidationModelBuilder;
import org.apache.sling.validation.impl.util.ResourcePropertyNameMatcher;
import org.apache.sling.validation.model.ResourceProperty;
import org.apache.sling.validation.model.ValidationModel;
import org.apache.sling.validation.model.spi.ValidationModelProvider;
import org.apache.sling.validation.spi.Validator;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class ValidationModelRetrieverImplTest {
private ValidationModelRetrieverImpl validationModelRetriever;
private MultiValuedMap<String, String> applicablePathPerResourceType;
private TestModelProvider modelProvider;
@Mock
private ResourceResolver resourceResolver;
@Mock
private ResourceResolverFactory resourceResolverFactory;
private static final String DATE_VALIDATOR_ID = "DateValidator";
/**
* Test model provider which only provides models for all resource types in map applicablePathPerResourceType with their according applicablePath!
* In addition those models have an (empty) resource property with a name equal to validated resource type.
*
*/
class TestModelProvider implements ValidationModelProvider {
private @Nonnull final String source;
public TestModelProvider(@Nonnull String source) {
this.source = source;
}
@Override
public @Nonnull List<ValidationModel> getValidationModels(@Nonnull String relativeResourceType) {
List<ValidationModel> models = new ArrayList<ValidationModel>();
Collection<String> applicablePaths = applicablePathPerResourceType.get(relativeResourceType);
if (applicablePaths != null) {
for (String applicablePath : applicablePaths) {
ValidationModelBuilder modelBuilder = new ValidationModelBuilder();
if (applicablePath != null) {
modelBuilder.addApplicablePath(applicablePath);
}
modelBuilder.resourceProperty(new ResourcePropertyBuilder().build(relativeResourceType));
models.add(modelBuilder.build(relativeResourceType, source));
}
}
return models;
}
}
@Before
public void setup() throws LoginException {
applicablePathPerResourceType = new ArrayListValuedHashMap<>();
validationModelRetriever = new ValidationModelRetrieverImpl();
modelProvider = new TestModelProvider("source1");
validationModelRetriever.modelProviders = new ArrayList<>();
validationModelRetriever.modelProviders.add(modelProvider);
Map<String, Object> validatorProperties = new HashMap<>();
validatorProperties.put(Validator.PROPERTY_VALIDATOR_ID, DATE_VALIDATOR_ID);
validatorProperties.put(Validator.PROPERTY_VALIDATOR_SEVERITY, 1);
validationModelRetriever.resourceResolverFactory = resourceResolverFactory;
Mockito.when(resourceResolverFactory.getServiceResourceResolver(Mockito.anyObject())).thenReturn(resourceResolver);
}
@Test
public void testGetModel() {
applicablePathPerResourceType.put("test/type", "/content/site1");
applicablePathPerResourceType.put("test/type", "/content/site1/subnode/test");
applicablePathPerResourceType.put("test/type", "/content/site1/subnode");
applicablePathPerResourceType.put("test/type", "/content/site1/subnode/test/somepage/within");
applicablePathPerResourceType.put("test/type", "/content/site1/subnode/test/testoutside");
ValidationModel model = validationModelRetriever.getValidationModel("test/type", "/content/site1/subnode/test/somepage", false);
Assert.assertNotNull(model);
Assert.assertThat(model.getApplicablePaths(), Matchers.contains("/content/site1/subnode/test"));
}
@Test
public void testGetModelWithExactlyMatchingApplicablePath() {
applicablePathPerResourceType.put("test/type", "/content/site1/subnode/test/somepage");
applicablePathPerResourceType.put("test/type", "/content/site1/subnode/test/somepage/");
ValidationModel model = validationModelRetriever.getValidationModel("test/type", "/content/site1/subnode/test/somepage", false);
Assert.assertNotNull(model);
Assert.assertThat(model.getApplicablePaths(), Matchers.contains("/content/site1/subnode/test/somepage"));
}
@Test
public void testGetModelWithNullApplicablePathPath() {
applicablePathPerResourceType.put("test/type", "/content/site1");
applicablePathPerResourceType.put("test/type", "");
applicablePathPerResourceType.put("test/type", "/content/site1/subnode");
ValidationModel model = validationModelRetriever.getValidationModel("test/type", null, false);
Assert.assertNotNull(model);
Assert.assertThat(model.getApplicablePaths(), Matchers.contains(""));
}
@Test
public void testGetModelWithResourceInheritance() {
// in case no super type is known, just return model
applicablePathPerResourceType.put("test/type", "/content/site1");
ValidationModel model = validationModelRetriever.getValidationModel("test/type", "/content/site1", true);
Assert.assertNotNull(model);
Assert.assertThat(model.getResourceProperties(), Matchers.contains(new ResourcePropertyNameMatcher("test/type")));
// in case there is one super type make sure the merged model is returned!
Mockito.when(resourceResolver.getParentResourceType("test/type")).thenReturn("test/supertype");
applicablePathPerResourceType.put("test/supertype", "/content/site1");
model = validationModelRetriever.getValidationModel("test/type", "/content/site1", true);
Assert.assertNotNull(model);
Assert.assertThat(model.getResourceProperties(), Matchers.<ResourceProperty>containsInAnyOrder(Arrays.asList(new ResourcePropertyNameMatcher("test/type"), new ResourcePropertyNameMatcher("test/supertype"))));
}
@Test
public void testGetModelWithResourceInheritanceAndNoSuitableBaseModelFound() {
// no model found for base type and no resource super type set
ValidationModel model = validationModelRetriever.getValidationModel("test/type", "/content/site1", true);
Assert.assertNull("Found model although no model has been specified", model);
// set super super type
Mockito.when(resourceResolver.getParentResourceType("test/type")).thenReturn("test/supertype");
// no model found at all (neither base nor super type)
model = validationModelRetriever.getValidationModel("test/type", "/content/site1", true);
Assert.assertNull("Found model although no model has been specified (neither in base nor in super type)", model);
// only supertype has model being set
applicablePathPerResourceType.put("test/supertype", "/content/site1");
model = validationModelRetriever.getValidationModel("test/type", "/content/site1", true);
Assert.assertNotNull(model);
Assert.assertThat(model.getResourceProperties(), Matchers.contains(new ResourcePropertyNameMatcher("test/supertype")));
}
@Test
public void testGetModelWithResourceInheritanceAndNoModelForSuperTypeFound() {
applicablePathPerResourceType.put("test/type", "/content/site1");
Mockito.when(resourceResolver.getParentResourceType("test/type")).thenReturn("test/supertype");
Mockito.when(resourceResolver.getParentResourceType("test/supertype")).thenReturn("test/supersupertype");
// only model found for base type
ValidationModel model = validationModelRetriever.getValidationModel("test/type", "/content/site1", true);
Assert.assertNotNull(model);
Assert.assertThat(model.getResourceProperties(), Matchers.contains(new ResourcePropertyNameMatcher("test/type")));
}
@Test
public void testGetModelWithMultipleProvidersHigherRanking() {
ValidationModelProvider modelProvider2 = new TestModelProvider("source2");
validationModelRetriever.modelProviders.clear();
validationModelRetriever.modelProviders.add(modelProvider);
validationModelRetriever.modelProviders.add(modelProvider2);
// each provider must return the same applicable path but different
applicablePathPerResourceType.put("test/type", "/content/site1");
ValidationModel model = validationModelRetriever.getValidationModel("test/type", "/content/site1/somepage", false);
Assert.assertNotNull(model);
Assert.assertEquals("source2", model.getSource());
}
@Test
public void testGetModelWithMultipleProvidersLowerRanking() {
ValidationModelProvider modelProvider2 = new TestModelProvider("source2");
validationModelRetriever.modelProviders.clear();
validationModelRetriever.modelProviders.add(modelProvider2);
validationModelRetriever.modelProviders.add(modelProvider);
// each provider must return the same applicable path but different
applicablePathPerResourceType.put("test/type", "/content/site1");
ValidationModel model = validationModelRetriever.getValidationModel("test/type", "/content/site1/somepage", false);
Assert.assertNotNull(model);
Assert.assertEquals("source1", model.getSource());
}
}