2 * Copyright (c) 2014, 2015 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.schema.mapping;
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertNull;
14 import static org.junit.Assert.assertThat;
15 import static org.junit.Assert.assertTrue;
16 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.CREATE_SUBSCRIPTION_RPC_CONTENT;
17 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.CREATE_SUBSCRIPTION_RPC_QNAME;
18 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.GET_SCHEMA_QNAME;
19 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_CANDIDATE_QNAME;
20 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME;
21 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_DATA_QNAME;
22 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_DISCARD_CHANGES_QNAME;
23 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME;
24 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME;
25 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_QNAME;
26 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_LOCK_QNAME;
27 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_RUNNING_QNAME;
28 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.createEditConfigStructure;
29 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.toFilterStructure;
30 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.toId;
31 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.toPath;
33 import com.google.common.base.Optional;
34 import com.google.common.collect.Iterables;
35 import com.google.common.collect.Lists;
36 import com.google.common.collect.Maps;
37 import java.io.IOException;
38 import java.util.Collections;
39 import java.util.List;
41 import javax.xml.transform.dom.DOMSource;
42 import org.custommonkey.xmlunit.Diff;
43 import org.custommonkey.xmlunit.ElementNameAndAttributeQualifier;
44 import org.custommonkey.xmlunit.XMLUnit;
45 import org.hamcrest.CoreMatchers;
46 import org.junit.Before;
47 import org.junit.Test;
48 import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
49 import org.opendaylight.mdsal.binding.generator.impl.ModuleInfoBackedContext;
50 import org.opendaylight.netconf.api.NetconfMessage;
51 import org.opendaylight.netconf.api.xml.XmlUtil;
52 import org.opendaylight.netconf.sal.connect.netconf.schema.NetconfRemoteSchemaYangSourceProvider;
53 import org.opendaylight.netconf.sal.connect.netconf.util.NetconfBaseOps;
54 import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.$YangModuleInfoImpl;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Capabilities;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.Schema;
60 import org.opendaylight.yangtools.yang.common.QName;
61 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
62 import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
63 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
64 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
65 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
66 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
67 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
68 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
69 import org.xml.sax.SAXException;
71 public class NetconfMessageTransformerTest {
73 private NetconfMessageTransformer netconfMessageTransformer;
74 private SchemaContext schema;
77 public void setUp() throws Exception {
78 XMLUnit.setIgnoreWhitespace(true);
79 XMLUnit.setIgnoreAttributeOrder(true);
80 XMLUnit.setIgnoreComments(true);
82 schema = getSchema(true);
83 netconfMessageTransformer = getTransformer(schema);
88 public void testLockRequestBaseSchemaNotPresent() throws Exception {
89 final SchemaContext partialSchema = getSchema(false);
90 final NetconfMessageTransformer transformer = getTransformer(partialSchema);
91 final NetconfMessage netconfMessage = transformer.toRpcRequest(toPath(NETCONF_LOCK_QNAME),
92 NetconfBaseOps.getLockContent(NETCONF_CANDIDATE_QNAME));
94 assertThat(XmlUtil.toString(netconfMessage.getDocument()), CoreMatchers.containsString("<lock"));
95 assertThat(XmlUtil.toString(netconfMessage.getDocument()), CoreMatchers.containsString("<rpc"));
99 public void testCreateSubscriberNotificationSchemaNotPresent() throws Exception {
100 final SchemaContext partialSchema = getSchema(true);
101 final NetconfMessageTransformer transformer = new NetconfMessageTransformer(
104 BaseSchema.BASE_NETCONF_CTX_WITH_NOTIFICATIONS
106 NetconfMessage netconfMessage = transformer.toRpcRequest(
107 toPath(CREATE_SUBSCRIPTION_RPC_QNAME),
108 CREATE_SUBSCRIPTION_RPC_CONTENT
110 String documentString = XmlUtil.toString(netconfMessage.getDocument());
111 assertThat(documentString, CoreMatchers.containsString("<create-subscription"));
112 assertThat(documentString, CoreMatchers.containsString("<rpc"));
116 public void tesLockSchemaRequest() throws Exception {
117 final SchemaContext partialSchema = getSchema(false);
118 final NetconfMessageTransformer transformer = getTransformer(partialSchema);
119 final String result = "<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><ok/></rpc-reply>";
121 transformer.toRpcResult(new NetconfMessage(XmlUtil.readXmlToDocument(result)), toPath(NETCONF_LOCK_QNAME));
125 public void testDiscardChangesRequest() throws Exception {
126 final NetconfMessage netconfMessage =
127 netconfMessageTransformer.toRpcRequest(toPath(NETCONF_DISCARD_CHANGES_QNAME), null);
128 assertThat(XmlUtil.toString(netconfMessage.getDocument()), CoreMatchers.containsString("<discard"));
129 assertThat(XmlUtil.toString(netconfMessage.getDocument()), CoreMatchers.containsString("<rpc"));
130 assertThat(XmlUtil.toString(netconfMessage.getDocument()), CoreMatchers.containsString("message-id"));
134 public void tesGetSchemaRequest() throws Exception {
135 final NetconfMessage netconfMessage = netconfMessageTransformer.toRpcRequest(toPath(GET_SCHEMA_QNAME),
136 NetconfRemoteSchemaYangSourceProvider.createGetSchemaRequest("module", Optional.of("2012-12-12")));
137 assertSimilarXml(netconfMessage, "<rpc message-id=\"m-0\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
138 + "<get-schema xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n"
139 + "<format>yang</format>\n"
140 + "<identifier>module</identifier>\n"
141 + "<version>2012-12-12</version>\n"
147 public void tesGetSchemaResponse() throws Exception {
148 final NetconfMessageTransformer transformer = getTransformer(getSchema(true));
149 final NetconfMessage response = new NetconfMessage(XmlUtil.readXmlToDocument(
150 "<rpc-reply message-id=\"101\"\n"
151 + "xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
153 + "xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n"
154 + "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n"
155 + "Random YANG SCHEMA\n"
160 final DOMRpcResult compositeNodeRpcResult = transformer.toRpcResult(response, toPath(GET_SCHEMA_QNAME));
161 assertTrue(compositeNodeRpcResult.getErrors().isEmpty());
162 assertNotNull(compositeNodeRpcResult.getResult());
163 final DOMSource schemaContent =
164 ((AnyXmlNode) ((ContainerNode) compositeNodeRpcResult.getResult()).getValue().iterator().next()).getValue();
165 assertThat(schemaContent.getNode().getTextContent(),
166 CoreMatchers.containsString("Random YANG SCHEMA"));
170 public void testGetConfigResponse() throws Exception {
171 final NetconfMessage response = new NetconfMessage(XmlUtil.readXmlToDocument("<rpc-reply message-id=\"101\"\n"
172 + "xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
174 + "<netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n"
177 + "<identifier>module</identifier>\n"
178 + "<version>2012-12-12</version>\n"
179 + "<format xmlns:x=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">x:yang</format>\n"
182 + "</netconf-state>\n"
186 final NetconfMessageTransformer transformer = getTransformer(getSchema(true));
187 final DOMRpcResult compositeNodeRpcResult =
188 transformer.toRpcResult(response, toPath(NETCONF_GET_CONFIG_QNAME));
189 assertTrue(compositeNodeRpcResult.getErrors().isEmpty());
190 assertNotNull(compositeNodeRpcResult.getResult());
192 final List<DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?>> values = Lists.newArrayList(
193 NetconfRemoteSchemaYangSourceProvider
194 .createGetSchemaRequest("module", Optional.of("2012-12-12")).getValue());
196 final Map<QName, Object> keys = Maps.newHashMap();
197 for (final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> value : values) {
198 keys.put(value.getNodeType(), value.getValue());
201 final YangInstanceIdentifier.NodeIdentifierWithPredicates identifierWithPredicates =
202 new YangInstanceIdentifier.NodeIdentifierWithPredicates(Schema.QNAME, keys);
203 final MapEntryNode schemaNode =
204 Builders.mapEntryBuilder().withNodeIdentifier(identifierWithPredicates).withValue(values).build();
206 final ContainerNode data = (ContainerNode) ((ContainerNode) compositeNodeRpcResult
207 .getResult()).getChild(toId(NETCONF_DATA_QNAME)).get();
208 final ContainerNode state = (ContainerNode) data.getChild(toId(NetconfState.QNAME)).get();
209 final ContainerNode schemas = (ContainerNode) state.getChild(toId(Schemas.QNAME)).get();
210 final MapNode schemaParent = (MapNode) schemas.getChild(toId(Schema.QNAME)).get();
211 assertEquals(1, Iterables.size(schemaParent.getValue()));
213 assertEquals(schemaNode, schemaParent.getValue().iterator().next());
217 public void testGetConfigRequest() throws Exception {
218 final DataContainerChild<?, ?> filter = toFilterStructure(
219 YangInstanceIdentifier.create(toId(NetconfState.QNAME), toId(Schemas.QNAME)), schema);
221 final DataContainerChild<?, ?> source = NetconfBaseOps.getSourceNode(NETCONF_RUNNING_QNAME);
223 final NetconfMessage netconfMessage = netconfMessageTransformer.toRpcRequest(toPath(NETCONF_GET_CONFIG_QNAME),
224 NetconfMessageTransformUtil.wrap(NETCONF_GET_CONFIG_QNAME, source, filter));
226 assertSimilarXml(netconfMessage, "<rpc message-id=\"m-0\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
227 + "<get-config xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
228 + "<filter xmlns:ns0=\"urn:ietf:params:xml:ns:netconf:base:1.0\" ns0:type=\"subtree\">\n"
229 + "<netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n"
241 public void testEditConfigRequest() throws Exception {
242 final List<DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?>> values = Lists.newArrayList(
243 NetconfRemoteSchemaYangSourceProvider
244 .createGetSchemaRequest("module", Optional.of("2012-12-12")).getValue());
246 final Map<QName, Object> keys = Maps.newHashMap();
247 for (final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> value : values) {
248 keys.put(value.getNodeType(), value.getValue());
251 final YangInstanceIdentifier.NodeIdentifierWithPredicates identifierWithPredicates =
252 new YangInstanceIdentifier.NodeIdentifierWithPredicates(Schema.QNAME, keys);
253 final MapEntryNode schemaNode =
254 Builders.mapEntryBuilder().withNodeIdentifier(identifierWithPredicates).withValue(values).build();
256 final YangInstanceIdentifier id = YangInstanceIdentifier.builder()
257 .node(NetconfState.QNAME).node(Schemas.QNAME).node(Schema.QNAME)
258 .nodeWithKey(Schema.QNAME, keys).build();
259 final DataContainerChild<?, ?> editConfigStructure =
260 createEditConfigStructure(BaseSchema.BASE_NETCONF_CTX_WITH_NOTIFICATIONS.getSchemaContext(), id,
261 Optional.absent(), Optional.fromNullable(schemaNode));
263 final DataContainerChild<?, ?> target = NetconfBaseOps.getTargetNode(NETCONF_CANDIDATE_QNAME);
265 final ContainerNode wrap =
266 NetconfMessageTransformUtil.wrap(NETCONF_EDIT_CONFIG_QNAME, editConfigStructure, target);
267 final NetconfMessage netconfMessage =
268 netconfMessageTransformer.toRpcRequest(toPath(NETCONF_EDIT_CONFIG_QNAME), wrap);
270 assertSimilarXml(netconfMessage, "<rpc message-id=\"m-0\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
276 + "<netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n"
279 + "<identifier>module</identifier>\n"
280 + "<version>2012-12-12</version>\n"
281 + "<format>yang</format>\n"
284 + "</netconf-state>\n"
290 private static void assertSimilarXml(final NetconfMessage netconfMessage, final String xmlContent)
291 throws SAXException, IOException {
292 final Diff diff = XMLUnit.compareXML(netconfMessage.getDocument(), XmlUtil.readXmlToDocument(xmlContent));
293 diff.overrideElementQualifier(new ElementNameAndAttributeQualifier());
294 assertTrue(diff.toString(), diff.similar());
298 public void testGetRequest() throws Exception {
300 final QName capability = QName.create(Capabilities.QNAME, "capability");
301 final DataContainerChild<?, ?> filter = toFilterStructure(
302 YangInstanceIdentifier.create(toId(NetconfState.QNAME), toId(Capabilities.QNAME), toId(capability),
303 new YangInstanceIdentifier.NodeWithValue<>(capability, "a:b:c")), schema);
305 final NetconfMessage netconfMessage = netconfMessageTransformer.toRpcRequest(toPath(NETCONF_GET_QNAME),
306 NetconfMessageTransformUtil.wrap(NETCONF_GET_QNAME, filter));
308 assertSimilarXml(netconfMessage, "<rpc message-id=\"m-0\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
309 + "<get xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
310 + "<filter xmlns:ns0=\"urn:ietf:params:xml:ns:netconf:base:1.0\" ns0:type=\"subtree\">\n"
311 + "<netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n"
313 + "<capability>a:b:c</capability>\n"
314 + "</capabilities>\n"
321 private static NetconfMessageTransformer getTransformer(final SchemaContext schema) {
322 return new NetconfMessageTransformer(schema, true);
326 public void testCommitResponse() throws Exception {
327 final NetconfMessage response = new NetconfMessage(XmlUtil.readXmlToDocument(
328 "<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><ok/></rpc-reply>"
330 final DOMRpcResult compositeNodeRpcResult =
331 netconfMessageTransformer.toRpcResult(response, toPath(NETCONF_COMMIT_QNAME));
332 assertTrue(compositeNodeRpcResult.getErrors().isEmpty());
333 assertNull(compositeNodeRpcResult.getResult());
336 public SchemaContext getSchema(final boolean addBase) {
337 final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
339 moduleInfoBackedContext.addModuleInfos(Collections.singleton($YangModuleInfoImpl.getInstance()));
341 moduleInfoBackedContext
342 .addModuleInfos(Collections.singleton(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
343 .netconf.monitoring.rev101004.$YangModuleInfoImpl.getInstance()));
344 return moduleInfoBackedContext.tryToCreateSchemaContext().get();