Skip to content

Commit f134bfb

Browse files
authored
Merge pull request #563 from jamezp/WFARQ-148
[WFARQ-148] Allow the ManagementClient to be injected in the containe…
2 parents 622db23 + 1655581 commit f134bfb

File tree

13 files changed

+352
-161
lines changed

13 files changed

+352
-161
lines changed

common/src/main/java/org/jboss/as/arquillian/container/CommonContainerArchiveAppender.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
package org.jboss.as.arquillian.container;
77

8+
import org.jboss.arquillian.container.test.spi.RemoteLoadableExtension;
89
import org.jboss.arquillian.container.test.spi.client.deployment.AuxiliaryArchiveAppender;
910
import org.jboss.as.arquillian.api.ServerSetup;
1011
import org.jboss.as.arquillian.api.ServerSetupTask;
@@ -28,12 +29,18 @@ public Archive<?> createAuxiliaryArchive() {
2829
// These two types are added to avoid exceptions with class loading for in-container tests. These
2930
// shouldn't really be used for in-container tests.
3031
.addClasses(ServerSetupTask.class, ServerSetup.class)
31-
.addClasses(ManagementClient.class)
32+
.addClasses(
33+
ManagementClient.class,
34+
Authentication.class,
35+
ManagedContainerRemoteExtension.class,
36+
WildFlyArquillianConfiguration.class,
37+
InContainerManagementClientProvider.class)
3238
// Add the setup task implementations
3339
.addPackage(ConfigureLoggingSetupTask.class.getPackage())
3440
// Adds wildfly-plugin-tools, this exception itself is explicitly needed
3541
.addPackages(true, OperationExecutionException.class.getPackage())
36-
.setManifest(new StringAsset("Manifest-Version: 1.0\n"
37-
+ "Dependencies: org.jboss.as.controller-client,org.jboss.dmr\n"));
42+
.addAsServiceProvider(RemoteLoadableExtension.class, ManagedContainerRemoteExtension.class)
43+
.setManifest(new StringAsset("Manifest-Version: 1.0\r\n"
44+
+ "Dependencies: org.jboss.as.controller-client export,org.jboss.dmr export\r\n"));
3845
}
3946
}

common/src/main/java/org/jboss/as/arquillian/container/CommonContainerExtension.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import org.jboss.arquillian.container.spi.client.container.DeploymentExceptionTransformer;
88
import org.jboss.arquillian.container.test.spi.client.deployment.AuxiliaryArchiveAppender;
9+
import org.jboss.arquillian.container.test.spi.client.deployment.ProtocolArchiveProcessor;
910
import org.jboss.arquillian.core.spi.LoadableExtension;
1011
import org.jboss.arquillian.test.spi.TestEnricher;
1112
import org.jboss.arquillian.test.spi.enricher.resource.ResourceProvider;
@@ -34,8 +35,11 @@ public void register(final ExtensionBuilder builder) {
3435
builder.service(ResourceProvider.class, ServerManagerProvider.class);
3536
builder.service(TestEnricher.class, ContainerResourceTestEnricher.class);
3637
builder.service(AuxiliaryArchiveAppender.class, CommonContainerArchiveAppender.class);
38+
builder.service(ProtocolArchiveProcessor.class, WildFlyProtocolArchiveProcessor.class);
3739

38-
builder.observer(ServerSetupObserver.class);
40+
builder.observer(ServerSetupObserver.class)
41+
// Provides the ManagementClient resource for in-container tests
42+
.observer(InContainerManagementClientProvider.class);
3943

4044
// WildFlyContainerController
4145
builder
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright The WildFly Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
package org.jboss.as.arquillian.container;
6+
7+
import static org.jboss.as.arquillian.container.Authentication.getCallbackHandler;
8+
9+
import java.lang.annotation.Annotation;
10+
import java.net.URI;
11+
import java.util.concurrent.locks.Lock;
12+
import java.util.concurrent.locks.ReentrantLock;
13+
14+
import org.jboss.arquillian.core.api.annotation.Observes;
15+
import org.jboss.arquillian.test.api.ArquillianResource;
16+
import org.jboss.arquillian.test.spi.enricher.resource.ResourceProvider;
17+
import org.jboss.arquillian.test.spi.event.suite.AfterSuite;
18+
import org.jboss.as.controller.client.ModelControllerClient;
19+
import org.jboss.as.controller.client.ModelControllerClientConfiguration;
20+
21+
/**
22+
* A provider and observer for allowing a {@link ManagementClient} to be usable inside a container for testing.
23+
*
24+
* @author <a href="mailto:jperkins@redhat.com">James R. Perkins</a>
25+
*/
26+
public class InContainerManagementClientProvider implements ResourceProvider {
27+
28+
private static final Lock lock = new ReentrantLock();
29+
private static ManagementClient current;
30+
31+
@Override
32+
public boolean canProvide(final Class<?> type) {
33+
return type.isAssignableFrom(ManagementClient.class);
34+
}
35+
36+
@Override
37+
@SuppressWarnings("deprecation")
38+
public Object lookup(final ArquillianResource arquillianResource, final Annotation... annotations) {
39+
lock.lock();
40+
try {
41+
if (current != null) {
42+
return current;
43+
}
44+
WildFlyArquillianConfiguration.getConfiguration().ifPresent(properties -> {
45+
final String protocol;
46+
final String address;
47+
final int port;
48+
protocol = properties.getProperty("management.protocol", "remote+http");
49+
address = properties.getProperty("management.address", "localhost");
50+
port = Integer.parseInt(properties.getProperty("management.port", "9990"));
51+
52+
// Configure a client for in-container tests based on the config data within the deployment
53+
final ModelControllerClientConfiguration.Builder builder = new ModelControllerClientConfiguration.Builder()
54+
.setHostName(address)
55+
.setPort(port)
56+
.setProtocol(protocol);
57+
58+
Authentication.username = properties.getProperty("username", "");
59+
Authentication.password = properties.getProperty("password", "");
60+
61+
if (!Authentication.username.isEmpty()) {
62+
builder.setHandler(getCallbackHandler());
63+
}
64+
65+
final String authenticationConfig = properties.getProperty("authenticationConfig");
66+
if (authenticationConfig != null) {
67+
builder.setAuthenticationConfigUri(URI.create(authenticationConfig));
68+
}
69+
current = new ManagementClient(ModelControllerClient.Factory.create(builder.build()), address,
70+
port,
71+
protocol);
72+
});
73+
return current;
74+
} finally {
75+
lock.unlock();
76+
}
77+
}
78+
79+
public void cleanUp(@Observes AfterSuite afterSuite) {
80+
lock.lock();
81+
try {
82+
if (current != null) {
83+
current.close();
84+
current = null;
85+
}
86+
} finally {
87+
lock.unlock();
88+
}
89+
}
90+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright The WildFly Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package org.jboss.as.arquillian.container;
7+
8+
import org.jboss.arquillian.container.test.spi.RemoteLoadableExtension;
9+
import org.jboss.arquillian.test.spi.enricher.resource.ResourceProvider;
10+
11+
/**
12+
* An extension register resources for in-container testing.
13+
*
14+
* @author <a href="mailto:jperkins@redhat.com">James R. Perkins</a>
15+
*/
16+
public class ManagedContainerRemoteExtension implements RemoteLoadableExtension {
17+
@Override
18+
public void register(final ExtensionBuilder builder) {
19+
builder
20+
.observer(InContainerManagementClientProvider.class)
21+
.service(ResourceProvider.class, InContainerManagementClientProvider.class);
22+
}
23+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/*
2+
* Copyright The WildFly Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package org.jboss.as.arquillian.container;
7+
8+
import java.io.ByteArrayOutputStream;
9+
import java.io.IOException;
10+
import java.io.InputStream;
11+
import java.io.UncheckedIOException;
12+
import java.net.URL;
13+
import java.security.AccessController;
14+
import java.security.PrivilegedAction;
15+
import java.util.Map;
16+
import java.util.Optional;
17+
import java.util.Properties;
18+
19+
import org.jboss.arquillian.container.spi.client.deployment.Validate;
20+
import org.jboss.shrinkwrap.api.Archive;
21+
import org.jboss.shrinkwrap.api.asset.Asset;
22+
import org.jboss.shrinkwrap.api.asset.ByteArrayAsset;
23+
import org.jboss.shrinkwrap.api.spec.WebArchive;
24+
25+
/**
26+
* A utility which creates and retrieves the required configuration for resource providers.
27+
*
28+
* @author <a href="mailto:jperkins@redhat.com">James R. Perkins</a>
29+
*/
30+
public class WildFlyArquillianConfiguration {
31+
private static final String CONFIG_FILE = "wildfly-arquillian-config.properties";
32+
33+
/**
34+
* Adds the file {@code wildfly-arquillian-config.properties} to the deployment.
35+
*
36+
* @param config the configuration used to get the container properties from
37+
* @param archive the deployment to add the file to
38+
*/
39+
public static void addConfiguration(final Map<String, String> config, final Archive<?> archive) {
40+
// A configuration file was already added. We will not add a new one or append to the current one
41+
if (archive.get(CONFIG_FILE) != null) {
42+
return;
43+
}
44+
// Create properties to later be retrieved to create a client
45+
final Properties properties = new Properties();
46+
properties.setProperty("management.protocol", config.getOrDefault("managementProtocol", "remote+http"));
47+
properties.setProperty("management.address", config.getOrDefault("managementAddress", "localhost"));
48+
properties.setProperty("management.port", config.getOrDefault("managementPort", "9990"));
49+
50+
final String username = config.get("username");
51+
if (username != null) {
52+
properties.setProperty("username", username);
53+
}
54+
final String password = config.get("password");
55+
if (password != null) {
56+
properties.setProperty("password", password);
57+
}
58+
final String authenticationConfig = config.get("authenticationConfig");
59+
if (authenticationConfig != null) {
60+
properties.setProperty("authenticationConfig", authenticationConfig);
61+
}
62+
63+
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
64+
properties.store(out, "");
65+
final Asset asset = new ByteArrayAsset(out.toByteArray());
66+
// We want to make sure the file ends up on the class path
67+
if (Validate.isArchiveOfType(WebArchive.class, archive)) {
68+
archive.add(asset, "WEB-INF/classes/" + CONFIG_FILE);
69+
} else {
70+
archive.add(asset, CONFIG_FILE);
71+
}
72+
73+
} catch (IOException e) {
74+
// This likely won't happen, but we will re-throw as a RuntimeException
75+
throw new UncheckedIOException(e);
76+
}
77+
}
78+
79+
/**
80+
* Returns the previously configured {@code wildfly-arquillian-config.properties} from the deployments class
81+
* path
82+
*
83+
* @return the properties if found
84+
*/
85+
public static Optional<Properties> getConfiguration() {
86+
final ClassLoader classLoader = getClassLoader();
87+
final URL resourceUrl = classLoader.getResource(CONFIG_FILE);
88+
if (resourceUrl != null) {
89+
try (InputStream in = resourceUrl.openStream()) {
90+
final Properties properties = new Properties();
91+
properties.load(in);
92+
return Optional.of(properties);
93+
} catch (IOException e) {
94+
throw new UncheckedIOException(e);
95+
}
96+
}
97+
return Optional.empty();
98+
}
99+
100+
private static ClassLoader getClassLoader() {
101+
if (System.getSecurityManager() == null) {
102+
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
103+
if (classLoader == null) {
104+
classLoader = WildFlyArquillianConfiguration.class.getClassLoader();
105+
}
106+
return classLoader;
107+
}
108+
return AccessController.doPrivileged((PrivilegedAction<ClassLoader>) () -> {
109+
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
110+
if (classLoader == null) {
111+
classLoader = WildFlyArquillianConfiguration.class.getClassLoader();
112+
}
113+
return classLoader;
114+
});
115+
}
116+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright The WildFly Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package org.jboss.as.arquillian.container;
7+
8+
import java.util.Map;
9+
10+
import org.jboss.arquillian.container.spi.Container;
11+
import org.jboss.arquillian.container.spi.ContainerRegistry;
12+
import org.jboss.arquillian.container.test.spi.TestDeployment;
13+
import org.jboss.arquillian.container.test.spi.client.deployment.ProtocolArchiveProcessor;
14+
import org.jboss.arquillian.core.api.Instance;
15+
import org.jboss.arquillian.core.api.annotation.Inject;
16+
import org.jboss.logging.Logger;
17+
import org.jboss.shrinkwrap.api.Archive;
18+
19+
/**
20+
* Appends the WildFly Arquillian Configuration to the deployment archive.
21+
*
22+
* @author <a href="mailto:jperkins@redhat.com">James R. Perkins</a>
23+
*/
24+
public class WildFlyProtocolArchiveProcessor implements ProtocolArchiveProcessor {
25+
private static final Logger LOGGER = Logger.getLogger(WildFlyProtocolArchiveProcessor.class);
26+
27+
@Inject
28+
private Instance<ContainerRegistry> containerRegistry;
29+
30+
@Override
31+
public void process(final TestDeployment testDeployment, final Archive<?> protocolArchive) {
32+
final Container<?> container = findContainer(testDeployment.getTargetDescription().getName());
33+
if (container == null) {
34+
// We couldn't find the container, log a debug message to indicate this
35+
LOGGER.debugf("Could not find a container named %s", testDeployment.getTargetDescription().getName());
36+
return;
37+
}
38+
final Map<String, String> config = container.getContainerConfiguration().getContainerProperties();
39+
WildFlyArquillianConfiguration.addConfiguration(config, protocolArchive);
40+
}
41+
42+
private Container<?> findContainer(final String targetName) {
43+
final var registry = containerRegistry.get();
44+
if (registry == null) {
45+
return null;
46+
}
47+
final var containers = registry.getContainers();
48+
if (containers.size() == 1) {
49+
return containers.get(0);
50+
}
51+
if ("_DEFAULT_".equals(targetName)) {
52+
// Find the default container
53+
for (Container<?> container : containers) {
54+
if (container.getContainerConfiguration().isDefault()) {
55+
return container;
56+
}
57+
}
58+
}
59+
return registry.getContainer(targetName);
60+
}
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright The WildFly Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
package org.jboss.as.arquillian.container.managed;
6+
7+
import org.jboss.arquillian.container.test.api.RunAsClient;
8+
import org.jboss.arquillian.junit5.ArquillianExtension;
9+
import org.jboss.as.arquillian.container.ManagementClient;
10+
import org.junit.jupiter.api.extension.ExtendWith;
11+
12+
/**
13+
* Ensures a {@link ManagementClient} can be injected to a client test.
14+
*
15+
* @author <a href="mailto:alr@jboss.org">Andrew Lee Rubinger</a>
16+
*/
17+
@ExtendWith(ArquillianExtension.class)
18+
@RunAsClient
19+
public class ClientInjectManagementClientTestCase extends InjectManagementClientTestCase {
20+
}

container-managed/src/test/java/org/jboss/as/arquillian/container/managed/InjectManagementClientTestCase.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import org.jboss.shrinkwrap.api.ShrinkWrap;
1212
import org.jboss.shrinkwrap.api.spec.WebArchive;
1313
import org.junit.jupiter.api.Assertions;
14-
import org.junit.jupiter.api.Tag;
1514
import org.junit.jupiter.api.Test;
1615
import org.junit.jupiter.api.extension.ExtendWith;
1716

@@ -21,13 +20,12 @@
2120
* @author <a href="mailto:alr@jboss.org">Andrew Lee Rubinger</a>
2221
*/
2322
@ExtendWith(ArquillianExtension.class)
24-
@Tag("JmxProtocol")
2523
public class InjectManagementClientTestCase {
2624

2725
@ArquillianResource
2826
private ManagementClient managementClient;
2927

30-
@Deployment(testable = false)
28+
@Deployment
3129
public static WebArchive createDeployment() throws Exception {
3230
return ShrinkWrap.create(WebArchive.class).addClass(HelloWorldServlet.class);
3331
}

0 commit comments

Comments
 (0)