Convert anyxml nodes lazily
[netconf.git] / netconf / sal-netconf-connector / src / test / java / org / opendaylight / netconf / sal / connect / netconf / schema / mapping / NetconfMessageTransformerTest.java
1 /*
2  * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.netconf.sal.connect.netconf.schema.mapping;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotNull;
12 import static org.junit.Assert.assertNull;
13 import static org.junit.Assert.assertThat;
14 import static org.junit.Assert.assertTrue;
15 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.CREATE_SUBSCRIPTION_RPC_CONTENT;
16 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.CREATE_SUBSCRIPTION_RPC_QNAME;
17 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.GET_SCHEMA_QNAME;
18 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_CANDIDATE_QNAME;
19 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME;
20 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_DATA_QNAME;
21 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_DISCARD_CHANGES_QNAME;
22 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME;
23 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME;
24 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_QNAME;
25 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_LOCK_QNAME;
26 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_RUNNING_QNAME;
27 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.createEditConfigStructure;
28 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.toFilterStructure;
29 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.toId;
30 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.toPath;
31
32 import com.google.common.collect.ImmutableMap;
33 import com.google.common.collect.Iterables;
34 import com.google.common.collect.Lists;
35 import java.io.IOException;
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.Collections;
39 import java.util.HashMap;
40 import java.util.HashSet;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.Optional;
44 import java.util.Set;
45 import javax.xml.transform.dom.DOMSource;
46 import org.custommonkey.xmlunit.Diff;
47 import org.custommonkey.xmlunit.ElementNameAndAttributeQualifier;
48 import org.custommonkey.xmlunit.XMLUnit;
49 import org.hamcrest.CoreMatchers;
50 import org.junit.Before;
51 import org.junit.Test;
52 import org.opendaylight.mdsal.binding.generator.impl.ModuleInfoBackedContext;
53 import org.opendaylight.mdsal.dom.api.DOMActionResult;
54 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
55 import org.opendaylight.mdsal.dom.api.DOMRpcResult;
56 import org.opendaylight.netconf.api.NetconfMessage;
57 import org.opendaylight.netconf.api.xml.XmlUtil;
58 import org.opendaylight.netconf.sal.connect.netconf.schema.NetconfRemoteSchemaYangSourceProvider;
59 import org.opendaylight.netconf.sal.connect.netconf.util.NetconfBaseOps;
60 import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
61 import org.opendaylight.netconf.util.NetconfUtil;
62 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.$YangModuleInfoImpl;
63 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState;
64 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Capabilities;
65 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
66 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.Schema;
67 import org.opendaylight.yangtools.yang.common.QName;
68 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
69 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
70 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
71 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
72 import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
73 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
74 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
75 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
76 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
77 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
78 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
79 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
80 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
81 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
82 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder;
83 import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
84 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
85 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
86 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
87 import org.w3c.dom.Node;
88 import org.xml.sax.SAXException;
89
90 public class NetconfMessageTransformerTest {
91
92     private static final String REVISION_EXAMPLE_SERVER_FARM = "2018-08-07";
93     private static final String URN_EXAMPLE_SERVER_FARM = "urn:example:server-farm";
94
95     private static final String REVISION_EXAMPLE_SERVER_FARM_2 = "2019-05-20";
96     private static final String URN_EXAMPLE_SERVER_FARM_2 = "urn:example:server-farm-2";
97
98     private NetconfMessageTransformer actionNetconfMessageTransformer;
99     private NetconfMessageTransformer netconfMessageTransformer;
100     private SchemaContext schema;
101
102     @Before
103     public void setUp() throws Exception {
104         XMLUnit.setIgnoreWhitespace(true);
105         XMLUnit.setIgnoreAttributeOrder(true);
106         XMLUnit.setIgnoreComments(true);
107
108         schema = getSchema(true);
109         netconfMessageTransformer = getTransformer(schema);
110         actionNetconfMessageTransformer = getActionMessageTransformer();
111     }
112
113     @Test
114     public void testLockRequestBaseSchemaNotPresent() throws Exception {
115         final SchemaContext partialSchema = getSchema(false);
116         final NetconfMessageTransformer transformer = getTransformer(partialSchema);
117         final NetconfMessage netconfMessage = transformer.toRpcRequest(toPath(NETCONF_LOCK_QNAME),
118                 NetconfBaseOps.getLockContent(NETCONF_CANDIDATE_QNAME));
119
120         assertThat(XmlUtil.toString(netconfMessage.getDocument()), CoreMatchers.containsString("<lock"));
121         assertThat(XmlUtil.toString(netconfMessage.getDocument()), CoreMatchers.containsString("<rpc"));
122     }
123
124     @Test
125     public void testCreateSubscriberNotificationSchemaNotPresent() throws Exception {
126         final SchemaContext partialSchema = getSchema(true);
127         final NetconfMessageTransformer transformer = new NetconfMessageTransformer(
128                 partialSchema,
129                 true,
130                 BaseSchema.BASE_NETCONF_CTX_WITH_NOTIFICATIONS
131         );
132         NetconfMessage netconfMessage = transformer.toRpcRequest(
133                 toPath(CREATE_SUBSCRIPTION_RPC_QNAME),
134                 CREATE_SUBSCRIPTION_RPC_CONTENT
135         );
136         String documentString = XmlUtil.toString(netconfMessage.getDocument());
137         assertThat(documentString, CoreMatchers.containsString("<create-subscription"));
138         assertThat(documentString, CoreMatchers.containsString("<rpc"));
139     }
140
141     @Test
142     public void tesLockSchemaRequest() throws Exception {
143         final SchemaContext partialSchema = getSchema(false);
144         final NetconfMessageTransformer transformer = getTransformer(partialSchema);
145         final String result = "<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><ok/></rpc-reply>";
146
147         transformer.toRpcResult(new NetconfMessage(XmlUtil.readXmlToDocument(result)), toPath(NETCONF_LOCK_QNAME));
148     }
149
150     @Test
151     public void testDiscardChangesRequest() throws Exception {
152         final NetconfMessage netconfMessage =
153                 netconfMessageTransformer.toRpcRequest(toPath(NETCONF_DISCARD_CHANGES_QNAME), null);
154         assertThat(XmlUtil.toString(netconfMessage.getDocument()), CoreMatchers.containsString("<discard"));
155         assertThat(XmlUtil.toString(netconfMessage.getDocument()), CoreMatchers.containsString("<rpc"));
156         assertThat(XmlUtil.toString(netconfMessage.getDocument()), CoreMatchers.containsString("message-id"));
157     }
158
159     @Test
160     public void testGetSchemaRequest() throws Exception {
161         final NetconfMessage netconfMessage = netconfMessageTransformer.toRpcRequest(toPath(GET_SCHEMA_QNAME),
162                 NetconfRemoteSchemaYangSourceProvider.createGetSchemaRequest("module", Optional.of("2012-12-12")));
163         assertSimilarXml(netconfMessage, "<rpc message-id=\"m-0\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
164                 + "<get-schema xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n"
165                 + "<format>yang</format>\n"
166                 + "<identifier>module</identifier>\n"
167                 + "<version>2012-12-12</version>\n"
168                 + "</get-schema>\n"
169                 + "</rpc>");
170     }
171
172     @Test
173     public void testGetSchemaResponse() throws Exception {
174         final NetconfMessageTransformer transformer = getTransformer(getSchema(true));
175         final NetconfMessage response = new NetconfMessage(XmlUtil.readXmlToDocument(
176                 "<rpc-reply message-id=\"101\"\n"
177                         + "xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
178                         + "<data\n"
179                         + "xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n"
180                         + "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n"
181                         + "Random YANG SCHEMA\n"
182                         + "</xs:schema>\n"
183                         + "</data>\n"
184                         + "</rpc-reply>"
185         ));
186         final DOMRpcResult compositeNodeRpcResult = transformer.toRpcResult(response, toPath(GET_SCHEMA_QNAME));
187         assertTrue(compositeNodeRpcResult.getErrors().isEmpty());
188         assertNotNull(compositeNodeRpcResult.getResult());
189         final DOMSource schemaContent =
190             ((AnyXmlNode) ((ContainerNode) compositeNodeRpcResult.getResult()).getValue().iterator().next()).getValue();
191         assertThat(schemaContent.getNode().getTextContent(),
192                 CoreMatchers.containsString("Random YANG SCHEMA"));
193     }
194
195     @Test
196     public void testGetConfigResponse() throws Exception {
197         final NetconfMessage response = new NetconfMessage(XmlUtil.readXmlToDocument("<rpc-reply message-id=\"101\"\n"
198                 + "xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
199                 + "<data>\n"
200                 + "<netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n"
201                 + "<schemas>\n"
202                 + "<schema>\n"
203                 + "<identifier>module</identifier>\n"
204                 + "<version>2012-12-12</version>\n"
205                 + "<format xmlns:x=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">x:yang</format>\n"
206                 + "</schema>\n"
207                 + "</schemas>\n"
208                 + "</netconf-state>\n"
209                 + "</data>\n"
210                 + "</rpc-reply>"));
211
212         final NetconfMessageTransformer transformer = getTransformer(getSchema(true));
213         final DOMRpcResult compositeNodeRpcResult =
214                 transformer.toRpcResult(response, toPath(NETCONF_GET_CONFIG_QNAME));
215         assertTrue(compositeNodeRpcResult.getErrors().isEmpty());
216         assertNotNull(compositeNodeRpcResult.getResult());
217
218         final List<DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?>> values = Lists.newArrayList(
219                 NetconfRemoteSchemaYangSourceProvider
220                         .createGetSchemaRequest("module", Optional.of("2012-12-12")).getValue());
221
222         final Map<QName, Object> keys = new HashMap<>();
223         for (final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> value : values) {
224             keys.put(value.getNodeType(), value.getValue());
225         }
226
227         final YangInstanceIdentifier.NodeIdentifierWithPredicates identifierWithPredicates =
228                 new YangInstanceIdentifier.NodeIdentifierWithPredicates(Schema.QNAME, keys);
229         final MapEntryNode schemaNode =
230                 Builders.mapEntryBuilder().withNodeIdentifier(identifierWithPredicates).withValue(values).build();
231
232         final AnyXmlNode data = (AnyXmlNode) ((ContainerNode) compositeNodeRpcResult
233                 .getResult()).getChild(toId(NETCONF_DATA_QNAME)).get();
234
235         NormalizedNodeResult nodeResult =
236                 NetconfUtil.transformDOMSourceToNormalizedNode(schema, data.getValue());
237         ContainerNode result = (ContainerNode) nodeResult.getResult();
238         final ContainerNode state = (ContainerNode) result.getChild(toId(NetconfState.QNAME)).get();
239         final ContainerNode schemas = (ContainerNode) state.getChild(toId(Schemas.QNAME)).get();
240         final MapNode schemaParent = (MapNode) schemas.getChild(toId(Schema.QNAME)).get();
241         assertEquals(1, Iterables.size(schemaParent.getValue()));
242
243         assertEquals(schemaNode, schemaParent.getValue().iterator().next());
244     }
245
246     @Test
247     public void testGetConfigLeafRequest() throws Exception {
248         final DataContainerChild<?, ?> filter = toFilterStructure(
249                 YangInstanceIdentifier.create(toId(NetconfState.QNAME), toId(Schemas.QNAME), toId(Schema.QNAME),
250                     new NodeIdentifierWithPredicates(Schema.QNAME, ImmutableMap.of()),
251                     toId(QName.create(Schemas.QNAME, "version"))), schema);
252
253         final DataContainerChild<?, ?> source = NetconfBaseOps.getSourceNode(NETCONF_RUNNING_QNAME);
254
255         final NetconfMessage netconfMessage = netconfMessageTransformer.toRpcRequest(toPath(NETCONF_GET_CONFIG_QNAME),
256                 NetconfMessageTransformUtil.wrap(NETCONF_GET_CONFIG_QNAME, source, filter));
257
258         assertSimilarXml(netconfMessage, "<rpc message-id=\"m-0\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
259                 + "<get-config xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
260                 + "<filter xmlns:ns0=\"urn:ietf:params:xml:ns:netconf:base:1.0\" ns0:type=\"subtree\">\n"
261                 + "<netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n"
262                 + "<schemas>\n"
263                 + "<schema>\n"
264                 + "<version/>\n"
265                 + "</schema>\n"
266                 + "</schemas>\n"
267                 + "</netconf-state>\n"
268                 + "</filter>\n"
269                 + "<source>\n"
270                 + "<running/>\n"
271                 + "</source>\n"
272                 + "</get-config>\n"
273                 + "</rpc>");
274     }
275
276     @Test
277     public void testGetConfigRequest() throws Exception {
278         final DataContainerChild<?, ?> filter = toFilterStructure(
279                 YangInstanceIdentifier.create(toId(NetconfState.QNAME), toId(Schemas.QNAME)), schema);
280
281         final DataContainerChild<?, ?> source = NetconfBaseOps.getSourceNode(NETCONF_RUNNING_QNAME);
282
283         final NetconfMessage netconfMessage = netconfMessageTransformer.toRpcRequest(toPath(NETCONF_GET_CONFIG_QNAME),
284                 NetconfMessageTransformUtil.wrap(NETCONF_GET_CONFIG_QNAME, source, filter));
285
286         assertSimilarXml(netconfMessage, "<rpc message-id=\"m-0\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
287                 + "<get-config xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
288                 + "<filter xmlns:ns0=\"urn:ietf:params:xml:ns:netconf:base:1.0\" ns0:type=\"subtree\">\n"
289                 + "<netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n"
290                 + "<schemas/>\n"
291                 + "</netconf-state>"
292                 + "</filter>\n"
293                 + "<source>\n"
294                 + "<running/>\n"
295                 + "</source>\n"
296                 + "</get-config>"
297                 + "</rpc>");
298     }
299
300     @Test
301     public void testEditConfigRequest() throws Exception {
302         final List<DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?>> values = Lists.newArrayList(
303                 NetconfRemoteSchemaYangSourceProvider
304                         .createGetSchemaRequest("module", Optional.of("2012-12-12")).getValue());
305
306         final Map<QName, Object> keys = new HashMap<>();
307         for (final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> value : values) {
308             keys.put(value.getNodeType(), value.getValue());
309         }
310
311         final YangInstanceIdentifier.NodeIdentifierWithPredicates identifierWithPredicates =
312                 new YangInstanceIdentifier.NodeIdentifierWithPredicates(Schema.QNAME, keys);
313         final MapEntryNode schemaNode =
314                 Builders.mapEntryBuilder().withNodeIdentifier(identifierWithPredicates).withValue(values).build();
315
316         final YangInstanceIdentifier id = YangInstanceIdentifier.builder()
317                 .node(NetconfState.QNAME).node(Schemas.QNAME).node(Schema.QNAME)
318                 .nodeWithKey(Schema.QNAME, keys).build();
319         final DataContainerChild<?, ?> editConfigStructure =
320                 createEditConfigStructure(BaseSchema.BASE_NETCONF_CTX_WITH_NOTIFICATIONS.getSchemaContext(), id,
321                     Optional.empty(), Optional.ofNullable(schemaNode));
322
323         final DataContainerChild<?, ?> target = NetconfBaseOps.getTargetNode(NETCONF_CANDIDATE_QNAME);
324
325         final ContainerNode wrap =
326                 NetconfMessageTransformUtil.wrap(NETCONF_EDIT_CONFIG_QNAME, editConfigStructure, target);
327         final NetconfMessage netconfMessage =
328                 netconfMessageTransformer.toRpcRequest(toPath(NETCONF_EDIT_CONFIG_QNAME), wrap);
329
330         assertSimilarXml(netconfMessage, "<rpc message-id=\"m-0\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
331                 + "<edit-config>\n"
332                 + "<target>\n"
333                 + "<candidate/>\n"
334                 + "</target>\n"
335                 + "<config>\n"
336                 + "<netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n"
337                 + "<schemas>\n"
338                 + "<schema>\n"
339                 + "<identifier>module</identifier>\n"
340                 + "<version>2012-12-12</version>\n"
341                 + "<format>yang</format>\n"
342                 + "</schema>\n"
343                 + "</schemas>\n"
344                 + "</netconf-state>\n"
345                 + "</config>\n"
346                 + "</edit-config>\n"
347                 + "</rpc>");
348     }
349
350     private static void assertSimilarXml(final NetconfMessage netconfMessage, final String xmlContent)
351             throws SAXException, IOException {
352         final Diff diff = XMLUnit.compareXML(netconfMessage.getDocument(), XmlUtil.readXmlToDocument(xmlContent));
353         diff.overrideElementQualifier(new ElementNameAndAttributeQualifier());
354         assertTrue(diff.toString(), diff.similar());
355     }
356
357     @Test
358     public void testGetRequest() throws Exception {
359
360         final QName capability = QName.create(Capabilities.QNAME, "capability");
361         final DataContainerChild<?, ?> filter = toFilterStructure(
362                 YangInstanceIdentifier.create(toId(NetconfState.QNAME), toId(Capabilities.QNAME), toId(capability),
363                     new YangInstanceIdentifier.NodeWithValue<>(capability, "a:b:c")), schema);
364
365         final NetconfMessage netconfMessage = netconfMessageTransformer.toRpcRequest(toPath(NETCONF_GET_QNAME),
366                 NetconfMessageTransformUtil.wrap(NETCONF_GET_QNAME, filter));
367
368         assertSimilarXml(netconfMessage, "<rpc message-id=\"m-0\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
369                 + "<get xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
370                 + "<filter xmlns:ns0=\"urn:ietf:params:xml:ns:netconf:base:1.0\" ns0:type=\"subtree\">\n"
371                 + "<netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n"
372                 + "<capabilities>\n"
373                 + "<capability>a:b:c</capability>\n"
374                 + "</capabilities>\n"
375                 + "</netconf-state>"
376                 + "</filter>\n"
377                 + "</get>"
378                 + "</rpc>");
379     }
380
381     private static NetconfMessageTransformer getTransformer(final SchemaContext schema) {
382         return new NetconfMessageTransformer(schema, true);
383     }
384
385     @Test
386     public void testCommitResponse() throws Exception {
387         final NetconfMessage response = new NetconfMessage(XmlUtil.readXmlToDocument(
388                 "<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><ok/></rpc-reply>"
389         ));
390         final DOMRpcResult compositeNodeRpcResult =
391                 netconfMessageTransformer.toRpcResult(response, toPath(NETCONF_COMMIT_QNAME));
392         assertTrue(compositeNodeRpcResult.getErrors().isEmpty());
393         assertNull(compositeNodeRpcResult.getResult());
394     }
395
396     public SchemaContext getSchema(final boolean addBase) {
397         final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
398         if (addBase) {
399             moduleInfoBackedContext.addModuleInfos(Collections.singleton($YangModuleInfoImpl.getInstance()));
400         }
401         moduleInfoBackedContext
402                 .addModuleInfos(Collections.singleton(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
403                         .netconf.monitoring.rev101004.$YangModuleInfoImpl.getInstance()));
404         return moduleInfoBackedContext.tryToCreateSchemaContext().get();
405     }
406
407     @Test
408     public void getActionsTest() {
409         QName reset = QName.create(URN_EXAMPLE_SERVER_FARM, REVISION_EXAMPLE_SERVER_FARM, "reset");
410         QName start = QName.create(reset, "start");
411         QName open = QName.create(start, "open");
412         QName enable = QName.create(open, "enable");
413         QName kill = QName.create(URN_EXAMPLE_SERVER_FARM_2, REVISION_EXAMPLE_SERVER_FARM_2, "kill");
414         Set<QName> qnames = new HashSet<>(Arrays.asList(reset, start, open, enable, kill));
415         Set<ActionDefinition> actions = actionNetconfMessageTransformer.getActions();
416         assertTrue(!actions.isEmpty());
417         for (ActionDefinition actionDefinition : actions) {
418             QName qname = actionDefinition.getQName();
419             assertTrue(qnames.contains(qname));
420             qnames.remove(qname);
421         }
422     }
423
424     @Test
425     public void toActionRequestListTopLevelTest() {
426         QName qname = QName.create(URN_EXAMPLE_SERVER_FARM, REVISION_EXAMPLE_SERVER_FARM, "server");
427         QName nameQname = QName.create(qname, "name");
428         QName actionResetQName = QName.create(qname, "reset");
429         List<PathArgument> nodeIdentifiers = new ArrayList<>();
430         nodeIdentifiers.add(new NodeIdentifier(qname));
431         nodeIdentifiers.add(new NodeIdentifierWithPredicates(qname, nameQname, "test"));
432         DOMDataTreeIdentifier domDataTreeIdentifier = prepareDataTreeId(nodeIdentifiers);
433
434         ContainerNode data = initInputAction(QName.create(qname, "reset-at"), "now");
435
436         NetconfMessage actionRequest = actionNetconfMessageTransformer.toActionRequest(
437                 SchemaPath.create(true, actionResetQName), domDataTreeIdentifier, data);
438
439         Node childAction = checkBasePartOfActionRequest(actionRequest);
440
441         Node childServer = childAction.getFirstChild();
442         checkNode(childServer, "server", "server", qname.getNamespace().toString());
443
444         Node childName = childServer.getFirstChild();
445         checkNode(childName, "name", "name", qname.getNamespace().toString());
446
447         Node childTest = childName.getFirstChild();
448         assertEquals(childTest.getNodeValue(), "test");
449
450         checkAction(actionResetQName, childName.getNextSibling(), "reset-at", "reset-at", "now");
451     }
452
453     @Test
454     public void toActionRequestContainerTopLevelTest() {
455         QName qname = QName.create(URN_EXAMPLE_SERVER_FARM, REVISION_EXAMPLE_SERVER_FARM, "device");
456         QName actionStartQName = QName.create(qname, "start");
457
458         List<PathArgument> nodeIdentifiers = Collections.singletonList(NodeIdentifier.create(qname));
459         DOMDataTreeIdentifier domDataTreeIdentifier = prepareDataTreeId(nodeIdentifiers);
460
461         NormalizedNode<?, ?> payload = initInputAction(QName.create(qname, "start-at"), "now");
462         NetconfMessage actionRequest = actionNetconfMessageTransformer.toActionRequest(
463                 SchemaPath.create(true, actionStartQName), domDataTreeIdentifier, payload);
464
465         Node childAction = checkBasePartOfActionRequest(actionRequest);
466
467         Node childDevice = childAction.getFirstChild();
468         checkNode(childDevice, "device", "device", qname.getNamespace().toString());
469
470         checkAction(actionStartQName, childDevice.getFirstChild(), "start-at", "start-at", "now");
471     }
472
473     @Test
474     public void toActionRequestContainerInContainerTest() {
475         QName boxOutQName = QName.create(URN_EXAMPLE_SERVER_FARM, REVISION_EXAMPLE_SERVER_FARM, "box-out");
476         QName boxInQName = QName.create(URN_EXAMPLE_SERVER_FARM, REVISION_EXAMPLE_SERVER_FARM, "box-in");
477         QName actionOpenQName = QName.create(boxOutQName, "open");
478
479         List<PathArgument> nodeIdentifiers = new ArrayList<>();
480         nodeIdentifiers.add(NodeIdentifier.create(boxOutQName));
481         nodeIdentifiers.add(NodeIdentifier.create(boxInQName));
482
483         DOMDataTreeIdentifier domDataTreeIdentifier = prepareDataTreeId(nodeIdentifiers);
484
485         NormalizedNode<?, ?> payload = initInputAction(QName.create(boxOutQName, "start-at"), "now");
486         NetconfMessage actionRequest = actionNetconfMessageTransformer.toActionRequest(
487                 SchemaPath.create(true, actionOpenQName), domDataTreeIdentifier, payload);
488
489         Node childAction = checkBasePartOfActionRequest(actionRequest);
490
491         Node childBoxOut = childAction.getFirstChild();
492         checkNode(childBoxOut, "box-out", "box-out", boxOutQName.getNamespace().toString());
493
494         Node childBoxIn = childBoxOut.getFirstChild();
495         checkNode(childBoxIn, "box-in", "box-in", boxOutQName.getNamespace().toString());
496
497         Node action = childBoxIn.getFirstChild();
498         checkNode(action, null, actionOpenQName.getLocalName(), null);
499     }
500
501     @Test
502     public void toActionRequestListInContainerTest() {
503         QName qnameDevice = QName.create(URN_EXAMPLE_SERVER_FARM, REVISION_EXAMPLE_SERVER_FARM, "device");
504         QName qnameInterface = QName.create(URN_EXAMPLE_SERVER_FARM, REVISION_EXAMPLE_SERVER_FARM, "interface");
505         QName nameQname = QName.create(qnameInterface, "name");
506         QName actionEnableQName = QName.create(qnameInterface, "enable");
507
508         List<PathArgument> nodeIdentifiers = new ArrayList<>();
509         nodeIdentifiers.add(NodeIdentifier.create(qnameDevice));
510         nodeIdentifiers.add(NodeIdentifier.create(qnameInterface));
511         nodeIdentifiers.add(new NodeIdentifierWithPredicates(qnameInterface, nameQname, "test"));
512
513         DOMDataTreeIdentifier domDataTreeIdentifier = prepareDataTreeId(nodeIdentifiers);
514
515         NormalizedNode<?, ?> payload = initEmptyInputAction(qnameInterface);
516         NetconfMessage actionRequest = actionNetconfMessageTransformer.toActionRequest(
517                 SchemaPath.create(true, actionEnableQName), domDataTreeIdentifier, payload);
518
519         Node childAction = checkBasePartOfActionRequest(actionRequest);
520
521         Node childDevice = childAction.getFirstChild();
522         checkNode(childDevice, "device", "device", qnameDevice.getNamespace().toString());
523
524         Node childInterface = childDevice.getFirstChild();
525         checkNode(childInterface, "interface", "interface", qnameInterface.getNamespace().toString());
526
527         Node childName = childInterface.getFirstChild();
528         checkNode(childName, "name", "name", nameQname.getNamespace().toString());
529
530         Node childTest = childName.getFirstChild();
531         assertEquals(childTest.getNodeValue(), "test");
532
533         Node action = childInterface.getLastChild();
534         checkNode(action, null, actionEnableQName.getLocalName(), null);
535     }
536
537     @Test
538     public void toActionRequestListInContainerAugmentedIntoListTest() {
539         QName qnameServer = QName.create(URN_EXAMPLE_SERVER_FARM, REVISION_EXAMPLE_SERVER_FARM, "server");
540         QName serverNameQname = QName.create(qnameServer, "name");
541         QName qnameAppliactions = QName.create(URN_EXAMPLE_SERVER_FARM_2,
542                 REVISION_EXAMPLE_SERVER_FARM_2, "applications");
543         QName qnameAppliaction = QName.create(URN_EXAMPLE_SERVER_FARM_2,
544                 REVISION_EXAMPLE_SERVER_FARM_2, "application");
545         QName applicationNameQname = QName.create(qnameAppliaction, "name");
546         QName actionKillQName = QName.create(qnameAppliaction, "kill");
547
548         List<PathArgument> nodeIdentifiers = new ArrayList<>();
549         nodeIdentifiers.add(NodeIdentifier.create(qnameServer));
550         nodeIdentifiers.add(new NodeIdentifierWithPredicates(qnameServer, serverNameQname, "testServer"));
551         nodeIdentifiers.add(new YangInstanceIdentifier
552                 .AugmentationIdentifier(Collections.singleton(qnameAppliactions)));
553         nodeIdentifiers.add(NodeIdentifier.create(qnameAppliactions));
554         nodeIdentifiers.add(NodeIdentifier.create(qnameAppliaction));
555         nodeIdentifiers.add(new NodeIdentifierWithPredicates(qnameAppliaction,
556                 applicationNameQname, "testApplication"));
557
558         DOMDataTreeIdentifier domDataTreeIdentifier = prepareDataTreeId(nodeIdentifiers);
559
560         NormalizedNode<?, ?> payload = initEmptyInputAction(qnameAppliaction);
561         NetconfMessage actionRequest = actionNetconfMessageTransformer.toActionRequest(
562                 SchemaPath.create(true, actionKillQName), domDataTreeIdentifier, payload);
563
564         Node childAction = checkBasePartOfActionRequest(actionRequest);
565
566         Node childServer = childAction.getFirstChild();
567         checkNode(childServer, "server", "server", qnameServer.getNamespace().toString());
568
569         Node childServerName = childServer.getFirstChild();
570         checkNode(childServerName, "name", "name", serverNameQname.getNamespace().toString());
571
572         Node childServerNameTest = childServerName.getFirstChild();
573         assertEquals(childServerNameTest.getNodeValue(), "testServer");
574
575         Node childApplications = childServer.getLastChild();
576         checkNode(childApplications, "applications", "applications", qnameAppliactions.getNamespace().toString());
577
578         Node childApplication = childApplications.getFirstChild();
579         checkNode(childApplication, "application", "application", qnameAppliaction.getNamespace().toString());
580
581         Node childApplicationName = childApplication.getFirstChild();
582         checkNode(childApplicationName, "name", "name", applicationNameQname.getNamespace().toString());
583
584         Node childApplicationNameTest = childApplicationName.getFirstChild();
585         assertEquals(childApplicationNameTest.getNodeValue(), "testApplication");
586
587         Node childKillAction = childApplication.getLastChild();
588         checkNode(childApplication, "application", "application", qnameAppliaction.getNamespace().toString());
589         checkNode(childKillAction, null, actionKillQName.getLocalName(), null);
590     }
591
592     @SuppressWarnings({ "rawtypes", "unchecked" })
593     @Test
594     public void toActionResultTest() throws Exception {
595         QName qname = QName.create(URN_EXAMPLE_SERVER_FARM, REVISION_EXAMPLE_SERVER_FARM, "reset");
596
597         NetconfMessage message = new NetconfMessage(XmlUtil.readXmlToDocument(
598                 "<rpc-reply message-id=\"101\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
599                 + "<reset-finished-at xmlns=\"urn:example:server-farm\">"
600                 + "now"
601                 + "</reset-finished-at>"
602                 + "</rpc-reply>"));
603         DOMActionResult actionResult = actionNetconfMessageTransformer.toActionResult(
604                 SchemaPath.create(true, qname), message);
605         assertNotNull(actionResult);
606         ContainerNode containerNode = actionResult.getOutput().get();
607         assertNotNull(containerNode);
608         LeafNode<String> leaf = (LeafNode) containerNode.getValue().iterator().next();
609         assertEquals("now", leaf.getValue());
610     }
611
612     private static void checkAction(final QName actionQname, final Node action , final String inputLocalName,
613             final String inputNodeName, final String inputValue) {
614         checkNode(action, null, actionQname.getLocalName(), null);
615
616         Node childResetAt = action.getFirstChild();
617         checkNode(childResetAt, inputLocalName, inputNodeName, actionQname.getNamespace().toString());
618
619         Node firstChild = childResetAt.getFirstChild();
620         assertEquals(firstChild.getNodeValue(), inputValue);
621     }
622
623     private static Node checkBasePartOfActionRequest(final NetconfMessage actionRequest) {
624         Node baseRpc = actionRequest.getDocument().getFirstChild();
625         checkNode(baseRpc, "rpc", "rpc", NetconfMessageTransformUtil.NETCONF_QNAME.getNamespace().toString());
626         assertTrue(baseRpc.getLocalName().equals("rpc"));
627         assertTrue(baseRpc.getNodeName().equals("rpc"));
628
629         Node messageId = baseRpc.getAttributes().getNamedItem("message-id");
630         assertNotNull(messageId);
631         assertTrue(messageId.getNodeValue().contains("m-"));
632
633         Node childAction = baseRpc.getFirstChild();
634         checkNode(childAction, "action", "action", NetconfMessageTransformUtil.NETCONF_ACTION_NAMESPACE.toString());
635         return childAction;
636     }
637
638     private static DOMDataTreeIdentifier prepareDataTreeId(final List<PathArgument> nodeIdentifiers) {
639         YangInstanceIdentifier yangInstanceIdentifier =
640                 YangInstanceIdentifier.builder().append(nodeIdentifiers).build();
641         DOMDataTreeIdentifier domDataTreeIdentifier =
642                 new DOMDataTreeIdentifier(org.opendaylight.mdsal.common.api.LogicalDatastoreType.CONFIGURATION,
643                         yangInstanceIdentifier);
644         return domDataTreeIdentifier;
645     }
646
647     private static ContainerNode initInputAction(final QName qname, final String value) {
648         ImmutableLeafNodeBuilder<String> immutableLeafNodeBuilder = new ImmutableLeafNodeBuilder<>();
649         DataContainerChild<NodeIdentifier, String> build = immutableLeafNodeBuilder.withNodeIdentifier(
650                 NodeIdentifier.create(qname)).withValue(value).build();
651         ContainerNode data = ImmutableContainerNodeBuilder.create().withNodeIdentifier(NodeIdentifier.create(
652                 QName.create(qname, "input"))).withChild(build).build();
653         return data;
654     }
655
656     private static ContainerNode initEmptyInputAction(final QName qname) {
657         return ImmutableContainerNodeBuilder.create().withNodeIdentifier(NodeIdentifier.create(
658                 QName.create(qname, "input"))).build();
659     }
660
661     private static void checkNode(final Node childServer, final String expectedLocalName, final String expectedNodeName,
662             final String expectedNamespace) {
663         assertNotNull(childServer);
664         assertEquals(childServer.getLocalName(), expectedLocalName);
665         assertEquals(childServer.getNodeName(), expectedNodeName);
666         assertEquals(childServer.getNamespaceURI(), expectedNamespace);
667     }
668
669     private static SchemaContext getActionSchema() {
670         return YangParserTestUtils.parseYangResources(NetconfMessageTransformerTest.class,
671                 "/schemas/example-server-farm.yang","/schemas/example-server-farm-2.yang");
672     }
673
674     private static NetconfMessageTransformer getActionMessageTransformer() {
675         return new NetconfMessageTransformer(getActionSchema(), true);
676     }
677 }