[SPR-5914] ProfileValueUtils now properly ensures that class-level usage of @IfProfileValue overrides method-level usage.

This commit is contained in:
Sam Brannen
2009-07-10 11:45:31 +00:00
parent 0d98baa5c1
commit 696d78c144
6 changed files with 400 additions and 122 deletions

View File

@@ -31,62 +31,64 @@ import java.lang.annotation.Target;
* test will be enabled.
* </p>
* <p>
* Note: <code>&#064;IfProfileValue</code> can be applied at either the
* class or method level.
* Note: <code>&#064;IfProfileValue</code> can be applied at the class level,
* the method level, or both. <code>&#064;IfProfileValue</code> at the class
* level overrides method-level usage of <code>&#064;IfProfileValue</code> for
* any methods within that class.
* </p>
* <p>
* Examples: when using {@link SystemProfileValueSource} as the
* {@link ProfileValueSource} implementation, you can configure a test method to
* run only on Java VMs from Sun Microsystems as follows:
* </p>
*
*
* <pre class="code">
* &#064;IfProfileValue(name=&quot;java.vendor&quot;, value=&quot;Sun Microsystems Inc.&quot;)
* &#064;IfProfileValue(name = &quot;java.vendor&quot;, value = &quot;Sun Microsystems Inc.&quot;)
* public void testSomething() {
* // ...
* // ...
* }
* </pre>
*
* <p>
* You can alternatively configure <code>&#064;IfProfileValue</code> with
* <em>OR</em> semantics for multiple {@link #values() values} as follows
* (assuming a {@link ProfileValueSource} has been appropriately configured for
* the &quot;test-groups&quot; name):
* </p>
*
*
* <pre class="code">
* &#064;IfProfileValue(name=&quot;test-groups&quot;, values={&quot;unit-tests&quot;, &quot;integration-tests&quot;})
* &#064;IfProfileValue(name = &quot;test-groups&quot;, values = { &quot;unit-tests&quot;, &quot;integration-tests&quot; })
* public void testWhichRunsForUnitOrIntegrationTestGroups() {
* // ...
* // ...
* }
* </pre>
*
*
* @author Rod Johnson
* @author Sam Brannen
* @since 2.0
* @see ProfileValueSource
* @see ProfileValueSourceConfiguration
* @see ProfileValueUtils
* @see AbstractAnnotationAwareTransactionalTests
* @see org.springframework.test.context.junit38.AbstractJUnit38SpringContextTests
* @see org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests
* @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Target( { ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface IfProfileValue {
/**
* The <code>name</code> of the <em>profile value</em> against which to test.
* The <code>name</code> of the <em>profile value</em> against which to
* test.
*/
String name();
/**
* A single, permissible <code>value</code> of the <em>profile value</em>
* for the given {@link #name() name}.
* <p>Note: Assigning values to both {@link #value()} and {@link #values()}
* <p>
* Note: Assigning values to both {@link #value()} and {@link #values()}
* will lead to a configuration conflict.
*/
String value() default "";
@@ -94,7 +96,8 @@ public @interface IfProfileValue {
/**
* A list of all permissible <code>values</code> of the
* <em>profile value</em> for the given {@link #name() name}.
* <p>Note: Assigning values to both {@link #value()} and {@link #values()}
* <p>
* Note: Assigning values to both {@link #value()} and {@link #values()}
* will lead to a configuration conflict.
*/
String[] values() default {};

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,7 +20,6 @@ import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
@@ -28,7 +27,7 @@ import org.springframework.util.StringUtils;
/**
* General utility methods for working with <em>profile values</em>.
*
*
* @author Sam Brannen
* @author Juergen Hoeller
* @since 2.5
@@ -44,15 +43,15 @@ public abstract class ProfileValueUtils {
/**
* Retrieves the {@link ProfileValueSource} type for the specified
* {@link Class test class} as configured via the
* {@link ProfileValueSourceConfiguration @ProfileValueSourceConfiguration}
* annotation and instantiates a new instance of that type.
* {@link ProfileValueSourceConfiguration
* &#064;ProfileValueSourceConfiguration} annotation and instantiates a new
* instance of that type.
* <p>
* If
* {@link ProfileValueSourceConfiguration @ProfileValueSourceConfiguration}
* is not present on the specified class or if a custom
* {@link ProfileValueSource} is not declared, the default
* {@link SystemProfileValueSource} will be returned instead.
*
* If {@link ProfileValueSourceConfiguration
* &#064;ProfileValueSourceConfiguration} is not present on the specified
* class or if a custom {@link ProfileValueSource} is not declared, the
* default {@link SystemProfileValueSource} will be returned instead.
*
* @param testClass The test class for which the ProfileValueSource should
* be retrieved
* @return the configured (or default) ProfileValueSource for the specified
@@ -103,95 +102,92 @@ public abstract class ProfileValueUtils {
}
/**
* Determine if the supplied <code>testClass</code> is <em>enabled</em>
* in the current environment, as specified by the
* {@link IfProfileValue @IfProfileValue} annotation at the class level.
* Determine if the supplied <code>testClass</code> is <em>enabled</em> in
* the current environment, as specified by the {@link IfProfileValue
* &#064;IfProfileValue} annotation at the class level.
* <p>
* Defaults to <code>true</code> if no
* {@link IfProfileValue @IfProfileValue} annotation is declared.
*
* Defaults to <code>true</code> if no {@link IfProfileValue
* &#064;IfProfileValue} annotation is declared.
*
* @param testClass the test class
* @return <code>true</code> if the test is <em>enabled</em> in the
* current environment
* @return <code>true</code> if the test is <em>enabled</em> in the current
* environment
*/
public static boolean isTestEnabledInThisEnvironment(Class<?> testClass) {
IfProfileValue ifProfileValue = testClass.getAnnotation(IfProfileValue.class);
if (ifProfileValue == null) {
return true;
}
ProfileValueSource profileValueSource = retrieveProfileValueSource(testClass);
return isTestEnabledInThisEnvironment(profileValueSource, ifProfileValue);
return isTestEnabledInThisEnvironment(retrieveProfileValueSource(testClass), ifProfileValue);
}
/**
* Determine if the supplied <code>testMethod</code> is <em>enabled</em>
* in the current environment, as specified by the
* {@link IfProfileValue @IfProfileValue} annotation, which may be declared
* on the test method itself or at the class level.
* Determine if the supplied <code>testMethod</code> is <em>enabled</em> in
* the current environment, as specified by the {@link IfProfileValue
* &#064;IfProfileValue} annotation, which may be declared on the test
* method itself or at the class level. Class-level usage overrides
* method-level usage.
* <p>
* Defaults to <code>true</code> if no
* {@link IfProfileValue @IfProfileValue} annotation is declared.
*
* Defaults to <code>true</code> if no {@link IfProfileValue
* &#064;IfProfileValue} annotation is declared.
*
* @param testMethod the test method
* @param testClass the test class
* @return <code>true</code> if the test is <em>enabled</em> in the
* current environment
* @return <code>true</code> if the test is <em>enabled</em> in the current
* environment
*/
public static boolean isTestEnabledInThisEnvironment(Method testMethod, Class<?> testClass) {
IfProfileValue ifProfileValue = testMethod.getAnnotation(IfProfileValue.class);
if (ifProfileValue == null) {
ifProfileValue = testClass.getAnnotation(IfProfileValue.class);
if (ifProfileValue == null) {
return true;
}
}
ProfileValueSource profileValueSource = retrieveProfileValueSource(testClass);
return isTestEnabledInThisEnvironment(profileValueSource, ifProfileValue);
return isTestEnabledInThisEnvironment(retrieveProfileValueSource(testClass), testMethod, testClass);
}
/**
* Determine if the supplied <code>testMethod</code> is <em>enabled</em>
* in the current environment, as specified by the
* {@link IfProfileValue @IfProfileValue} annotation, which may be declared
* on the test method itself or at the class level.
* Determine if the supplied <code>testMethod</code> is <em>enabled</em> in
* the current environment, as specified by the {@link IfProfileValue
* &#064;IfProfileValue} annotation, which may be declared on the test
* method itself or at the class level. Class-level usage overrides
* method-level usage.
* <p>
* Defaults to <code>true</code> if no
* {@link IfProfileValue @IfProfileValue} annotation is declared.
*
* Defaults to <code>true</code> if no {@link IfProfileValue
* &#064;IfProfileValue} annotation is declared.
*
* @param profileValueSource the ProfileValueSource to use to determine if
* the test is enabled
* @param testMethod the test method
* @param testClass the test class
* @return <code>true</code> if the test is <em>enabled</em> in the
* current environment
* @return <code>true</code> if the test is <em>enabled</em> in the current
* environment
*/
public static boolean isTestEnabledInThisEnvironment(ProfileValueSource profileValueSource, Method testMethod,
Class<?> testClass) {
IfProfileValue ifProfileValue = testMethod.getAnnotation(IfProfileValue.class);
if (ifProfileValue == null) {
ifProfileValue = testClass.getAnnotation(IfProfileValue.class);
if (ifProfileValue == null) {
return true;
}
IfProfileValue ifProfileValue = testClass.getAnnotation(IfProfileValue.class);
boolean classLevelEnabled = isTestEnabledInThisEnvironment(profileValueSource, ifProfileValue);
if (classLevelEnabled) {
ifProfileValue = testMethod.getAnnotation(IfProfileValue.class);
return isTestEnabledInThisEnvironment(profileValueSource, ifProfileValue);
}
return isTestEnabledInThisEnvironment(profileValueSource, ifProfileValue);
return false;
}
/**
* Determine if the <code>value</code> (or one of the <code>values</code>)
* in the supplied {@link IfProfileValue @IfProfileValue} annotation is
* in the supplied {@link IfProfileValue &#064;IfProfileValue} annotation is
* <em>enabled</em> in the current environment.
*
*
* @param profileValueSource the ProfileValueSource to use to determine if
* the test is enabled
* @param ifProfileValue the annotation to introspect
* @return <code>true</code> if the test is <em>enabled</em> in the
* current environment
* @param ifProfileValue the annotation to introspect; may be
* <code>null</code>
* @return <code>true</code> if the test is <em>enabled</em> in the current
* environment or if the supplied <code>ifProfileValue</code> is
* <code>null</code>
*/
private static boolean isTestEnabledInThisEnvironment(ProfileValueSource profileValueSource,
IfProfileValue ifProfileValue) {
if (ifProfileValue == null) {
return true;
}
String environmentValue = profileValueSource.get(ifProfileValue.name());
String[] annotatedValues = ifProfileValue.values();
if (StringUtils.hasLength(ifProfileValue.value())) {