diff --git a/common/src/main/java/org/jboss/as/arquillian/container/ServerSetupObserver.java b/common/src/main/java/org/jboss/as/arquillian/container/ServerSetupObserver.java index 2cd1d220..e714bdb4 100644 --- a/common/src/main/java/org/jboss/as/arquillian/container/ServerSetupObserver.java +++ b/common/src/main/java/org/jboss/as/arquillian/container/ServerSetupObserver.java @@ -166,6 +166,26 @@ public synchronized void handleAfterUndeploy(@Observes AfterUnDeploy afterDeploy } private static class ServerSetupTaskHolder { + + // Use reflection to access the various 'assumption' failure classes + // to avoid compile deps on JUnit 4 and 5 + private static final Class ASSUMPTION_VIOLATED_EXCEPTION = loadAssumptionFailureClass( + "org.junit.AssumptionViolatedException"); + private static final Class TEST_ABORTED_EXCEPTION = loadAssumptionFailureClass( + "org.opentest4j.TestAbortedException"); + + private static Class loadAssumptionFailureClass(String classname) { + Class result = null; + try { + result = ServerSetupObserver.class.getClassLoader().loadClass(classname); + } catch (ClassNotFoundException cnfe) { + log.debugf("%s is not available", classname); + } catch (Throwable t) { + log.warnf(t, "Failed to load %s", classname); + } + return result; + } + private final ManagementClient client; private final Deque setupTasks; private final Set deployments; @@ -187,6 +207,9 @@ void setup(final ServerSetup setup, final String containerName) try { task.setup(client, containerName); } catch (Throwable e) { + // If this is one of the 'assumption failed' exceptions used in JUnit 4 or 5, throw it on + rethrowFailedAssumptions(e); + // Some other failure -- log it log.errorf(e, "Setup failed during setup. Offending class '%s'", task); } } @@ -202,6 +225,14 @@ public void tearDown(final String containerName) { try { task.tearDown(client, containerName); } catch (Throwable e) { + // Unlike with setup, here we don't propagate assumption failures. + // Whatever was meant to be turned off by an assumption failure in setup has + // already been turned off; here we want to ensure all tear down work proceeds. + // + // Best practice for a ServerSetupTask that throws an assumption failure in setup + // would be to make tearDown a no-op, but implementors may not do that and may + // instead throw the assumption failure in tearDown as well. So we guard against that. + log.errorf(e, "Setup task failed during tear down. Offending class '%s'", task); } } @@ -217,5 +248,16 @@ public String toString() { deployments + "]"; } + + private static void rethrowFailedAssumptions(Throwable t) { + rethrowFailedAssumption(t, ASSUMPTION_VIOLATED_EXCEPTION); + rethrowFailedAssumption(t, TEST_ABORTED_EXCEPTION); + } + + private static void rethrowFailedAssumption(Throwable t, Class failureType) { + if (failureType != null && t.getClass().isAssignableFrom(failureType)) { + throw (RuntimeException) t; + } + } } }