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