Skip to content

Commit

Permalink
[WFCORE-5861] Test case to verify JPMS settings works with non-modula…
Browse files Browse the repository at this point in the history
…r CLI client launching an embedded server

Jira Issue: https://issues.redhat.com/browse/WFCORE-5861
  • Loading branch information
yersan committed Apr 8, 2022
1 parent c3977da commit c91d78f
Show file tree
Hide file tree
Showing 13 changed files with 273 additions and 32 deletions.
Expand Up @@ -34,7 +34,7 @@ setDefaultModularJvmOptions() {
DEFAULT_MODULAR_JVM_OPTIONS=`echo $* | $GREP "\-\-add\-modules"`
if [ "x$DEFAULT_MODULAR_JVM_OPTIONS" = "x" ]; then
# Set default modular jdk options
# NB: In case an update is made to these exports and opens, make sure that bootable-jar/boot/pom.xml script is in sync.
# NB: In case an update is made to these exports and opens, make sure that bootable-jar/boot/pom.xml and cli/pom.xml script is in sync.
# Needed by the iiop-openjdk subsystem
DEFAULT_MODULAR_JVM_OPTIONS="$DEFAULT_MODULAR_JVM_OPTIONS --add-exports=java.desktop/sun.awt=ALL-UNNAMED"
# Needed to instantiate the default InitialContextFactory implementation used by the
Expand Down
Expand Up @@ -3,4 +3,10 @@
<tasks xmlns="urn:wildfly:wildfly-feature-pack-tasks:2.0">
<copy-artifact artifact="org.wildfly.core:wildfly-launcher" to-location="bin/launcher.jar"/>
<copy-artifact artifact="org.wildfly.core:wildfly-elytron-tool-wrapper" to-location="bin/wildfly-elytron-tool.jar"/>
<copy-artifact artifact="org.wildfly.core:wildfly-cli::client" to-location="bin/client/jboss-cli-client.jar"/>
<file-permissions phase="FINALIZING">
<permission value="755">
<filter pattern="bin/client/jboss-cli-client.jar" include="true"/>
</permission>
</file-permissions>
</tasks>
Expand Up @@ -219,7 +219,7 @@ private void setSingleServerArg(final String key, final String value) {
* @return a new builder
*/
public static BootableJarCommandBuilder of(final Path bootableJar) {
return new BootableJarCommandBuilder(Environment.validateBootableJar(bootableJar));
return new BootableJarCommandBuilder(Environment.validateJar(bootableJar));
}

/**
Expand All @@ -230,7 +230,7 @@ public static BootableJarCommandBuilder of(final Path bootableJar) {
* @return a new builder
*/
public static BootableJarCommandBuilder of(final String bootableJar) {
return new BootableJarCommandBuilder(Environment.validateBootableJar(bootableJar));
return new BootableJarCommandBuilder(Environment.validateJar(bootableJar));
}

/**
Expand Down
Expand Up @@ -47,6 +47,8 @@
@SuppressWarnings("unused")
public class CliCommandBuilder implements CommandBuilder {

private static Path cliClientJar = Paths.get("bin").resolve("client").resolve("jboss-cli-client.jar");

enum CliArgument {
CONNECT("--connect", "-c"),
CONTROLLER("--controller", "controller"),
Expand Down Expand Up @@ -94,13 +96,17 @@ public static CliArgument find(final Argument argument) {
private final Environment environment;
private final Arguments javaOpts;
private final Arguments cliArgs;
private final boolean modularLauncher;

private CliCommandBuilder(final Environment environment) {
private CliCommandBuilder(final Environment environment, boolean modularLauncher) {
this.environment = environment;
this.modularLauncher = modularLauncher;
javaOpts = new Arguments();
cliArgs = new Arguments();
// Add the default logging.properties file
javaOpts.add("-Dlogging.configuration=file:" + environment.resolvePath("bin", "jboss-cli-logging.properties"));
if (modularLauncher) {
// Add the default logging.properties file
javaOpts.add("-Dlogging.configuration=file:" + environment.resolvePath("bin", "jboss-cli-logging.properties"));
}
}

/**
Expand All @@ -110,8 +116,8 @@ private CliCommandBuilder(final Environment environment) {
*
* @return a new builder
*/
public static CliCommandBuilder of(final Path wildflyHome) {
return new CliCommandBuilder(new Environment(wildflyHome));
public static CliCommandBuilder asModularLauncher(final Path wildflyHome) {
return new CliCommandBuilder(new Environment(wildflyHome), true);
}

/**
Expand All @@ -121,8 +127,34 @@ public static CliCommandBuilder of(final Path wildflyHome) {
*
* @return a new builder
*/
public static CliCommandBuilder of(final String wildflyHome) {
return new CliCommandBuilder(new Environment(wildflyHome));
public static CliCommandBuilder asModularLauncher(final String wildflyHome) {
return new CliCommandBuilder(new Environment(wildflyHome), true);
}

/**
* Creates a command builder for a non-modular CLI instance launched from wildflyHome/bin/client/jboss-client.jar.
*
* @param wildflyHome the path to the WildFly home directory
*
* @return a new builder
*/
public static CliCommandBuilder asJarLauncher(final Path wildflyHome) {
Environment environment = new Environment(wildflyHome);
Environment.validateJar(environment.getWildflyHome().resolve(cliClientJar));
return new CliCommandBuilder(environment, false);
}

/**
* Creates a command builder for a non-modular CLI instance launched from wildflyHome/bin/client/jboss-client.jar.
*
* @param wildflyHome the path to the WildFly home directory
*
* @return a new builder
*/
public static CliCommandBuilder asJarLauncher(final String wildflyHome) {
Environment environment = new Environment(wildflyHome);
Environment.validateJar(environment.getWildflyHome().resolve(cliClientJar));
return new CliCommandBuilder(environment, false);
}

/**
Expand Down Expand Up @@ -617,21 +649,29 @@ public Path getJavaHome() {
public List<String> buildArguments() {
final List<String> cmd = new ArrayList<>();
cmd.addAll(getJavaOptions());
if (environment.getJvm().isModular()) {
cmd.addAll(AbstractCommandBuilder.DEFAULT_MODULAR_VM_ARGUMENTS);
if (modularLauncher) {
if (environment.getJvm().isModular()) {
cmd.addAll(AbstractCommandBuilder.DEFAULT_MODULAR_VM_ARGUMENTS);
}
}
if (environment.getJvm().enhancedSecurityManagerAvailable()) {
cmd.add(AbstractCommandBuilder.SECURITY_MANAGER_PROP_WITH_ALLOW_VALUE);
}
cmd.add("-jar");
cmd.add(environment.getModuleJar().toString());
cmd.add("-mp");
cmd.add(getModulePaths());
cmd.add("org.jboss.as.cli");
cmd.add("-D" + Environment.HOME_DIR + "=" + environment.getWildflyHome());

if (modularLauncher) {
cmd.add(environment.getModuleJar().toString());
cmd.add("-mp");
cmd.add(getModulePaths());
cmd.add("org.jboss.as.cli");
cmd.add("-D" + Environment.HOME_DIR + "=" + environment.getWildflyHome());
} else {
cmd.add(environment.getWildflyHome().resolve(cliClientJar).toString());
}

cmd.addAll(cliArgs.asList());
return cmd;

}

@Override
Expand Down
19 changes: 11 additions & 8 deletions launcher/src/main/java/org/wildfly/core/launcher/Environment.java
Expand Up @@ -241,18 +241,21 @@ static Path validateWildFlyDir(final Path wildflyHome) {
return result;
}

static Path validateBootableJar(final Path bootableJar) {
if (bootableJar == null || Files.notExists(bootableJar)) {
throw LauncherMessages.MESSAGES.pathDoesNotExist(bootableJar);
static Path validateJar(final Path jarPath) {
if (jarPath == null || Files.notExists(jarPath)) {
throw LauncherMessages.MESSAGES.pathDoesNotExist(jarPath);
}
if (Files.isDirectory(bootableJar)) {
throw LauncherMessages.MESSAGES.pathNotAFile(bootableJar);
if (Files.isDirectory(jarPath)) {
throw LauncherMessages.MESSAGES.pathNotAFile(jarPath);
}
final Path result = bootableJar.toAbsolutePath().normalize();
final Path result = jarPath.toAbsolutePath().normalize();
return result;
}

static Path validateBootableJar(final String bootableJar) {
return validateBootableJar(Paths.get(bootableJar));
static Path validateJar(final String jarPath) {
if (jarPath == null) {
throw LauncherMessages.MESSAGES.pathDoesNotExist(null);
}
return validateJar(Paths.get(jarPath));
}
}
Expand Up @@ -199,7 +199,7 @@ public void testDomainBuilder() {
@Test
public void testCliBuilder() {
// Set up a standalone command builder
final CliCommandBuilder commandBuilder = CliCommandBuilder.of(WILDFLY_HOME)
final CliCommandBuilder commandBuilder = CliCommandBuilder.asModularLauncher(WILDFLY_HOME)
.addJavaOption("-Djava.net.preferIPv4Stack=true")
.addJavaOption("-Djava.net.preferIPv4Stack=false");

Expand Down
1 change: 1 addition & 0 deletions testsuite/manualmode/pom.xml
Expand Up @@ -641,6 +641,7 @@
<!-- no proper JBOSS_HOME dir -->
<exclude>org.jboss.as.test.manualmode.management.cli.CliEmbedServerInProcessTestCase</exclude>
<exclude>org.jboss.as.test.manualmode.management.cli.CLIEmbedServerTestCase</exclude>
<exclude>org.jboss.as.test.manualmode.management.cli.JbossCliClientJarJPMSSettingsTestCase</exclude>
<!-- copy standalone.xml, stop/start...-->
<exclude>org.jboss.as.test.manualmode.management.cli.CLIScriptSupportTestCase</exclude>
<!-- remove some file after cleanup -->
Expand Down
@@ -0,0 +1,129 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2022 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.as.test.manualmode.management.cli;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.PropertyPermission;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

import org.jboss.as.test.integration.management.cli.CliProcessWrapper;
import org.jboss.as.test.manualmode.management.cli.jpms.JPMSTestActivator;
import org.jboss.as.test.shared.PermissionUtils;
import org.jboss.as.test.shared.TestSuiteEnvironment;
import org.jboss.msc.service.ServiceActivator;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.jboss.shrinkwrap.impl.base.exporter.zip.ZipExporterImpl;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

/**
* Launches a non-modular CLI client and deploys an application that requires specific JPMS settings. This test case is used to
* verify that jboss-cli-client.jar is able to run properly without requiring the user to add JVM modular settings when it
* launches an embedded server.
*/
public class JbossCliClientJarJPMSSettingsTestCase {
private static final Path SERVER_HOME = Paths.get(TestSuiteEnvironment.getSystemProperty("jboss.dist"));
private static CliProcessWrapper cli;
private static File cliTestAppJar;

@BeforeClass
public static void setup() throws Exception {
cli = new CliProcessWrapper(false).addCliArgument("--no-color-output").addCliArgument("--timeout=30000");
cli.executeInteractive();
cliTestAppJar = createTestArchive("jpms-test-app.jar");
}

@AfterClass
public static void cleanup() throws Exception {
cli.destroyProcess();
Files.deleteIfExists(cliTestAppJar.toPath());
}

@Test
public void testManifestEntries() throws Exception {
JarFile clientJar = new JarFile(
SERVER_HOME.resolve("bin").resolve("client").resolve("jboss-cli-client.jar").toString());
Manifest manifest = clientJar.getManifest();
Attributes mainAttribs = manifest.getMainAttributes();
String addOpens = mainAttribs.getValue("Add-Opens");
Assert.assertTrue("Unexpected value for Manifest Add-Opens. Current: " + addOpens,
addOpens.contains("java.base/java.util"));
}

@Test
public void testDeploymentRequiringJMPSSettings() throws Exception {
String line = "embed-server --admin-only=false --jboss-home=" + SERVER_HOME.toAbsolutePath();
cli.pushLineAndWaitForResults(line);
Assert.assertTrue("The CLI message that describes it is running on a non-modular environment was not found: \n" + cli.getOutput(), cli.getOutput().contains("non-modular"));
cli.clearOutput();

// ensure there is no deployment yet
cli.pushLineAndWaitForResults("deployment-info --name=" + cliTestAppJar.getName());
Assert.assertTrue("Apparently the deployment already exists: \n" + cli.getOutput(), cli.getOutput().contains("WFLYCTL0216"));
cli.clearOutput();

// ensure that properties added by the deployment are not there
cli.pushLineAndWaitForResults("/core-service=platform-mbean/type=runtime:read-attribute(name=system-properties)");
Assert.assertTrue(JPMSTestActivator.DEFAULT_SYS_PROP_NAME + " name has been found after getting current System Properties. \n" + cli.getOutput(), !cli.getOutput().contains(JPMSTestActivator.DEFAULT_SYS_PROP_NAME));
Assert.assertTrue(JPMSTestActivator.DEFAULT_SYS_PROP_VALUE + " value has been found after getting current System Properties. \n" + cli.getOutput(), !cli.getOutput().contains(JPMSTestActivator.DEFAULT_SYS_PROP_VALUE));
cli.clearOutput();

// deploy and verify
cli.pushLineAndWaitForResults("deploy " + cliTestAppJar.getAbsolutePath());
cli.pushLineAndWaitForResults("deployment-info --name=" + cliTestAppJar.getName());
Assert.assertTrue("The deployment Failed: \n" + cli.getOutput(), !cli.getOutput().contains("WFLYCTL0216"));
cli.clearOutput();

// verifies the activator was executed
cli.pushLineAndWaitForResults("/core-service=platform-mbean/type=runtime:read-attribute(name=system-properties)");
Assert.assertTrue(JPMSTestActivator.DEFAULT_SYS_PROP_NAME + " name has not been found after getting current System Properties. \n" + cli.getOutput(), cli.getOutput().contains(JPMSTestActivator.DEFAULT_SYS_PROP_NAME));
Assert.assertTrue(JPMSTestActivator.DEFAULT_SYS_PROP_VALUE + " value has not been found after getting current System Properties. \n" + cli.getOutput(), cli.getOutput().contains(JPMSTestActivator.DEFAULT_SYS_PROP_VALUE));
cli.clearOutput();

// undeploy
cli.pushLineAndWaitForResults("undeploy " + cliTestAppJar.getAbsolutePath());
cli.pushLineAndWaitForResults("deployment-info --name=" + cliTestAppJar.getName());
Assert.assertTrue("The undeploy Failed: \n" + cli.getOutput(), cli.getOutput().contains("WFLYCTL0216"));

cli.pushLineAndWaitForResults("stop-embedded-server");
}

public static File createTestArchive(String archiveName) {
JavaArchive jar = ShrinkWrap.create(JavaArchive.class, archiveName);
jar.addClass(JPMSTestActivator.class);
jar.addAsServiceProvider(ServiceActivator.class, JPMSTestActivator.class);
jar.addAsManifestResource(new StringAsset("Dependencies: org.jboss.msc\n"), "MANIFEST.MF");
jar.addAsManifestResource(
PermissionUtils.createPermissionsXmlAsset(new PropertyPermission("test.deployment.trivial.prop", "write")),
"permissions.xml");

final String tempDir = TestSuiteEnvironment.getTmpDir();
File file = new File(tempDir, jar.getName());
new ZipExporterImpl(jar).exportTo(file, true);
return file;
}
}
@@ -0,0 +1,46 @@
package org.jboss.as.test.manualmode.management.cli.jpms;

import java.lang.reflect.Field;
import java.util.EnumMap;

import org.jboss.msc.Service;
import org.jboss.msc.service.ServiceActivator;
import org.jboss.msc.service.ServiceActivatorContext;
import org.jboss.msc.service.ServiceController;
import org.jboss.msc.service.ServiceName;
import org.jboss.msc.service.ServiceRegistryException;
import org.jboss.msc.service.StartContext;
import org.jboss.msc.service.StartException;
import org.jboss.msc.service.StopContext;

public class JPMSTestActivator implements ServiceActivator, Service {
public static final ServiceName SERVICE_NAME = ServiceName.of("test", "deployment", "trivial");
public static final String DEFAULT_SYS_PROP_NAME = "test.deployment.trivial.prop";
public static final String DEFAULT_SYS_PROP_VALUE = "default-value";

@Override
public void activate(ServiceActivatorContext serviceActivatorContext) throws ServiceRegistryException {
// requires opens java.base/java.util
for (Field field : EnumMap.class.getDeclaredFields()) {
if (field.getType() == Class.class) {
field.setAccessible(true);
}
}

serviceActivatorContext.getServiceTarget()
.addService(SERVICE_NAME)
.setInstance(this)
.setInitialMode(ServiceController.Mode.ACTIVE)
.install();
}

@Override
public void start(StartContext context) throws StartException {
System.setProperty(DEFAULT_SYS_PROP_NAME, DEFAULT_SYS_PROP_VALUE);
}

@Override
public void stop(StopContext context) {
System.clearProperty(DEFAULT_SYS_PROP_NAME);
}
}

0 comments on commit c91d78f

Please sign in to comment.