| /* |
| * 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); |
| } |
| |
| } |