/* * Jopr Management Platform * Copyright (C) 2012 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2, as * published by the Free Software Foundation, and/or the GNU Lesser * General Public License, version 2.1, also as published by the Free * Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License and the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU General Public License * and the GNU Lesser General Public License along with this program; * if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.rhq.plugins.jbossas5.itest; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; import java.io.File; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; import org.hyperic.sigar.SigarException; import org.testng.Assert; import org.testng.annotations.AfterSuite; import org.testng.annotations.Test; import org.rhq.core.clientapi.agent.PluginContainerException; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.configuration.PropertySimple; import org.rhq.core.domain.measurement.AvailabilityType; import org.rhq.core.domain.resource.InventoryStatus; import org.rhq.core.domain.resource.Resource; import org.rhq.core.domain.resource.ResourceCategory; import org.rhq.core.domain.resource.ResourceType; import org.rhq.core.domain.util.ResourceUtility; import org.rhq.core.domain.util.TypeAndKeyResourceFilter; import org.rhq.core.pc.inventory.InventoryManager; import org.rhq.core.pc.inventory.ResourceContainer; import org.rhq.core.pluginapi.configuration.ListPropertySimpleWrapper; import org.rhq.core.pluginapi.configuration.MapPropertySimpleWrapper; import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException; import org.rhq.core.pluginapi.operation.OperationResult; import org.rhq.core.pluginapi.util.FileUtils; import org.rhq.core.pluginapi.util.StartScriptConfiguration; import org.rhq.core.system.ProcessInfo; import org.rhq.core.system.SystemInfo; import org.rhq.core.system.SystemInfoFactory; import org.rhq.plugins.jbossas5.helper.JBossProductType; import org.rhq.test.arquillian.RunDiscovery; /** * An integration test for the AS5 server type. * * @author Ian Springer */ @Test(groups = { "integration" }, singleThreaded = true) public class ApplicationServerComponentTest extends AbstractJBossAS5PluginTest { protected static final File JBOSS_HOME = new File(FileUtils.getCanonicalPath(System.getProperty("jboss5.home"))); protected static final String BIND_ADDRESS = System.getProperty("jboss.bind.address"); protected static final String SERVICE_BINDING_SET = System.getProperty("jboss.serviceBindingSet"); protected static final int PORT_OFFSET = Integer.valueOf(System.getProperty("jboss.portOffset")); protected static final ResourceType RESOURCE_TYPE = new ResourceType("JBossAS Server", PLUGIN_NAME, ResourceCategory.SERVER, null); // The key of an AS5 Server Resource is its configuration directory. protected static final String RESOURCE_KEY = FileUtils.getCanonicalPath(System.getProperty("jboss5.home") + "/server/default"); private static final String SHUTDOWN_OPERATION_NAME = "shutdown"; private static final String START_OPERATION_NAME = "start"; @Test @RunDiscovery public void testAutoDiscovery() throws Exception { System.out.println("\n****** Running " + getClass().getSimpleName() + ".testAutoDiscovery..."); Resource platform = this.pluginContainer.getInventoryManager().getPlatform(); System.out.println("~~~~~ Platform: " + platform); Assert.assertNotNull(platform); Assert.assertEquals(platform.getInventoryStatus(), InventoryStatus.COMMITTED); Assert.assertNotNull(getServerResource(), RESOURCE_TYPE + " Resource with key [" + RESOURCE_KEY + "] was not discovered."); System.out.println("===== Discovered: " + getServerResource()); Configuration pluginConfig = getServerResource().getPluginConfiguration(); System.out.println("---------- " + pluginConfig.toString(true)); validatePluginConfiguration(pluginConfig); System.out.println("---------- Finished " + getClass().getSimpleName() + ".testAutoDiscovery..."); } @Test(dependsOnMethods = { "testAutoDiscovery" }) public void testConnection() throws Exception { System.out.println("\n****** Running " + getClass().getSimpleName() + ".testConnection..."); Resource platform = this.pluginContainer.getInventoryManager().getPlatform(); Assert.assertNotNull(platform); Assert.assertEquals(platform.getInventoryStatus(), InventoryStatus.COMMITTED); Configuration pluginConfig = getServerResource().getPluginConfiguration(); // We need to set the principal and credentials to admin:admin in order to connect to the managed server. pluginConfig.setSimpleValue("principal", "admin"); pluginConfig.setSimpleValue("credentials", "admin"); // Restart the server ResourceComponent so it picks up the changes we just made to the plugin config. System.out.println("===== Updating Server Resource's plugin configuration: " + pluginConfig.toString(true)); restartServerResourceComponent(); // If the ResourceComponent connected to the managed server successfully, the Resource should now be UP. Thread.sleep(1000); AvailabilityType avail = getAvailability(getServerResource()); assertEquals(avail, AvailabilityType.UP); System.out.println("---------- Finished " + getClass().getSimpleName() + ".testConnection..."); } protected void validatePluginConfiguration(Configuration pluginConfig) { // "hostname" prop String hostname = pluginConfig.getSimpleValue("hostname", null); String expectedHostname = BIND_ADDRESS; assertEquals(hostname, expectedHostname, "Plugin config prop [hostname]."); // "serverName" prop String serverName = pluginConfig.getSimpleValue("serverName", null); String expectedServerName = System.getProperty("jboss.server.name"); expectedServerName = (null == expectedServerName) ? JBossProductType.AS.DEFAULT_CONFIG_NAME : expectedServerName; assertEquals(serverName, expectedServerName, "Plugin config prop [serverName]."); // "startScript" prop String startScript = pluginConfig.getSimpleValue("startScript"); startScript = (null == startScript) ? ("bin/" + getExpectedStartScriptFileName()) : startScript; Assert.assertNotNull(startScript); File startScriptFile = new File(startScript); String expectedStartScriptFileName = getExpectedStartScriptFileName(); Assert.assertEquals(startScriptFile.getName(), expectedStartScriptFileName); if (!startScriptFile.isAbsolute()) { // If it's relative, e.g. "bin/standalone.sh", it will be resolved relative to the AS home dir. startScriptFile = new File(JBOSS_HOME, startScript); } Assert.assertTrue(startScriptFile.exists(), "Start script [" + startScriptFile + "] does not exist."); // "startScriptEnv" prop PropertySimple startScriptEnvProp = pluginConfig.getSimple("startScriptEnv"); MapPropertySimpleWrapper startScriptEnvPropWrapper = new MapPropertySimpleWrapper(startScriptEnvProp); Map<String, String> env = startScriptEnvPropWrapper.getValue(); validateStartScriptEnv(env); // "startScriptArgs" prop PropertySimple startScriptArgsProp = pluginConfig.getSimple("startScriptArgs"); ListPropertySimpleWrapper startScriptArgsPropWrapper = new ListPropertySimpleWrapper(startScriptArgsProp); List<String> args = startScriptArgsPropWrapper.getValue(); Assert.assertEquals(args, getExpectedStartScriptArgs(), "Plugin config prop [startScriptArgs]"); } protected void validateStartScriptEnv(Map<String, String> env) { Assert.assertTrue(env.size() <= 4, env.toString()); String javaHome = env.get("JAVA_HOME"); Assert.assertNotNull(javaHome); Assert.assertTrue(new File(javaHome).isDirectory()); String path = env.get("PATH"); Assert.assertNotNull(path); String[] pathElements = path.split(File.pathSeparator); Assert.assertTrue(pathElements.length >= 1); Assert.assertTrue(new File(pathElements[0]).isDirectory()); String javaOpts = env.get("JAVA_OPTS"); Assert.assertNull(javaOpts); } @Test(dependsOnMethods = { "testConnection" }) public void testShutdownAndStartOperations() throws Exception { System.out.println("\n****** Running " + getClass().getSimpleName() + ".testShutdownAndStartOperations..."); // First make sure the server is up. AvailabilityType avail = getAvailability(getServerResource()); assertEquals(avail, AvailabilityType.UP); System.out.println("===== Shutting Down Managed Server: " + getServerResource()); // Now shut it down using the Shutdown op and make sure it has gone down. invokeOperationAndAssertSuccess(getServerResource(), SHUTDOWN_OPERATION_NAME, null); avail = getAvailability(getServerResource()); assertEquals(avail, AvailabilityType.DOWN); //change the plugin config to shutdown via JMX Configuration pluginConfig = getServerResource().getPluginConfiguration(); pluginConfig.getSimple("shutdownMethod").setValue("JMX"); restartServerResourceComponent(); //invoke the shutdown operation again and assert that it actually ran and generated some error message. OperationResult operationResult = invokeOperation(getServerResource(), SHUTDOWN_OPERATION_NAME, null); avail = getAvailability(getServerResource()); assertEquals(avail, AvailabilityType.DOWN); assertNotNull(operationResult.getErrorMessage()); //ok, now try the same with the script shutdown method pluginConfig = getServerResource().getPluginConfiguration(); pluginConfig.getSimple("shutdownMethod").setValue("SCRIPT"); restartServerResourceComponent(); //invoke the shutdown operation again and assert that it actually ran operationResult = invokeOperation(getServerResource(), SHUTDOWN_OPERATION_NAME, null); avail = getAvailability(getServerResource()); assertEquals(avail, AvailabilityType.DOWN); assertNotNull(operationResult.getErrorMessage()); assertNull(operationResult.getSimpleResult()); // Before restarting it, add some stuff to the 'startScriptEnv' and 'startScriptArgs' props so we can verify // they are used correctly by the Start op. pluginConfig = getServerResource().getPluginConfiguration(); StartScriptConfiguration startScriptConfig = new StartScriptConfiguration(pluginConfig); // Add a var to the start script env. Map<String, String> env = startScriptConfig.getStartScriptEnv(); env.put("FOO", "bar"); // uppercase env var name or Windows will do it for you startScriptConfig.setStartScriptEnv(env); // Add an arg to the start script args. List<String> args = startScriptConfig.getStartScriptArgs(); args.add("-Dfoo=bar"); startScriptConfig.setStartScriptArgs(args); // Restart the server ResourceComponent so it picks up the changes we just made to the plugin config. System.out.println("===== Updating Server Resource's plugin configuration: " + pluginConfig.toString(true)); restartServerResourceComponent(); System.out.println("===== Restarting Managed Server: " + getServerResource()); // Finally restart it using the Start op and make sure it has come back up. invokeOperationAndAssertSuccess(getServerResource(), START_OPERATION_NAME, null); avail = getAvailability(getServerResource()); assertEquals(avail, AvailabilityType.UP); System.out.println("===== Validating Server Process: " + getServerResource()); List<ProcessInfo> processes = getServerProcesses(); Assert.assertEquals(processes.size(), 1, "Can't find AS Process."); ProcessInfo serverProcess = processes.get(0); Map<String, String> processEnv = serverProcess.getEnvironmentVariables(); assertEquals(processEnv.get("FOO"), "bar", processEnv.toString()); List<String> processArgs = Arrays.asList(serverProcess.getCommandLine()); assertTrue(processArgs.contains("-Dfoo=bar"), processArgs.toString()); System.out.println("---------- Finished " + getClass().getSimpleName() + ". testShutdownAndStartOperations..."); } private void restartServerResourceComponent() throws PluginContainerException { InventoryManager inventoryManager = this.pluginContainer.getInventoryManager(); inventoryManager.deactivateResource(getServerResource()); ResourceContainer serverContainer = inventoryManager.getResourceContainer(getServerResource()); try { inventoryManager.activateResource(getServerResource(), serverContainer, true); } catch (InvalidPluginConfigurationException ex) { // we may fail to start the component in case the server is down and connection to ProfileService cannot be obtained } } protected String getExpectedStartScriptFileName() { return (File.separatorChar == '/') ? "run.sh" : "run.bat"; } protected List<String> getExpectedStartScriptArgs() { String[] args = new String[] { "--configuration=default", "--host=127.0.0.1", "-Djboss.service.binding.set=ports-03" }; return Arrays.asList(args); } @AfterSuite public void killServerProcesses() { List<ProcessInfo> processes = getServerProcesses(); System.out.println("\n=== Killing " + processes.size() + " AS5 processes..."); for (ProcessInfo process : processes) { System.out.println("====== Killing process with pid [" + process.getPid() + "] and command line [" + Arrays.toString(process.getCommandLine()) + "]..."); try { process.kill("KILL"); } catch (SigarException e) { System.err.println("Failed to kill " + process + ": " + e); } } processes = getServerProcesses(); Assert.assertEquals(processes.size(), 0, "Failed to kill " + processes.size() + " AS5 processes: " + processes); } private Resource getServerResource() { Resource platform = this.pluginContainer.getInventoryManager().getPlatform(); Set<Resource> childResources = ResourceUtility.getChildResources(platform, new TypeAndKeyResourceFilter( RESOURCE_TYPE, RESOURCE_KEY)); if (childResources.size() > 1) { throw new IllegalStateException(platform + " has more than one child Resource with same type (" + RESOURCE_TYPE + ") and key (" + RESOURCE_KEY + ")."); } return (childResources.isEmpty()) ? null : childResources.iterator().next(); } private List<ProcessInfo> getServerProcesses() { SystemInfo systemInfo = SystemInfoFactory.createSystemInfo(); return systemInfo.getProcesses("arg|*|match=org\\.jboss\\.Main|-Djboss.service.binding.set|match=" + SERVICE_BINDING_SET); } }