| /*========================================================================= |
| * Copyright (c) 2002-2014 Pivotal Software, Inc. All Rights Reserved. |
| * This product is protected by U.S. and international copyright |
| * and intellectual property laws. Pivotal products are covered by |
| * more patents listed at http://www.pivotal.io/patents. |
| *========================================================================= |
| */ |
| package com.gemstone.gemfire.management.internal.configuration.utils; |
| |
| import static org.junit.Assert.*; |
| |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import javax.xml.parsers.ParserConfigurationException; |
| import javax.xml.xpath.XPathExpressionException; |
| |
| import org.junit.AfterClass; |
| import org.junit.Before; |
| import org.junit.BeforeClass; |
| import org.junit.Test; |
| import org.junit.experimental.categories.Category; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| import org.xml.sax.SAXException; |
| |
| import com.gemstone.gemfire.cache.Cache; |
| import com.gemstone.gemfire.cache.CacheFactory; |
| import com.gemstone.gemfire.distributed.internal.SharedConfiguration; |
| import com.gemstone.gemfire.internal.cache.extension.Extension; |
| import com.gemstone.gemfire.internal.cache.xmlcache.CacheXml; |
| import com.gemstone.gemfire.management.internal.configuration.domain.XmlEntity; |
| import com.gemstone.gemfire.management.internal.configuration.utils.XmlUtils.XPathContext; |
| import com.gemstone.gemfire.test.junit.categories.IntegrationTest; |
| |
| /** |
| * Unit tests for {@link XmlUtils#addNewNode(Document, XmlEntity)} and |
| * {@link XmlUtils#deleteNode(Document, XmlEntity)}. Simulates the |
| * {@link SharedConfiguration} method of extracting {@link XmlEntity} from the |
| * new config and applying it to the current shared config. |
| * |
| * @author jbarrett@pivotal.io |
| * |
| * @since 8.1 |
| */ |
| @Category(IntegrationTest.class) |
| public class XmlUtilsAddNewNodeJUnitTest { |
| |
| private static final String TEST_PREFIX = "test"; |
| private static final String TEST_NAMESPACE = "urn:java:com/gemstone/gemfire/management/internal/configuration/utils/XmlUtilsAddNewNodeJUnitTest"; |
| private static final XPathContext xPathContext = new XPathContext(); |
| |
| private static Cache cache; |
| |
| private Document config; |
| |
| @BeforeClass |
| public static void beforeClass() { |
| cache = new CacheFactory().set("mcast-port", "0").create(); |
| xPathContext.addNamespace(CacheXml.PREFIX, CacheXml.NAMESPACE); |
| xPathContext.addNamespace(TEST_PREFIX, TEST_NAMESPACE); |
| } |
| |
| @Before |
| public void before() throws SAXException, ParserConfigurationException, IOException { |
| config = XmlUtils.createDocumentFromReader(new InputStreamReader(this.getClass().getResourceAsStream("XmlUtilsAddNewNodeJUnitTest.xml"))); |
| } |
| |
| @AfterClass |
| public static void afterClass() { |
| cache.close(); |
| cache = null; |
| } |
| |
| /** |
| * Tests {@link XmlUtils#addNewNode(Document, XmlEntity)} with |
| * {@link CacheXml} element with a <code>name</code> attribute, |
| * <code>region</code>. It should be added after other <code>region</code> |
| * elements. |
| * |
| * @throws Exception |
| * @throws XPathExpressionException |
| * @since 8.1 |
| */ |
| @Test |
| public void testAddNewNodeNewNamed() throws Exception { |
| final String xPath = "/cache:cache/cache:region[@name='r3']"; |
| NodeList nodes = XmlUtils.query(config, xPath, xPathContext); |
| assertEquals(0, nodes.getLength()); |
| |
| final Document changes = XmlUtils.createDocumentFromReader(new InputStreamReader(this.getClass().getResourceAsStream( |
| "XmlUtilsAddNewNodeJUnitTest.testAddNewNodeNewNamed.xml"))); |
| nodes = XmlUtils.query(changes, xPath, xPathContext); |
| assertEquals(1, nodes.getLength()); |
| Element element = (Element) nodes.item(0); |
| assertEquals(CacheXml.NAMESPACE, element.getNamespaceURI()); |
| |
| final XmlEntity xmlEntity = XmlEntity.builder().withType("region").withAttribute("name", "r3").withConfig(changes).build(); |
| XmlUtils.addNewNode(config, xmlEntity); |
| |
| nodes = XmlUtils.query(config, xPath, xPathContext); |
| assertEquals(1, nodes.getLength()); |
| element = (Element) nodes.item(0); |
| assertEquals(CacheXml.NAMESPACE, element.getNamespaceURI()); |
| |
| final List<Node> childNodes = getElementNodes(config.getFirstChild().getChildNodes()); |
| |
| assertEquals("r2", childNodes.get(4).getAttributes().getNamedItem("name").getNodeValue()); |
| assertEquals("r3", childNodes.get(5).getAttributes().getNamedItem("name").getNodeValue()); |
| assertEquals("test:cache", childNodes.get(6).getNodeName()); |
| } |
| |
| /** |
| * Return just the nodes from a nodelist that are of type |
| * element. |
| */ |
| private List<Node> getElementNodes(NodeList nodes) { |
| ArrayList<Node> result = new ArrayList<Node>(); |
| for(int i = 0; i < nodes.getLength(); i++) { |
| Node node = nodes.item(i); |
| if(node.getNodeType() == Node.ELEMENT_NODE) { |
| result.add(node); |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Tests {@link XmlUtils#addNewNode(Document, XmlEntity)} with |
| * {@link CacheXml} element that does not have a name or id attribute, |
| * <code>jndi-bindings</code>. It should be added between <code>pdx</code> and |
| * <code>region</code> elements. |
| * |
| * @throws Exception |
| * @since 8.1 |
| */ |
| @Test |
| public void testAddNewNodeNewUnnamed() throws Exception { |
| final String xPath = "/cache:cache/cache:jndi-bindings"; |
| NodeList nodes = XmlUtils.query(config, xPath, xPathContext); |
| assertEquals(0, nodes.getLength()); |
| |
| final Document changes = XmlUtils.createDocumentFromReader(new InputStreamReader(this.getClass().getResourceAsStream( |
| "XmlUtilsAddNewNodeJUnitTest.testAddNewNodeNewUnnamed.xml"))); |
| nodes = XmlUtils.query(changes, xPath, xPathContext); |
| assertEquals(1, nodes.getLength()); |
| Element element = (Element) nodes.item(0); |
| assertEquals(CacheXml.NAMESPACE, element.getNamespaceURI()); |
| |
| final XmlEntity xmlEntity = XmlEntity.builder().withType("jndi-bindings").withConfig(changes).build(); |
| XmlUtils.addNewNode(config, xmlEntity); |
| |
| nodes = XmlUtils.query(config, xPath, xPathContext); |
| assertEquals(1, nodes.getLength()); |
| element = (Element) nodes.item(0); |
| assertEquals(CacheXml.NAMESPACE, element.getNamespaceURI()); |
| |
| final List<Node> childElements = getElementNodes(config.getFirstChild().getChildNodes()); |
| assertEquals("pdx", childElements.get(2).getNodeName()); |
| assertEquals("jndi-bindings", childElements.get(3).getNodeName()); |
| assertEquals("region", childElements.get(4).getNodeName()); |
| } |
| |
| /** |
| * Tests {@link XmlUtils#addNewNode(Document, XmlEntity)} with an |
| * {@link Extension} that does not have a name or id attribute. It should be |
| * added to the end of the config xml. Attempts a name collision with |
| * test:region, it should not collide with the similarly named cache:region |
| * element. |
| * |
| * @throws Exception |
| * @since 8.1 |
| */ |
| @Test |
| public void testAddNewNodeNewUnnamedExtension() throws Exception { |
| final String xPath = "/cache:cache/test:region"; |
| NodeList nodes = XmlUtils.query(config, xPath, xPathContext); |
| assertEquals(0, nodes.getLength()); |
| |
| final Document changes = XmlUtils.createDocumentFromReader(new InputStreamReader(this.getClass().getResourceAsStream( |
| "XmlUtilsAddNewNodeJUnitTest.testAddNewNodeNewUnnamedExtension.xml"))); |
| nodes = XmlUtils.query(changes, xPath, xPathContext); |
| assertEquals(1, nodes.getLength()); |
| Element element = (Element) nodes.item(0); |
| assertEquals(TEST_NAMESPACE, element.getNamespaceURI()); |
| assertEquals("test:region", element.getNodeName()); |
| |
| final XmlEntity xmlEntity = XmlEntity.builder().withType("region").withNamespace(TEST_PREFIX, TEST_NAMESPACE).withConfig(changes).build(); |
| XmlUtils.addNewNode(config, xmlEntity); |
| |
| nodes = XmlUtils.query(config, xPath, xPathContext); |
| assertEquals(1, nodes.getLength()); |
| element = (Element) nodes.item(0); |
| assertEquals(TEST_NAMESPACE, element.getNamespaceURI()); |
| assertEquals("test:region", element.getNodeName()); |
| |
| final List<Node> childElements = getElementNodes(config.getFirstChild().getChildNodes()); |
| |
| |
| assertEquals("test:cache", childElements.get(5).getNodeName()); |
| assertEquals("test:region", childElements.get(6).getNodeName()); |
| assertEquals(7, childElements.size()); |
| } |
| |
| /** |
| * Tests {@link XmlUtils#addNewNode(Document, XmlEntity)} with |
| * {@link CacheXml} element with a <code>name</code> attribute, |
| * <code>region</code>. It should replace existing <code>region</code> element |
| * with same <code>name</code>. |
| * |
| * @throws Exception |
| * @since 8.1 |
| */ |
| @Test |
| public void testAddNewNodeReplaceNamed() throws Exception { |
| final String xPath = "/cache:cache/cache:region[@name='r1']"; |
| NodeList nodes = XmlUtils.query(config, xPath, xPathContext); |
| assertEquals(1, nodes.getLength()); |
| Element element = (Element) nodes.item(0); |
| assertEquals(1, getElementNodes(element.getChildNodes()).size()); |
| assertEquals(CacheXml.NAMESPACE, element.getNamespaceURI()); |
| |
| final Document changes = XmlUtils.createDocumentFromReader(new InputStreamReader(this.getClass().getResourceAsStream( |
| "XmlUtilsAddNewNodeJUnitTest.testAddNewNodeReplaceNamed.xml"))); |
| nodes = XmlUtils.query(changes, xPath, xPathContext); |
| assertEquals(1, nodes.getLength()); |
| element = (Element) nodes.item(0); |
| assertEquals(0, element.getChildNodes().getLength()); |
| assertEquals(CacheXml.NAMESPACE, element.getNamespaceURI()); |
| |
| final XmlEntity xmlEntity = XmlEntity.builder().withType("region").withAttribute("name", "r1").withConfig(changes).build(); |
| XmlUtils.addNewNode(config, xmlEntity); |
| |
| nodes = XmlUtils.query(config, xPath, xPathContext); |
| assertEquals(1, nodes.getLength()); |
| element = (Element) nodes.item(0); |
| assertEquals(0, element.getChildNodes().getLength()); |
| assertEquals(CacheXml.NAMESPACE, element.getNamespaceURI()); |
| } |
| |
| /** |
| * Tests {@link XmlUtils#addNewNode(Document, XmlEntity)} with |
| * {@link CacheXml} element that does not have a name or id attribute, |
| * <code>pdx</code>. It should replace <code>pdx</code> element. |
| * |
| * @throws Exception |
| * @since 8.1 |
| */ |
| @Test |
| public void testAddNewNodeReplaceUnnamed() throws Exception { |
| final String xPath = "/cache:cache/cache:pdx"; |
| NodeList nodes = XmlUtils.query(config, xPath, xPathContext); |
| assertEquals(1, nodes.getLength()); |
| Element element = (Element) nodes.item(0); |
| assertEquals("foo", XmlUtils.getAttribute(element, "disk-store-name")); |
| assertEquals(CacheXml.NAMESPACE, element.getNamespaceURI()); |
| |
| final Document changes = XmlUtils.createDocumentFromReader(new InputStreamReader(this.getClass().getResourceAsStream( |
| "XmlUtilsAddNewNodeJUnitTest.testAddNewNodeReplaceUnnamed.xml"))); |
| nodes = XmlUtils.query(changes, xPath, xPathContext); |
| assertEquals(1, nodes.getLength()); |
| element = (Element) nodes.item(0); |
| assertEquals("bar", XmlUtils.getAttribute(element, "disk-store-name")); |
| assertEquals(CacheXml.NAMESPACE, element.getNamespaceURI()); |
| |
| final XmlEntity xmlEntity = XmlEntity.builder().withType("pdx").withConfig(changes).build(); |
| XmlUtils.addNewNode(config, xmlEntity); |
| |
| nodes = XmlUtils.query(config, xPath, xPathContext); |
| assertEquals(1, nodes.getLength()); |
| element = (Element) nodes.item(0); |
| assertEquals("bar", XmlUtils.getAttribute(element, "disk-store-name")); |
| assertEquals(CacheXml.NAMESPACE, element.getNamespaceURI()); |
| } |
| |
| /** |
| * Tests {@link XmlUtils#addNewNode(Document, XmlEntity)} with an |
| * {@link Extension} that does not have a name or id attribute, |
| * <code>test:cache</code>. It should replace the existing |
| * <code>test:cache</code> element. |
| * |
| * @throws Exception |
| * @since 8.1 |
| */ |
| @Test |
| public void testAddNewNodeReplaceUnnamedExtension() throws Exception { |
| final String xPath = "/cache:cache/test:cache"; |
| NodeList nodes = XmlUtils.query(config, xPath, xPathContext); |
| assertEquals(1, nodes.getLength()); |
| Element element = (Element) nodes.item(0); |
| assertEquals("1", XmlUtils.getAttribute(element, "value")); |
| assertEquals(TEST_NAMESPACE, element.getNamespaceURI()); |
| |
| final org.w3c.dom.Document changes = XmlUtils.createDocumentFromReader(new InputStreamReader(this.getClass().getResourceAsStream( |
| "XmlUtilsAddNewNodeJUnitTest.testAddNewNodeReplaceUnnamedExtension.xml"))); |
| nodes = XmlUtils.query(changes, xPath, xPathContext); |
| assertEquals(1, nodes.getLength()); |
| element = (Element) nodes.item(0); |
| assertEquals("2", XmlUtils.getAttribute(element, "value")); |
| assertEquals(TEST_NAMESPACE, element.getNamespaceURI()); |
| |
| final XmlEntity xmlEntity = XmlEntity.builder().withType("cache").withNamespace(TEST_PREFIX, TEST_NAMESPACE).withConfig(changes).build(); |
| XmlUtils.addNewNode(config, xmlEntity); |
| |
| nodes = XmlUtils.query(config, xPath, xPathContext); |
| assertEquals(1, nodes.getLength()); |
| element = (Element) nodes.item(0); |
| assertEquals("2", XmlUtils.getAttribute(element, "value")); |
| assertEquals(TEST_NAMESPACE, element.getNamespaceURI()); |
| } |
| |
| /** |
| * Tests {@link XmlUtils#deleteNode(Document, XmlEntity)} with |
| * {@link CacheXml} element with a <code>name</code> attribute, |
| * <code>region</code>. It should remove existing <code>region</code> element |
| * with same <code>name</code>. |
| * |
| * @throws Exception |
| * @since 8.1 |
| */ |
| @Test |
| public void testDeleteNodeNamed() throws Exception { |
| final String xPath = "/cache:cache/cache:region[@name='r1']"; |
| NodeList nodes = XmlUtils.query(config, xPath, xPathContext); |
| assertEquals(1, nodes.getLength()); |
| Element element = (Element) nodes.item(0); |
| assertEquals(1, getElementNodes(element.getChildNodes()).size()); |
| assertEquals(CacheXml.NAMESPACE, element.getNamespaceURI()); |
| |
| final Document changes = XmlUtils.createDocumentFromReader(new InputStreamReader(this.getClass().getResourceAsStream( |
| "XmlUtilsAddNewNodeJUnitTest.testDeleteNodeNamed.xml"))); |
| nodes = XmlUtils.query(changes, xPath, xPathContext); |
| assertEquals(0, nodes.getLength()); |
| |
| final XmlEntity xmlEntity = XmlEntity.builder().withType("region").withAttribute("name", "r1").withConfig(changes).build(); |
| XmlUtils.deleteNode(config, xmlEntity); |
| |
| nodes = XmlUtils.query(config, xPath, xPathContext); |
| assertEquals(0, nodes.getLength()); |
| } |
| |
| /** |
| * Tests {@link XmlUtils#addNewNode(Document, XmlEntity)} with |
| * {@link CacheXml} element that does not have a name or id attribute, |
| * <code>pdx</code>. It should remove the existing <code>pdx</code> element. |
| * |
| * @throws Exception |
| * @since 8.1 |
| */ |
| @Test |
| public void testDeleteNodeUnnamed() throws Exception { |
| final String xPath = "/cache:cache/cache:pdx"; |
| NodeList nodes = XmlUtils.query(config, xPath, xPathContext); |
| assertEquals(1, nodes.getLength()); |
| Element element = (Element) nodes.item(0); |
| assertEquals("foo", XmlUtils.getAttribute(element, "disk-store-name")); |
| assertEquals(CacheXml.NAMESPACE, element.getNamespaceURI()); |
| |
| final Document changes = XmlUtils.createDocumentFromReader(new InputStreamReader(this.getClass().getResourceAsStream( |
| "XmlUtilsAddNewNodeJUnitTest.testDeleteNodeUnnamed.xml"))); |
| nodes = XmlUtils.query(changes, xPath, xPathContext); |
| assertEquals(0, nodes.getLength()); |
| |
| final XmlEntity xmlEntity = XmlEntity.builder().withType("pdx").withConfig(changes).build(); |
| XmlUtils.deleteNode(config, xmlEntity); |
| |
| nodes = XmlUtils.query(config, xPath, xPathContext); |
| assertEquals(0, nodes.getLength()); |
| } |
| |
| /** |
| * Tests {@link XmlUtils#addNewNode(Document, XmlEntity)} with an |
| * {@link Extension} that does not have a name or id attribute, |
| * <code>test:cache</code>. It should remove the existing |
| * <code>test:cache</code> element. |
| * |
| * @throws Exception |
| * @since 8.1 |
| */ |
| @Test |
| public void testDeleteNodeUnnamedExtension() throws Exception { |
| final String xPath = "/cache:cache/test:cache"; |
| NodeList nodes = XmlUtils.query(config, xPath, xPathContext); |
| assertEquals(1, nodes.getLength()); |
| Element element = (Element) nodes.item(0); |
| assertEquals("1", XmlUtils.getAttribute(element, "value")); |
| assertEquals(TEST_NAMESPACE, element.getNamespaceURI()); |
| |
| final Document changes = XmlUtils.createDocumentFromReader(new InputStreamReader(this.getClass().getResourceAsStream( |
| "XmlUtilsAddNewNodeJUnitTest.testDeleteNodeUnnamedExtension.xml"))); |
| nodes = XmlUtils.query(changes, xPath, xPathContext); |
| assertEquals(0, nodes.getLength()); |
| |
| final XmlEntity xmlEntity = XmlEntity.builder().withType("cache").withNamespace(TEST_PREFIX, TEST_NAMESPACE).withConfig(changes).build(); |
| XmlUtils.deleteNode(config, xmlEntity); |
| |
| nodes = XmlUtils.query(config, xPath, xPathContext); |
| assertEquals(0, nodes.getLength()); |
| } |
| |
| } |