Package org.ops4j.pax.exam.servlet

Source Code of org.ops4j.pax.exam.servlet.ParameterizedContainerTestRunner

/*
* Copyright 2013 Harald Wellmann
*
* Licensed 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.ops4j.pax.exam.servlet;

import java.lang.reflect.Field;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.transaction.NotSupportedException;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;

import org.junit.Ignore;
import org.junit.internal.AssumptionViolatedException;
import org.junit.internal.runners.model.EachTestNotifier;
import org.junit.runner.Description;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
import org.junit.runners.model.FrameworkField;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.ops4j.pax.exam.util.Injector;
import org.ops4j.pax.exam.util.Transactional;

public class ParameterizedContainerTestRunner extends BlockJUnit4ClassRunner {

    private Injector injector;
    private boolean transactionalClass;
    private Object[] parameters;

    public ParameterizedContainerTestRunner(Class<?> klass, Injector injector, Integer index)
        throws InitializationError {
        super(klass);
        this.injector = injector;
        transactionalClass = klass.getAnnotation(Transactional.class) != null;
        if (index != null) {
            try {
                Iterator<Object[]> it = allParameters().iterator();
                for (int i = 0; i <= index; i++) {
                    parameters = it.next();
                }
            }
            // CHECKSTYLE:SKIP - JUnit API
            catch (Throwable t) {
                throw new InitializationError(Collections.singletonList(t));
            }
        }
    }

    protected void validateConstructor(List<Throwable> errors) {
        validateOnlyOneConstructor(errors);
    }

    @Override
    protected Object createTest() throws Exception {
        Object test = null;
        if (fieldsAreAnnotated()) {
            test = createTestUsingFieldInjection();
        }
        else {
            test = createTestUsingConstructorInjection();
        }
        injector.injectFields(test);
        return test;
    }

    private Object createTestUsingConstructorInjection() throws Exception {
        return getTestClass().getOnlyConstructor().newInstance(parameters);
    }

    private Object createTestUsingFieldInjection() throws Exception {
        List<FrameworkField> annotatedFieldsByParameter = getAnnotatedFieldsByParameter();
        if (annotatedFieldsByParameter.size() != parameters.length) {
            throw new Exception("Wrong number of parameters and @Parameter fields."
                + " @Parameter fields counted: " + annotatedFieldsByParameter.size()
                + ", available parameters: " + parameters.length + ".");
        }
        Object testClassInstance = getTestClass().getJavaClass().newInstance();
        for (FrameworkField each : annotatedFieldsByParameter) {
            Field field = each.getField();
            Parameter annotation = field.getAnnotation(Parameter.class);
            int index = annotation.value();
            try {
                field.set(testClassInstance, parameters[index]);
            }
            catch (IllegalArgumentException iare) {
                throw new Exception(getTestClass().getName() + ": Trying to set " + field.getName()
                    + " with the value " + parameters[index] + " that is not the right type ("
                    + parameters[index].getClass().getSimpleName() + " instead of "
                    + field.getType().getSimpleName() + ").", iare);
            }
        }
        return testClassInstance;
    }

    private List<FrameworkField> getAnnotatedFieldsByParameter() {
        return getTestClass().getAnnotatedFields(Parameter.class);
    }

    private boolean fieldsAreAnnotated() {
        return !getAnnotatedFieldsByParameter().isEmpty();
    }

    @SuppressWarnings("unchecked")
    // CHECKSTYLE:SKIP - JUnit API
    private Iterable<Object[]> allParameters() throws Throwable {
        Object params = getParametersMethod().invokeExplosively(null);
        if (params instanceof Iterable) {
            return (Iterable<Object[]>) params;
        }
        else {
            throw parametersMethodReturnedWrongType();
        }
    }

    private Exception parametersMethodReturnedWrongType() throws Exception {
        String className = getTestClass().getName();
        String methodName = getParametersMethod().getName();
        String message = MessageFormat.format("{0}.{1}() must return an Iterable of arrays.",
            className, methodName);
        return new Exception(message);
    }

    private FrameworkMethod getParametersMethod() throws Exception {
        List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(Parameters.class);
        for (FrameworkMethod each : methods) {
            if (each.isStatic() && each.isPublic()) {
                return each;
            }
        }

        throw new Exception("No public static parameters method on class "
            + getTestClass().getName());
    }

    @Override
    protected void runChild(FrameworkMethod method, RunNotifier notifier) {
        boolean transactional = isTransactional(method);
        if (transactional) {
            runInTransaction(method, notifier);
        }
        else {
            super.runChild(method, notifier);
        }
    }

    private void runInTransaction(FrameworkMethod method, RunNotifier notifier) {
        UserTransaction tx = null;
        EachTestNotifier eachNotifier = makeNotifier(method, notifier);
        if (method.getAnnotation(Ignore.class) != null) {
            eachNotifier.fireTestIgnored();
            return;
        }

        eachNotifier.fireTestStarted();
        try {
            InitialContext ctx = new InitialContext();
            tx = (UserTransaction) ctx.lookup("java:comp/UserTransaction");
            tx.begin();
            methodBlock(method).evaluate();
        }
        catch (NamingException exc) {
            eachNotifier.addFailure(exc);
        }
        catch (NotSupportedException exc) {
            eachNotifier.addFailure(exc);
        }
        catch (SystemException exc) {
            eachNotifier.addFailure(exc);
        }
        catch (AssumptionViolatedException e) {
            eachNotifier.addFailedAssumption(e);
        }
        // CHECKSTYLE:SKIP : base class API
        catch (Throwable e) {
            eachNotifier.addFailure(e);
        }
        finally {
            rollback(tx, eachNotifier);
            eachNotifier.fireTestFinished();
        }
    }

    private void rollback(UserTransaction tx, EachTestNotifier eachNotifier) {
        if (tx != null) {
            try {
                tx.rollback();
            }
            catch (IllegalStateException exc) {
                eachNotifier.addFailure(exc);
            }
            catch (SecurityException exc) {
                eachNotifier.addFailure(exc);
            }
            catch (SystemException exc) {
                eachNotifier.addFailure(exc);
            }
        }
    }

    private boolean isTransactional(FrameworkMethod method) {
        return (method.getAnnotation(Transactional.class) != null) || transactionalClass;
    }

    private EachTestNotifier makeNotifier(FrameworkMethod method, RunNotifier notifier) {
        Description description = describeChild(method);
        return new EachTestNotifier(notifier, description);
    }

}
TOP

Related Classes of org.ops4j.pax.exam.servlet.ParameterizedContainerTestRunner

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.