blob: ec62954e93f91173819e0ceef31add94928e417c [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.models.impl;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.request.RequestPathInfo;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.factory.ModelClassException;
import org.apache.sling.models.impl.injectors.RequestAttributeInjector;
import org.apache.sling.models.impl.injectors.SelfInjector;
import org.apache.sling.models.impl.via.BeanPropertyViaProvider;
import org.apache.sling.models.testmodels.classes.InvalidConstructorModel;
import org.apache.sling.models.testmodels.classes.SuperclassConstructorModel;
import org.apache.sling.models.testmodels.classes.WithOneConstructorModel;
import org.apache.sling.models.testmodels.classes.WithThreeConstructorsModel;
import org.apache.sling.models.testmodels.classes.WithTwoConstructorsModel;
import org.apache.sling.models.testmodels.classes.constructorinjection.NoNameModel;
import org.apache.sling.models.testmodels.classes.constructorinjection.ViaRequestSuffixModel;
import org.apache.sling.models.testmodels.classes.constructorinjection.WithThreeConstructorsOneInjectModel;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class ConstructorTest {
private ModelAdapterFactory factory;
@Mock
private SlingHttpServletRequest request;
private static final int INT_VALUE = 42;
private static final String STRING_VALUE = "myValue";
@Before
public void setup() {
when(request.getAttribute("attribute")).thenReturn(INT_VALUE);
when(request.getAttribute("attribute2")).thenReturn(STRING_VALUE);
factory = AdapterFactoryTest.createModelAdapterFactory();
factory.bindInjector(new RequestAttributeInjector(), new ServicePropertiesMap(1, 1));
factory.bindInjector(new SelfInjector(), new ServicePropertiesMap(2, 2));
factory.bindViaProvider(new BeanPropertyViaProvider(), null);
factory.adapterImplementations.addClassesAsAdapterAndImplementation(
WithOneConstructorModel.class,
WithThreeConstructorsModel.class,
WithTwoConstructorsModel.class,
SuperclassConstructorModel.class,
InvalidConstructorModel.class,
WithThreeConstructorsOneInjectModel.class,
NoNameModel.class,
ViaRequestSuffixModel.class
);
}
@Test
public void testConstructorInjection() {
WithOneConstructorModel model = factory.getAdapter(request, WithOneConstructorModel.class);
assertNotNull(model);
assertEquals(request, model.getRequest());
assertEquals(INT_VALUE, model.getAttribute());
}
@Test
public void testThreeConstructorsInjection() {
WithThreeConstructorsModel model = factory.getAdapter(request, WithThreeConstructorsModel.class);
assertNotNull(model);
assertEquals(request, model.getRequest());
assertEquals(INT_VALUE, model.getAttribute());
}
@Test
public void testTwoConstructorsInjection() {
WithTwoConstructorsModel model = factory.getAdapter(request, WithTwoConstructorsModel.class);
assertNotNull(model);
assertEquals(request, model.getRequest());
assertEquals(INT_VALUE, model.getAttribute());
}
@Test
public void testSuperclassConstructorsInjection() {
SuperclassConstructorModel model = factory.getAdapter(request, SuperclassConstructorModel.class);
assertNotNull(model);
assertEquals(request, model.getRequest());
assertEquals(INT_VALUE, model.getAttribute());
}
@Test
public void testInvalidConstructorInjector() {
InvalidConstructorModel model = factory.getAdapter(request, InvalidConstructorModel.class);
assertNull(model);
}
@Test(expected = ModelClassException.class)
public void testInvalidConstructorInjectorException() {
factory.createModel(request, InvalidConstructorModel.class);
}
/**
* Test model object with three constructors, and make sure that one with @Inject is picked for instantiation.
* Test mixing of constructor injection and field injection as well.
*/
@Test
public void testThreeConstructorsOneInjectInjection() {
WithThreeConstructorsOneInjectModel model = factory.getAdapter(request,
WithThreeConstructorsOneInjectModel.class);
assertNotNull(model);
assertNull(model.getRequest());
assertEquals(INT_VALUE, model.getAttribute());
assertEquals(STRING_VALUE, model.getAttribute2());
}
@Test
public void testMultiThreadedConstructorInjection() throws InterruptedException, ExecutionException {
class ModelCreator implements Callable<String> {
@Override
public String call() throws Exception {
try {
WithOneConstructorModel model = factory.getAdapter(request, WithOneConstructorModel.class);
if (model == null) {
return "Expected model not null";
}
if (!request.equals(model.getRequest())) {
return "Expected same request";
}
if (INT_VALUE != model.getAttribute()) {
return "Expected same value for attribute";
}
} catch (Throwable e) {
return "Exception not expected: " + e;
}
return null;
}
}
int tries = 10000;
int threads = 10;
ExecutorService executorService = Executors.newFixedThreadPool(threads);
List<ModelCreator> modelCreators = new ArrayList<>(tries);
for (int i = 0; i < tries; i++) {
modelCreators.add(new ModelCreator());
}
List<Future<String>> futures = executorService.invokeAll(modelCreators);
executorService.shutdown();
for (Future<String> f : futures) {
String res = f.get();
if (res != null) {
fail(res);
}
}
}
@Test
public void testNoNameModel() {
NoNameModel model = factory.getAdapter(request, NoNameModel.class);
assertNull(model);
}
@Test
public void testViaInjectionModel() throws Exception {
Resource suffixResource = mock(Resource.class);
when(suffixResource.getPath()).thenReturn("/the/suffix");
RequestPathInfo requestPathInfo = mock(RequestPathInfo.class);
when(requestPathInfo.getSuffixResource()).thenReturn(suffixResource);
when(request.getRequestPathInfo()).thenReturn(requestPathInfo);
ViaRequestSuffixModel model = factory.getAdapter(request, ViaRequestSuffixModel.class);
assertThat(model, Matchers.notNullValue());
assertThat(model.getSuffix(), Matchers.is("/the/suffix"));
}
}