From 9d37ca79e9884f63f3275f6c201ea5be1b898318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20Jan=C3=ADk?= Date: Thu, 9 Aug 2018 07:51:38 +0200 Subject: [PATCH] [WFCORE-3991] Test coverage for read-config-as-features --- .../ModelDescriptionConstants.java | 5 +- .../ReadConfigAsFeaturesDomainTestCase.java | 209 +++++++++++++ .../api/ReadConfigAsFeaturesTestBase.java | 188 +++++++++++ ...eadConfigAsFeaturesStandaloneTestCase.java | 294 ++++++++++++++++++ 4 files changed, 695 insertions(+), 1 deletion(-) create mode 100644 testsuite/domain/src/test/java/org/jboss/as/test/integration/domain/management/ReadConfigAsFeaturesDomainTestCase.java create mode 100644 testsuite/shared/src/main/java/org/jboss/as/test/integration/management/api/ReadConfigAsFeaturesTestBase.java create mode 100644 testsuite/standalone/src/test/java/org/wildfly/core/test/standalone/mgmt/api/core/ReadConfigAsFeaturesStandaloneTestCase.java diff --git a/controller/src/main/java/org/jboss/as/controller/descriptions/ModelDescriptionConstants.java b/controller/src/main/java/org/jboss/as/controller/descriptions/ModelDescriptionConstants.java index 4d006ba65b0..fc44a26cdbd 100644 --- a/controller/src/main/java/org/jboss/as/controller/descriptions/ModelDescriptionConstants.java +++ b/controller/src/main/java/org/jboss/as/controller/descriptions/ModelDescriptionConstants.java @@ -240,6 +240,7 @@ public class ModelDescriptionConstants { public static final String HTTP_UPGRADE = "http-upgrade"; public static final String HTTP_UPGRADE_ENABLED = "http-upgrade-enabled"; public static final String HTTP_INTERFACE = "http-interface"; + public static final String ID = "id"; public static final String IDENTITY = "identity"; public static final String IGNORED = "ignored-by-unaffected-host-controller"; public static final String IGNORED_RESOURCES = "ignored-resources"; @@ -275,6 +276,7 @@ public class ModelDescriptionConstants { public static final String LEVEL = "level"; public static final String LDAP = "ldap"; public static final String LDAP_CONNECTION = "ldap-connection"; + public static final String LIST_SNAPSHOTS_OPERATION = "list-snapshots"; public static final String LOCAL = "local"; public static final String LOCAL_DESTINATION_OUTBOUND_SOCKET_BINDING = "local-destination-outbound-socket-binding"; public static final String LOCAL_HOST_NAME = "local-host-name"; @@ -359,10 +361,10 @@ public class ModelDescriptionConstants { public static final String PASSWORD = "password"; public static final String PATH = "path"; public static final String PATHS = "paths"; + public static final String PATTERN = "pattern"; public static final String PERIODIC_ROTATING_FILE_HANDLER = "periodic-rotating-file-handler"; public static final String PERMISSION_COMBINATION_POLICY = "permission-combination-policy"; public static final String PERSIST_NAME = "persist-name"; - public static final String PATTERN = "pattern"; public static final String PERSISTENT = "persistent"; public static final String PLAIN_TEXT = "plain-text"; public static final String PLATFORM_MBEAN = "platform-mbean"; @@ -549,6 +551,7 @@ public class ModelDescriptionConstants { */ public static final String SYNC_REMOVED_FOR_READD = "sync-dropped-for-readd"; public static final String TAIL_COMMENT_ALLOWED = "tail-comment-allowed"; + public static final String TAKE_SNAPSHOT_OPERATION = "take-snapshot"; public static final String TARGET_PATH = "target-path"; public static final String TCP = "tcp"; public static final String TIMEOUT = "timeout"; diff --git a/testsuite/domain/src/test/java/org/jboss/as/test/integration/domain/management/ReadConfigAsFeaturesDomainTestCase.java b/testsuite/domain/src/test/java/org/jboss/as/test/integration/domain/management/ReadConfigAsFeaturesDomainTestCase.java new file mode 100644 index 00000000000..0f71a47996a --- /dev/null +++ b/testsuite/domain/src/test/java/org/jboss/as/test/integration/domain/management/ReadConfigAsFeaturesDomainTestCase.java @@ -0,0 +1,209 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2018, 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 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 software 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 software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.as.test.integration.domain.management; + +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.operations.common.Util; +import org.jboss.as.test.integration.domain.management.util.DomainLifecycleUtil; +import org.jboss.as.test.integration.domain.management.util.DomainTestSupport; +import org.jboss.as.test.integration.management.api.ReadConfigAsFeaturesTestBase; +import org.jboss.dmr.ModelNode; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeoutException; + +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.*; + +/** + * Tests {@code read-config-as-features} operation in domain mode. + * + * @author Richard Janík + */ +public class ReadConfigAsFeaturesDomainTestCase extends ReadConfigAsFeaturesTestBase { + + private static DomainTestSupport testSupport; + private static DomainLifecycleUtil domainMasterLifecycleUtil; + + private String defaultDomainConfig; + private String defaultHostConfig; + private ModelNode defaultDomainConfigAsFeatures; + private ModelNode defaultHostConfigAsFeatures; + + @BeforeClass + public static void setupDomain() { + testSupport = DomainTestSupport.createAndStartSupport(DomainTestSupport.Configuration.create(ReadConfigAsFeaturesDomainTestCase.class.getSimpleName(), + "domain-configs/domain-standard.xml", "host-configs/host-master.xml", "host-configs/host-slave.xml")); + domainMasterLifecycleUtil = testSupport.getDomainMasterLifecycleUtil(); + } + + @AfterClass + public static void tearDownDomain() { + testSupport.stop(); + testSupport = null; + domainMasterLifecycleUtil = null; + } + + @Test + public void domainSystemPropertyTest() { + ModelNode redefineProperty = Util.getWriteAttributeOperation(PathAddress.pathAddress(SYSTEM_PROPERTY, "jboss.domain.test.property.one"), VALUE, "SIX"); + ModelNode addProperty = Util.createAddOperation(PathAddress.pathAddress(SYSTEM_PROPERTY, "customProp")); + addProperty.get(BOOT_TIME).set(false); + addProperty.get(VALUE).set("customPropVal"); + + ModelNode expectedDomainConfigAsFeatures = defaultDomainConfigAsFeatures.clone(); + + // modify the existing property + ModelNode propertyId = new ModelNode(); + propertyId.get(SYSTEM_PROPERTY).set("jboss.domain.test.property.one"); + ModelNode existingProperty = getListElement(expectedDomainConfigAsFeatures, "domain.system-property", propertyId); + existingProperty.get(PARAMS).get(VALUE).set("SIX"); + + // add the new property + ModelNode newPropertyId = new ModelNode(); + ModelNode newPropertyParams = new ModelNode(); + ModelNode newProperty = new ModelNode(); + newPropertyId.get(SYSTEM_PROPERTY).set("customProp"); + newPropertyParams.get(BOOT_TIME).set(false); + newPropertyParams.get(VALUE).set("customPropVal"); + newProperty.get(SPEC).set("domain.system-property"); + newProperty.get(ID).set(newPropertyId); + newProperty.get(PARAMS).set(newPropertyParams); + // add the new property + expectedDomainConfigAsFeatures.add(newProperty); + + doTest(Arrays.asList(redefineProperty, addProperty), expectedDomainConfigAsFeatures, PathAddress.EMPTY_ADDRESS); + } + + @Test + public void domainProfileTest() { + ModelNode redefineProfileAttribute = Util.getWriteAttributeOperation( + PathAddress.pathAddress(PROFILE, DEFAULT).append(SUBSYSTEM, "io").append("buffer-pool", "default"), + "buffer-size", 500); + ModelNode removeSubsystemFromProfile = Util.createRemoveOperation(PathAddress.pathAddress(PROFILE, DEFAULT).append(SUBSYSTEM, "request-controller")); + + ModelNode expectedDomainConfigAsFeatures = defaultDomainConfigAsFeatures.clone(); + + // remove the request controller subsystem + ModelNode defaultProfileId = new ModelNode(); + defaultProfileId.get(PROFILE).set(DEFAULT); + ModelNode defaultProfile = getListElement(expectedDomainConfigAsFeatures, PROFILE, defaultProfileId); + int requestControllerSubsystemIndex = getFeatureNodeChildIndex(defaultProfile, "profile.subsystem.request-controller"); + defaultProfile.get(CHILDREN).remove(requestControllerSubsystemIndex); + + // rewrite the buffer-pool attribute + ModelNode ioSubsystem = getFeatureNodeChild(defaultProfile, "profile.subsystem.io"); + ModelNode bufferPool = getFeatureNodeChild(ioSubsystem, "profile.subsystem.io.buffer-pool"); + ModelNode bufferPoolParams = new ModelNode(); + bufferPoolParams.get("buffer-size").set(500); + bufferPool.get(PARAMS).set(bufferPoolParams); + + doTest(Arrays.asList(redefineProfileAttribute, removeSubsystemFromProfile), expectedDomainConfigAsFeatures, PathAddress.EMPTY_ADDRESS); + } + + @Test + public void hostInterfaceTest() { + ModelNode redefineInterface = Util.getWriteAttributeOperation(PathAddress.pathAddress(HOST, MASTER).append(INTERFACE, "management"), INET_ADDRESS, "10.10.10.10"); + + ModelNode expectedHostConfigAsFeatures = defaultHostConfigAsFeatures.clone(); + + ModelNode managementInterfaceId = new ModelNode(); + managementInterfaceId.get(INTERFACE).set("management"); + ModelNode managementInterface = getFeatureNodeChild(expectedHostConfigAsFeatures.get(0), "host.interface", managementInterfaceId); + ModelNode managementInterfaceParams = new ModelNode(); + managementInterfaceParams.get(INET_ADDRESS).set("10.10.10.10"); + managementInterface.get(PARAMS).set(managementInterfaceParams); + + doTest(Collections.singletonList(redefineInterface), expectedHostConfigAsFeatures, PathAddress.pathAddress(HOST, MASTER)); + } + + @Test + public void hostSubsystemTest() { + ModelNode redefineJmxAttribute = Util.getWriteAttributeOperation( + PathAddress.pathAddress(HOST, MASTER).append(SUBSYSTEM, "jmx").append("expose-model", "resolved"), + "domain-name", "customDomainName"); + + ModelNode expectedHostConfigAsFeatures = defaultHostConfigAsFeatures.clone(); + + ModelNode jmxSubsystem = getFeatureNodeChild(expectedHostConfigAsFeatures.get(0), "host.subsystem.jmx"); + ModelNode exposeModelResolved = getFeatureNodeChild(jmxSubsystem, "host.subsystem.jmx.expose-model.resolved"); + ModelNode exposeModelResolvedParams = new ModelNode(); + exposeModelResolvedParams.get("domain-name").set("customDomainName"); + exposeModelResolved.get(PARAMS).set(exposeModelResolvedParams); + + doTest(Collections.singletonList(redefineJmxAttribute), expectedHostConfigAsFeatures, PathAddress.pathAddress(HOST, MASTER)); + } + + private void doTest(List operations, ModelNode expectedConfigAsFeatures, PathAddress domainOrHostPath) { + for (ModelNode operation : operations) { + domainMasterLifecycleUtil.executeForResult(operation); + } + if (!equalsWithoutListOrder(expectedConfigAsFeatures, getConfigAsFeatures(domainOrHostPath))) { + System.out.println("Actual:\n" + getConfigAsFeatures(domainOrHostPath).toJSONString(false) + "\nExpected:\n" + expectedConfigAsFeatures.toJSONString(false)); + Assert.fail("There are differences between the expected and the actual model, see the test output for details"); + } + } + + @Override + protected void saveDefaultConfig() { + if (defaultDomainConfig == null || defaultHostConfig == null) { + ModelNode takeSnapshotOnDomain = Util.createEmptyOperation(TAKE_SNAPSHOT_OPERATION, PathAddress.EMPTY_ADDRESS); + ModelNode takeSnapshotOnHost = Util.createEmptyOperation(TAKE_SNAPSHOT_OPERATION, PathAddress.pathAddress(HOST, MASTER)); + domainMasterLifecycleUtil.executeForResult(takeSnapshotOnDomain); + domainMasterLifecycleUtil.executeForResult(takeSnapshotOnHost); + ModelNode listDomainSnapshots = Util.createEmptyOperation(LIST_SNAPSHOTS_OPERATION, PathAddress.EMPTY_ADDRESS); + ModelNode listHostSnapshots = Util.createEmptyOperation(LIST_SNAPSHOTS_OPERATION, PathAddress.pathAddress(HOST, MASTER)); + ModelNode domainSnapshots = domainMasterLifecycleUtil.executeForResult(listDomainSnapshots); + ModelNode hostSnapshots = domainMasterLifecycleUtil.executeForResult(listHostSnapshots); + + defaultDomainConfig = domainSnapshots.get("names").get(0).asString(); + defaultHostConfig = hostSnapshots.get("names").get(0).asString(); + } + } + + @Override + protected void saveDefaultResult() { + if (defaultDomainConfigAsFeatures == null || defaultHostConfigAsFeatures == null) { + defaultDomainConfigAsFeatures = getConfigAsFeatures(PathAddress.EMPTY_ADDRESS); + defaultHostConfigAsFeatures = getConfigAsFeatures(PathAddress.pathAddress(HOST, MASTER)); + } + } + + @Override + protected void restoreDefaultConfig() throws TimeoutException, InterruptedException { + ModelNode reloadWithSnapshots = Util.createEmptyOperation(RELOAD, PathAddress.pathAddress(HOST, MASTER)); + reloadWithSnapshots.get(DOMAIN_CONFIG).set(defaultDomainConfig); + reloadWithSnapshots.get(HOST_CONFIG).set(defaultHostConfig); + domainMasterLifecycleUtil.executeForResult(reloadWithSnapshots); + domainMasterLifecycleUtil.awaitHostController(System.currentTimeMillis()); + } + + private ModelNode getConfigAsFeatures(PathAddress pathAddress) { + return domainMasterLifecycleUtil.executeForResult( + Util.createEmptyOperation(READ_CONFIG_AS_FEATURES_OPERATION, pathAddress)); + } +} diff --git a/testsuite/shared/src/main/java/org/jboss/as/test/integration/management/api/ReadConfigAsFeaturesTestBase.java b/testsuite/shared/src/main/java/org/jboss/as/test/integration/management/api/ReadConfigAsFeaturesTestBase.java new file mode 100644 index 00000000000..9042840da64 --- /dev/null +++ b/testsuite/shared/src/main/java/org/jboss/as/test/integration/management/api/ReadConfigAsFeaturesTestBase.java @@ -0,0 +1,188 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2018, 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 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 software 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 software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.as.test.integration.management.api; + +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.wildfly.core.testrunner.UnsuccessfulOperationException; + +import java.util.concurrent.TimeoutException; + +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.CHILDREN; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ID; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SPEC; +import static org.jboss.dmr.ModelType.LIST; +import static org.jboss.dmr.ModelType.OBJECT; + +/** + * @author Richard Janík + */ +public abstract class ReadConfigAsFeaturesTestBase { + + @Before + public void setUp() throws UnsuccessfulOperationException { + saveDefaultConfig(); + saveDefaultResult(); + } + + @After + public void tearDown() throws TimeoutException, InterruptedException { + restoreDefaultConfig(); + } + + protected abstract void saveDefaultConfig() throws UnsuccessfulOperationException; + + protected abstract void saveDefaultResult() throws UnsuccessfulOperationException; + + protected abstract void restoreDefaultConfig() throws TimeoutException, InterruptedException; + + protected ModelNode getFeatureNodeChild(ModelNode node, String spec) { + return getListElement(node.get(CHILDREN), spec); + } + + protected ModelNode getFeatureNodeChild(ModelNode node, String spec, ModelNode id) { + return getListElement(node.get(CHILDREN), spec, id); + } + + protected int getFeatureNodeChildIndex(ModelNode node, String spec) { + return getListElementIndex(node.get(CHILDREN), spec); + } + + protected int getFeatureNodeChildIndex(ModelNode node, String spec, ModelNode id) { + return getListElementIndex(node.get(CHILDREN), spec, id); + } + + protected ModelNode getListElement(ModelNode list, String spec) { + return getListElement(list, spec, null); + } + + protected ModelNode getListElement(ModelNode list, String spec, ModelNode id) { + for (ModelNode element : list.asList()) { + if (element.get(SPEC).asString().equals(spec) && + (id == null || id.equals(element.get(ID)))) { + return element; + } + } + + throw new IllegalArgumentException("no element for spec " + spec + " and id " + ((id == null) ? "null" : id.toJSONString(true))); + } + + protected int getListElementIndex(ModelNode list, String spec) { + return getListElementIndex(list, spec, null); + } + + protected int getListElementIndex(ModelNode list, String spec, ModelNode id) { + for (int i = 0; i < list.asList().size(); i++) { + if (list.get(i).get(SPEC).asString().equals(spec) && + (id == null || id.equals(list.get(i).get(ID)))) { + return i; + } + } + throw new IllegalArgumentException("no element for spec " + spec + " and id " + ((id == null) ? "null" : id.toJSONString(true))); + } + + private String getProgrammingErrorMessage(String expectedType) { + return "model types are expected to be " + expectedType + "LIST, likely a programming error"; + } + + protected boolean isFeatureNode(ModelNode node) { + return ModelType.OBJECT.equals(node.getType()) && + node.hasDefined(SPEC) && + node.hasDefined(ID); + } + + /** + * This is the entry-point for the {@code ModelNode} comparison, eschewing list order. + */ + protected boolean equalsWithoutListOrder(ModelNode model1, ModelNode model2) { + if (!model1.getType().equals(model2.getType())) { + return false; + } + + switch (model1.getType()) { + case OBJECT: + return compareObjects(model1, model2); + case LIST: + return compareLists(model1, model2); + default: + return model1.equals(model2); + } + } + + protected boolean compareLists(ModelNode model1, ModelNode model2) { + Assert.assertEquals(getProgrammingErrorMessage("LIST"), model1.getType(), model2.getType()); + Assert.assertEquals(getProgrammingErrorMessage("LIST"), LIST, model1.getType()); + + if (!(model1.asList().size() == model2.asList().size())) { + return false; + } + + for (ModelNode element : model1.asList()) { + if (isFeatureNode(element)) { + // if it's a feature node, we don't have to do a complicated comparison with every element of the other model + try { + ModelNode model2Element = getListElement(model2, element.get(SPEC).asString(), element.get(ID)); + if (!equalsWithoutListOrder(element, model2Element)) return false; + } catch (IllegalArgumentException e) { + return false; + } + } else { + // if it's not a feature node, let's find a matching element the hard way + boolean foundMatch = false; + for (ModelNode model2Element : model2.asList()) { + foundMatch = equalsWithoutListOrder(element, model2Element); + if (foundMatch) break; + } + if (!foundMatch) return false; + } + } + + return true; + } + + protected boolean compareObjects(ModelNode model1, ModelNode model2) { + Assert.assertEquals(getProgrammingErrorMessage("OBJECT"), model1.getType(), model2.getType()); + Assert.assertEquals(getProgrammingErrorMessage("OBJECT"), OBJECT, model1.getType()); + + if (!model1.keys().equals(model2.keys())) { + return false; + } + + for (String key : model1.keys()) { + switch (model1.get(key).getType()) { + case OBJECT: + if (!compareObjects(model1.get(key), model2.get(key))) return false; + break; + case LIST: + if (!compareLists(model1.get(key), model2.get(key))) return false; + break; + default: + if (!model1.get(key).equals(model2.get(key))) return false; + } + } + + return true; + } +} diff --git a/testsuite/standalone/src/test/java/org/wildfly/core/test/standalone/mgmt/api/core/ReadConfigAsFeaturesStandaloneTestCase.java b/testsuite/standalone/src/test/java/org/wildfly/core/test/standalone/mgmt/api/core/ReadConfigAsFeaturesStandaloneTestCase.java new file mode 100644 index 00000000000..a224e8afd88 --- /dev/null +++ b/testsuite/standalone/src/test/java/org/wildfly/core/test/standalone/mgmt/api/core/ReadConfigAsFeaturesStandaloneTestCase.java @@ -0,0 +1,294 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2018, 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 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 software 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 software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.core.test.standalone.mgmt.api.core; + +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.operations.common.Util; +import org.jboss.as.test.integration.management.api.ReadConfigAsFeaturesTestBase; +import org.jboss.dmr.ModelNode; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.wildfly.core.testrunner.ManagementClient; +import org.wildfly.core.testrunner.ServerController; +import org.wildfly.core.testrunner.UnsuccessfulOperationException; +import org.wildfly.core.testrunner.WildflyTestRunner; + +import javax.inject.Inject; +import java.io.File; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.*; + +/** + * Tests operation {@code read-config-as-features} in standalone mode. + * + * @author Richard Janík + */ +@RunWith(WildflyTestRunner.class) +public class ReadConfigAsFeaturesStandaloneTestCase extends ReadConfigAsFeaturesTestBase { + + private File defaultConfig; + private ModelNode defaultConfigAsFeatures; + + @Inject + private ManagementClient managementClient; + + @Inject + private static ServerController serverController; + + @Test + public void writeParameterTest() throws UnsuccessfulOperationException { + ModelNode writeParameterOpertaion = Util.getWriteAttributeOperation( + PathAddress.pathAddress(SUBSYSTEM, "request-controller"), + "max-requests", 10); + + ModelNode expectedConfigAsFeatures = defaultConfigAsFeatures.clone(); + ModelNode requestControllerSubsystem = getFeatureNodeChild(expectedConfigAsFeatures.get(0), "subsystem.request-controller"); + requestControllerSubsystem.get(PARAMS).set(new ModelNode()).get("max-requests").set(10); + + doTest(Collections.singletonList(writeParameterOpertaion), expectedConfigAsFeatures); + } + + @Test + public void undefineParameterTest() throws UnsuccessfulOperationException { + ModelNode undefineParameterOperation = Util.getUndefineAttributeOperation( + PathAddress.pathAddress(SUBSYSTEM, "security-manager").append("deployment-permissions", "default"), + "maximum-permissions"); + + ModelNode expectedConfigAsFeatures = defaultConfigAsFeatures.clone(); + ModelNode securityManagerSubsystem = getFeatureNodeChild(expectedConfigAsFeatures.get(0), "subsystem.security-manager"); + securityManagerSubsystem.get(CHILDREN).get(0).remove(PARAMS); + + doTest(Collections.singletonList(undefineParameterOperation), expectedConfigAsFeatures); + } + + @Test + public void addChildrenTest() throws UnsuccessfulOperationException { + ModelNode addChildrenOperation = Util.createAddOperation( + PathAddress.pathAddress(SUBSYSTEM, "jmx").append("configuration", "audit-log")); + addChildrenOperation.get("enabled").set(true); + addChildrenOperation.get("log-boot").set(true); + addChildrenOperation.get("log-read-only").set(false); + + ModelNode expectedConfigAsFeatures = defaultConfigAsFeatures.clone(); + ModelNode jmxSubsystem = getFeatureNodeChild(expectedConfigAsFeatures.get(0), "subsystem.jmx"); + ModelNode auditLog = new ModelNode(); + auditLog.get(SPEC).set("subsystem.jmx.configuration.audit-log"); + auditLog.get(ID).set(new ModelNode()).get("configuration").set("audit-log"); + ModelNode params = new ModelNode(); + params.get("log-read-only").set(false); + params.get("log-boot").set(true); + params.get("enabled").set(true); + auditLog.get(PARAMS).set(params); + jmxSubsystem.get(CHILDREN).add(auditLog); + + doTest(Collections.singletonList(addChildrenOperation), expectedConfigAsFeatures); + } + + @Test + public void removeChildrenTest() throws UnsuccessfulOperationException { + ModelNode removeChildrenOperation = Util.createRemoveOperation( + PathAddress.pathAddress(SUBSYSTEM, "elytron").append(HTTP_AUTHENTICATION_FACTORY, "management-http-authentication")); + + ModelNode expectedConfigAsFeatures = defaultConfigAsFeatures.clone(); + ModelNode elytronSubsystem = getFeatureNodeChild(expectedConfigAsFeatures.get(0), "subsystem.elytron"); + int httpAuthenticationFactoryIndex = getFeatureNodeChildIndex(elytronSubsystem, "subsystem.elytron.http-authentication-factory"); + elytronSubsystem.get(CHILDREN).remove(httpAuthenticationFactoryIndex); + + doTest(Collections.singletonList(removeChildrenOperation), expectedConfigAsFeatures); + } + + @Test + public void removeSubsystemTest() throws UnsuccessfulOperationException { + ModelNode removeSubsystemOperation = Util.createRemoveOperation(PathAddress.pathAddress(SUBSYSTEM, "discovery")); + + ModelNode expectedConfigAsFeatures = defaultConfigAsFeatures.clone(); + int discoverySubsystemIndex = getFeatureNodeChildIndex(expectedConfigAsFeatures.get(0), "subsystem.discovery"); + expectedConfigAsFeatures.get(0).get(CHILDREN).remove(discoverySubsystemIndex); + + doTest(Collections.singletonList(removeSubsystemOperation), expectedConfigAsFeatures); + } + + @Test + public void coreManagementTest() throws UnsuccessfulOperationException { + ModelNode removeSecurityRealm = Util.createRemoveOperation( + PathAddress.pathAddress(CORE_SERVICE, MANAGEMENT).append(SECURITY_REALM, "ApplicationRealm")); + ModelNode addCustomSecurityRealm = Util.createAddOperation( + PathAddress.pathAddress(CORE_SERVICE, MANAGEMENT).append(SECURITY_REALM, "CustomRealm")); + addCustomSecurityRealm.get("map-groups-to-roles").set(false); + ModelNode configureCustomSecurityRealm = Util.createAddOperation( + PathAddress.pathAddress(CORE_SERVICE, MANAGEMENT).append(SECURITY_REALM, "CustomRealm").append("authentication", "local")); + configureCustomSecurityRealm.get("default-user").set("john"); + configureCustomSecurityRealm.get("allowed-users").set("john"); + configureCustomSecurityRealm.get("skip-group-loading").set(true); + + ModelNode expectedConfigAsFeatures = defaultConfigAsFeatures.clone(); + ModelNode managementCoreService = getFeatureNodeChild(expectedConfigAsFeatures.get(0), "core-service.management"); + + // remove ApplicationRealm + ModelNode applicationSecurityRealmId = new ModelNode(); + applicationSecurityRealmId.get(SECURITY_REALM).set("ApplicationRealm"); + int applicationSecurityRealmIndex = getFeatureNodeChildIndex(managementCoreService, "core-service.management.security-realm", applicationSecurityRealmId); + managementCoreService.get(CHILDREN).remove(applicationSecurityRealmIndex); + + // create model nodes for the new CustomRealm + ModelNode customRealmId = new ModelNode(); + customRealmId.get(SECURITY_REALM).set("CustomRealm"); + ModelNode customRealmParams = new ModelNode(); + customRealmParams.get("map-groups-to-roles").set(false); + + // create the authentication model node for the new CustomRealm + ModelNode customRealmAuthentication = new ModelNode(); + customRealmAuthentication.get(SPEC).set("core-service.management.security-realm.authentication.local"); + ModelNode authenticationId = new ModelNode(); + authenticationId.get(AUTHENTICATION).set(LOCAL); + customRealmAuthentication.get(ID).set(authenticationId); + ModelNode authenticationParams = new ModelNode(); + authenticationParams.get("default-user").set("john"); + authenticationParams.get("allowed-users").set("john"); + authenticationParams.get("skip-group-loading").set(true); + customRealmAuthentication.get(PARAMS).set(authenticationParams); + + // set up the CustomRealm model node + ModelNode customRealm = new ModelNode(); + customRealm.get(SPEC).set("core-service.management.security-realm"); + customRealm.get(ID).set(customRealmId); + customRealm.get(PARAMS).set(customRealmParams); + customRealm.get(CHILDREN).add(customRealmAuthentication); + + // append the CustomRealm model node to the expected model + managementCoreService.get(CHILDREN).add(customRealm); + + doTest(Arrays.asList(removeSecurityRealm, addCustomSecurityRealm, configureCustomSecurityRealm), expectedConfigAsFeatures); + } + + @Test + public void interfaceTest() throws UnsuccessfulOperationException { + ModelNode modifyManagementInterface = Util.getWriteAttributeOperation(PathAddress.pathAddress(INTERFACE, "management"), INET_ADDRESS, "10.10.10.10"); + ModelNode createCustomInterface = Util.createAddOperation(PathAddress.pathAddress(INTERFACE, "custom")); + createCustomInterface.get(ANY_ADDRESS).set(true); + + ModelNode expectedConfigAsFeatures = defaultConfigAsFeatures.clone(); + + // modify managemnet interface + ModelNode managementInterfaceId = new ModelNode(); + managementInterfaceId.get(INTERFACE).set("management"); + ModelNode managementInterface = getFeatureNodeChild(expectedConfigAsFeatures.get(0), INTERFACE, managementInterfaceId); + managementInterface.get(PARAMS).get(INET_ADDRESS).set("10.10.10.10"); + + // add the custom interface + ModelNode customInterfaceParams = new ModelNode(); + ModelNode customInterfaceId = new ModelNode(); + customInterfaceParams.get(ANY_ADDRESS).set(true); + customInterfaceId.get(INTERFACE).set("custom"); + ModelNode customInterface = new ModelNode(); + customInterface.get(SPEC).set(INTERFACE); + customInterface.get(ID).set(customInterfaceId); + customInterface.get(PARAMS).set(customInterfaceParams); + expectedConfigAsFeatures.get(0).get(CHILDREN).add(customInterface); + + doTest(Arrays.asList(modifyManagementInterface, createCustomInterface), expectedConfigAsFeatures); + + ModelNode removeCustomInterface = Util.createRemoveOperation(PathAddress.pathAddress(INTERFACE, "custom")); + int customInterfaceIndex = getFeatureNodeChildIndex(expectedConfigAsFeatures.get(0), customInterface.get(SPEC).asString(), customInterfaceId); + expectedConfigAsFeatures.get(0).get(CHILDREN).remove(customInterfaceIndex); + + doTest(Collections.singletonList(removeCustomInterface), expectedConfigAsFeatures); + } + + @Test + public void socketBindingGroupTest() throws UnsuccessfulOperationException { + ModelNode modifyPortOffsetOperation = Util.getWriteAttributeOperation(PathAddress.pathAddress(SOCKET_BINDING_GROUP, "standard-sockets"), PORT_OFFSET, 100); + ModelNode addCustomSocketBindingOperation = Util.createAddOperation(PathAddress.pathAddress(SOCKET_BINDING_GROUP, "standard-sockets").append(SOCKET_BINDING, "custom")); + addCustomSocketBindingOperation.get(INTERFACE).set("public"); + addCustomSocketBindingOperation.get(MULTICAST_ADDRESS).set("230.0.0.10"); + ModelNode removeCustomSocketBindingOperation = Util.createRemoveOperation(PathAddress.pathAddress(SOCKET_BINDING_GROUP, "standard-sockets").append(SOCKET_BINDING, "custom")); + + ModelNode expectedConfigAsFeatures = defaultConfigAsFeatures.clone(); + + // modify the port offset + ModelNode standardSocketsId = new ModelNode(); + standardSocketsId.get(SOCKET_BINDING_GROUP).set("standard-sockets"); + ModelNode standardSocketBindingGroup = getFeatureNodeChild(expectedConfigAsFeatures.get(0), SOCKET_BINDING_GROUP, standardSocketsId); + standardSocketBindingGroup.get(PARAMS).get(PORT_OFFSET).set(100); + + // add custom socket-binding + ModelNode customSocketBinding = new ModelNode(); + ModelNode customSocketBindingId = new ModelNode(); + ModelNode customSocketBindingParams = new ModelNode(); + customSocketBindingId.get(SOCKET_BINDING).set("custom"); + customSocketBindingParams.get(INTERFACE).set("public"); + customSocketBindingParams.get(MULTICAST_ADDRESS).set("230.0.0.10"); + customSocketBinding.get(SPEC).set("socket-binding-group.socket-binding"); + customSocketBinding.get(ID).set(customSocketBindingId); + customSocketBinding.get(PARAMS).set(customSocketBindingParams); + standardSocketBindingGroup.get(CHILDREN).add(customSocketBinding); + + doTest(Arrays.asList(modifyPortOffsetOperation, addCustomSocketBindingOperation), expectedConfigAsFeatures); + + // remove the custom socket binding + int customSocketBindingIndex = getFeatureNodeChildIndex(standardSocketBindingGroup, customSocketBinding.get(SPEC).asString(), customSocketBindingId); + standardSocketBindingGroup.get(CHILDREN).remove(customSocketBindingIndex); + + doTest(Collections.singletonList(removeCustomSocketBindingOperation), expectedConfigAsFeatures); + } + + private void doTest(List operations, ModelNode expectedConfigAsFeatures) throws UnsuccessfulOperationException { + for (ModelNode operation : operations) { + managementClient.executeForResult(operation); + } + if (!equalsWithoutListOrder(expectedConfigAsFeatures, getConfigAsFeatures())) { + System.out.println("Actual:\n" + getConfigAsFeatures().toJSONString(false) + "\nExpected:\n" + expectedConfigAsFeatures.toJSONString(false)); + Assert.fail("There are differences between the expected and the actual model, see the test output for details"); + } + } + + @Override + protected void saveDefaultConfig() throws UnsuccessfulOperationException { + if (defaultConfig == null) { + ModelNode result = managementClient.executeForResult( + Util.createEmptyOperation(TAKE_SNAPSHOT_OPERATION, PathAddress.EMPTY_ADDRESS)); + defaultConfig = Paths.get(result.asString()).toFile(); + } + } + + @Override + protected void saveDefaultResult() throws UnsuccessfulOperationException { + if (defaultConfigAsFeatures == null) { + defaultConfigAsFeatures = getConfigAsFeatures(); + } + } + + @Override + protected void restoreDefaultConfig() { + serverController.reload(defaultConfig.getName()); + } + + private ModelNode getConfigAsFeatures() throws UnsuccessfulOperationException { + return managementClient.executeForResult( + Util.createEmptyOperation(READ_CONFIG_AS_FEATURES_OPERATION, PathAddress.EMPTY_ADDRESS)); + } +}