Skip to content

Commit

Permalink
Merge pull request #404 from jamezp/WFARQ-142
Browse files Browse the repository at this point in the history
[WFARQ-142] Add support for launching the server in debug mode.
  • Loading branch information
jamezp authored Jan 5, 2024
2 parents 3d2a67d + 3b33082 commit c18e377
Show file tree
Hide file tree
Showing 9 changed files with 350 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ public class BootableContainerConfiguration extends CommonManagedContainerConfig

private String javaVmArguments = System.getProperty("jboss.options");

private boolean debug = getBooleanProperty("wildfly.debug", false);
private int debugPort = Integer.parseInt(System.getProperty("wildfly.debug.port", "8787"));

private boolean debugSuspend = getBooleanProperty("wildfly.debug.suspend", true);

private String jbossArguments;

private boolean enableAssertions = true;
Expand All @@ -43,6 +48,30 @@ public void setJavaVmArguments(String javaVmArguments) {
this.javaVmArguments = javaVmArguments;
}

public boolean isDebug() {
return debug;
}

public void setDebug(final boolean debug) {
this.debug = debug;
}

public int getDebugPort() {
return debugPort;
}

public void setDebugPort(final int debugPort) {
this.debugPort = debugPort;
}

public boolean isDebugSuspend() {
return debugSuspend;
}

public void setDebugSuspend(final boolean debugSuspend) {
this.debugSuspend = debugSuspend;
}

public String getJbossArguments() {
return jbossArguments;
}
Expand Down Expand Up @@ -80,4 +109,12 @@ public String getInstallDir() {
public void setInstallDir(String installDir) {
this.installDir = installDir;
}

private static boolean getBooleanProperty(final String key, final boolean dft) {
final String value = System.getProperty(key);
if (value != null) {
return value.isBlank() || Boolean.parseBoolean(value);
}
return dft;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ protected CommandBuilder createCommandBuilder(final BootableContainerConfigurati
commandBuilder.addServerArguments(ParameterUtils.splitParams(jbossArguments));
}

// Check if we should enable debug
if (config.isDebug()) {
commandBuilder.setDebug(config.isDebugSuspend(), config.getDebugPort());
}

return commandBuilder;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* 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.jboss.as.arquillian.container.managed.manual;

import java.io.IOException;
import java.util.List;

import org.jboss.arquillian.container.test.api.ContainerController;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.container.test.api.TargetsContainer;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.as.arquillian.container.ManagementClient;
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.After;
import org.junit.Assert;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;

import com.sun.jdi.Bootstrap;
import com.sun.jdi.VirtualMachine;
import com.sun.jdi.connect.AttachingConnector;
import com.sun.jdi.connect.IllegalConnectorArgumentsException;

/**
* @author <a href="mailto:[email protected]">James R. Perkins</a>
*/
@Category(ManualMode.class)
@RunWith(Arquillian.class)
@RunAsClient
public class DebugManualModeTestCase {
private static final String DEBUG_SUSPEND_CONTAINER_ID = "debug-config";

@ArquillianResource
private static ContainerController controller;

@ArquillianResource
@TargetsContainer(DEBUG_SUSPEND_CONTAINER_ID)
private ManagementClient debugSuspendClient;

@Deployment(managed = false, name = "dep1")
public static WebArchive createDeployment() {
return ShrinkWrap.create(WebArchive.class)
// Required for JUnit when running in ARQ
.addClass(ManualMode.class);
}

@After
public void shutdown() {
if (controller.isStarted(DEBUG_SUSPEND_CONTAINER_ID)) {
controller.stop(DEBUG_SUSPEND_CONTAINER_ID);
}
}

@Test
public void debugConfig() throws Exception {
controller.start(DEBUG_SUSPEND_CONTAINER_ID);

// Attach a debugger
final VirtualMachine vm = attachDebugger();
try {
Assert.assertFalse("VM should be able to see all threads: " + vm, vm.allThreads().isEmpty());
// Check the server-state
final ModelNode address = new ModelNode().setEmptyList();
final ModelNode op = Operations.createReadAttributeOperation(address, "server-state");
final ModelNode result = executeOperation(debugSuspendClient, op);
Assert.assertEquals("running", result.asString());
} finally {
vm.dispose();
}
}

private static ModelNode executeOperation(final ManagementClient client, final ModelNode op) throws IOException {
final ModelNode result = client.getControllerClient().execute(op);
if (!Operations.isSuccessfulOutcome(result)) {
Assert.fail(Operations.getFailureDescription(result).asString());
}
return Operations.readResult(result);
}

private static VirtualMachine attachDebugger() throws IllegalConnectorArgumentsException, IOException {
final var manager = Bootstrap.virtualMachineManager();
final AttachingConnector connector = findSocket(manager.attachingConnectors());
Assert.assertNotNull("Failed to find socket connector", connector);
final var defaultArguments = connector.defaultArguments();
defaultArguments.get("port").setValue(System.getProperty("test.debug.port", "5005"));
return connector.attach(defaultArguments);
}

private static AttachingConnector findSocket(final List<AttachingConnector> connectors) {
// Attempt to find the socket connector and configure it
for (AttachingConnector connector : connectors) {
if (connector.defaultArguments().containsKey("port")) {
return connector;
}
}
return null;
}
}
12 changes: 12 additions & 0 deletions container-bootable/src/test/resources/manual-arquillian.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,17 @@
<property name="javaVmArguments">${jvm.args}</property>
</configuration>
</container>
<!-- Debug testing configurations -->
<container qualifier="debug-config" mode="manual">
<configuration>
<property name="installDir">${install.dir}</property>
<property name="jarFile">${bootable.jar}</property>
<property name="allowConnectingToRunningServer">false</property>
<property name="javaVmArguments">${jvm.args}</property>
<property name="debug">true</property>
<property name="debugPort">${test.debug.port:5005}</property>
<property name="debugSuspend">false</property>
</configuration>
</container>
</group>
</arquillian>
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ public class ManagedContainerConfiguration extends DistributionContainerConfigur

private String moduleOptions;

private boolean debug = getBooleanProperty("wildfly.debug", false);
private int debugPort = Integer.parseInt(System.getProperty("wildfly.debug.port", "8787"));

private boolean debugSuspend = getBooleanProperty("wildfly.debug.suspend", true);

private String serverConfig = System.getProperty("jboss.server.config.file.name");

private String readOnlyServerConfig = System.getProperty("jboss.server.config.file.name.readonly");
Expand Down Expand Up @@ -109,6 +114,30 @@ public void setModuleOptions(String moduleOptions) {
this.moduleOptions = moduleOptions;
}

public boolean isDebug() {
return debug;
}

public void setDebug(final boolean debug) {
this.debug = debug;
}

public int getDebugPort() {
return debugPort;
}

public void setDebugPort(final int debugPort) {
this.debugPort = debugPort;
}

public boolean isDebugSuspend() {
return debugSuspend;
}

public void setDebugSuspend(final boolean debugSuspend) {
this.debugSuspend = debugSuspend;
}

/**
* Get the server configuration file name. Equivalent to [-server-config=...] on the command line.
*/
Expand Down Expand Up @@ -244,4 +273,12 @@ private static boolean isWindows() {
final String os = System.getProperty("os.name", "generic").toLowerCase(Locale.ROOT);
return os.contains("windows");
}

private static boolean getBooleanProperty(final String key, final boolean dft) {
final String value = System.getProperty(key);
if (value != null) {
return value.isBlank() || Boolean.parseBoolean(value);
}
return dft;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ protected CommandBuilder createCommandBuilder(ManagedContainerConfiguration conf
}
}

// Check if we should enable debug
if (config.isDebug()) {
commandBuilder.setDebug(config.isDebugSuspend(), config.getDebugPort());
}

// Previous versions of arquillian set the jboss.home.dir property in the JVM properties.
// Some tests may rely on this behavior, but could be considered to be removed as all the scripts add this
// property after the modules path (-mp) has been defined. The command builder will set the property after
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* 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.jboss.as.arquillian.container.managed.manual;

import java.io.IOException;
import java.util.List;

import org.jboss.arquillian.container.test.api.ContainerController;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.container.test.api.TargetsContainer;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.as.arquillian.container.ManagementClient;
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.After;
import org.junit.Assert;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;

import com.sun.jdi.Bootstrap;
import com.sun.jdi.VirtualMachine;
import com.sun.jdi.connect.AttachingConnector;
import com.sun.jdi.connect.IllegalConnectorArgumentsException;

/**
* @author <a href="mailto:[email protected]">James R. Perkins</a>
*/
@Category(ManualMode.class)
@RunWith(Arquillian.class)
@RunAsClient
public class DebugManualModeTestCase {
private static final String DEBUG_SUSPEND_CONTAINER_ID = "debug-config";

@ArquillianResource
private static ContainerController controller;

@ArquillianResource
@TargetsContainer(DEBUG_SUSPEND_CONTAINER_ID)
private ManagementClient debugSuspendClient;

@Deployment(managed = false, name = "dep1")
public static WebArchive createDeployment() {
return ShrinkWrap.create(WebArchive.class)
// Required for JUnit when running in ARQ
.addClass(ManualMode.class);
}

@After
public void shutdown() {
if (controller.isStarted(DEBUG_SUSPEND_CONTAINER_ID)) {
controller.stop(DEBUG_SUSPEND_CONTAINER_ID);
}
}

@Test
public void debugConfig() throws Exception {
controller.start(DEBUG_SUSPEND_CONTAINER_ID);

// Attach a debugger
final VirtualMachine vm = attachDebugger();
try {
Assert.assertFalse("VM should be able to see all threads: " + vm, vm.allThreads().isEmpty());
// Check the server-state
final ModelNode address = new ModelNode().setEmptyList();
final ModelNode op = Operations.createReadAttributeOperation(address, "server-state");
final ModelNode result = executeOperation(debugSuspendClient, op);
Assert.assertEquals("running", result.asString());
} finally {
vm.dispose();
}
}

private static ModelNode executeOperation(final ManagementClient client, final ModelNode op) throws IOException {
final ModelNode result = client.getControllerClient().execute(op);
if (!Operations.isSuccessfulOutcome(result)) {
Assert.fail(Operations.getFailureDescription(result).asString());
}
return Operations.readResult(result);
}

private static VirtualMachine attachDebugger() throws IllegalConnectorArgumentsException, IOException {
final var manager = Bootstrap.virtualMachineManager();
final AttachingConnector connector = findSocket(manager.attachingConnectors());
Assert.assertNotNull("Failed to find socket connector", connector);
final var defaultArguments = connector.defaultArguments();
defaultArguments.get("port").setValue(System.getProperty("test.debug.port", "5005"));
return connector.attach(defaultArguments);
}

private static AttachingConnector findSocket(final List<AttachingConnector> connectors) {
// Attempt to find the socket connector and configure it
for (AttachingConnector connector : connectors) {
if (connector.defaultArguments().containsKey("port")) {
return connector;
}
}
return null;
}
}
Loading

0 comments on commit c18e377

Please sign in to comment.