2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netconf.sal.connect.netconf.util;
10 import static org.mockito.ArgumentMatchers.any;
11 import static org.mockito.ArgumentMatchers.argThat;
12 import static org.mockito.ArgumentMatchers.eq;
13 import static org.mockito.Mockito.verify;
14 import static org.mockito.Mockito.when;
16 import com.google.common.util.concurrent.FluentFuture;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.net.InetSocketAddress;
20 import java.util.ArrayList;
21 import java.util.List;
22 import java.util.Optional;
23 import org.custommonkey.xmlunit.Diff;
24 import org.custommonkey.xmlunit.XMLUnit;
25 import org.junit.Assert;
26 import org.junit.Before;
27 import org.junit.Test;
28 import org.mockito.ArgumentMatcher;
29 import org.mockito.Mock;
30 import org.mockito.MockitoAnnotations;
31 import org.opendaylight.mdsal.dom.api.DOMRpcService;
32 import org.opendaylight.netconf.api.ModifyAction;
33 import org.opendaylight.netconf.api.NetconfMessage;
34 import org.opendaylight.netconf.api.xml.XmlUtil;
35 import org.opendaylight.netconf.sal.connect.api.MessageTransformer;
36 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceCommunicator;
37 import org.opendaylight.netconf.sal.connect.netconf.AbstractTestModelTest;
38 import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceRpc;
39 import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.NetconfMessageTransformer;
40 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
41 import org.opendaylight.netconf.util.NetconfUtil;
42 import org.opendaylight.yangtools.rcf8528.data.util.EmptyMountPointContext;
43 import org.opendaylight.yangtools.yang.common.QName;
44 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
45 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
46 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
47 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
48 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
49 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
50 import org.w3c.dom.Document;
51 import org.w3c.dom.Element;
52 import org.w3c.dom.NamedNodeMap;
53 import org.xml.sax.SAXException;
55 public class NetconfBaseOpsTest extends AbstractTestModelTest {
56 private static final QName CONTAINER_Q_NAME = QName.create("test:namespace", "2013-07-22", "c");
59 XMLUnit.setIgnoreWhitespace(true);
60 XMLUnit.setIgnoreComments(true);
64 private RemoteDeviceCommunicator<NetconfMessage> listener;
65 private NetconfRpcFutureCallback callback;
66 private NetconfBaseOps baseOps;
69 public void setUp() throws Exception {
70 MockitoAnnotations.initMocks(this);
71 final InputStream okStream = getClass().getResourceAsStream("/netconfMessages/rpc-reply_ok.xml");
72 final InputStream dataStream = getClass().getResourceAsStream("/netconfMessages/rpc-reply_get.xml");
73 final NetconfMessage ok = new NetconfMessage(XmlUtil.readXmlToDocument(okStream));
74 final NetconfMessage data = new NetconfMessage(XmlUtil.readXmlToDocument(dataStream));
75 when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME)))
76 .thenReturn(FluentFuture.from(RpcResultBuilder.success(data).buildFuture()));
77 when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_GET_QNAME)))
78 .thenReturn(FluentFuture.from(RpcResultBuilder.success(data).buildFuture()));
79 when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME)))
80 .thenReturn(FluentFuture.from(RpcResultBuilder.success(ok).buildFuture()));
81 when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_COPY_CONFIG_QNAME)))
82 .thenReturn(FluentFuture.from(RpcResultBuilder.success(ok).buildFuture()));
83 when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_DISCARD_CHANGES_QNAME)))
84 .thenReturn(FluentFuture.from(RpcResultBuilder.success(ok).buildFuture()));
85 when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_VALIDATE_QNAME)))
86 .thenReturn(FluentFuture.from(RpcResultBuilder.success(ok).buildFuture()));
87 when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_LOCK_QNAME)))
88 .thenReturn(FluentFuture.from(RpcResultBuilder.success(ok).buildFuture()));
89 when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_UNLOCK_QNAME)))
90 .thenReturn(FluentFuture.from(RpcResultBuilder.success(ok).buildFuture()));
91 when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME)))
92 .thenReturn(FluentFuture.from(RpcResultBuilder.success(ok).buildFuture()));
93 final MessageTransformer<NetconfMessage> transformer = new NetconfMessageTransformer(
94 new EmptyMountPointContext(SCHEMA_CONTEXT), true);
95 final DOMRpcService rpc = new NetconfDeviceRpc(SCHEMA_CONTEXT, listener, transformer);
96 final RemoteDeviceId id =
97 new RemoteDeviceId("device-1", InetSocketAddress.createUnresolved("localhost", 17830));
98 callback = new NetconfRpcFutureCallback("prefix", id);
99 baseOps = new NetconfBaseOps(rpc, SCHEMA_CONTEXT);
103 public void testLock() throws Exception {
104 baseOps.lock(callback, NetconfMessageTransformUtil.NETCONF_CANDIDATE_QNAME);
105 verifyMessageSent("lock", NetconfMessageTransformUtil.NETCONF_LOCK_QNAME);
109 public void testLockCandidate() throws Exception {
110 baseOps.lockCandidate(callback);
111 verifyMessageSent("lock", NetconfMessageTransformUtil.NETCONF_LOCK_QNAME);
115 public void testUnlock() throws Exception {
116 baseOps.unlock(callback, NetconfMessageTransformUtil.NETCONF_CANDIDATE_QNAME);
117 verifyMessageSent("unlock", NetconfMessageTransformUtil.NETCONF_UNLOCK_QNAME);
121 public void testUnlockCandidate() throws Exception {
122 baseOps.unlockCandidate(callback);
123 verifyMessageSent("unlock", NetconfMessageTransformUtil.NETCONF_UNLOCK_QNAME);
127 public void testLockRunning() throws Exception {
128 baseOps.lockRunning(callback);
129 verifyMessageSent("lock-running", NetconfMessageTransformUtil.NETCONF_LOCK_QNAME);
133 public void testUnlockRunning() throws Exception {
134 baseOps.unlockRunning(callback);
135 verifyMessageSent("unlock-running", NetconfMessageTransformUtil.NETCONF_UNLOCK_QNAME);
139 public void testDiscardChanges() throws Exception {
140 baseOps.discardChanges(callback);
141 verifyMessageSent("discardChanges", NetconfMessageTransformUtil.NETCONF_DISCARD_CHANGES_QNAME);
145 public void testCommit() throws Exception {
146 baseOps.commit(callback);
147 verifyMessageSent("commit", NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME);
151 public void testValidateCandidate() throws Exception {
152 baseOps.validateCandidate(callback);
153 verifyMessageSent("validate", NetconfMessageTransformUtil.NETCONF_VALIDATE_QNAME);
157 public void testValidateRunning() throws Exception {
158 baseOps.validateRunning(callback);
159 verifyMessageSent("validate-running", NetconfMessageTransformUtil.NETCONF_VALIDATE_QNAME);
164 public void testCopyConfig() throws Exception {
165 baseOps.copyConfig(callback, NetconfMessageTransformUtil.NETCONF_RUNNING_QNAME,
166 NetconfMessageTransformUtil.NETCONF_CANDIDATE_QNAME);
167 verifyMessageSent("copy-config", NetconfMessageTransformUtil.NETCONF_COPY_CONFIG_QNAME);
171 public void testCopyRunningToCandidate() throws Exception {
172 baseOps.copyRunningToCandidate(callback);
173 verifyMessageSent("copy-config", NetconfMessageTransformUtil.NETCONF_COPY_CONFIG_QNAME);
178 public void testGetConfigRunningData() throws Exception {
179 final Optional<NormalizedNode<?, ?>> dataOpt =
180 baseOps.getConfigRunningData(callback, Optional.of(YangInstanceIdentifier.EMPTY)).get();
181 Assert.assertTrue(dataOpt.isPresent());
182 Assert.assertEquals(NetconfUtil.NETCONF_DATA_QNAME, dataOpt.get().getNodeType());
186 public void testGetData() throws Exception {
187 final Optional<NormalizedNode<?, ?>> dataOpt =
188 baseOps.getData(callback, Optional.of(YangInstanceIdentifier.EMPTY)).get();
189 Assert.assertTrue(dataOpt.isPresent());
190 Assert.assertEquals(NetconfUtil.NETCONF_DATA_QNAME, dataOpt.get().getNodeType());
194 public void testGetConfigRunning() throws Exception {
195 baseOps.getConfigRunning(callback, Optional.empty());
196 verifyMessageSent("getConfig", NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME);
200 public void testGetConfigCandidate() throws Exception {
201 baseOps.getConfigCandidate(callback, Optional.empty());
202 verifyMessageSent("getConfig_candidate", NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME);
206 public void testGetConfigCandidateWithFilter() throws Exception {
207 final YangInstanceIdentifier id = YangInstanceIdentifier.builder()
208 .node(CONTAINER_Q_NAME)
210 baseOps.getConfigCandidate(callback, Optional.of(id));
211 verifyMessageSent("getConfig_candidate-filter", NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME);
215 public void testGet() throws Exception {
216 baseOps.get(callback, Optional.empty());
217 verifyMessageSent("get", NetconfMessageTransformUtil.NETCONF_GET_QNAME);
221 public void testEditConfigCandidate() throws Exception {
222 final QName leafQName = QName.create(CONTAINER_Q_NAME, "a");
223 final LeafNode<Object> leaf = Builders.leafBuilder()
224 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(leafQName))
225 .withValue("leaf-value")
227 final YangInstanceIdentifier leafId = YangInstanceIdentifier.builder()
228 .node(CONTAINER_Q_NAME)
231 final DataContainerChild<?, ?> structure = baseOps.createEditConfigStrcture(Optional.of(leaf),
232 Optional.of(ModifyAction.REPLACE), leafId);
233 baseOps.editConfigCandidate(callback, structure, true);
234 verifyMessageSent("edit-config-test-module", NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME);
238 public void testEditConfigRunning() throws Exception {
239 final QName containerQName = QName.create("test:namespace", "2013-07-22", "c");
240 final QName leafQName = QName.create(containerQName, "a");
241 final LeafNode<Object> leaf = Builders.leafBuilder()
242 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(leafQName))
243 .withValue("leaf-value")
245 final YangInstanceIdentifier leafId = YangInstanceIdentifier.builder()
246 .node(containerQName)
249 final DataContainerChild<?, ?> structure = baseOps.createEditConfigStrcture(Optional.of(leaf),
250 Optional.of(ModifyAction.REPLACE), leafId);
251 baseOps.editConfigRunning(callback, structure, ModifyAction.MERGE, true);
252 verifyMessageSent("edit-config-test-module-running", NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME);
255 private void verifyMessageSent(final String fileName, final QName name) {
256 final String path = "/netconfMessages/" + fileName + ".xml";
257 verify(listener).sendRequest(msg(path), eq(name));
260 private static NetconfMessage msg(final String name) {
261 final InputStream stream = NetconfBaseOpsTest.class.getResourceAsStream(name);
263 return argThat(new NetconfMessageMatcher(XmlUtil.readXmlToDocument(stream)));
264 } catch (SAXException | IOException e) {
265 throw new IllegalStateException("Failed to read xml file " + name, e);
269 private static class NetconfMessageMatcher implements ArgumentMatcher<NetconfMessage> {
271 private final Document expected;
273 NetconfMessageMatcher(final Document expected) {
274 this.expected = removeAttrs(expected);
278 public boolean matches(final NetconfMessage message) {
279 final Document actualDoc = removeAttrs(message.getDocument());
280 actualDoc.normalizeDocument();
281 expected.normalizeDocument();
282 final Diff diff = XMLUnit.compareXML(expected, actualDoc);
283 return diff.similar();
286 private static Document removeAttrs(final Document input) {
287 final Document copy = XmlUtil.newDocument();
288 copy.appendChild(copy.importNode(input.getDocumentElement(), true));
289 final Element element = copy.getDocumentElement();
290 final List<String> attrNames = new ArrayList<>();
291 final NamedNodeMap attributes = element.getAttributes();
292 for (int i = 0; i < attributes.getLength(); i++) {
293 final String nodeName = attributes.item(i).getNodeName();
294 if ("xmlns".equals(nodeName)) {
297 attrNames.add(nodeName);
299 attrNames.forEach(element::removeAttribute);