/* * (C) Copyright 2014-2015 Nuxeo SA (http://nuxeo.com/) and others. * * 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. * * Contributors: * Stephane Lacoin, Julien Carsique * */ package org.nuxeo.runtime.test.runner; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Field; import java.lang.reflect.Method; import javax.inject.Inject; import javax.inject.Named; import org.apache.commons.lang3.SystemUtils; import org.junit.Rule; import org.junit.rules.MethodRule; import org.junit.runner.Description; import org.junit.runner.notification.RunNotifier; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.Statement; public class ConditionalIgnoreRule implements MethodRule { @Inject private RunNotifier runNotifier; @Inject private FeaturesRunner runner; public static class Feature extends SimpleFeature { protected static final ConditionalIgnoreRule rule = new ConditionalIgnoreRule(); @Rule public MethodRule methodRule() { return rule; } } @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE, ElementType.METHOD }) public @interface Ignore { Class<? extends Condition> condition(); /** * Optional reason why the test is ignored, reported additionally to the condition class simple name. */ String cause() default ""; } public interface Condition { boolean shouldIgnore(); } public static final class NXP10926H2Upgrade implements Condition { @Override public boolean shouldIgnore() { return false; } } public static final class IgnoreIsolated implements Condition { boolean isIsolated = "org.nuxeo.runtime.testsuite.IsolatedClassloader" .equals(getClass().getClassLoader().getClass().getName()); @Override public boolean shouldIgnore() { return isIsolated; } } public static final class IgnoreLongRunning implements Condition { @Override public boolean shouldIgnore() { return true; } } public static final class IgnoreWindows implements Condition { @Override public boolean shouldIgnore() { return SystemUtils.IS_OS_WINDOWS; } } @Override public Statement apply(Statement base, FrameworkMethod method, Object fixtureTarget) { Class<?> fixtureType = fixtureTarget.getClass(); Method fixtureMethod = method.getMethod(); Description description = Description.createTestDescription(fixtureType, fixtureMethod.getName(), fixtureMethod.getAnnotations()); return shouldIgnore(base, description, runner.getConfig(method, Ignore.class), fixtureType, fixtureMethod, fixtureTarget); } protected Statement shouldIgnore(Statement base, Description description, Ignore ignore, Class<?> type) { return shouldIgnore(base, description, ignore, type, null, null); } protected Statement shouldIgnore(Statement base, Description description, Ignore ignore, Class<?> type, Method method, Object target) { Class<? extends Condition> conditionType = ignore.condition(); if (conditionType == null) { return base; } if (!newCondition(type, method, target, conditionType).shouldIgnore()) { return base; } return new Statement() { @Override public void evaluate() throws Throwable { runNotifier.fireTestIgnored(description); } }; } protected Condition newCondition(Class<?> type, Method method, Object target, Class<? extends Condition> conditionType) throws Error { Condition condition; try { condition = conditionType.newInstance(); } catch (InstantiationException | IllegalAccessException cause) { throw new Error("Cannot instantiate condition of type " + conditionType, cause); } injectCondition(type, method, target, condition); return condition; } protected void injectCondition(Class<?> type, Method method, Object target, Condition condition) throws SecurityException, Error { Error errors = new Error("Cannot inject condition parameters in " + condition.getClass()); for (Field eachField : condition.getClass().getDeclaredFields()) { if (!eachField.isAnnotationPresent(Inject.class)) { continue; } Object eachValue = null; if (eachField.isAnnotationPresent(Named.class)) { String name = eachField.getAnnotation(Named.class).value(); if ("type".equals(name)) { eachValue = type; } else if ("target".equals(name)) { eachValue = target; } else if ("method".equals(name)) { eachValue = method; } } else { Class<?> eachType = eachField.getType(); if (eachType.equals(Class.class)) { eachValue = type; } else if (eachType.equals(Object.class)) { eachValue = target; } else if (eachType.equals(Method.class)) { eachValue = method; } } if (eachValue == null) { continue; } eachField.setAccessible(true); try { eachField.set(condition, eachValue); } catch (IllegalArgumentException | IllegalAccessException cause) { errors.addSuppressed(new Error("Cannot inject " + eachField.getName(), cause)); } } if (errors.getSuppressed().length > 0) { throw errors; } runner.getInjector().injectMembers(condition); } }