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
9 package org.opendaylight.netconf.sal.connect.netconf.util;
11 import static org.mockito.Matchers.any;
12 import static org.mockito.Matchers.argThat;
13 import static org.mockito.Matchers.eq;
14 import static org.mockito.Mockito.verify;
15 import static org.mockito.Mockito.when;
17 import com.google.common.base.Optional;
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.net.InetSocketAddress;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.List;
24 import org.custommonkey.xmlunit.Diff;
25 import org.custommonkey.xmlunit.XMLUnit;
26 import org.hamcrest.BaseMatcher;
27 import org.hamcrest.Description;
28 import org.junit.Assert;
29 import org.junit.Before;
30 import org.junit.Test;
31 import org.mockito.Mock;
32 import org.mockito.MockitoAnnotations;
33 import org.opendaylight.controller.config.util.xml.XmlUtil;
34 import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
35 import org.opendaylight.netconf.api.NetconfMessage;
36 import org.opendaylight.netconf.sal.connect.api.MessageTransformer;
37 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceCommunicator;
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.yangtools.yang.common.QName;
42 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
43 import org.opendaylight.yangtools.yang.data.api.ModifyAction;
44 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
45 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
46 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
47 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
48 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
49 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
50 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
51 import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
52 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
53 import org.w3c.dom.Document;
54 import org.w3c.dom.Element;
55 import org.w3c.dom.NamedNodeMap;
56 import org.xml.sax.SAXException;
58 public class NetconfBaseOpsTest {
61 XMLUnit.setIgnoreWhitespace(true);
62 XMLUnit.setIgnoreComments(true);
65 private static final QName CONTAINER_Q_NAME = QName.create("test:namespace", "2013-07-22", "c");
68 private RemoteDeviceCommunicator<NetconfMessage> listener;
69 private NetconfRpcFutureCallback callback;
70 private NetconfBaseOps baseOps;
73 public void setUp() throws Exception {
74 MockitoAnnotations.initMocks(this);
75 final InputStream okStream = getClass().getResourceAsStream("/netconfMessages/rpc-reply_ok.xml");
76 final InputStream dataStream = getClass().getResourceAsStream("/netconfMessages/rpc-reply_get.xml");
77 final NetconfMessage ok = new NetconfMessage(XmlUtil.readXmlToDocument(okStream));
78 final NetconfMessage data = new NetconfMessage(XmlUtil.readXmlToDocument(dataStream));
79 when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME)))
80 .thenReturn(RpcResultBuilder.success(data).buildFuture());
81 when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_GET_QNAME)))
82 .thenReturn(RpcResultBuilder.success(data).buildFuture());
83 when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME)))
84 .thenReturn(RpcResultBuilder.success(ok).buildFuture());
85 when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_COPY_CONFIG_QNAME)))
86 .thenReturn(RpcResultBuilder.success(ok).buildFuture());
87 when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_DISCARD_CHANGES_QNAME)))
88 .thenReturn(RpcResultBuilder.success(ok).buildFuture());
89 when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_VALIDATE_QNAME)))
90 .thenReturn(RpcResultBuilder.success(ok).buildFuture());
91 when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_LOCK_QNAME)))
92 .thenReturn(RpcResultBuilder.success(ok).buildFuture());
93 when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_UNLOCK_QNAME)))
94 .thenReturn(RpcResultBuilder.success(ok).buildFuture());
95 when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME)))
96 .thenReturn(RpcResultBuilder.success(ok).buildFuture());
97 final SchemaContext schemaContext =
98 parseYangStreams(getClass().getResourceAsStream("/schemas/test-module.yang"));
99 final MessageTransformer<NetconfMessage> transformer = new NetconfMessageTransformer(schemaContext, true);
100 final DOMRpcService rpc = new NetconfDeviceRpc(schemaContext, listener, transformer);
101 final RemoteDeviceId id =
102 new RemoteDeviceId("device-1", InetSocketAddress.createUnresolved("localhost", 17830));
103 callback = new NetconfRpcFutureCallback("prefix", id);
104 baseOps = new NetconfBaseOps(rpc, schemaContext);
108 public void testLock() throws Exception {
109 baseOps.lock(callback, NetconfMessageTransformUtil.NETCONF_CANDIDATE_QNAME);
110 verifyMessageSent("lock", NetconfMessageTransformUtil.NETCONF_LOCK_QNAME);
114 public void testLockCandidate() throws Exception {
115 baseOps.lockCandidate(callback);
116 verifyMessageSent("lock", NetconfMessageTransformUtil.NETCONF_LOCK_QNAME);
120 public void testUnlock() throws Exception {
121 baseOps.unlock(callback, NetconfMessageTransformUtil.NETCONF_CANDIDATE_QNAME);
122 verifyMessageSent("unlock", NetconfMessageTransformUtil.NETCONF_UNLOCK_QNAME);
126 public void testUnlockCandidate() throws Exception {
127 baseOps.unlockCandidate(callback);
128 verifyMessageSent("unlock", NetconfMessageTransformUtil.NETCONF_UNLOCK_QNAME);
132 public void testLockRunning() throws Exception {
133 baseOps.lockRunning(callback);
134 verifyMessageSent("lock-running", NetconfMessageTransformUtil.NETCONF_LOCK_QNAME);
138 public void testUnlockRunning() throws Exception {
139 baseOps.unlockRunning(callback);
140 verifyMessageSent("unlock-running", NetconfMessageTransformUtil.NETCONF_UNLOCK_QNAME);
144 public void testDiscardChanges() throws Exception {
145 baseOps.discardChanges(callback);
146 verifyMessageSent("discardChanges", NetconfMessageTransformUtil.NETCONF_DISCARD_CHANGES_QNAME);
150 public void testCommit() throws Exception {
151 baseOps.commit(callback);
152 verifyMessageSent("commit", NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME);
156 public void testValidateCandidate() throws Exception {
157 baseOps.validateCandidate(callback);
158 verifyMessageSent("validate", NetconfMessageTransformUtil.NETCONF_VALIDATE_QNAME);
162 public void testValidateRunning() throws Exception {
163 baseOps.validateRunning(callback);
164 verifyMessageSent("validate-running", NetconfMessageTransformUtil.NETCONF_VALIDATE_QNAME);
169 public void testCopyConfig() throws Exception {
170 baseOps.copyConfig(callback, NetconfMessageTransformUtil.NETCONF_RUNNING_QNAME,
171 NetconfMessageTransformUtil.NETCONF_CANDIDATE_QNAME);
172 verifyMessageSent("copy-config", NetconfMessageTransformUtil.NETCONF_COPY_CONFIG_QNAME);
176 public void testCopyRunningToCandidate() throws Exception {
177 baseOps.copyRunningToCandidate(callback);
178 verifyMessageSent("copy-config", NetconfMessageTransformUtil.NETCONF_COPY_CONFIG_QNAME);
183 public void testGetConfigRunningData() throws Exception {
184 final Optional<NormalizedNode<?, ?>> dataOpt =
185 baseOps.getConfigRunningData(callback, Optional.of(YangInstanceIdentifier.EMPTY)).get();
186 Assert.assertTrue(dataOpt.isPresent());
187 Assert.assertEquals(NetconfMessageTransformUtil.NETCONF_DATA_QNAME, dataOpt.get().getNodeType());
191 public void testGetData() throws Exception {
192 final Optional<NormalizedNode<?, ?>> dataOpt =
193 baseOps.getData(callback, Optional.of(YangInstanceIdentifier.EMPTY)).get();
194 Assert.assertTrue(dataOpt.isPresent());
195 Assert.assertEquals(NetconfMessageTransformUtil.NETCONF_DATA_QNAME, dataOpt.get().getNodeType());
199 public void testGetConfigRunning() throws Exception {
200 baseOps.getConfigRunning(callback, Optional.absent());
201 verifyMessageSent("getConfig", NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME);
205 public void testGetConfigCandidate() throws Exception {
206 baseOps.getConfigCandidate(callback, Optional.absent());
207 verifyMessageSent("getConfig_candidate", NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME);
211 public void testGetConfigCandidateWithFilter() throws Exception {
212 final YangInstanceIdentifier id = YangInstanceIdentifier.builder()
213 .node(CONTAINER_Q_NAME)
215 baseOps.getConfigCandidate(callback, Optional.of(id));
216 verifyMessageSent("getConfig_candidate-filter", NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME);
220 public void testGet() throws Exception {
221 baseOps.get(callback, Optional.absent());
222 verifyMessageSent("get", NetconfMessageTransformUtil.NETCONF_GET_QNAME);
226 public void testEditConfigCandidate() throws Exception {
227 final QName leafQName = QName.create(CONTAINER_Q_NAME, "a");
228 final LeafNode<Object> leaf = Builders.leafBuilder()
229 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(leafQName))
230 .withValue("leaf-value")
232 final YangInstanceIdentifier leafId = YangInstanceIdentifier.builder()
233 .node(CONTAINER_Q_NAME)
236 final DataContainerChild<?, ?> structure = baseOps.createEditConfigStrcture(Optional.of(leaf),
237 Optional.of(ModifyAction.REPLACE), leafId);
238 baseOps.editConfigCandidate(callback, structure, true);
239 verifyMessageSent("edit-config-test-module", NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME);
243 public void testEditConfigRunning() throws Exception {
244 final QName containerQName = QName.create("test:namespace", "2013-07-22", "c");
245 final QName leafQName = QName.create(containerQName, "a");
246 final LeafNode<Object> leaf = Builders.leafBuilder()
247 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(leafQName))
248 .withValue("leaf-value")
250 final YangInstanceIdentifier leafId = YangInstanceIdentifier.builder()
251 .node(containerQName)
254 final DataContainerChild<?, ?> structure = baseOps.createEditConfigStrcture(Optional.of(leaf),
255 Optional.of(ModifyAction.REPLACE), leafId);
256 baseOps.editConfigRunning(callback, structure, ModifyAction.MERGE, true);
257 verifyMessageSent("edit-config-test-module-running", NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME);
260 private static SchemaContext parseYangStreams(final InputStream... streams) {
261 final CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR
263 final SchemaContext schemaContext;
265 schemaContext = reactor.buildEffective(Arrays.asList(streams));
266 } catch (final ReactorException e) {
267 throw new RuntimeException("Unable to build schema context from " + streams, e);
269 return schemaContext;
272 private void verifyMessageSent(final String fileName, final QName name) {
273 final String path = "/netconfMessages/" + fileName + ".xml";
274 verify(listener).sendRequest(msg(path), eq(name));
277 private static NetconfMessage msg(final String name) {
278 final InputStream stream = NetconfBaseOpsTest.class.getResourceAsStream(name);
280 return argThat(new NetconfMessageMatcher(XmlUtil.readXmlToDocument(stream)));
281 } catch (SAXException | IOException e) {
282 throw new IllegalStateException("Failed to read xml file " + name, e);
286 private static class NetconfMessageMatcher extends BaseMatcher<NetconfMessage> {
288 private final Document expected;
290 private NetconfMessageMatcher(final Document expected) {
291 this.expected = removeAttrs(expected);
295 public boolean matches(final Object item) {
296 if (!(item instanceof NetconfMessage)) {
299 final NetconfMessage message = (NetconfMessage) item;
300 final Document actualDoc = removeAttrs(message.getDocument());
301 actualDoc.normalizeDocument();
302 expected.normalizeDocument();
303 final Diff diff = XMLUnit.compareXML(expected, actualDoc);
304 return diff.similar();
308 public void describeTo(final Description description) {
309 description.appendText(XmlUtil.toString(expected));
312 private static Document removeAttrs(final Document input) {
313 final Document copy = XmlUtil.newDocument();
314 copy.appendChild(copy.importNode(input.getDocumentElement(), true));
315 final Element element = copy.getDocumentElement();
316 final List<String> attrNames = new ArrayList<>();
317 final NamedNodeMap attributes = element.getAttributes();
318 for (int i = 0; i < attributes.getLength(); i++) {
319 final String nodeName = attributes.item(i).getNodeName();
320 if ("xmlns".equals(nodeName)) {
323 attrNames.add(nodeName);
325 attrNames.forEach(element::removeAttribute);