Package org.apache.sling.junit.performance.runner

Source Code of org.apache.sling.junit.performance.runner.PerformanceRunner

/*
* 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.junit.performance.runner;

import org.apache.sling.junit.performance.impl.*;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkField;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;

import java.util.ArrayList;
import java.util.List;

/**
* Custom runner to execute performance tests using JUnit.
* <p/>
* For a method to be executed as a performance test, it must be annotated with {@link PerformanceTest}. Every time this
* annotation is specified, the user must also specify the warm up and execution strategy, because these information are
* mandatory for the runner to work properly. The warm up and execution strategy can be provided in two ways: by
* specifying the number of executions to run, or by specifying the amount of time the method should run.
* <p/>
* The runner can also invoke one or more {@link Listener}. The listener is specified as a static variable of the test
* class or as the result of a static method. The listeners are made available to the runner by annotating them with the
* {@link Listen} annotation.
* <p/>
* The runner support lifecycle methods which are executed at various stages of the performance test. These methods are
* annotated with {@link BeforePerformanceIteration}, {@link AfterPerformanceIteration}, {@link BeforePerformanceTest},
* {@link AfterPerformanceTest}, {@link BeforeWarmUpIteration}, {@link AfterWarmUpIteration}, {@link BeforeWarmUp} and
* {@link AfterWarmUp}. Every other standard JUnit annotation is also supported.
*/
public class PerformanceRunner extends BlockJUnit4ClassRunner {

    private Listeners listeners;

    public PerformanceRunner(Class<?> testClass) throws InitializationError {
        super(testClass);

        try {
            listeners = new Listeners(getListeners());
        } catch (Throwable e) {
            throw new InitializationError(e);
        }
    }

    @Override
    protected void collectInitializationErrors(List<Throwable> errors) {
        super.collectInitializationErrors(errors);

        validatePublicVoidNoArgMethods(PerformanceTest.class, false, errors);
        validatePublicVoidNoArgMethods(BeforeWarmUpIteration.class, false, errors);
        validatePublicVoidNoArgMethods(AfterWarmUpIteration.class, false, errors);
        validatePublicVoidNoArgMethods(BeforeWarmUp.class, false, errors);
        validatePublicVoidNoArgMethods(AfterWarmUp.class, false, errors);
        validatePublicVoidNoArgMethods(BeforePerformanceIteration.class, false, errors);
        validatePublicVoidNoArgMethods(AfterPerformanceIteration.class, false, errors);
        validatePublicVoidNoArgMethods(BeforePerformanceTest.class, false, errors);
        validatePublicVoidNoArgMethods(AfterPerformanceTest.class, false, errors);
        validatePerformanceTestsExecutionStrategy(errors);
        validateListenMethodsReturnType(errors);
        validateListenMethodsStatic(errors);
        validateListenMethodPublic(errors);
        validateListenFieldsType(errors);
        validateListenFieldsStatic(errors);
        validateListenFieldPublic(errors);
    }

    private void validatePerformanceTestsExecutionStrategy(List<Throwable> errors) {
        for (FrameworkMethod method : getTestClass().getAnnotatedMethods(PerformanceTest.class)) {
            int warmUpInvocations = getWarmUpInvocations(method);
            int warmUpTime = getWarmUpTime(method);

            if (warmUpInvocations <= 0 && warmUpTime <= 0) {
                errors.add(new Error("Method " + method.getName() + "() should provide a valid warmUpInvocations or warmUpTime"));
            }

            if (warmUpInvocations > 0 && warmUpTime > 0) {
                errors.add(new Error("Method " + method.getName() + "() provides both a valid warmUpInvocations and a warmUpTime"));
            }

            int runInvocations = getRunInvocations(method);
            int runTime = getRunTime(method);

            if (runInvocations <= 0 && runTime <= 0) {
                errors.add(new Error("Method " + method.getName() + "() should provide a valid runInvocations or runTime"));
            }

            if (runInvocations > 0 && runTime > 0) {
                errors.add(new Error("Method " + method.getName() + "() provides both a valid runInvocations or runTime"));
            }
        }
    }

    private void validateListenMethodsReturnType(List<Throwable> errors) {
        for (FrameworkMethod method : getTestClass().getAnnotatedMethods(Listen.class)) {
            if (Listener.class.isAssignableFrom(method.getReturnType())) {
                continue;
            }

            errors.add(new Error("Method " + method.getName() + "() should return an object of type Listener"));
        }
    }

    private void validateListenMethodsStatic(List<Throwable> errors) {
        for (FrameworkMethod method : getTestClass().getAnnotatedMethods(Listen.class)) {
            if (method.isStatic()) {
                continue;
            }

            errors.add(new Error("Method " + method.getName() + "() should be static"));
        }
    }

    private void validateListenMethodPublic(List<Throwable> errors) {
        for (FrameworkMethod method : getTestClass().getAnnotatedMethods(Listen.class)) {
            if (method.isPublic()) {
                continue;
            }

            errors.add(new Error("Method " + method.getName() + "() should be public"));
        }
    }

    private void validateListenFieldsType(List<Throwable> errors) {
        for (FrameworkField field : getTestClass().getAnnotatedFields(Listen.class)) {
            if (Listener.class.isAssignableFrom(field.getType())) {
                continue;
            }

            errors.add(new Error("Field " + field.getName() + " should be of type Listener"));
        }
    }

    private void validateListenFieldsStatic(List<Throwable> errors) {
        for (FrameworkField field : getTestClass().getAnnotatedFields(Listen.class)) {
            if (field.isStatic()) {
                continue;
            }

            errors.add(new Error("Field " + field.getName() + " should be static"));
        }
    }

    private void validateListenFieldPublic(List<Throwable> errors) {
        for (FrameworkField field : getTestClass().getAnnotatedFields(Listen.class)) {
            if (field.isPublic()) {
                continue;
            }

            errors.add(new Error("Field " + field.getName() + " should be public"));
        }
    }

    @Override
    protected List<FrameworkMethod> computeTestMethods() {
        return getTestClass().getAnnotatedMethods(PerformanceTest.class);
    }

    @Override
    protected Statement methodInvoker(FrameworkMethod method, Object test) {
        Statement methodInvoker = super.methodInvoker(method, test);

        Statement invokeWarmUp = methodInvoker;

        invokeWarmUp = withWarmUpIterationStartedEvents(method, test, invokeWarmUp);
        invokeWarmUp = withWarmUpIterationFinishedEvents(method, test, invokeWarmUp);
        invokeWarmUp = withBeforeWarmUpIterations(method, test, invokeWarmUp);
        invokeWarmUp = withAfterWarmUpIterations(method, test, invokeWarmUp);
        invokeWarmUp = withWarmUpIterations(method, test, invokeWarmUp);
        invokeWarmUp = withWarmUpStartedEvents(method, test, invokeWarmUp);
        invokeWarmUp = withWarmUpFinishedEvents(method, test, invokeWarmUp);
        invokeWarmUp = withBeforeWarmUps(method, test, invokeWarmUp);
        invokeWarmUp = withAfterWarmUps(method, test, invokeWarmUp);

        Statement invokePerformanceTest = methodInvoker;

        invokePerformanceTest = withExecutionIterationStartedEvents(method, test, invokePerformanceTest);
        invokePerformanceTest = withExecutionIterationFinishedEvents(method, test, invokePerformanceTest);
        invokePerformanceTest = withBeforePerformanceIterations(method, test, invokePerformanceTest);
        invokePerformanceTest = withAfterPerformanceIterations(method, test, invokePerformanceTest);
        invokePerformanceTest = withPerformanceIterations(method, test, invokePerformanceTest);
        invokePerformanceTest = withExecutionStartedEvents(method, test, invokePerformanceTest);
        invokePerformanceTest = withExecutionFinishedEvents(method, test, invokePerformanceTest);
        invokePerformanceTest = withBeforePerformanceTests(method, test, invokePerformanceTest);
        invokePerformanceTest = withAfterPerformanceTests(method, test, invokePerformanceTest);

        return new RunSerial(invokeWarmUp, invokePerformanceTest);
    }


    protected Statement withBeforeWarmUpIterations(FrameworkMethod method, Object test, Statement next) {
        List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(BeforeWarmUpIteration.class);

        if (methods.size() == 0) {
            return next;
        }

        return new RunBefores(next, methods, test);
    }

    protected Statement withAfterWarmUpIterations(FrameworkMethod method, Object test, Statement next) {
        List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(AfterWarmUpIteration.class);

        if (methods.size() == 0) {
            return next;
        }

        return new RunAfters(next, methods, test);
    }

    protected Statement withWarmUpIterations(FrameworkMethod method, Object test, Statement iteration) {
        return new RunIterations(getWarmUpInvocations(method), getWarmUpTime(method), iteration);
    }

    protected Statement withBeforeWarmUps(FrameworkMethod method, Object test, Statement next) {
        List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(BeforeWarmUp.class);

        if (methods.size() == 0) {
            return next;
        }

        return new RunBefores(next, methods, test);
    }

    protected Statement withAfterWarmUps(FrameworkMethod method, Object test, Statement next) {
        List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(AfterWarmUp.class);

        if (methods.size() == 0) {
            return next;
        }

        return new RunAfters(next, methods, test);
    }

    protected Statement withBeforePerformanceIterations(FrameworkMethod method, Object test, Statement next) {
        List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(BeforePerformanceIteration.class);

        if (methods.size() == 0) {
            return next;
        }

        return new RunBefores(next, methods, test);
    }

    protected Statement withAfterPerformanceIterations(FrameworkMethod method, Object test, Statement next) {
        List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(AfterPerformanceIteration.class);

        if (methods.size() == 0) {
            return next;
        }

        return new RunAfters(next, methods, test);
    }

    protected Statement withPerformanceIterations(FrameworkMethod method, Object test, Statement iteration) {
        return new RunIterations(getRunInvocations(method), getRunTime(method), iteration);
    }

    protected Statement withBeforePerformanceTests(FrameworkMethod method, Object test, Statement next) {
        List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(BeforePerformanceTest.class);

        if (methods.size() == 0) {
            return next;
        }

        return new RunBefores(next, methods, test);
    }

    protected Statement withAfterPerformanceTests(FrameworkMethod method, Object test, Statement next) {
        List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(AfterPerformanceTest.class);

        if (methods.size() == 0) {
            return next;
        }

        return new RunAfters(next, methods, test);
    }

    protected Statement withWarmUpIterationStartedEvents(FrameworkMethod method, Object test, Statement next) {
        return new RunWarmUpIterationStartedEvents(listeners, getTestClass(), method, next);
    }

    protected Statement withWarmUpIterationFinishedEvents(FrameworkMethod method, Object test, Statement next) {
        return new RunWarmUpIterationFinishedEvents(listeners, getTestClass(), method, next);
    }

    protected Statement withWarmUpStartedEvents(FrameworkMethod method, Object test, Statement next) {
        return new RunWarmUpStartedEvents(listeners, getTestClass(), method, next);
    }

    protected Statement withWarmUpFinishedEvents(FrameworkMethod method, Object test, Statement next) {
        return new RunWarmUpFinishedEvents(listeners, getTestClass(), method, next);
    }

    protected Statement withExecutionIterationStartedEvents(FrameworkMethod method, Object test, Statement next) {
        return new RunExecutionIterationStartedEvents(listeners, getTestClass(), method, next);
    }

    protected Statement withExecutionIterationFinishedEvents(FrameworkMethod method, Object test, Statement next) {
        return new RunExecutionIterationFinishedEvents(listeners, getTestClass(), method, next);
    }

    protected Statement withExecutionStartedEvents(FrameworkMethod method, Object test, Statement next) {
        return new RunExecutionStartedEvents(listeners, getTestClass(), method, next);
    }

    protected Statement withExecutionFinishedEvents(FrameworkMethod method, Object test, Statement next) {
        return new RunExecutionFinishedEvents(listeners, getTestClass(), method, next);
    }

    private List<Listener> getListeners() throws Throwable {
        List<Listener> listeners = new ArrayList<Listener>();

        listeners.addAll(readListenersFromStaticFields());
        listeners.addAll(readListenersFromStaticMethods());

        return listeners;
    }

    private List<Listener> readListenersFromStaticMethods() throws Throwable {
        List<Listener> listeners = new ArrayList<Listener>();

        for (FrameworkMethod method : getTestClass().getAnnotatedMethods(Listen.class)) {
            Listener listener = (Listener) method.invokeExplosively(null);

            if (listener == null) {
                throw new IllegalArgumentException("Method " + method.getName() + "() should not return null");
            }

            listeners.add(listener);
        }

        return listeners;
    }

    private List<Listener> readListenersFromStaticFields() throws Exception {
        List<Listener> listeners = new ArrayList<Listener>();

        for (FrameworkField field : getTestClass().getAnnotatedFields(Listen.class)) {
            Listener listener = (Listener) field.get(null);

            if (listener == null) {
                throw new IllegalArgumentException("Field " + field.getName() + " should not be null");
            }

            listeners.add(listener);
        }

        return listeners;
    }

    private int getWarmUpInvocations(FrameworkMethod method) {
        return method.getAnnotation(PerformanceTest.class).warmUpInvocations();
    }

    private int getWarmUpTime(FrameworkMethod method) {
        return method.getAnnotation(PerformanceTest.class).warmUpTime();
    }

    private int getRunInvocations(FrameworkMethod method) {
        return method.getAnnotation(PerformanceTest.class).runInvocations();
    }

    private int getRunTime(FrameworkMethod method) {
        return method.getAnnotation(PerformanceTest.class).runTime();
    }

}
TOP

Related Classes of org.apache.sling.junit.performance.runner.PerformanceRunner

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.