Skip to content

Commit 2dabedb

Browse files
committed
[661] Add a new event which will handle injecting method parameters. This allows @beforeeach annotated methods to start a container and deploy a deployment for manual mode tests.
Signed-off-by: James R. Perkins <[email protected]>
1 parent 7602c7a commit 2dabedb

File tree

6 files changed

+306
-14
lines changed

6 files changed

+306
-14
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
* JBoss, Home of Professional Open Source.
3+
*
4+
* Copyright 2025 Red Hat, Inc., and individual contributors
5+
* as indicated by the @author tags.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
package org.jboss.arquillian.integration.test.manual;
21+
22+
import java.net.URI;
23+
import java.net.URL;
24+
25+
import org.jboss.arquillian.container.test.api.ContainerController;
26+
import org.jboss.arquillian.container.test.api.Deployer;
27+
import org.jboss.arquillian.container.test.api.Deployment;
28+
import org.jboss.arquillian.container.test.api.OperateOnDeployment;
29+
import org.jboss.arquillian.container.test.api.RunAsClient;
30+
import org.jboss.arquillian.integration.test.common.app.EchoResource;
31+
import org.jboss.arquillian.integration.test.common.app.RestActivator;
32+
import org.jboss.arquillian.junit5.container.annotation.ArquillianTest;
33+
import org.jboss.arquillian.test.api.ArquillianResource;
34+
import org.jboss.shrinkwrap.api.ShrinkWrap;
35+
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
36+
import org.jboss.shrinkwrap.api.spec.WebArchive;
37+
import org.junit.jupiter.api.AfterEach;
38+
import org.junit.jupiter.api.Assertions;
39+
import org.junit.jupiter.api.BeforeEach;
40+
import org.junit.jupiter.api.Test;
41+
42+
/**
43+
* @author <a href="mailto:[email protected]">James R. Perkins</a>
44+
*/
45+
@ArquillianTest
46+
@RunAsClient
47+
public class ManualModeInjectionMultiDeploymentTest {
48+
private static final String CONTAINER_NAME = "default";
49+
static final String DEPLOYMENT_NAME_1 = "manual-mode-default";
50+
static final String DEPLOYMENT_NAME_2 = "manual-mode-secondary";
51+
52+
@ArquillianResource
53+
private static ContainerController controller;
54+
55+
@ArquillianResource
56+
private static Deployer deployer;
57+
58+
@Deployment(name = DEPLOYMENT_NAME_1, managed = false)
59+
public static WebArchive createDeployment() {
60+
return ShrinkWrap.create(WebArchive.class, DEPLOYMENT_NAME_1 + ".war")
61+
.addClasses(RestActivator.class, EchoResource.class)
62+
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
63+
}
64+
65+
@Deployment(name = DEPLOYMENT_NAME_2, managed = false)
66+
public static WebArchive createDeploymentSecondary() {
67+
return ShrinkWrap.create(WebArchive.class, DEPLOYMENT_NAME_2 + ".war")
68+
.addClasses(RestActivator.class, EchoResource.class)
69+
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
70+
}
71+
72+
@BeforeEach
73+
public void startAndDeploy() {
74+
controller.start(CONTAINER_NAME);
75+
deployer.deploy(DEPLOYMENT_NAME_1);
76+
deployer.deploy(DEPLOYMENT_NAME_2);
77+
}
78+
79+
@AfterEach
80+
public void stop() {
81+
if (controller.isStarted(CONTAINER_NAME)) {
82+
deployer.undeploy(DEPLOYMENT_NAME_1);
83+
deployer.undeploy(DEPLOYMENT_NAME_2);
84+
controller.stop(CONTAINER_NAME);
85+
}
86+
}
87+
88+
@Test
89+
public void checkUri(@OperateOnDeployment(DEPLOYMENT_NAME_1) @ArquillianResource final URI uri) {
90+
Assertions.assertNotNull(uri);
91+
Assertions.assertTrue(uri.toString().contains("/" + DEPLOYMENT_NAME_1));
92+
}
93+
94+
@Test
95+
public void checkUrl(@OperateOnDeployment(DEPLOYMENT_NAME_1) @ArquillianResource final URL url) {
96+
Assertions.assertNotNull(url);
97+
Assertions.assertTrue(url.toString().contains("/" + DEPLOYMENT_NAME_1));
98+
}
99+
100+
@Test
101+
public void checkSecondaryUri(@OperateOnDeployment(DEPLOYMENT_NAME_2) @ArquillianResource final URI uri) {
102+
Assertions.assertNotNull(uri);
103+
Assertions.assertTrue(uri.toString().contains("/" + DEPLOYMENT_NAME_2));
104+
}
105+
106+
@Test
107+
public void checkSecondaryUrl(@OperateOnDeployment(DEPLOYMENT_NAME_2) @ArquillianResource final URL url) {
108+
Assertions.assertNotNull(url);
109+
Assertions.assertTrue(url.toString().contains("/" + DEPLOYMENT_NAME_2));
110+
}
111+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* JBoss, Home of Professional Open Source.
3+
*
4+
* Copyright 2025 Red Hat, Inc., and individual contributors
5+
* as indicated by the @author tags.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
package org.jboss.arquillian.integration.test.manual;
21+
22+
import java.net.URI;
23+
import java.net.URL;
24+
25+
import org.jboss.arquillian.container.test.api.ContainerController;
26+
import org.jboss.arquillian.container.test.api.Deployer;
27+
import org.jboss.arquillian.container.test.api.Deployment;
28+
import org.jboss.arquillian.container.test.api.RunAsClient;
29+
import org.jboss.arquillian.integration.test.common.app.EchoResource;
30+
import org.jboss.arquillian.integration.test.common.app.RestActivator;
31+
import org.jboss.arquillian.junit5.container.annotation.ArquillianTest;
32+
import org.jboss.arquillian.test.api.ArquillianResource;
33+
import org.jboss.shrinkwrap.api.ShrinkWrap;
34+
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
35+
import org.jboss.shrinkwrap.api.spec.WebArchive;
36+
import org.junit.jupiter.api.AfterEach;
37+
import org.junit.jupiter.api.Assertions;
38+
import org.junit.jupiter.api.BeforeEach;
39+
import org.junit.jupiter.api.Test;
40+
41+
/**
42+
* @author <a href="mailto:[email protected]">James R. Perkins</a>
43+
*/
44+
@ArquillianTest
45+
@RunAsClient
46+
public class ManualModeInjectionTest {
47+
private static final String CONTAINER_NAME = "default";
48+
static final String DEPLOYMENT_NAME = "manual-mode";
49+
50+
@ArquillianResource
51+
private static ContainerController controller;
52+
53+
@ArquillianResource
54+
private static Deployer deployer;
55+
56+
@Deployment(name = DEPLOYMENT_NAME, managed = false)
57+
public static WebArchive createDeployment() {
58+
return ShrinkWrap.create(WebArchive.class, DEPLOYMENT_NAME + ".war")
59+
.addClasses(RestActivator.class, EchoResource.class)
60+
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
61+
}
62+
63+
@BeforeEach
64+
public void startAndDeploy() {
65+
controller.start(CONTAINER_NAME);
66+
deployer.deploy(DEPLOYMENT_NAME);
67+
}
68+
69+
@AfterEach
70+
public void stop() {
71+
if (controller.isStarted(CONTAINER_NAME)) {
72+
deployer.undeploy(DEPLOYMENT_NAME);
73+
controller.stop(CONTAINER_NAME);
74+
}
75+
}
76+
77+
@Test
78+
public void checkUri(@ArquillianResource final URI uri) {
79+
Assertions.assertNotNull(uri);
80+
Assertions.assertTrue(uri.toString().contains("/" + DEPLOYMENT_NAME));
81+
}
82+
83+
@Test
84+
public void checkUrl(@ArquillianResource final URL url) {
85+
Assertions.assertNotNull(url);
86+
Assertions.assertTrue(url.toString().contains("/" + DEPLOYMENT_NAME));
87+
}
88+
}

junit5/core/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
<artifactId>arquillian-test-spi</artifactId>
2727
<version>${project.version}</version>
2828
</dependency>
29+
<dependency>
30+
<groupId>org.jboss.arquillian.container</groupId>
31+
<artifactId>arquillian-container-spi</artifactId>
32+
<version>${project.version}</version>
33+
</dependency>
2934

3035
<dependency>
3136
<groupId>org.junit.jupiter</groupId>

junit5/core/src/main/java/org/jboss/arquillian/junit5/ArquillianExtension.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.junit.jupiter.api.extension.AfterEachCallback;
1515
import org.junit.jupiter.api.extension.BeforeAllCallback;
1616
import org.junit.jupiter.api.extension.BeforeEachCallback;
17+
import org.junit.jupiter.api.extension.BeforeTestExecutionCallback;
1718
import org.junit.jupiter.api.extension.ExtensionContext;
1819
import org.junit.jupiter.api.extension.InvocationInterceptor;
1920
import org.junit.jupiter.api.extension.ParameterContext;
@@ -27,7 +28,7 @@
2728
import static org.jboss.arquillian.junit5.ContextStore.getContextStore;
2829
import static org.jboss.arquillian.junit5.JUnitJupiterTestClassLifecycleManager.getManager;
2930

30-
public class ArquillianExtension implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback, InvocationInterceptor, TestExecutionExceptionHandler, ParameterResolver {
31+
public class ArquillianExtension implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback, BeforeTestExecutionCallback, InvocationInterceptor, TestExecutionExceptionHandler, ParameterResolver {
3132
public static final String RUNNING_INSIDE_ARQUILLIAN = "insideArquillian";
3233

3334
private static final String CHAIN_EXCEPTION_MESSAGE_PREFIX = "Chain of InvocationInterceptors never called invocation";
@@ -78,6 +79,16 @@ public void afterEach(ExtensionContext context) throws Exception {
7879
}
7980
}
8081

82+
@Override
83+
public void beforeTestExecution(final ExtensionContext context) throws Exception {
84+
// Get the adapter, test instance and method
85+
final TestRunnerAdaptor adapter = getManager(context)
86+
.getAdaptor();
87+
final Object instance = context.getRequiredTestInstance();
88+
final Method method = context.getRequiredTestMethod();
89+
adapter.fireCustomLifecycle(new BeforeTestExecutionEvent(instance, method));
90+
}
91+
8192
@Override
8293
public void interceptTestTemplateMethod(Invocation<Void> invocation, ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
8394
if (IS_INSIDE_ARQUILLIAN.test(extensionContext)) {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* JBoss, Home of Professional Open Source.
3+
*
4+
* Copyright 2025 Red Hat, Inc., and individual contributors
5+
* as indicated by the @author tags.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
package org.jboss.arquillian.junit5;
21+
22+
import java.lang.reflect.Method;
23+
24+
import org.jboss.arquillian.test.spi.event.suite.TestLifecycleEvent;
25+
26+
/**
27+
* An event triggered before each test is invoked.
28+
*
29+
* @author <a href="mailto:[email protected]">James R. Perkins</a>
30+
*/
31+
public class BeforeTestExecutionEvent extends TestLifecycleEvent {
32+
/**
33+
* Creates a new event.
34+
*
35+
* @param testInstance The test case instance
36+
* @param testMethod The test method
37+
*
38+
* @throws IllegalArgumentException if testInstance is null
39+
* @throws IllegalArgumentException if testMethod is null
40+
*/
41+
BeforeTestExecutionEvent(final Object testInstance, final Method testMethod) {
42+
super(testInstance, testMethod);
43+
}
44+
}

junit5/core/src/main/java/org/jboss/arquillian/junit5/MethodParameterObserver.java

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@
2121

2222
import java.lang.reflect.Method;
2323
import java.util.Collection;
24+
import java.util.stream.Collectors;
2425

26+
import org.jboss.arquillian.container.spi.client.deployment.Deployment;
27+
import org.jboss.arquillian.container.spi.client.deployment.DeploymentScenario;
28+
import org.jboss.arquillian.container.spi.context.DeploymentContext;
2529
import org.jboss.arquillian.core.api.Event;
2630
import org.jboss.arquillian.core.api.Instance;
2731
import org.jboss.arquillian.core.api.InstanceProducer;
@@ -33,7 +37,6 @@
3337
import org.jboss.arquillian.test.spi.event.enrichment.AfterEnrichment;
3438
import org.jboss.arquillian.test.spi.event.enrichment.BeforeEnrichment;
3539
import org.jboss.arquillian.test.spi.event.enrichment.EnrichmentEvent;
36-
import org.jboss.arquillian.test.spi.event.suite.Before;
3740

3841
/**
3942
* The observer used to process method parameters provided by Arquillian.
@@ -52,26 +55,39 @@ public class MethodParameterObserver {
5255
@TestScoped
5356
private InstanceProducer<MethodParameters> methodParametersProducer;
5457

58+
@Inject
59+
private Instance<DeploymentContext> deploymentContext;
60+
61+
@Inject
62+
private Instance<DeploymentScenario> deploymentScenario;
63+
5564
/**
5665
* Updates the stored {@link MethodParameters} for method parameters which can be provided by Arquillian.
5766
*
5867
* @param event the fired event
5968
*/
60-
public void injectParameters(@Observes final Before event) {
61-
final Object testInstance = event.getTestInstance();
62-
final Method testMethod = event.getTestMethod();
63-
enrichmentEvent.fire(new BeforeEnrichment(testInstance, testMethod));
64-
final MethodParameters methodParameters = methodParametersProducer.get();
65-
final Collection<TestEnricher> testEnrichers = serviceLoader.get().all(TestEnricher.class);
66-
for (TestEnricher enricher : testEnrichers) {
67-
final Object[] values = enricher.resolve(testMethod);
68-
for (int i = 0; i < values.length; i++) {
69-
if (values[i] != null) {
70-
methodParameters.add(i, values[i]);
69+
public void injectParameters(@Observes final BeforeTestExecutionEvent event) {
70+
final boolean contextActivated = activateDeployments();
71+
try {
72+
final Object testInstance = event.getTestInstance();
73+
final Method testMethod = event.getTestMethod();
74+
enrichmentEvent.fire(new BeforeEnrichment(testInstance, testMethod));
75+
final MethodParameters methodParameters = methodParametersProducer.get();
76+
final Collection<TestEnricher> testEnrichers = serviceLoader.get().all(TestEnricher.class);
77+
for (TestEnricher enricher : testEnrichers) {
78+
final Object[] values = enricher.resolve(testMethod);
79+
for (int i = 0; i < values.length; i++) {
80+
if (values[i] != null) {
81+
methodParameters.add(i, values[i]);
82+
}
7183
}
7284
}
85+
enrichmentEvent.fire(new AfterEnrichment(testEnrichers, testMethod));
86+
} finally {
87+
if (contextActivated) {
88+
deploymentContext.get().deactivate();
89+
}
7390
}
74-
enrichmentEvent.fire(new AfterEnrichment(testEnrichers, testMethod));
7591
}
7692

7793
/**
@@ -82,4 +98,21 @@ public void injectParameters(@Observes final Before event) {
8298
public void injectParameters(@Observes MethodParameterProducerEvent event) {
8399
methodParametersProducer.set(event.getTestParameterHolder());
84100
}
101+
102+
private boolean activateDeployments() {
103+
final DeploymentContext context = deploymentContext.get();
104+
// If the deployment context is not available or already active, we don't need to activate the deployment context
105+
if (context == null || context.isActive()) {
106+
return false;
107+
}
108+
final Collection<Deployment> activeDeployments = deploymentScenario.get().deployments().stream()
109+
.filter(Deployment::isDeployed)
110+
.collect(Collectors.toList());
111+
// If there are multiple deployments, don't activate any of them as an @OperatesOnDeployment should be used
112+
if (activeDeployments.size() != 1) {
113+
return false;
114+
}
115+
activeDeployments.forEach(context::activate);
116+
return true;
117+
}
85118
}

0 commit comments

Comments
 (0)