/* * Copyright (C) 2014 Red Hat, inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ package org.jboss.as.test.shared; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.FAILURE_DESCRIPTION; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.HOST; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OUTCOME; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RESULT; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUCCESS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.IOException; import java.util.List; import java.util.Set; import org.jboss.as.controller.ControlledProcessState; import org.jboss.as.server.ServerEnvironment; import org.jboss.as.test.integration.management.util.CLIOpResult; import org.jboss.as.test.integration.management.util.CLIWrapper; import org.jboss.dmr.ModelNode; import org.jboss.dmr.ModelType; import org.jboss.dmr.Property; import org.junit.Assert; /** * * @author <a href="mailto:ehugonne@redhat.com">Emmanuel Hugonnet</a> (c) 2014 Red Hat, inc. */ public class ModelParserUtils { /** * Tests the ability to boot an admin-only server using the given config, persist the config, * reload it, and confirm that the configuration model from the original boot matches the model * from the reload. * * @param originalConfig the config file to use * @param jbossHome directory to use as $JBOSS_HOME * @return the configuration model read after the reload * @throws Exception */ public static ModelNode standaloneXmlTest(File originalConfig, File jbossHome) throws Exception { File serverDir = new File(jbossHome, "standalone"); File configCopy = new File(serverDir, "configuration" + File.separatorChar + originalConfig.getName()); FileUtils.copyFile(originalConfig, configCopy); CLIWrapper cli = new CLIWrapper(false); try { String line = "embed-server --admin-only=true --server-config=" + originalConfig.getName() + " --std-out=echo --jboss-home=" + jbossHome.getCanonicalPath(); cli.sendLine(line); assertProcessState(cli, ControlledProcessState.State.RUNNING.toString(), TimeoutUtil.adjust(30000), false); ModelNode firstResult = readResourceTree(cli); cli.sendLine("/system-property=model-parser-util:add(value=true)"); cli.sendLine("/system-property=model-parser-util:remove"); cli.sendLine("reload --admin-only=true"); assertProcessState(cli, ControlledProcessState.State.RUNNING.toString(), TimeoutUtil.adjust(30000), false); ModelNode secondResult = readResourceTree(cli); compare(firstResult, secondResult); return secondResult; } finally { try { cli.quit(); } finally { System.clearProperty(ServerEnvironment.SERVER_BASE_DIR); } } } /** * Tests the ability to boot an admin-only Host Controller using the given host config, persist the config, * reload it, and confirm that the configuration model from the original boot matches the model * from the reload. * * @param originalConfig the config file to use for the host model * @param jbossHome directory to use as $JBOSS_HOME * @return the host subtree from the configuration model read after the reload * @throws Exception */ public static ModelNode hostXmlTest(final File originalConfig, File jbossHome) throws Exception { return hostControllerTest(originalConfig, jbossHome, true); } private static ModelNode hostControllerTest(final File originalConfig, final File target, boolean hostXml) throws Exception { File domainDir = new File(target, "domain"); File configCopy = new File(domainDir, "configuration" + File.separatorChar + originalConfig.getName()); FileUtils.copyFile(originalConfig, configCopy); CLIWrapper cli = new CLIWrapper(false); try { String configType = hostXml ? "--host-config=" : "--domain-config="; String line = "embed-host-controller " + configType + originalConfig.getName() + " --std-out=echo --jboss-home=" + target.getCanonicalPath(); cli.sendLine(line); assertProcessState(cli, ControlledProcessState.State.RUNNING.toString(), TimeoutUtil.adjust(30000), true); ModelNode firstResult = readResourceTree(cli); String hostName = firstResult.get(HOST).asProperty().getName(); cli.sendLine("/system-property=model-parser-util:add(value=true)"); cli.sendLine("/system-property=model-parser-util:remove"); cli.sendLine("reload --host=" + hostName + " --admin-only=true"); assertProcessState(cli, ControlledProcessState.State.RUNNING.toString(), TimeoutUtil.adjust(30000), true); ModelNode secondResult = readResourceTree(cli); compare(pruneDomainModel(firstResult, hostXml), pruneDomainModel(secondResult, hostXml)); return secondResult; } finally { try { cli.quit(); } finally { System.clearProperty(ServerEnvironment.SERVER_BASE_DIR); } } } private static ModelNode pruneDomainModel(ModelNode model, boolean forHost) { ModelNode result = new ModelNode(); if (forHost) { result.get(HOST).set(model.get(HOST)); } else { for (Property prop : model.asPropertyList()) { if (!HOST.equals(prop.getName())) { result.get(prop.getName()).set(prop.getValue()); } } } return result; } /** * Tests the ability to boot an admin-only Host Controller using the given domain config, persist the config, * reload it, and confirm that the configuration model from the original boot matches the model * from the reload. * * @param originalConfig the config file to use for the domain model * @param jbossHome directory to use as $JBOSS_HOME * @return the configuration model read after the reload, excluding the host subtree * @throws Exception */ public static ModelNode domainXmlTest(File originalConfig, File jbossHome) throws Exception { return hostControllerTest(originalConfig, jbossHome, false); } private static void assertProcessState(CLIWrapper cli, String expected, int timeout, boolean forHost) throws IOException, InterruptedException { long done = timeout < 1 ? 0 : System.currentTimeMillis() + timeout; String history = ""; String state = null; do { try { state = forHost ? getHostState(cli) : getServerState(cli); history += state+"\n"; } catch (Exception ignored) { // history += ignored.toString()+ "--" + cli.readOutput() + "\n"; } if (expected.equals(state)) { return; } else { Thread.sleep(20); } } while (timeout > 0 && System.currentTimeMillis() < done); assertEquals(history, expected, state); } private static String getServerState(CLIWrapper cli) throws IOException { cli.sendLine(":read-attribute(name=server-state)", true); CLIOpResult result = cli.readAllAsOpResult(); ModelNode resp = result.getResponseNode(); ModelNode stateNode = result.isIsOutcomeSuccess() ? resp.get(RESULT) : resp.get(FAILURE_DESCRIPTION); return stateNode.asString(); } private static String getHostState(CLIWrapper cli) throws IOException { cli.sendLine("/host=*:read-attribute(name=host-state)", true); CLIOpResult result = cli.readAllAsOpResult(); ModelNode resp = result.getResponseNode(); ModelNode stateNode; if (result.isIsOutcomeSuccess()) { stateNode = resp.get(RESULT).get(0).get(RESULT); } else { stateNode = resp.get(FAILURE_DESCRIPTION); } return stateNode.asString(); } private static ModelNode readResourceTree(CLIWrapper cli) { cli.sendLine("/:read-resource(recursive=true)"); ModelNode response = ModelNode.fromString(cli.readOutput()); assertTrue(response.toString(), SUCCESS.equals(response.get(OUTCOME).asString())); ModelNode firstResult = response.get(RESULT); assertTrue(response.toString(), firstResult.isDefined()); return firstResult; } private static void compare(ModelNode node1, ModelNode node2) { Assert.assertEquals(node1.getType(), node2.getType()); if (node1.getType() == ModelType.OBJECT) { final Set<String> keys1 = node1.keys(); final Set<String> keys2 = node2.keys(); Assert.assertEquals(node1 + "\n" + node2, keys1.size(), keys2.size()); for (String key : keys1) { final ModelNode child1 = node1.get(key); Assert.assertTrue("Missing: " + key + "\n" + node1 + "\n" + node2, node2.has(key)); final ModelNode child2 = node2.get(key); if (child1.isDefined()) { Assert.assertTrue(child1.toString(), child2.isDefined()); compare(child1, child2); } else { Assert.assertFalse(child2.asString(), child2.isDefined()); } } } else if (node1.getType() == ModelType.LIST) { List<ModelNode> list1 = node1.asList(); List<ModelNode> list2 = node2.asList(); Assert.assertEquals(list1 + "\n" + list2, list1.size(), list2.size()); for (int i = 0; i < list1.size(); i++) { compare(list1.get(i), list2.get(i)); } } else if (node1.getType() == ModelType.PROPERTY) { Property prop1 = node1.asProperty(); Property prop2 = node2.asProperty(); Assert.assertEquals(prop1 + "\n" + prop2, prop1.getName(), prop2.getName()); compare(prop1.getValue(), prop2.getValue()); } else { Assert.assertEquals("\n\"" + node1.asString() + "\"\n\"" + node2.asString() + "\"\n-----", node1.asString().trim(), node2.asString().trim()); } } }