Skip to content

Commit

Permalink
[661] Add a new event which will handle injecting method parameters. …
Browse files Browse the repository at this point in the history
…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]>
  • Loading branch information
jamezp committed Mar 7, 2025
1 parent 7602c7a commit 2dabedb
Show file tree
Hide file tree
Showing 6 changed files with 306 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* JBoss, Home of Professional Open Source.
*
* Copyright 2025 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.jboss.arquillian.integration.test.manual;

import java.net.URI;
import java.net.URL;

import org.jboss.arquillian.container.test.api.ContainerController;
import org.jboss.arquillian.container.test.api.Deployer;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.OperateOnDeployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.integration.test.common.app.EchoResource;
import org.jboss.arquillian.integration.test.common.app.RestActivator;
import org.jboss.arquillian.junit5.container.annotation.ArquillianTest;
import org.jboss.arquillian.test.api.ArquillianResource;
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.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

/**
* @author <a href="mailto:[email protected]">James R. Perkins</a>
*/
@ArquillianTest
@RunAsClient
public class ManualModeInjectionMultiDeploymentTest {
private static final String CONTAINER_NAME = "default";
static final String DEPLOYMENT_NAME_1 = "manual-mode-default";
static final String DEPLOYMENT_NAME_2 = "manual-mode-secondary";

@ArquillianResource
private static ContainerController controller;

@ArquillianResource
private static Deployer deployer;

@Deployment(name = DEPLOYMENT_NAME_1, managed = false)
public static WebArchive createDeployment() {
return ShrinkWrap.create(WebArchive.class, DEPLOYMENT_NAME_1 + ".war")
.addClasses(RestActivator.class, EchoResource.class)
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
}

@Deployment(name = DEPLOYMENT_NAME_2, managed = false)
public static WebArchive createDeploymentSecondary() {
return ShrinkWrap.create(WebArchive.class, DEPLOYMENT_NAME_2 + ".war")
.addClasses(RestActivator.class, EchoResource.class)
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
}

@BeforeEach
public void startAndDeploy() {
controller.start(CONTAINER_NAME);
deployer.deploy(DEPLOYMENT_NAME_1);
deployer.deploy(DEPLOYMENT_NAME_2);
}

@AfterEach
public void stop() {
if (controller.isStarted(CONTAINER_NAME)) {
deployer.undeploy(DEPLOYMENT_NAME_1);
deployer.undeploy(DEPLOYMENT_NAME_2);
controller.stop(CONTAINER_NAME);
}
}

@Test
public void checkUri(@OperateOnDeployment(DEPLOYMENT_NAME_1) @ArquillianResource final URI uri) {
Assertions.assertNotNull(uri);
Assertions.assertTrue(uri.toString().contains("/" + DEPLOYMENT_NAME_1));
}

@Test
public void checkUrl(@OperateOnDeployment(DEPLOYMENT_NAME_1) @ArquillianResource final URL url) {
Assertions.assertNotNull(url);
Assertions.assertTrue(url.toString().contains("/" + DEPLOYMENT_NAME_1));
}

@Test
public void checkSecondaryUri(@OperateOnDeployment(DEPLOYMENT_NAME_2) @ArquillianResource final URI uri) {
Assertions.assertNotNull(uri);
Assertions.assertTrue(uri.toString().contains("/" + DEPLOYMENT_NAME_2));
}

@Test
public void checkSecondaryUrl(@OperateOnDeployment(DEPLOYMENT_NAME_2) @ArquillianResource final URL url) {
Assertions.assertNotNull(url);
Assertions.assertTrue(url.toString().contains("/" + DEPLOYMENT_NAME_2));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* JBoss, Home of Professional Open Source.
*
* Copyright 2025 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.jboss.arquillian.integration.test.manual;

import java.net.URI;
import java.net.URL;

import org.jboss.arquillian.container.test.api.ContainerController;
import org.jboss.arquillian.container.test.api.Deployer;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.integration.test.common.app.EchoResource;
import org.jboss.arquillian.integration.test.common.app.RestActivator;
import org.jboss.arquillian.junit5.container.annotation.ArquillianTest;
import org.jboss.arquillian.test.api.ArquillianResource;
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.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

/**
* @author <a href="mailto:[email protected]">James R. Perkins</a>
*/
@ArquillianTest
@RunAsClient
public class ManualModeInjectionTest {
private static final String CONTAINER_NAME = "default";
static final String DEPLOYMENT_NAME = "manual-mode";

@ArquillianResource
private static ContainerController controller;

@ArquillianResource
private static Deployer deployer;

@Deployment(name = DEPLOYMENT_NAME, managed = false)
public static WebArchive createDeployment() {
return ShrinkWrap.create(WebArchive.class, DEPLOYMENT_NAME + ".war")
.addClasses(RestActivator.class, EchoResource.class)
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
}

@BeforeEach
public void startAndDeploy() {
controller.start(CONTAINER_NAME);
deployer.deploy(DEPLOYMENT_NAME);
}

@AfterEach
public void stop() {
if (controller.isStarted(CONTAINER_NAME)) {
deployer.undeploy(DEPLOYMENT_NAME);
controller.stop(CONTAINER_NAME);
}
}

@Test
public void checkUri(@ArquillianResource final URI uri) {
Assertions.assertNotNull(uri);
Assertions.assertTrue(uri.toString().contains("/" + DEPLOYMENT_NAME));
}

@Test
public void checkUrl(@ArquillianResource final URL url) {
Assertions.assertNotNull(url);
Assertions.assertTrue(url.toString().contains("/" + DEPLOYMENT_NAME));
}
}
5 changes: 5 additions & 0 deletions junit5/core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
<artifactId>arquillian-test-spi</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.container</groupId>
<artifactId>arquillian-container-spi</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.BeforeTestExecutionCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.InvocationInterceptor;
import org.junit.jupiter.api.extension.ParameterContext;
Expand All @@ -27,7 +28,7 @@
import static org.jboss.arquillian.junit5.ContextStore.getContextStore;
import static org.jboss.arquillian.junit5.JUnitJupiterTestClassLifecycleManager.getManager;

public class ArquillianExtension implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback, InvocationInterceptor, TestExecutionExceptionHandler, ParameterResolver {
public class ArquillianExtension implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback, BeforeTestExecutionCallback, InvocationInterceptor, TestExecutionExceptionHandler, ParameterResolver {
public static final String RUNNING_INSIDE_ARQUILLIAN = "insideArquillian";

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

@Override
public void beforeTestExecution(final ExtensionContext context) throws Exception {
// Get the adapter, test instance and method
final TestRunnerAdaptor adapter = getManager(context)
.getAdaptor();
final Object instance = context.getRequiredTestInstance();
final Method method = context.getRequiredTestMethod();
adapter.fireCustomLifecycle(new BeforeTestExecutionEvent(instance, method));
}

@Override
public void interceptTestTemplateMethod(Invocation<Void> invocation, ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
if (IS_INSIDE_ARQUILLIAN.test(extensionContext)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* JBoss, Home of Professional Open Source.
*
* Copyright 2025 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.jboss.arquillian.junit5;

import java.lang.reflect.Method;

import org.jboss.arquillian.test.spi.event.suite.TestLifecycleEvent;

/**
* An event triggered before each test is invoked.
*
* @author <a href="mailto:[email protected]">James R. Perkins</a>
*/
public class BeforeTestExecutionEvent extends TestLifecycleEvent {
/**
* Creates a new event.
*
* @param testInstance The test case instance
* @param testMethod The test method
*
* @throws IllegalArgumentException if testInstance is null
* @throws IllegalArgumentException if testMethod is null
*/
BeforeTestExecutionEvent(final Object testInstance, final Method testMethod) {
super(testInstance, testMethod);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.stream.Collectors;

import org.jboss.arquillian.container.spi.client.deployment.Deployment;
import org.jboss.arquillian.container.spi.client.deployment.DeploymentScenario;
import org.jboss.arquillian.container.spi.context.DeploymentContext;
import org.jboss.arquillian.core.api.Event;
import org.jboss.arquillian.core.api.Instance;
import org.jboss.arquillian.core.api.InstanceProducer;
Expand All @@ -33,7 +37,6 @@
import org.jboss.arquillian.test.spi.event.enrichment.AfterEnrichment;
import org.jboss.arquillian.test.spi.event.enrichment.BeforeEnrichment;
import org.jboss.arquillian.test.spi.event.enrichment.EnrichmentEvent;
import org.jboss.arquillian.test.spi.event.suite.Before;

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

@Inject
private Instance<DeploymentContext> deploymentContext;

@Inject
private Instance<DeploymentScenario> deploymentScenario;

/**
* Updates the stored {@link MethodParameters} for method parameters which can be provided by Arquillian.
*
* @param event the fired event
*/
public void injectParameters(@Observes final Before event) {
final Object testInstance = event.getTestInstance();
final Method testMethod = event.getTestMethod();
enrichmentEvent.fire(new BeforeEnrichment(testInstance, testMethod));
final MethodParameters methodParameters = methodParametersProducer.get();
final Collection<TestEnricher> testEnrichers = serviceLoader.get().all(TestEnricher.class);
for (TestEnricher enricher : testEnrichers) {
final Object[] values = enricher.resolve(testMethod);
for (int i = 0; i < values.length; i++) {
if (values[i] != null) {
methodParameters.add(i, values[i]);
public void injectParameters(@Observes final BeforeTestExecutionEvent event) {
final boolean contextActivated = activateDeployments();
try {
final Object testInstance = event.getTestInstance();
final Method testMethod = event.getTestMethod();
enrichmentEvent.fire(new BeforeEnrichment(testInstance, testMethod));
final MethodParameters methodParameters = methodParametersProducer.get();
final Collection<TestEnricher> testEnrichers = serviceLoader.get().all(TestEnricher.class);
for (TestEnricher enricher : testEnrichers) {
final Object[] values = enricher.resolve(testMethod);
for (int i = 0; i < values.length; i++) {
if (values[i] != null) {
methodParameters.add(i, values[i]);
}
}
}
enrichmentEvent.fire(new AfterEnrichment(testEnrichers, testMethod));
} finally {
if (contextActivated) {
deploymentContext.get().deactivate();
}
}
enrichmentEvent.fire(new AfterEnrichment(testEnrichers, testMethod));
}

/**
Expand All @@ -82,4 +98,21 @@ public void injectParameters(@Observes final Before event) {
public void injectParameters(@Observes MethodParameterProducerEvent event) {
methodParametersProducer.set(event.getTestParameterHolder());
}

private boolean activateDeployments() {
final DeploymentContext context = deploymentContext.get();
// If the deployment context is not available or already active, we don't need to activate the deployment context
if (context == null || context.isActive()) {
return false;
}
final Collection<Deployment> activeDeployments = deploymentScenario.get().deployments().stream()
.filter(Deployment::isDeployed)
.collect(Collectors.toList());
// If there are multiple deployments, don't activate any of them as an @OperatesOnDeployment should be used
if (activeDeployments.size() != 1) {
return false;
}
activeDeployments.forEach(context::activate);
return true;
}
}

0 comments on commit 2dabedb

Please sign in to comment.