Merge "BUG 1839 - HTTP delete of non existing data"
[controller.git] / opendaylight / md-sal / sal-rest-connector / src / test / java / org / opendaylight / controller / sal / restconf / impl / json / to / cnsn / test / JsonToCnSnTest.java
1 /*
2  * Copyright (c) 2014 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.controller.sal.restconf.impl.json.to.cnsn.test;
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.assertTrue;
14 import static org.junit.Assert.fail;
15
16 import java.io.ByteArrayInputStream;
17 import java.io.InputStream;
18 import java.util.HashSet;
19 import java.util.List;
20 import java.util.Set;
21 import org.junit.Ignore;
22 import org.junit.Test;
23 import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider;
24 import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
25 import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
26 import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
27 import org.opendaylight.yangtools.yang.common.QName;
28 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
29 import org.opendaylight.yangtools.yang.data.api.Node;
30 import org.opendaylight.yangtools.yang.data.api.SimpleNode;
31 import org.opendaylight.yangtools.yang.model.api.Module;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 public class JsonToCnSnTest {
36
37     private static final Logger LOG = LoggerFactory.getLogger(JsonToCnSnTest.class);
38
39     @Test
40     public void simpleListTest() {
41         simpleTest("/json-to-cnsn/simple-list.json", "/json-to-cnsn/simple-list-yang/1", "lst", "simple:list:yang1",
42                 "simple-list-yang1");
43     }
44
45     @Test
46     public void simpleContainerTest() {
47         simpleTest("/json-to-cnsn/simple-container.json", "/json-to-cnsn/simple-container-yang", "cont",
48                 "simple:container:yang", "simple-container-yang");
49     }
50
51     /**
52      * test if for every leaf list item is simple node instance created
53      */
54     @Test
55     public void multipleItemsInLeafList() {
56         Node<?> node = TestUtils.readInputToCnSn("/json-to-cnsn/multiple-leaflist-items.json", true,
57                 JsonToCompositeNodeProvider.INSTANCE);
58         assertNotNull(node);
59         assertTrue(node instanceof CompositeNode);
60         CompositeNode compositeNode = (CompositeNode)node;
61         assertEquals(3, compositeNode.getValue().size());
62
63         boolean lflst1_1 = false;
64         boolean lflst1_2 = false;
65         boolean lflst1_3 = false;
66
67         for (Node<?> nd : compositeNode.getValue()) {
68             assertEquals("lflst1", nd.getNodeType().getLocalName());
69             assertTrue(nd instanceof SimpleNode<?>);
70             SimpleNode<?> simpleNode = (SimpleNode<?>) nd;
71             if (simpleNode.getValue().equals("45")) {
72                 lflst1_1 = true;
73             } else if (simpleNode.getValue().equals("55")) {
74                 lflst1_2 = true;
75             } else if (simpleNode.getValue().equals("66")) {
76                 lflst1_3 = true;
77             }
78         }
79
80         assertTrue(lflst1_1);
81         assertTrue(lflst1_2);
82         assertTrue(lflst1_3);
83
84     }
85
86     /**
87      * List contains 4 items and in every item are other elements. It is supposed that there should be: lf11, lflst11,
88      * cont11, lst11
89      */
90     @Test
91     public void multipleItemsInListTest() {
92         Node<?> node = TestUtils.readInputToCnSn("/json-to-cnsn/multiple-items-in-list.json", true,
93                 JsonToCompositeNodeProvider.INSTANCE);
94
95         assertTrue(node instanceof CompositeNode);
96         CompositeNode compositeNode = (CompositeNode)node;
97
98         assertNotNull(compositeNode);
99         assertEquals("lst", compositeNode.getNodeType().getLocalName());
100
101         verityMultipleItemsInList(compositeNode);
102     }
103
104     @Test
105     public void nullArrayToSimpleNodeWithNullValueTest() {
106         Node<?> node = TestUtils.readInputToCnSn("/json-to-cnsn/array-with-null.json", true,
107                 JsonToCompositeNodeProvider.INSTANCE);
108         assertTrue(node instanceof CompositeNode);
109         CompositeNode compositeNode = (CompositeNode)node;
110         assertEquals("cont", compositeNode.getNodeType().getLocalName());
111
112         assertNotNull(compositeNode.getValue());
113         assertEquals(1, compositeNode.getValue().size());
114         Node<?> lfNode = compositeNode.getValue().iterator().next();
115
116         assertTrue(lfNode instanceof SimpleNode<?>);
117         assertEquals(null, ((SimpleNode<?>) lfNode).getValue());
118
119     }
120
121     @Test
122     public void incorrectTopLevelElementsTest() {
123         RestconfDocumentedException cause1 = null;
124         try {
125             TestUtils
126                     .readInputToCnSn("/json-to-cnsn/wrong-top-level1.json", true, JsonToCompositeNodeProvider.INSTANCE);
127         } catch (RestconfDocumentedException e) {
128             cause1 = e;
129         }
130
131         assertNotNull(cause1);
132         assertTrue(cause1
133                 .getErrors()
134                 .get(0)
135                 .getErrorMessage()
136                 .contains(
137                         "First element in Json Object has to be \"Object\" or \"Array with one Object element\". Other scenarios are not supported yet."));
138
139         RestconfDocumentedException cause2 = null;
140         try {
141             TestUtils
142                     .readInputToCnSn("/json-to-cnsn/wrong-top-level2.json", true, JsonToCompositeNodeProvider.INSTANCE);
143         } catch (RestconfDocumentedException e) {
144             cause2 = e;
145         }
146         assertNotNull(cause2);
147         assertTrue(cause2.getErrors().get(0).getErrorMessage().contains("Json Object should contain one element"));
148
149         RestconfDocumentedException cause3 = null;
150         try {
151             TestUtils
152
153             .readInputToCnSn("/json-to-cnsn/wrong-top-level3.json", true, JsonToCompositeNodeProvider.INSTANCE);
154         } catch (RestconfDocumentedException e) {
155             cause3 = e;
156         }
157         assertNotNull(cause3);
158         assertTrue(cause3
159                 .getErrors()
160                 .get(0)
161                 .getErrorMessage()
162                 .contains(
163                         "First element in Json Object has to be \"Object\" or \"Array with one Object element\". Other scenarios are not supported yet."));
164
165     }
166
167     /**
168      * if leaf list with no data is in json then no corresponding data is created in composite node. if leaf with no
169      * data then exception is raised
170      */
171     @Test
172     public void emptyDataReadTest() {
173         Node<?> node = TestUtils.readInputToCnSn("/json-to-cnsn/empty-data.json", true,
174                 JsonToCompositeNodeProvider.INSTANCE);
175         assertTrue(node instanceof CompositeNode);
176         CompositeNode compositeNode = (CompositeNode)node;
177
178         assertEquals("cont", compositeNode.getNodeType().getLocalName());
179         assertTrue(compositeNode instanceof CompositeNode);
180         List<Node<?>> children = compositeNode.getValue();
181         assertEquals(1, children.size());
182         assertEquals("lflst2", children.get(0).getNodeType().getLocalName());
183         assertEquals("45", children.get(0).getValue());
184
185         String reason = null;
186         try {
187             TestUtils.readInputToCnSn("/json-to-cnsn/empty-data1.json", true, JsonToCompositeNodeProvider.INSTANCE);
188         } catch (RestconfDocumentedException e) {
189             reason = e.getErrors().get(0).getErrorMessage();
190         }
191
192         assertTrue(reason.contains("Expected value at line"));
193
194     }
195
196     @Test
197     public void testJsonBlankInput() throws Exception {
198         InputStream inputStream = new ByteArrayInputStream("".getBytes());
199         Node<?> node =
200                 JsonToCompositeNodeProvider.INSTANCE.readFrom(null, null, null, null, null, inputStream);
201         assertNull( node );
202     }
203
204     /**
205      * Tests whether namespace <b>stay unchanged</b> if concrete values are present in composite or simple node and if
206      * the method for update is called.
207      *
208      */
209     @Test
210     public void notSupplyNamespaceIfAlreadySupplied() {
211
212         Node<?> node = TestUtils.readInputToCnSn("/json-to-cnsn/simple-list.json", false,
213                 JsonToCompositeNodeProvider.INSTANCE);
214         assertTrue(node instanceof CompositeNode);
215         CompositeNode compositeNode = (CompositeNode)node;
216
217         // supplement namespaces according to first data schema -
218         // "simple:data:types1"
219         Set<Module> modules1 = new HashSet<>();
220         Set<Module> modules2 = new HashSet<>();
221         modules1 = TestUtils.loadModulesFrom("/json-to-cnsn/simple-list-yang/1");
222         modules2 = TestUtils.loadModulesFrom("/json-to-cnsn/simple-list-yang/2");
223         assertNotNull(modules1);
224         assertNotNull(modules2);
225
226         TestUtils.normalizeCompositeNode(compositeNode, modules1, "simple-list-yang1:lst");
227
228         assertTrue(compositeNode instanceof CompositeNodeWrapper);
229         CompositeNode compNode = ((CompositeNodeWrapper) compositeNode).unwrap();
230
231         assertEquals("lst", compNode.getNodeType().getLocalName());
232         verifyCompositeNode(compNode, "simple:list:yang1");
233
234         try {
235             TestUtils.normalizeCompositeNode(compositeNode, modules2, "simple-list-yang2:lst");
236             fail("Conversion to normalized node shouldn't be successfull because of different namespaces");
237         } catch (IllegalStateException e) {
238         }
239 //        veryfing has still meaning. despite exception, first phase where normalization of NodeWrappers is called passed successfuly.
240         verifyCompositeNode(compNode, "simple:list:yang1");
241     }
242
243     @Test
244     public void jsonIdentityrefToCompositeNode() {
245         Node<?> node = TestUtils.readInputToCnSn("/json-to-cnsn/identityref/json/data.json", false,
246                 JsonToCompositeNodeProvider.INSTANCE);
247         assertTrue(node instanceof CompositeNode);
248         CompositeNode compositeNode = (CompositeNode)node;
249
250         Set<Module> modules = TestUtils.loadModulesFrom("/json-to-cnsn/identityref");
251         assertEquals(2, modules.size());
252
253         TestUtils.normalizeCompositeNode(compositeNode, modules, "identityref-module:cont");
254
255         assertEquals("cont", compositeNode.getNodeType().getLocalName());
256
257         List<Node<?>> childs = compositeNode.getValue();
258         assertEquals(1, childs.size());
259         Node<?> nd = childs.iterator().next();
260         assertTrue(nd instanceof CompositeNode);
261         assertEquals("cont1", nd.getNodeType().getLocalName());
262
263         childs = ((CompositeNode) nd).getValue();
264         assertEquals(4, childs.size());
265         SimpleNode<?> lf11 = null;
266         SimpleNode<?> lf12 = null;
267         SimpleNode<?> lf13 = null;
268         SimpleNode<?> lf14 = null;
269         for (Node<?> child : childs) {
270             assertTrue(child instanceof SimpleNode);
271             if (child.getNodeType().getLocalName().equals("lf11")) {
272                 lf11 = (SimpleNode<?>) child;
273             } else if (child.getNodeType().getLocalName().equals("lf12")) {
274                 lf12 = (SimpleNode<?>) child;
275             } else if (child.getNodeType().getLocalName().equals("lf13")) {
276                 lf13 = (SimpleNode<?>) child;
277             } else if (child.getNodeType().getLocalName().equals("lf14")) {
278                 lf14 = (SimpleNode<?>) child;
279             }
280         }
281
282         assertTrue(lf11.getValue() instanceof QName);
283         assertEquals("iden", ((QName) lf11.getValue()).getLocalName());
284         assertEquals("identity:module", ((QName) lf11.getValue()).getNamespace().toString());
285
286         assertTrue(lf12.getValue() instanceof QName);
287         assertEquals("iden_local", ((QName) lf12.getValue()).getLocalName());
288         assertEquals("identityref:module", ((QName) lf12.getValue()).getNamespace().toString());
289
290         assertTrue(lf13.getValue() instanceof QName);
291         assertEquals("iden_local", ((QName) lf13.getValue()).getLocalName());
292         assertEquals("identityref:module", ((QName) lf13.getValue()).getNamespace().toString());
293
294         assertTrue(lf14.getValue() instanceof QName);
295         assertEquals("iden_local", ((QName) lf14.getValue()).getLocalName());
296         assertEquals("identity:module", ((QName) lf14.getValue()).getNamespace().toString());
297     }
298
299     @Ignore
300     @Test
301     public void loadDataAugmentedSchemaMoreEqualNamesTest() {
302         loadAndNormalizeData("/common/augment/json/dataa.json", "/common/augment/yang", "cont", "main");
303         loadAndNormalizeData("/common/augment/json/datab.json", "/common/augment/yang", "cont", "main");
304
305     }
306
307     private void simpleTest(final String jsonPath, final String yangPath, final String topLevelElementName,
308             final String namespace, final String moduleName) {
309         CompositeNode compNode = loadAndNormalizeData(jsonPath, yangPath, topLevelElementName, moduleName);
310         verifyCompositeNode(compNode, namespace);
311     }
312
313     private CompositeNode loadAndNormalizeData(final String jsonPath, final String yangPath,
314             final String topLevelElementName, final String moduleName) {
315         Node<?> node = TestUtils.readInputToCnSn(jsonPath, false, JsonToCompositeNodeProvider.INSTANCE);
316         assertTrue(node instanceof CompositeNode);
317         CompositeNode compositeNode = (CompositeNode)node;
318
319         Set<Module> modules = null;
320         modules = TestUtils.loadModulesFrom(yangPath);
321         assertNotNull(modules);
322
323         TestUtils.normalizeCompositeNode(compositeNode, modules, moduleName + ":" + topLevelElementName);
324
325         assertTrue(compositeNode instanceof CompositeNodeWrapper);
326         CompositeNode compNode = ((CompositeNodeWrapper) compositeNode).unwrap();
327
328         assertEquals(topLevelElementName, compNode.getNodeType().getLocalName());
329         return compNode;
330     }
331
332     private void verityMultipleItemsInList(final CompositeNode compositeNode) {
333         List<Node<?>> childrenNodes = compositeNode.getValue();
334         assertEquals(4, childrenNodes.size());
335         boolean lf11Found = false;
336         boolean cont11Found = false;
337         boolean lst11Found = false;
338         for (Node<?> lst1Item : childrenNodes) {
339             assertEquals("lst1", lst1Item.getNodeType().getLocalName());
340             assertTrue(lst1Item instanceof CompositeNode);
341
342             List<Node<?>> childrenLst1 = ((CompositeNode) lst1Item).getValue();
343             assertEquals(1, childrenLst1.size());
344             String localName = childrenLst1.get(0).getNodeType().getLocalName();
345             if (localName.equals("lf11")) {
346                 assertTrue(childrenLst1.get(0) instanceof SimpleNode);
347                 lf11Found = true;
348             } else if (localName.equals("lflst11")) {
349                 assertTrue(childrenLst1.get(0) instanceof SimpleNode);
350                 assertEquals("45", ((SimpleNode<?>) childrenLst1.get(0)).getValue());
351                 lf11Found = true;
352             } else if (localName.equals("cont11")) {
353                 assertTrue(childrenLst1.get(0) instanceof CompositeNode);
354                 cont11Found = true;
355             } else if (localName.equals("lst11")) {
356                 lst11Found = true;
357                 assertTrue(childrenLst1.get(0) instanceof CompositeNode);
358                 assertEquals(0, ((CompositeNode) childrenLst1.get(0)).getValue().size());
359             }
360
361         }
362         assertTrue(lf11Found);
363         assertTrue(cont11Found);
364         assertTrue(lst11Found);
365     }
366
367     private void verifyCompositeNode(final CompositeNode compositeNode, final String namespace) {
368         boolean cont1Found = false;
369         boolean lst1Found = false;
370         boolean lflst1_1Found = false;
371         boolean lflst1_2Found = false;
372         boolean lf1Found = false;
373
374         // assertEquals(namespace,
375         // compositeNode.getNodeType().getNamespace().toString());
376
377         for (Node<?> node : compositeNode.getValue()) {
378             if (node.getNodeType().getLocalName().equals("cont1")) {
379                 if (node instanceof CompositeNode) {
380                     cont1Found = true;
381                     assertEquals(0, ((CompositeNode) node).getValue().size());
382                 }
383             } else if (node.getNodeType().getLocalName().equals("lst1")) {
384                 if (node instanceof CompositeNode) {
385                     lst1Found = true;
386                     assertEquals(0, ((CompositeNode) node).getValue().size());
387                 }
388             } else if (node.getNodeType().getLocalName().equals("lflst1")) {
389                 if (node instanceof SimpleNode) {
390                     if (((SimpleNode<?>) node).getValue().equals("lflst1_1")) {
391                         lflst1_1Found = true;
392                     } else if (((SimpleNode<?>) node).getValue().equals("lflst1_2")) {
393                         lflst1_2Found = true;
394                     }
395                 }
396
397             } else if (node.getNodeType().getLocalName().equals("lf1")) {
398                 if (node instanceof SimpleNode) {
399                     if (((SimpleNode<?>) node).getValue().equals("lf1")) {
400                         lf1Found = true;
401                     }
402                 }
403             }
404             assertEquals(namespace, node.getNodeType().getNamespace().toString());
405         }
406         assertTrue(cont1Found);
407         assertTrue(lst1Found);
408         assertTrue(lflst1_1Found);
409         assertTrue(lflst1_2Found);
410         assertTrue(lf1Found);
411     }
412
413     @Test
414     public void unsupportedDataFormatTest() {
415         String exceptionMessage = "";
416         try {
417             TestUtils.readInputToCnSn("/json-to-cnsn/unsupported-json-format.json", true,
418                     JsonToCompositeNodeProvider.INSTANCE);
419         } catch (RestconfDocumentedException e) {
420             exceptionMessage = e.getErrors().get(0).getErrorMessage();
421         }
422         assertTrue(exceptionMessage.contains("Root element of Json has to be Object"));
423     }
424
425     /**
426      * Tests case when JSON input data value is in format string1:string2 and first string contain characters "<" or ">" (invalid URI characters).
427      *
428      * During loading data it is also interpreting as data value in moduleName:localName (potential leafref value).
429      * ModuleName part is transformed to URI which causes exception which is caught and URI value is null which cause that potential value in simple node is
430      * simple string (value from JSON input) and not IdentityValueDTO instance which is used for leaf-ref candidates.
431      */
432     @Test
433     public void invalidUriCharacterInValue() {
434         final Node<?> rootNode = TestUtils.readInputToCnSn("/json-to-cnsn/invalid-uri-character-in-value.json", true,
435                     JsonToCompositeNodeProvider.INSTANCE);
436
437         assertTrue(rootNode instanceof CompositeNode);
438         Node<?> lf1 = null;
439         Node<?> lf2 = null;
440         for(Node<?> child : ((CompositeNode)rootNode).getChildren()) {
441             if (child.getNodeType().getLocalName().equals("lf1")) {
442                 lf1 = child;
443             } else if (child.getNodeType().getLocalName().equals("lf2")) {
444                 lf2 = child;
445             }
446         }
447
448         assertNotNull(lf1);
449         assertNotNull(lf2);
450         assertTrue(lf1 instanceof SimpleNode<?>);
451         assertTrue(lf2 instanceof SimpleNode<?>);
452
453         assertEquals("module<Name:value lf1", ((SimpleNode<?>) lf1).getValue());
454         assertEquals("module>Name:value lf2", ((SimpleNode<?>) lf2).getValue());
455     }
456
457 }