package org.alfresco.util.test.junitrules;
import java.lang.annotation.Annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import junit.framework.Test;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.util.ParameterCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
/**
* This JUnit rule can be used to make test methods run as a particular user.
* A username can be provided on construction to the rule and then all @Test
methods will be
* run as that user.
*
@RunAsUser(userName="John")
than that
* method (and only that method) will be run as "John".
*
* Example usage:
* * public class YourTestClass * { * @ClassRule public static final ApplicationContextInit APP_CONTEXT_RULE = new ApplicationContextInit(); * @Rule public RunAsFullyAuthenticatedRule runAsGuidPerson = new RunAsFullyAuthenticatedRule("NeilM"); * * @Test public void doSomething() throws Exception * { * // This will run as NeilM * } * * @Test @RunAsUser(userName="DaveC") public void doSomething() throws Exception * { * // This will run as DaveC * } * } ** * @author Neil Mc Erlean * @since Odin */ public class RunAsFullyAuthenticatedRule implements TestRule { /** * This annotation can be used to mark an individual {@link Test} method for running as a named user. * * @author Neil Mc Erlean * @since Odin */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RunAsUser { String userName() default ""; } private static final Log log = LogFactory.getLog(RunAsFullyAuthenticatedRule.class); /** * A fixed username to run as. */ private final String fixedUserName; /** * A rule which will provide a username to run as */ private final AlfrescoPerson personRule; /** * This constructs a rule where there is no specified user to run as. * For this to be useful (or legal) a user must be specified on every test method using {@link RunAsUser}. */ public RunAsFullyAuthenticatedRule() { this.fixedUserName = null; this.personRule = null; } /** * @param userName the username which all test methods should run as. */ public RunAsFullyAuthenticatedRule(String userName) { ParameterCheck.mandatory("userName", userName); this.fixedUserName = userName; this.personRule = null; } /** * @param personRule the rule which will provide the username which all test methods should run as. */ public RunAsFullyAuthenticatedRule(AlfrescoPerson personRule) { ParameterCheck.mandatory("personRule", personRule); this.fixedUserName = null; this.personRule = personRule; } /** * Get the username which test methods will run as. */ public String getUsername() { return this.fixedUserName; } @Override public Statement apply(final Statement base, final Description description) { return new Statement() { @Override public void evaluate() throws Throwable { // Store the current authentication AuthenticationUtil.pushAuthentication(); // First, try for a username provided on the @Test method itself. String runAsUser = getMethodAnnotatedUserName(description); if (runAsUser != null) { // There is a @Test method username. log.debug("Running as method annotation-provided user: " + runAsUser); log.debug(" See " + description.getClassName() + "." + description.getMethodName()); } else { // There is no @Test method username, so fall back to rule-provided person. if (fixedUserName != null) { runAsUser = fixedUserName; log.debug("Running as username defined in this rule: " + runAsUser); } else if (personRule != null) { runAsUser = personRule.getUsername(); log.debug("Running as username provided by another rule: " + runAsUser); } else { throw new Exception("Illegal rule: must provide username or " + AlfrescoPerson.class.getSimpleName() + " at rule construction or else a " + RunAsUser.class.getSimpleName() + " annotation."); } } AuthenticationUtil.setFullyAuthenticatedUser(runAsUser); try { // Execute the test method or whatever other rules are configured further down the stack. base.evaluate(); } finally { // After - ensure that pass or fail, the authentication is restored. AuthenticationUtil.popAuthentication(); } } }; } /** * * @param description the description object from JUnit * @return the username specified in the {@link RunAsUser} annotation, if there was one, else
null
.
*/
private String getMethodAnnotatedUserName(Description description) throws IllegalArgumentException,
SecurityException, IllegalAccessException,
InvocationTargetException, NoSuchMethodException
{
String result = null;
Collection