From: Andrej Mak Date: Thu, 20 Oct 2016 07:19:39 +0000 (+0200) Subject: Add more unit tests for sal-netconf-connector X-Git-Tag: release/carbon~170^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=3efa320952d5ca78d92e8ff72e535485b62eea6a;hp=0e180ee7955d6770dc7d46d94164cf15fc17d3f7;p=netconf.git Add more unit tests for sal-netconf-connector Change-Id: I76df3726b4c99c93c3ab98edcf0e7aca94d99b79 Signed-off-by: Andrej Mak --- diff --git a/netconf/netconf-util/src/test/resources/netconfMessages/copy-config.xml b/netconf/netconf-util/src/test/resources/netconfMessages/copy-config.xml new file mode 100644 index 0000000000..ec32fc1253 --- /dev/null +++ b/netconf/netconf-util/src/test/resources/netconfMessages/copy-config.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/netconf/netconf-util/src/test/resources/netconfMessages/edit-config-test-module-running.xml b/netconf/netconf-util/src/test/resources/netconfMessages/edit-config-test-module-running.xml new file mode 100644 index 0000000000..107121d890 --- /dev/null +++ b/netconf/netconf-util/src/test/resources/netconfMessages/edit-config-test-module-running.xml @@ -0,0 +1,22 @@ + + + + + + + + merge + rollback-on-error + + + leaf-value + + + + \ No newline at end of file diff --git a/netconf/netconf-util/src/test/resources/netconfMessages/edit-config-test-module.xml b/netconf/netconf-util/src/test/resources/netconfMessages/edit-config-test-module.xml new file mode 100644 index 0000000000..81907d3a15 --- /dev/null +++ b/netconf/netconf-util/src/test/resources/netconfMessages/edit-config-test-module.xml @@ -0,0 +1,21 @@ + + + + + + + + rollback-on-error + + + leaf-value + + + + \ No newline at end of file diff --git a/netconf/netconf-util/src/test/resources/netconfMessages/getConfig_candidate-filter.xml b/netconf/netconf-util/src/test/resources/netconfMessages/getConfig_candidate-filter.xml new file mode 100644 index 0000000000..7ebbe15526 --- /dev/null +++ b/netconf/netconf-util/src/test/resources/netconfMessages/getConfig_candidate-filter.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/netconf/netconf-util/src/test/resources/netconfMessages/lock-running.xml b/netconf/netconf-util/src/test/resources/netconfMessages/lock-running.xml new file mode 100644 index 0000000000..9c202ecc4e --- /dev/null +++ b/netconf/netconf-util/src/test/resources/netconfMessages/lock-running.xml @@ -0,0 +1,16 @@ + + + + + + + + + \ No newline at end of file diff --git a/netconf/netconf-util/src/test/resources/netconfMessages/rpc-reply_get.xml b/netconf/netconf-util/src/test/resources/netconfMessages/rpc-reply_get.xml new file mode 100644 index 0000000000..b3209d740f --- /dev/null +++ b/netconf/netconf-util/src/test/resources/netconfMessages/rpc-reply_get.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/netconf/netconf-util/src/test/resources/netconfMessages/unlock-running.xml b/netconf/netconf-util/src/test/resources/netconfMessages/unlock-running.xml new file mode 100644 index 0000000000..a74377a151 --- /dev/null +++ b/netconf/netconf-util/src/test/resources/netconfMessages/unlock-running.xml @@ -0,0 +1,16 @@ + + + + + + + + + \ No newline at end of file diff --git a/netconf/netconf-util/src/test/resources/netconfMessages/validate-running.xml b/netconf/netconf-util/src/test/resources/netconfMessages/validate-running.xml new file mode 100644 index 0000000000..783192df22 --- /dev/null +++ b/netconf/netconf-util/src/test/resources/netconfMessages/validate-running.xml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/util/NetconfBaseOpsTest.java b/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/util/NetconfBaseOpsTest.java new file mode 100644 index 0000000000..6b47a72752 --- /dev/null +++ b/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/util/NetconfBaseOpsTest.java @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.netconf.sal.connect.netconf.util; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.argThat; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.google.common.base.Optional; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.custommonkey.xmlunit.Diff; +import org.custommonkey.xmlunit.XMLUnit; +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.config.util.xml.XmlUtil; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcService; +import org.opendaylight.netconf.api.NetconfMessage; +import org.opendaylight.netconf.sal.connect.api.MessageTransformer; +import org.opendaylight.netconf.sal.connect.api.RemoteDeviceCommunicator; +import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceRpc; +import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.NetconfMessageTransformer; +import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; +import org.opendaylight.yangtools.yang.data.api.ModifyAction; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; +import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException; +import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor; +import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.xml.sax.SAXException; + +public class NetconfBaseOpsTest { + + static { + XMLUnit.setIgnoreWhitespace(true); + XMLUnit.setIgnoreComments(true); + } + + private static final QName CONTAINER_Q_NAME = QName.create("test:namespace", "2013-07-22", "c"); + + @Mock + private RemoteDeviceCommunicator listener; + private NetconfRpcFutureCallback callback; + private NetconfBaseOps baseOps; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + final InputStream okStream = getClass().getResourceAsStream("/netconfMessages/rpc-reply_ok.xml"); + final InputStream dataStream = getClass().getResourceAsStream("/netconfMessages/rpc-reply_get.xml"); + final NetconfMessage ok = new NetconfMessage(XmlUtil.readXmlToDocument(okStream)); + final NetconfMessage data = new NetconfMessage(XmlUtil.readXmlToDocument(dataStream)); + when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME))) + .thenReturn(RpcResultBuilder.success(data).buildFuture()); + when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_GET_QNAME))) + .thenReturn(RpcResultBuilder.success(data).buildFuture()); + when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME))) + .thenReturn(RpcResultBuilder.success(ok).buildFuture()); + when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_COPY_CONFIG_QNAME))) + .thenReturn(RpcResultBuilder.success(ok).buildFuture()); + when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_DISCARD_CHANGES_QNAME))) + .thenReturn(RpcResultBuilder.success(ok).buildFuture()); + when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_VALIDATE_QNAME))) + .thenReturn(RpcResultBuilder.success(ok).buildFuture()); + when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_LOCK_QNAME))) + .thenReturn(RpcResultBuilder.success(ok).buildFuture()); + when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_UNLOCK_QNAME))) + .thenReturn(RpcResultBuilder.success(ok).buildFuture()); + when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME))) + .thenReturn(RpcResultBuilder.success(ok).buildFuture()); + final SchemaContext schemaContext = + parseYangStreams(getClass().getResourceAsStream("/schemas/test-module.yang")); + final MessageTransformer transformer = new NetconfMessageTransformer(schemaContext, true); + final DOMRpcService rpc = new NetconfDeviceRpc(schemaContext, listener, transformer); + final RemoteDeviceId id = + new RemoteDeviceId("device-1", InetSocketAddress.createUnresolved("localhost", 17830)); + callback = new NetconfRpcFutureCallback("prefix", id); + baseOps = new NetconfBaseOps(rpc, schemaContext); + } + + @Test + public void testLock() throws Exception { + baseOps.lock(callback, NetconfMessageTransformUtil.NETCONF_CANDIDATE_QNAME); + verifyMessageSent("lock", NetconfMessageTransformUtil.NETCONF_LOCK_QNAME); + } + + @Test + public void testLockCandidate() throws Exception { + baseOps.lockCandidate(callback); + verifyMessageSent("lock", NetconfMessageTransformUtil.NETCONF_LOCK_QNAME); + } + + @Test + public void testUnlock() throws Exception { + baseOps.unlock(callback, NetconfMessageTransformUtil.NETCONF_CANDIDATE_QNAME); + verifyMessageSent("unlock", NetconfMessageTransformUtil.NETCONF_UNLOCK_QNAME); + } + + @Test + public void testUnlockCandidate() throws Exception { + baseOps.unlockCandidate(callback); + verifyMessageSent("unlock", NetconfMessageTransformUtil.NETCONF_UNLOCK_QNAME); + } + + @Test + public void testLockRunning() throws Exception { + baseOps.lockRunning(callback); + verifyMessageSent("lock-running", NetconfMessageTransformUtil.NETCONF_LOCK_QNAME); + } + + @Test + public void testUnlockRunning() throws Exception { + baseOps.unlockRunning(callback); + verifyMessageSent("unlock-running", NetconfMessageTransformUtil.NETCONF_UNLOCK_QNAME); + } + + @Test + public void testDiscardChanges() throws Exception { + baseOps.discardChanges(callback); + verifyMessageSent("discardChanges", NetconfMessageTransformUtil.NETCONF_DISCARD_CHANGES_QNAME); + } + + @Test + public void testCommit() throws Exception { + baseOps.commit(callback); + verifyMessageSent("commit", NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME); + } + + @Test + public void testValidateCandidate() throws Exception { + baseOps.validateCandidate(callback); + verifyMessageSent("validate", NetconfMessageTransformUtil.NETCONF_VALIDATE_QNAME); + } + + @Test + public void testValidateRunning() throws Exception { + baseOps.validateRunning(callback); + verifyMessageSent("validate-running", NetconfMessageTransformUtil.NETCONF_VALIDATE_QNAME); + } + + + @Test + public void testCopyConfig() throws Exception { + baseOps.copyConfig(callback, NetconfMessageTransformUtil.NETCONF_RUNNING_QNAME, + NetconfMessageTransformUtil.NETCONF_CANDIDATE_QNAME); + verifyMessageSent("copy-config", NetconfMessageTransformUtil.NETCONF_COPY_CONFIG_QNAME); + } + + @Test + public void testCopyRunningToCandidate() throws Exception { + baseOps.copyRunningToCandidate(callback); + verifyMessageSent("copy-config", NetconfMessageTransformUtil.NETCONF_COPY_CONFIG_QNAME); + } + + + @Test + public void testGetConfigRunningData() throws Exception { + final Optional> dataOpt = + baseOps.getConfigRunningData(callback, Optional.of(YangInstanceIdentifier.EMPTY)).get(); + Assert.assertTrue(dataOpt.isPresent()); + Assert.assertEquals(NetconfMessageTransformUtil.NETCONF_DATA_QNAME, dataOpt.get().getNodeType()); + } + + @Test + public void testGetData() throws Exception { + final Optional> dataOpt = + baseOps.getData(callback, Optional.of(YangInstanceIdentifier.EMPTY)).get(); + Assert.assertTrue(dataOpt.isPresent()); + Assert.assertEquals(NetconfMessageTransformUtil.NETCONF_DATA_QNAME, dataOpt.get().getNodeType()); + } + + @Test + public void testGetConfigRunning() throws Exception { + baseOps.getConfigRunning(callback, Optional.absent()); + verifyMessageSent("getConfig", NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME); + } + + @Test + public void testGetConfigCandidate() throws Exception { + baseOps.getConfigCandidate(callback, Optional.absent()); + verifyMessageSent("getConfig_candidate", NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME); + } + + @Test + public void testGetConfigCandidateWithFilter() throws Exception { + final YangInstanceIdentifier id = YangInstanceIdentifier.builder() + .node(CONTAINER_Q_NAME) + .build(); + baseOps.getConfigCandidate(callback, Optional.of(id)); + verifyMessageSent("getConfig_candidate-filter", NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME); + } + + @Test + public void testGet() throws Exception { + baseOps.get(callback, Optional.absent()); + verifyMessageSent("get", NetconfMessageTransformUtil.NETCONF_GET_QNAME); + } + + @Test + public void testEditConfigCandidate() throws Exception { + final QName leafQName = QName.create(CONTAINER_Q_NAME, "a"); + final LeafNode leaf = Builders.leafBuilder() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(leafQName)) + .withValue("leaf-value") + .build(); + final YangInstanceIdentifier leafId = YangInstanceIdentifier.builder() + .node(CONTAINER_Q_NAME) + .node(leafQName) + .build(); + final DataContainerChild structure = baseOps.createEditConfigStrcture(Optional.of(leaf), + Optional.of(ModifyAction.REPLACE), leafId); + baseOps.editConfigCandidate(callback, structure, true); + verifyMessageSent("edit-config-test-module", NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME); + } + + @Test + public void testEditConfigRunning() throws Exception { + final QName containerQName = QName.create("test:namespace", "2013-07-22", "c"); + final QName leafQName = QName.create(containerQName, "a"); + final LeafNode leaf = Builders.leafBuilder() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(leafQName)) + .withValue("leaf-value") + .build(); + final YangInstanceIdentifier leafId = YangInstanceIdentifier.builder() + .node(containerQName) + .node(leafQName) + .build(); + final DataContainerChild structure = baseOps.createEditConfigStrcture(Optional.of(leaf), + Optional.of(ModifyAction.REPLACE), leafId); + baseOps.editConfigRunning(callback, structure, ModifyAction.MERGE, true); + verifyMessageSent("edit-config-test-module-running", NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME); + } + + private static SchemaContext parseYangStreams(final InputStream... streams) { + final CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR + .newBuild(); + final SchemaContext schemaContext; + try { + schemaContext = reactor.buildEffective(Arrays.asList(streams)); + } catch (final ReactorException e) { + throw new RuntimeException("Unable to build schema context from " + streams, e); + } + return schemaContext; + } + + private void verifyMessageSent(final String fileName, final QName name) { + final String path = "/netconfMessages/" + fileName + ".xml"; + verify(listener).sendRequest(msg(path), eq(name)); + } + + private static NetconfMessage msg(final String name) { + final InputStream stream = NetconfBaseOpsTest.class.getResourceAsStream(name); + try { + return argThat(new NetconfMessageMatcher(XmlUtil.readXmlToDocument(stream))); + } catch (SAXException | IOException e) { + throw new IllegalStateException("Failed to read xml file " + name, e); + } + } + + private static class NetconfMessageMatcher extends BaseMatcher { + + private final Document expected; + + private NetconfMessageMatcher(final Document expected) { + this.expected = removeAttrs(expected); + } + + @Override + public boolean matches(final Object item) { + if (!(item instanceof NetconfMessage)) { + return false; + } + final NetconfMessage message = (NetconfMessage) item; + final Document actualDoc = removeAttrs(message.getDocument()); + actualDoc.normalizeDocument(); + expected.normalizeDocument(); + final Diff diff = XMLUnit.compareXML(expected, actualDoc); + return diff.similar(); + } + + @Override + public void describeTo(final Description description) { + description.appendText(XmlUtil.toString(expected)); + } + + private static Document removeAttrs(final Document input) { + final Document copy = XmlUtil.newDocument(); + copy.appendChild(copy.importNode(input.getDocumentElement(), true)); + final Element element = copy.getDocumentElement(); + final List attrNames = new ArrayList<>(); + final NamedNodeMap attributes = element.getAttributes(); + for (int i = 0; i < attributes.getLength(); i++) { + final String nodeName = attributes.item(i).getNodeName(); + if ("xmlns".equals(nodeName)) { + continue; + } + attrNames.add(nodeName); + } + attrNames.forEach(element::removeAttribute); + return copy; + } + } + +} \ No newline at end of file diff --git a/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/util/NodeContainerProxyTest.java b/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/util/NodeContainerProxyTest.java new file mode 100644 index 0000000000..534a9520fc --- /dev/null +++ b/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/util/NodeContainerProxyTest.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.netconf.sal.connect.netconf.util; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.AugmentationSchema; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; + +public class NodeContainerProxyTest { + + private static final QName QNAME = QName.create("ns", "2016-10-19", "name"); + private static final QName NODE_1_QNAME = QName.create(QNAME, "node-1"); + private static final QName NODE_2_QNAME = QName.create(QNAME, "node-2"); + @Mock + private AugmentationSchema augSchema1; + @Mock + private AugmentationSchema augSchema2; + @Mock + private DataSchemaNode schemaNode1; + @Mock + private DataSchemaNode schemaNode2; + private NodeContainerProxy proxy; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + final Map childNodes = new HashMap<>(); + childNodes.put(NODE_1_QNAME, schemaNode1); + childNodes.put(NODE_2_QNAME, schemaNode2); + final Set augmentations = new HashSet<>(); + augmentations.add(augSchema1); + augmentations.add(augSchema2); + proxy = new NodeContainerProxy(QNAME, childNodes, augmentations); + } + + @Test + public void testGetQName() throws Exception { + Assert.assertEquals(QNAME, proxy.getQName()); + } + + @Test + public void testGetChildNodes() throws Exception { + Assert.assertEquals(2, proxy.getChildNodes().size()); + } + + @Test + public void testGetAvailableAugmentations() throws Exception { + final Set augmentations = proxy.getAvailableAugmentations(); + Assert.assertEquals(2, augmentations.size()); + Assert.assertTrue(augmentations.contains(augSchema1)); + Assert.assertTrue(augmentations.contains(augSchema2)); + } + + @Test + public void testGetDataChildByName() throws Exception { + final DataSchemaNode schemaNode = proxy.getDataChildByName(NODE_1_QNAME); + Assert.assertEquals(schemaNode1, schemaNode); + } + + @Test + public void testGetTypeDefinitions() throws Exception { + Assert.assertTrue(proxy.getTypeDefinitions().isEmpty()); + } + + @Test + public void testGetGroupings() throws Exception { + Assert.assertTrue(proxy.getGroupings().isEmpty()); + } + + @Test + public void testGetUses() throws Exception { + Assert.assertTrue(proxy.getUses().isEmpty()); + } + + @Test + public void testGetUnknownSchemaNodes() throws Exception { + Assert.assertTrue(proxy.getUnknownSchemaNodes().isEmpty()); + } + + @Test(expected = UnsupportedOperationException.class) + public void testIsPresenceContainer() throws Exception { + proxy.isPresenceContainer(); + } + + @Test(expected = UnsupportedOperationException.class) + public void testIsAugmenting() throws Exception { + proxy.isAugmenting(); + } + + @Test(expected = UnsupportedOperationException.class) + public void testIsAddedByUses() throws Exception { + proxy.isAddedByUses(); + } + + @Test(expected = UnsupportedOperationException.class) + public void testIsConfiguration() throws Exception { + proxy.isConfiguration(); + } + + @Test(expected = UnsupportedOperationException.class) + public void testGetConstraints() throws Exception { + proxy.getConstraints(); + } + + @Test(expected = UnsupportedOperationException.class) + public void testGetPath() throws Exception { + proxy.getPath(); + } + + @Test(expected = UnsupportedOperationException.class) + public void testGetDescription() throws Exception { + proxy.getDescription(); + } + + @Test(expected = UnsupportedOperationException.class) + public void testGetReference() throws Exception { + proxy.getReference(); + } + + @Test(expected = UnsupportedOperationException.class) + public void testGetStatus() throws Exception { + proxy.getStatus(); + } + +} \ No newline at end of file