blob: fef112cc96ad0adceaccebfac53189e01f503620 [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.performance;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import org.apache.sling.performance.annotation.AfterSuite;
import org.apache.sling.performance.annotation.BeforeSuite;
import org.apache.sling.performance.annotation.PerformanceTest;
import org.apache.sling.performance.annotation.PerformanceTestSuite;
import org.junit.After;
import org.junit.Before;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
/**
* The custom JUnit runner that collects the performance tests
*
*/
public class PerformanceRunner extends BlockJUnit4ClassRunner {
protected LinkedList<FrameworkMethod> tests = new LinkedList<FrameworkMethod>();
private List<PerformanceSuiteState> suitesState = new ArrayList<PerformanceSuiteState>();
public PerformanceRunner(Class<?> clazz) throws InitializationError {
super(clazz);
try {
computeTests();
} catch (Exception e) {
throw new InitializationError(e);
}
}
/**
* Compute the tests that will be run
*
* @throws Exception
*/
protected void computeTests() throws Exception {
tests.addAll(super.computeTestMethods());
// count the performance tests
tests.addAll(computePerformanceTests());
// This is called here to ensure the test class constructor is called at
// least
// once during testing.
createTest();
}
/**
* Compute performance tests
*
* @return the list containing the performance test methods
* @throws Exception
*/
protected Collection<? extends FrameworkMethod> computePerformanceTests()
throws Exception {
List<FrameworkPerformanceMethod> tests = new LinkedList<FrameworkPerformanceMethod>();
List<Object> testObjects = new ArrayList<Object>();
ParameterizedTestList testCenter = new ParameterizedTestList();
// Retrieve the test objects included in the Performance test suite
for (FrameworkMethod method : getTestClass().getAnnotatedMethods(
PerformanceTestSuite.class)) {
Object targetObject = getTestClass().getJavaClass().newInstance();
if (method.getMethod().getReturnType()
.equals(ParameterizedTestList.class)) {
testCenter = (ParameterizedTestList) method.getMethod().invoke(
targetObject);
testObjects = testCenter.getTestObjectList();
} else {
throw new InitializationError(
"Wrong signature for the @PerformanceSuite method");
}
}
// Retrieve the methods before running the methods from the test suite
List<FrameworkMethod> beforeSuiteMethods = getTestClass()
.getAnnotatedMethods(BeforeSuite.class);
if (beforeSuiteMethods.size() > 1) {
throw new InitializationError(
"Only one @BeforeSuite method is allowed for a @PerformanceSuite");
}
// Retrieve the methods before running the methods from the test suite
List<FrameworkMethod> afterSuiteMethods = getTestClass()
.getAnnotatedMethods(AfterSuite.class);
if (afterSuiteMethods.size() > 1) {
throw new InitializationError(
"Only one @AfterSuite method is allowed for a @PerformanceSuite");
}
PerformanceSuiteState current = null;
boolean suiteAlreadyRegistered = false;
for (PerformanceSuiteState suiteState : suitesState) {
if (suiteState.testSuiteName.equals(testCenter.getTestSuiteName())) {
suiteAlreadyRegistered = true;
suiteState.incrementNumberOfTestMethodsInSuite();
current = suiteState;
break;
}
}
// Create a new PerformanceSuiteState object
PerformanceSuiteState newSuite = new PerformanceSuiteState(
testCenter.getTestSuiteName());
if (!suiteAlreadyRegistered) {
if (beforeSuiteMethods.size() == 1) {
newSuite.setBeforeSuiteMethod(beforeSuiteMethods.get(0)
.getMethod());
}
if (afterSuiteMethods.size() == 1) {
newSuite.setAfterSuiteMethod(afterSuiteMethods.get(0)
.getMethod());
}
current = newSuite;
newSuite.setTargetObjectSuite(getTestClass().getJavaClass()
.newInstance());
}
// In case there are any objects retrieved from the Performance Suite
// we should add them to the tests that will be run and increase the
// number of methods
// contained in the PerformaceSuite
if (!testObjects.isEmpty()) {
for (Object testObject : testObjects) {
// retrieve the test methods from the test classes
Method[] testMethods = getSpecificMethods(
testObject.getClass(), PerformanceTest.class);
if (!suiteAlreadyRegistered) {
newSuite.incrementNumberOfTestMethodsInSuite();
}
for (Method method : testMethods) {
FrameworkPerformanceMethod performaceTestMethod = new FrameworkPerformanceMethod(
method, testObject, current);
tests.add(performaceTestMethod);
}
}
// add the new suite to the list of suites
suitesState.add(newSuite);
}
// Retrieve the performance tests in the case we don't have a
// performance test suite
for (FrameworkMethod method : getTestClass().getAnnotatedMethods(
PerformanceTest.class)) {
Object targetObject = getTestClass().getJavaClass().newInstance();
FrameworkPerformanceMethod performaceTestMethod = new FrameworkPerformanceMethod(
method.getMethod(), targetObject, current);
tests.add(performaceTestMethod);
}
return tests;
}
/**
* Retrieve specific method from test class
*
* @param testClass
* the test class that we need to search in
* @param annotation
* the annotation that we should look for
* @return the list with the methods that have the specified annotation
*/
@SuppressWarnings({ "rawtypes" })
private Method[] getSpecificMethods(Class testClass,
Class<? extends Annotation> annotation) {
Method[] allMethods = testClass.getDeclaredMethods();
List<Method> methodListResult = new ArrayList<Method>();
for (Method testMethod : allMethods) {
if (testMethod.isAnnotationPresent(annotation)) {
methodListResult.add(testMethod);
}
}
return methodListResult.toArray(new Method[] {});
}
/**
* {@inheritDoc}
*
* @see org.junit.runners.BlockJUnit4ClassRunner#computeTestMethods()
*/
@Override
protected List<FrameworkMethod> computeTestMethods() {
return tests;
}
/**
* Need to override method otherwise the validation will fail because of
* some hardcoded conditions in JUnit
*/
@Override
protected void validateInstanceMethods(List<Throwable> errors) {
validatePublicVoidNoArgMethods(After.class, false, errors);
validatePublicVoidNoArgMethods(Before.class, false, errors);
validateTestMethods(errors);
}
}