diff --git a/common/src/main/java/org/jboss/as/arquillian/api/ServerSetupTask.java b/common/src/main/java/org/jboss/as/arquillian/api/ServerSetupTask.java
index a9d117f7..b84fecb3 100644
--- a/common/src/main/java/org/jboss/as/arquillian/api/ServerSetupTask.java
+++ b/common/src/main/java/org/jboss/as/arquillian/api/ServerSetupTask.java
@@ -39,20 +39,25 @@ public interface ServerSetupTask {
* to the given container.
*
* Note on exception handling: If an implementation of this method
- * throws {@code org.junit.AssumptionViolatedException}, the implementation can assume
- * the following:
+ * throws any exception, the implementation can assume the following:
*
* - Any subsequent {@code ServerSetupTask}s {@link ServerSetup associated with test class}
* will not be executed.
* - The deployment event that triggered the call to this method will be skipped.
* - The {@link #tearDown(ManagementClient, String) tearDown} method of the instance
* that threw the exception will not be invoked. Therefore, implementations
- * that throw {@code AssumptionViolatedException} should do so before altering any
+ * that throw {@code AssumptionViolatedException}, or any other exception, should do so before altering any
* system state.
* - The {@link #tearDown(ManagementClient, String) tearDown} method for any
* previously executed {@code ServerSetupTask}s {@link ServerSetup associated with test class}
* will be invoked.
*
+ *
+ * If any other exception is thrown, the {@link #tearDown(ManagementClient, String)} will be executed, including
+ * this implementations {@code tearDown()}, re-throwing the original exception. The original exception will have
+ * any other exceptions thrown in the {@code tearDown()} methods add as
+ * {@linkplain Throwable#addSuppressed(Throwable) suppressed} messages.
+ *
*
* @param managementClient management client to use to interact with the container
* @param containerId id of the container to which the deployment will be deployed
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 03fd9c2d..76e15e50 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
@@ -17,7 +17,6 @@
package org.jboss.as.arquillian.container;
import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayDeque;
import java.util.Collection;
@@ -121,8 +120,7 @@ public synchronized void handleBeforeDeployment(@Observes BeforeDeploy event, Co
}
final ManagementClient client = managementClient.get();
- final ServerSetupTaskHolder holder = new ServerSetupTaskHolder(client, container, containerContext.get(), serviceLoader,
- enrichmentEvent);
+ final ServerSetupTaskHolder holder = new ServerSetupTaskHolder(client, container.getName());
executeSetup(holder, setup, containerName, event.getDeployment());
}
@@ -184,14 +182,15 @@ public synchronized void handleAfterUndeploy(@Observes AfterUnDeploy afterDeploy
private void executeSetup(final ServerSetupTaskHolder holder, ServerSetup setup, String containerName,
DeploymentDescription deployment)
- throws InvocationTargetException, NoSuchMethodException, IllegalAccessException, InstantiationException {
+ throws Exception {
holder.deployments.add(deployment);
setupTasks.put(containerName, holder);
try {
holder.setup(setup, containerName);
- } catch (FailedAssumptionException fae) {
+ } catch (Throwable t) {
+ final Throwable toThrow = t;
// We're going to throw on the underlying problem. But since that is going to
// propagate to surefire and prevent further processing of the currently executing
// test class, first we need to do cleanup work that's normally triggered by
@@ -210,10 +209,13 @@ private void executeSetup(final ServerSetupTaskHolder holder, ServerSetup setup,
// Tell the holder to do the normal tearDown
holder.tearDown(containerName);
- } catch (RuntimeException logged) { // just to be safe
+ } catch (Exception logged) { // just to be safe
String className = failedSetup != null ? failedSetup.getClass().getName()
: ServerSetupTask.class.getSimpleName();
- log.errorf(logged, "Failed tearing down ServerSetupTasks after a failed assumption in %s.setup()", className);
+ final String message = String
+ .format("Failed tearing down ServerSetupTasks after a failed assumption in %s.setup()", className);
+ toThrow.addSuppressed(new RuntimeException(message, logged));
+ log.errorf(logged, message);
} finally {
// Clean out our own state changes we made before calling holder.setup.
// Otherwise, later classes that use the same container may fail.
@@ -222,77 +224,40 @@ private void executeSetup(final ServerSetupTaskHolder holder, ServerSetup setup,
setupTasks.remove(containerName);
}
}
-
- throw fae.underlyingException;
+ if (toThrow instanceof Exception) {
+ throw (Exception) toThrow;
+ }
+ if (toThrow instanceof Error) {
+ throw (Error) toThrow;
+ }
+ // Throw the error as an assertion error to abort the testing
+ throw new AssertionError("Failed to invoke a ServerSetupTask.", toThrow);
}
-
}
- private static class ServerSetupTaskHolder {
-
- // Use reflection to access the various 'assumption' failure classes
- // to avoid compile dependencies 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 final Class> TESTNG_SKIPPED_EXCEPTION = loadAssumptionFailureClass(
- "org.testng.SkipException");
-
- @SuppressWarnings("SameParameterValue")
- 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 class ServerSetupTaskHolder {
private final ManagementClient client;
private final Deque setupTasks;
private final Set deployments;
- private final Container container;
- private final ContainerContext containerContext;
- private final Instance serviceLoader;
- private final Event enrichmentEvent;
-
- private ServerSetupTaskHolder(final ManagementClient client, final Container container,
- final ContainerContext containerContext,
- final Instance serviceLoader,
- final Event enrichmentEvent) {
+ private final String containerName;;
+
+ private ServerSetupTaskHolder(final ManagementClient client, final String containerName) {
this.client = client;
setupTasks = new ArrayDeque<>();
deployments = new HashSet<>();
- this.container = container;
- this.containerContext = containerContext;
- this.serviceLoader = serviceLoader;
- this.enrichmentEvent = enrichmentEvent;
+ this.containerName = containerName;
}
- void setup(final ServerSetup setup, final String containerName)
- throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException,
- FailedAssumptionException {
+ void setup(final ServerSetup setup, final String containerName) throws Throwable {
final Class extends ServerSetupTask>[] classes = setup.value();
for (Class extends ServerSetupTask> clazz : classes) {
final Constructor extends ServerSetupTask> ctor = clazz.getDeclaredConstructor();
ctor.setAccessible(true);
final ServerSetupTask task = ctor.newInstance();
- try {
- enrich(task, clazz.getMethod("setup", ManagementClient.class, String.class));
- setupTasks.add(task);
- 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, containerName);
- // Some other failure -- log it
- log.errorf(e, "Setup failed during setup. Offending class '%s'", task);
- }
+ enrich(task, clazz.getMethod("setup", ManagementClient.class, String.class));
+ setupTasks.add(task);
+ task.setup(client, containerName);
}
}
@@ -327,22 +292,9 @@ public String toString() {
"]";
}
- private void rethrowFailedAssumptions(final Throwable t, final String containerName) throws FailedAssumptionException {
- rethrowFailedAssumption(t, ASSUMPTION_VIOLATED_EXCEPTION);
- rethrowFailedAssumption(t, TEST_ABORTED_EXCEPTION);
- rethrowFailedAssumption(t, TESTNG_SKIPPED_EXCEPTION);
- }
-
- @SuppressWarnings("SameParameterValue")
- private void rethrowFailedAssumption(Throwable t, Class> failureType) throws FailedAssumptionException {
- if (failureType != null && failureType.isAssignableFrom(t.getClass())) {
- throw new FailedAssumptionException(t);
- }
- }
-
private void enrich(final ServerSetupTask task, final Method method) {
try {
- containerContext.activate(container.getName());
+ containerContext.get().activate(containerName);
enrichmentEvent.fire(new BeforeEnrichment(task, method));
Collection testEnrichers = serviceLoader.get().all(TestEnricher.class);
for (TestEnricher enricher : testEnrichers) {
@@ -350,16 +302,8 @@ private void enrich(final ServerSetupTask task, final Method method) {
}
enrichmentEvent.fire(new AfterEnrichment(task, method));
} finally {
- containerContext.deactivate();
+ containerContext.get().deactivate();
}
}
}
-
- private static class FailedAssumptionException extends Exception {
- private final RuntimeException underlyingException;
-
- private FailedAssumptionException(Object underlying) {
- this.underlyingException = (RuntimeException) underlying;
- }
- }
}
diff --git a/integration-tests/junit5-tests/pom.xml b/integration-tests/junit5-tests/pom.xml
index 41ac961d..885b18b6 100644
--- a/integration-tests/junit5-tests/pom.xml
+++ b/integration-tests/junit5-tests/pom.xml
@@ -68,6 +68,11 @@
junit-platform-testkit
test
+
+ org.wildfly.arquillian
+ wildfly-arquillian-junit-api
+ test
+
org.wildfly.arquillian
wildfly-arquillian-container-managed
diff --git a/integration-tests/junit5-tests/src/test/java/org/wildfly/arquillian/integration/test/junit5/server/setup/SetupTaskTestCase.java b/integration-tests/junit5-tests/src/test/java/org/wildfly/arquillian/integration/test/junit5/server/setup/SetupTaskTestCase.java
new file mode 100644
index 00000000..92764201
--- /dev/null
+++ b/integration-tests/junit5-tests/src/test/java/org/wildfly/arquillian/integration/test/junit5/server/setup/SetupTaskTestCase.java
@@ -0,0 +1,160 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ *
+ * Copyright 2024 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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.wildfly.arquillian.integration.test.junit5.server.setup;
+
+import java.io.IOException;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.as.arquillian.container.ManagementClient;
+import org.jboss.as.controller.client.Operation;
+import org.jboss.as.controller.client.helpers.ClientConstants;
+import org.jboss.as.controller.client.helpers.Operations;
+import org.jboss.as.controller.client.helpers.Operations.CompositeOperationBuilder;
+import org.jboss.dmr.ModelNode;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.EmptyAsset;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.platform.engine.discovery.DiscoverySelectors;
+import org.junit.platform.testkit.engine.EngineTestKit;
+import org.junit.platform.testkit.engine.EventConditions;
+import org.junit.platform.testkit.engine.TestExecutionResultConditions;
+import org.wildfly.arquillian.junit.annotations.WildFlyArquillian;
+
+/**
+ * @author James R. Perkins
+ */
+@WildFlyArquillian
+@RunAsClient
+public class SetupTaskTestCase {
+
+ @ArquillianResource
+ private ManagementClient client;
+
+ @Deployment
+ public static WebArchive createDeployment() {
+ return ShrinkWrap.create(WebArchive.class, "setup-task-test.war")
+ .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
+ }
+
+ @BeforeEach
+ public void clearSystemProperties() throws Exception {
+ final CompositeOperationBuilder builder = CompositeOperationBuilder.create();
+ for (ModelNode name : getSystemProperties()) {
+ final ModelNode address = Operations.createAddress("system-property", name.asString());
+ builder.addStep(Operations.createRemoveOperation(address));
+ }
+ executeOperation(builder.build());
+ }
+
+ @Test
+ public void successThenAssertionFail() throws Exception {
+ final var results = EngineTestKit.engine("junit-jupiter")
+ .selectors(DiscoverySelectors.selectClass(SetupTaskTests.SuccessThenAssertionFail.class))
+ .execute();
+ // No tests should have been executed
+ final var testEvents = results.testEvents();
+ testEvents.assertThatEvents().isEmpty();
+ // We should have one failure from the setup task
+ final var events = results.allEvents();
+ events.assertStatistics((stats) -> stats.failed(1L));
+ events.assertThatEvents()
+ .haveAtLeastOne(EventConditions.event(
+ EventConditions.finishedWithFailure(TestExecutionResultConditions.instanceOf(AssertionError.class))));
+ assertOnlyProperties(SetupTaskTests.AssertionErrorSetupTask.PROPERTY_NAME);
+ }
+
+ @Test
+ public void successThenRuntimeFail() throws Exception {
+ final var results = EngineTestKit.engine("junit-jupiter")
+ .selectors(DiscoverySelectors.selectClass(SetupTaskTests.SuccessThenRuntimeFail.class))
+ .execute();
+ // No tests should have been executed
+ final var testEvents = results.testEvents();
+ testEvents.assertThatEvents().isEmpty();
+ // We should have one failure from the setup task
+ final var events = results.allEvents();
+ events.assertStatistics((stats) -> stats.failed(1L));
+ events.assertThatEvents()
+ .haveAtLeastOne(EventConditions.event(
+ EventConditions.finishedWithFailure(TestExecutionResultConditions.instanceOf(RuntimeException.class))));
+ assertOnlyProperties(SetupTaskTests.RuntimeExceptionSetupTask.PROPERTY_NAME);
+ }
+
+ @Test
+ public void successAndAfter() throws Exception {
+ final var results = EngineTestKit.engine("junit-jupiter")
+ .selectors(DiscoverySelectors.selectMethod(SetupTaskTests.SuccessAndAfter.class, "systemPropertiesExist"))
+ .execute();
+ // The test should have been successful
+ final var testEvents = results.testEvents();
+ testEvents.assertThatEvents().haveExactly(1, EventConditions.finishedSuccessfully());
+ // All properties should have been removed in the SetupServerTask.tearDown()
+ assertNoSystemProperties();
+ }
+
+ private void assertOnlyProperties(final String... names) throws IOException {
+ final Set expectedNames = Set.of(names);
+ final Set allProperties = getSystemProperties()
+ .stream()
+ .map(ModelNode::asString)
+ .collect(Collectors.toCollection(LinkedHashSet::new));
+ Assertions.assertTrue(allProperties.containsAll(expectedNames), () -> String
+ .format("The following properties were expected in \"%s\", but not found; %s", allProperties, expectedNames));
+ // Remove the expected properties
+ allProperties.removeAll(expectedNames);
+ Assertions.assertTrue(allProperties.isEmpty(),
+ () -> String.format("The following properties exist which should not exist: %s", allProperties));
+ }
+
+ private void assertNoSystemProperties() throws IOException {
+ final ModelNode op = Operations.createOperation("read-children-names");
+ op.get(ClientConstants.CHILD_TYPE).set("system-property");
+ final ModelNode result = executeOperation(op);
+ Assertions.assertTrue(result.asList()
+ .isEmpty(), () -> "Expected no system properties, found: " + result.asString());
+ }
+
+ private List getSystemProperties() throws IOException {
+ final ModelNode op = Operations.createOperation("read-children-names");
+ op.get(ClientConstants.CHILD_TYPE).set("system-property");
+ return executeOperation(op).asList();
+ }
+
+ private ModelNode executeOperation(final ModelNode op) throws IOException {
+ return executeOperation(Operation.Factory.create(op));
+ }
+
+ private ModelNode executeOperation(final Operation op) throws IOException {
+ final ModelNode result = client.getControllerClient().execute(op);
+ if (!Operations.isSuccessfulOutcome(result)) {
+ Assertions.fail("Operation has failed: " + Operations.getFailureDescription(result).asString());
+ }
+ return Operations.readResult(result);
+ }
+}
diff --git a/integration-tests/junit5-tests/src/test/java/org/wildfly/arquillian/integration/test/junit5/server/setup/SetupTaskTests.java b/integration-tests/junit5-tests/src/test/java/org/wildfly/arquillian/integration/test/junit5/server/setup/SetupTaskTests.java
new file mode 100644
index 00000000..947cf336
--- /dev/null
+++ b/integration-tests/junit5-tests/src/test/java/org/wildfly/arquillian/integration/test/junit5/server/setup/SetupTaskTests.java
@@ -0,0 +1,162 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ *
+ * Copyright 2024 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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.wildfly.arquillian.integration.test.junit5.server.setup;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.as.arquillian.api.ServerSetup;
+import org.jboss.as.arquillian.api.ServerSetupTask;
+import org.jboss.as.arquillian.container.ManagementClient;
+import org.jboss.as.controller.client.helpers.ClientConstants;
+import org.jboss.as.controller.client.helpers.Operations;
+import org.jboss.dmr.ModelNode;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
+import org.wildfly.arquillian.junit.annotations.WildFlyArquillian;
+
+/**
+ * @author James R. Perkins
+ */
+@WildFlyArquillian
+@RunAsClient
+abstract class SetupTaskTests {
+
+ public static class SuccessfulSetupTask extends SystemPropertyServerSetupTask implements ServerSetupTask {
+ public static final String PROPERTY_NAME = "wildfly.arquillian.test.success";
+
+ public SuccessfulSetupTask() {
+ super(Map.of(PROPERTY_NAME, "true"));
+ }
+ }
+
+ public static class AfterSuccessfulSetupTask extends SystemPropertyServerSetupTask implements ServerSetupTask {
+ public static final String PROPERTY_NAME = "wildfly.arquillian.test.success.after";
+
+ public AfterSuccessfulSetupTask() {
+ super(Map.of(PROPERTY_NAME, "true"));
+ }
+ }
+
+ public static class RuntimeExceptionSetupTask extends SystemPropertyServerSetupTask implements ServerSetupTask {
+ public static final String PROPERTY_NAME = "wildfly.arquillian.test.runtime.exception";
+
+ public RuntimeExceptionSetupTask() {
+ super(Map.of(PROPERTY_NAME, "true"));
+ }
+
+ @Override
+ public void setup(final ManagementClient managementClient, final String containerId) throws Exception {
+ super.setup(managementClient, containerId);
+ throw new RuntimeException("RuntimeException failed on purpose");
+ }
+ }
+
+ public static class AssertionErrorSetupTask extends SystemPropertyServerSetupTask implements ServerSetupTask {
+ public static final String PROPERTY_NAME = "wildfly.arquillian.test.assertion.error";
+
+ public AssertionErrorSetupTask() {
+ super(Map.of(PROPERTY_NAME, "true"));
+ }
+
+ @Override
+ public void setup(final ManagementClient managementClient, final String containerId) throws Exception {
+ super.setup(managementClient, containerId);
+ Assertions.fail("AssertionError failed on purpose");
+ }
+ }
+
+ @ArquillianResource
+ private ManagementClient client;
+
+ @Deployment
+ public static WebArchive createDeployment() {
+ return ShrinkWrap.create(WebArchive.class, "inner-setup-task-tests.war")
+ .addClasses(SetupTaskTestCase.class,
+ SuccessfulSetupTask.class,
+ RuntimeExceptionSetupTask.class,
+ AssertionErrorSetupTask.class);
+ }
+
+ @Test
+ public void failIfExecuted(final TestInfo testInfo) {
+ Assertions.fail(String.format("Test %s.%s should not have been executed.",
+ testInfo.getTestClass().map(Class::getName).orElse("Unknown"),
+ testInfo.getTestMethod().map(Method::getName).orElse("Unknown")));
+ }
+
+ @Test
+ public void systemPropertiesExist() throws Exception {
+ final Set properties = getSystemProperties()
+ .stream()
+ .map(ModelNode::asString)
+ .collect(Collectors.toCollection(TreeSet::new));
+ Assertions.assertIterableEquals(
+ new TreeSet<>(Set.of(SuccessfulSetupTask.PROPERTY_NAME, AfterSuccessfulSetupTask.PROPERTY_NAME)), properties);
+ }
+
+ private List getSystemProperties() throws IOException {
+ final ModelNode op = Operations.createOperation("read-children-names");
+ op.get(ClientConstants.CHILD_TYPE).set("system-property");
+ return executeOperation(op).asList();
+ }
+
+ private ModelNode executeOperation(final ModelNode op) throws IOException {
+ final ModelNode result = client.getControllerClient().execute(op);
+ if (!Operations.isSuccessfulOutcome(result)) {
+ Assertions.fail("Operation has failed: " + Operations.getFailureDescription(result).asString());
+ }
+ return Operations.readResult(result);
+ }
+
+ @ServerSetup({
+ SuccessfulSetupTask.class,
+ RuntimeExceptionSetupTask.class,
+ AfterSuccessfulSetupTask.class
+ })
+ public static class SuccessThenRuntimeFail extends SetupTaskTests {
+ }
+
+ @ServerSetup({
+ SuccessfulSetupTask.class,
+ AssertionErrorSetupTask.class,
+ AfterSuccessfulSetupTask.class
+ })
+ public static class SuccessThenAssertionFail extends SetupTaskTests {
+ }
+
+ @ServerSetup({
+ SuccessfulSetupTask.class,
+ AfterSuccessfulSetupTask.class
+ })
+ public static class SuccessAndAfter extends SetupTaskTests {
+ }
+}
diff --git a/integration-tests/junit5-tests/src/test/java/org/wildfly/arquillian/integration/test/junit5/server/setup/SystemPropertyServerSetupTask.java b/integration-tests/junit5-tests/src/test/java/org/wildfly/arquillian/integration/test/junit5/server/setup/SystemPropertyServerSetupTask.java
new file mode 100644
index 00000000..58eadf58
--- /dev/null
+++ b/integration-tests/junit5-tests/src/test/java/org/wildfly/arquillian/integration/test/junit5/server/setup/SystemPropertyServerSetupTask.java
@@ -0,0 +1,60 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ *
+ * Copyright 2024 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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.wildfly.arquillian.integration.test.junit5.server.setup;
+
+import java.util.Map;
+
+import org.jboss.as.arquillian.api.ServerSetupTask;
+import org.jboss.as.arquillian.container.ManagementClient;
+import org.jboss.as.controller.client.helpers.Operations;
+import org.jboss.dmr.ModelNode;
+
+/**
+ * @author James R. Perkins
+ */
+public class SystemPropertyServerSetupTask implements ServerSetupTask {
+ public final Map properties;
+
+ public SystemPropertyServerSetupTask(final Map properties) {
+ this.properties = Map.copyOf(properties);
+ }
+
+ @Override
+ public void setup(final ManagementClient managementClient, final String containerId) throws Exception {
+ final Operations.CompositeOperationBuilder builder = Operations.CompositeOperationBuilder.create();
+ for (var entry : properties.entrySet()) {
+ final ModelNode address = Operations.createAddress("system-property", entry.getKey());
+ final ModelNode op = Operations.createAddOperation(address);
+ op.get("value").set(entry.getValue());
+ builder.addStep(op);
+ }
+ executeOperation(managementClient, builder.build());
+ }
+
+ @Override
+ public void tearDown(final ManagementClient managementClient, final String containerId) throws Exception {
+ final Operations.CompositeOperationBuilder builder = Operations.CompositeOperationBuilder.create();
+ for (var entry : properties.entrySet()) {
+ final ModelNode address = Operations.createAddress("system-property", entry.getKey());
+ builder.addStep(Operations.createRemoveOperation(address));
+ }
+ executeOperation(managementClient, builder.build());
+ }
+}
diff --git a/integration-tests/junit5-tests/src/test/resources/arquillian.xml b/integration-tests/junit5-tests/src/test/resources/arquillian.xml
index c619b203..94b49d1a 100644
--- a/integration-tests/junit5-tests/src/test/resources/arquillian.xml
+++ b/integration-tests/junit5-tests/src/test/resources/arquillian.xml
@@ -22,7 +22,8 @@
${jboss.home}
${debug.vm.args} ${jvm.args}
- false
+
+ true
diff --git a/pom.xml b/pom.xml
index 447f9aab..efd99976 100644
--- a/pom.xml
+++ b/pom.xml
@@ -592,6 +592,11 @@
wildfly-arquillian-container-remote
${project.version}
+
+ org.wildfly.arquillian
+ wildfly-arquillian-junit-api
+ ${project.version}
+
org.wildfly.arquillian
wildfly-arquillian-protocol-jmx