a961f6a5af287b3371872ad3ee12a86a57b4cb5c
[controller.git] / opendaylight / md-sal / sal-clustering-commons / src / test / java / org / opendaylight / controller / cluster / datastore / node / utils / transformer / NormalizedNodePrunerTest.java
1 /*
2  * Copyright (c) 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
9 package org.opendaylight.controller.cluster.datastore.node.utils.transformer;
10
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertNull;
13 import static org.junit.Assert.assertTrue;
14 import static org.mockito.Mockito.mock;
15 import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntry;
16 import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntryBuilder;
17 import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapNodeBuilder;
18
19 import com.google.common.collect.Sets;
20 import java.io.IOException;
21 import java.util.concurrent.atomic.AtomicInteger;
22 import javax.xml.transform.dom.DOMSource;
23 import org.junit.Assert;
24 import org.junit.Before;
25 import org.junit.Test;
26 import org.mockito.MockitoAnnotations;
27 import org.opendaylight.controller.cluster.datastore.node.utils.NormalizedNodeNavigator;
28 import org.opendaylight.controller.cluster.datastore.util.TestModel;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
30 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
31 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
32 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
33 import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
34 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
35 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
36 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
37 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
38 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
39 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
40 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
41 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetEntryNodeBuilder;
42 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
43 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
44
45 public class NormalizedNodePrunerTest {
46     private static final SchemaContext NO_TEST_SCHEMA = TestModel.createTestContextWithoutTestSchema();
47     private static final SchemaContext NO_AUG_SCHEMA = TestModel.createTestContextWithoutAugmentationSchema();
48     private static final SchemaContext FULL_SCHEMA = TestModel.createTestContext();
49
50     @Before
51     public void setUp() {
52         MockitoAnnotations.initMocks(this);
53     }
54
55     private static NormalizedNodePruner prunerFullSchema(YangInstanceIdentifier path) {
56         return new NormalizedNodePruner(path, FULL_SCHEMA);
57     }
58
59     private static NormalizedNodePruner prunerNoAugSchema(YangInstanceIdentifier path) {
60         return new NormalizedNodePruner(path, NO_AUG_SCHEMA);
61     }
62
63     private static NormalizedNodePruner prunerNoTestSchema(YangInstanceIdentifier path) {
64         return new NormalizedNodePruner(path, NO_TEST_SCHEMA);
65     }
66
67     @Test
68     public void testNodesNotPrunedWhenSchemaPresent() throws IOException {
69         NormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH);
70
71         NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
72
73         NormalizedNode<?, ?> expected = createTestContainer();
74
75         normalizedNodeWriter.write(expected);
76
77         NormalizedNode<?, ?> actual = pruner.normalizedNode();
78
79         assertEquals(expected, actual);
80
81     }
82
83     @Test(expected = IllegalStateException.class)
84     public void testReusePruner() throws IOException {
85         NormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH);
86
87         NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
88
89         NormalizedNode<?, ?> expected = createTestContainer();
90
91         normalizedNodeWriter.write(expected);
92
93         NormalizedNode<?, ?> actual = pruner.normalizedNode();
94
95         assertEquals(expected, actual);
96
97         NormalizedNodeWriter.forStreamWriter(pruner).write(expected);
98
99     }
100
101
102     @Test
103     public void testNodesPrunedWhenAugmentationSchemaMissing() throws IOException {
104         NormalizedNodePruner pruner = prunerNoAugSchema(TestModel.TEST_PATH);
105
106         NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
107
108         NormalizedNode<?, ?> expected = createTestContainer();
109
110         normalizedNodeWriter.write(expected);
111
112         NormalizedNode<?, ?> actual = pruner.normalizedNode();
113
114         Assert.assertNotEquals(expected, actual);
115
116         // Asserting true here instead of checking actual value because I don't want this assertion to be fragile
117         assertTrue(countNodes(expected, "store:aug") > 0);
118
119         // All nodes from the augmentation module are gone from the resulting node
120         assertEquals(0, countNodes(actual, "store:aug"));
121     }
122
123     @Test
124     public void testNodesPrunedWhenTestSchemaMissing() throws IOException {
125         NormalizedNodePruner pruner = prunerNoTestSchema(TestModel.TEST_PATH);
126
127         NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
128
129         NormalizedNode<?, ?> expected = createTestContainer();
130
131         normalizedNodeWriter.write(expected);
132
133         NormalizedNode<?, ?> actual = pruner.normalizedNode();
134
135         // Since top level schema is missing null is returned
136         assertNull(actual);
137
138         // Asserting true here instead of checking actual value because I don't want this assertion to be fragile
139         assertTrue(countNodes(expected, "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test") > 0);
140
141     }
142
143     private static int countNodes(NormalizedNode<?,?> normalizedNode, final String namespaceFilter) {
144         if (normalizedNode == null) {
145             return 0;
146         }
147         final AtomicInteger count = new AtomicInteger();
148         new NormalizedNodeNavigator((level, parentPath, normalizedNode1) -> {
149             if (!(normalizedNode1.getIdentifier() instanceof AugmentationIdentifier)) {
150                 if (normalizedNode1.getIdentifier().getNodeType().getNamespace().toString().contains(namespaceFilter)) {
151                     count.incrementAndGet();
152                 }
153             }
154         }).navigate(YangInstanceIdentifier.EMPTY.toString(), normalizedNode);
155
156         return count.get();
157     }
158
159     @Test
160     public void testLeafNodeNotPrunedWhenHasNoParent() throws IOException {
161         NormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.DESC_QNAME));
162         NormalizedNode<?, ?> input = Builders.leafBuilder().withNodeIdentifier(
163                 new NodeIdentifier(TestModel.DESC_QNAME)).withValue("test").build();
164         NormalizedNodeWriter.forStreamWriter(pruner).write(input);
165
166         NormalizedNode<?, ?> actual = pruner.normalizedNode();
167         assertEquals("normalizedNode", input, actual);
168     }
169
170     @Test
171     public void testLeafNodePrunedWhenHasAugmentationParentAndSchemaMissing() throws IOException {
172         AugmentationIdentifier augId = new AugmentationIdentifier(Sets.newHashSet(TestModel.AUG_CONT_QNAME));
173         NormalizedNodePruner pruner = prunerFullSchema(YangInstanceIdentifier.builder()
174                 .node(TestModel.TEST_QNAME).node(TestModel.AUGMENTED_LIST_QNAME)
175                         .node(TestModel.AUGMENTED_LIST_QNAME).node(augId).build());
176         LeafNode<Object> child = Builders.leafBuilder().withNodeIdentifier(
177                 new NodeIdentifier(TestModel.INVALID_QNAME)).withValue("test").build();
178         NormalizedNode<?, ?> input = Builders.augmentationBuilder().withNodeIdentifier(augId).withChild(child).build();
179         NormalizedNodeWriter.forStreamWriter(pruner).write(input);
180
181         NormalizedNode<?, ?> actual = pruner.normalizedNode();
182         assertEquals("normalizedNode", Builders.augmentationBuilder().withNodeIdentifier(augId).build(), actual);
183     }
184
185     @Test
186     public void testLeafNodePrunedWhenHasNoParentAndSchemaMissing() throws IOException {
187         NormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.INVALID_QNAME));
188         NormalizedNode<?, ?> input = Builders.leafBuilder().withNodeIdentifier(
189                 new NodeIdentifier(TestModel.INVALID_QNAME)).withValue("test").build();
190         NormalizedNodeWriter.forStreamWriter(pruner).write(input);
191
192         NormalizedNode<?, ?> actual = pruner.normalizedNode();
193         assertNull(actual);
194     }
195
196
197     @Test
198     public void testLeafSetEntryNodeNotPrunedWhenHasNoParent() throws IOException {
199         NormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.SHOE_QNAME));
200         NormalizedNode<?, ?> input = Builders.leafSetEntryBuilder().withValue("puma").withNodeIdentifier(
201                 new NodeWithValue<>(TestModel.SHOE_QNAME, "puma")).build();
202         NormalizedNodeWriter.forStreamWriter(pruner).write(input);
203
204         NormalizedNode<?, ?> actual = pruner.normalizedNode();
205         assertEquals("normalizedNode", input, actual);
206     }
207
208     @Test
209     public void testLeafSetEntryNodeNotPrunedWhenHasParent() throws IOException {
210         NormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.SHOE_QNAME));
211         LeafSetEntryNode<Object> child = Builders.leafSetEntryBuilder().withValue("puma").withNodeIdentifier(
212                 new NodeWithValue<>(TestModel.SHOE_QNAME, "puma")).build();
213         NormalizedNode<?, ?> input = Builders.leafSetBuilder().withNodeIdentifier(
214                 new NodeIdentifier(TestModel.SHOE_QNAME)).withChild(child).build();
215         NormalizedNodeWriter.forStreamWriter(pruner).write(input);
216
217         NormalizedNode<?, ?> actual = pruner.normalizedNode();
218         assertEquals("normalizedNode", input, actual);
219     }
220
221     @Test
222     public void testLeafSetEntryNodePrunedWhenHasNoParentAndSchemaMissing() throws IOException {
223         NormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.INVALID_QNAME));
224         NormalizedNode<?, ?> input = Builders.leafSetEntryBuilder().withValue("test").withNodeIdentifier(
225                 new NodeWithValue<>(TestModel.INVALID_QNAME, "test")).build();
226         NormalizedNodeWriter.forStreamWriter(pruner).write(input);
227
228         NormalizedNode<?, ?> actual = pruner.normalizedNode();
229         assertNull(actual);
230     }
231
232     @Test
233     public void testLeafSetEntryNodePrunedWhenHasParentAndSchemaMissing() throws IOException {
234         NormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.INVALID_QNAME));
235         LeafSetEntryNode<Object> child = Builders.leafSetEntryBuilder().withValue("test").withNodeIdentifier(
236                 new NodeWithValue<>(TestModel.INVALID_QNAME, "test")).build();
237         NormalizedNode<?, ?> input = Builders.leafSetBuilder().withNodeIdentifier(
238                 new NodeIdentifier(TestModel.INVALID_QNAME)).withChild(child).build();
239         NormalizedNodeWriter.forStreamWriter(pruner).write(input);
240
241         NormalizedNode<?, ?> actual = pruner.normalizedNode();
242         assertNull(actual);
243     }
244
245     @Test
246     public void testAnyXMLNodeNotPrunedWhenHasNoParent() throws IOException {
247         NormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.ANY_XML_QNAME));
248         NormalizedNode<?, ?> input = Builders.anyXmlBuilder().withNodeIdentifier(
249                 new NodeIdentifier(TestModel.ANY_XML_QNAME)).withValue(mock(DOMSource.class)).build();
250         NormalizedNodeWriter.forStreamWriter(pruner).write(input);
251
252         NormalizedNode<?, ?> actual = pruner.normalizedNode();
253         assertEquals("normalizedNode", input, actual);
254     }
255
256
257     @Test
258     public void testAnyXMLNodeNotPrunedWhenHasParent() throws IOException {
259         NormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH);
260         AnyXmlNode child = Builders.anyXmlBuilder().withNodeIdentifier(
261                 new NodeIdentifier(TestModel.ANY_XML_QNAME)).withValue(mock(DOMSource.class)).build();
262         NormalizedNode<?, ?> input = Builders.containerBuilder().withNodeIdentifier(
263                 new NodeIdentifier(TestModel.TEST_QNAME)).withChild(child).build();
264         NormalizedNodeWriter.forStreamWriter(pruner).write(input);
265
266         NormalizedNode<?, ?> actual = pruner.normalizedNode();
267         assertEquals("normalizedNode", input, actual);
268     }
269
270     @Test
271     public void testAnyXmlNodePrunedWhenHasNoParentAndSchemaMissing() throws IOException {
272         NormalizedNodePruner pruner = prunerNoTestSchema(TestModel.TEST_PATH.node(TestModel.ANY_XML_QNAME));
273         NormalizedNode<?, ?> input = Builders.anyXmlBuilder().withNodeIdentifier(
274                 new NodeIdentifier(TestModel.ANY_XML_QNAME)).withValue(mock(DOMSource.class)).build();
275         NormalizedNodeWriter.forStreamWriter(pruner).write(input);
276
277         NormalizedNode<?, ?> actual = pruner.normalizedNode();
278         assertNull(actual);
279     }
280
281     @Test
282     public void testInnerContainerNodeWithFullPathPathNotPruned() throws IOException {
283         YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
284                 .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
285                 .node(TestModel.INNER_LIST_QNAME).nodeWithKey(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "one")
286                 .node(TestModel.INNER_CONTAINER_QNAME).build();
287         NormalizedNodePruner pruner = prunerFullSchema(path);
288
289         NormalizedNode<?, ?> input = ImmutableNodes.containerNode(TestModel.INNER_CONTAINER_QNAME);
290         NormalizedNodeWriter.forStreamWriter(pruner).write(input);
291
292         NormalizedNode<?, ?> actual = pruner.normalizedNode();
293         assertEquals("normalizedNode", input, actual);
294     }
295
296     @Test
297     public void testInnerContainerNodeWithFullPathPrunedWhenSchemaMissing() throws IOException {
298         YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
299                 .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
300                 .node(TestModel.INNER_LIST_QNAME).nodeWithKey(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "one")
301                 .node(TestModel.INVALID_QNAME).build();
302         NormalizedNodePruner pruner = prunerFullSchema(path);
303
304         NormalizedNode<?, ?> input = ImmutableNodes.containerNode(TestModel.INVALID_QNAME);
305         NormalizedNodeWriter.forStreamWriter(pruner).write(input);
306
307         NormalizedNode<?, ?> actual = pruner.normalizedNode();
308         assertNull(actual);
309     }
310
311     @Test
312     public void testInnerContainerNodeWithParentPathPrunedWhenSchemaMissing() throws IOException {
313         YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
314                 .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
315                 .build();
316         NormalizedNodePruner pruner = prunerFullSchema(path);
317
318         MapNode innerList = mapNodeBuilder(TestModel.INNER_LIST_QNAME).withChild(mapEntryBuilder(
319                 TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "one").withChild(
320                         ImmutableNodes.containerNode(TestModel.INVALID_QNAME)).build()).build();
321         NormalizedNode<?, ?> input = mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
322                 .withChild(innerList).build();
323         NormalizedNodeWriter.forStreamWriter(pruner).write(input);
324
325         NormalizedNode<?, ?> expected = mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
326                 .withChild(mapNodeBuilder(TestModel.INNER_LIST_QNAME).withChild(mapEntryBuilder(
327                     TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "one").build()).build()).build();
328         NormalizedNode<?, ?> actual = pruner.normalizedNode();
329         assertEquals("normalizedNode", expected, actual);
330     }
331
332     @Test
333     public void testInnerListNodeWithFullPathNotPruned() throws IOException {
334         YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
335                 .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
336                 .node(TestModel.INNER_LIST_QNAME).build();
337         NormalizedNodePruner pruner = prunerFullSchema(path);
338
339         MapNode input = mapNodeBuilder(TestModel.INNER_LIST_QNAME).withChild(mapEntryBuilder(
340                 TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "one").withChild(
341                         ImmutableNodes.containerNode(TestModel.INNER_CONTAINER_QNAME)).build()).build();
342         NormalizedNodeWriter.forStreamWriter(pruner).write(input);
343
344         NormalizedNode<?, ?> actual = pruner.normalizedNode();
345         assertEquals("normalizedNode", input, actual);
346     }
347
348     @Test
349     public void testInnerListNodeWithFullPathPrunedWhenSchemaMissing() throws IOException {
350         YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
351                 .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
352                 .node(TestModel.INVALID_QNAME).build();
353         NormalizedNodePruner pruner = prunerFullSchema(path);
354
355         MapNode input = mapNodeBuilder(TestModel.INVALID_QNAME).withChild(mapEntryBuilder(
356                 TestModel.INVALID_QNAME, TestModel.NAME_QNAME, "one").withChild(
357                         ImmutableNodes.containerNode(TestModel.INNER_CONTAINER_QNAME)).build()).build();
358         NormalizedNodeWriter.forStreamWriter(pruner).write(input);
359
360         NormalizedNode<?, ?> actual = pruner.normalizedNode();
361         assertNull(actual);
362     }
363
364     @Test
365     public void testInnerListNodeWithParentPathPrunedWhenSchemaMissing() throws IOException {
366         YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
367                 .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
368                 .build();
369         NormalizedNodePruner pruner = prunerFullSchema(path);
370
371         MapNode innerList = mapNodeBuilder(TestModel.INVALID_QNAME).withChild(mapEntryBuilder(
372                 TestModel.INVALID_QNAME, TestModel.NAME_QNAME, "one").withChild(
373                         ImmutableNodes.containerNode(TestModel.INNER_CONTAINER_QNAME)).build()).build();
374         NormalizedNode<?, ?> input = mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
375                 .withChild(innerList).build();
376         NormalizedNodeWriter.forStreamWriter(pruner).write(input);
377
378         NormalizedNode<?, ?> expected = mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1);
379         NormalizedNode<?, ?> actual = pruner.normalizedNode();
380         assertEquals("normalizedNode", expected, actual);
381     }
382
383     private static NormalizedNode<?, ?> createTestContainer() {
384         byte[] bytes1 = {1,2,3};
385         LeafSetEntryNode<Object> entry1 = ImmutableLeafSetEntryNodeBuilder.create().withNodeIdentifier(
386                 new NodeWithValue<>(TestModel.BINARY_LEAF_LIST_QNAME, bytes1)).withValue(bytes1).build();
387
388         byte[] bytes2 = {};
389         LeafSetEntryNode<Object> entry2 = ImmutableLeafSetEntryNodeBuilder.create().withNodeIdentifier(
390                 new NodeWithValue<>(TestModel.BINARY_LEAF_LIST_QNAME, bytes2)).withValue(bytes2).build();
391
392         LeafSetEntryNode<Object> entry3 = ImmutableLeafSetEntryNodeBuilder.create().withNodeIdentifier(
393                 new NodeWithValue<>(TestModel.BINARY_LEAF_LIST_QNAME, null)).withValue(null).build();
394
395
396         return TestModel.createBaseTestContainerBuilder()
397                 .withChild(ImmutableLeafSetNodeBuilder.create().withNodeIdentifier(
398                         new NodeIdentifier(TestModel.BINARY_LEAF_LIST_QNAME))
399                         .withChild(entry1).withChild(entry2).withChild(entry3).build())
400                 .withChild(ImmutableNodes.leafNode(TestModel.SOME_BINARY_DATA_QNAME, new byte[]{1, 2, 3, 4}))
401                 .build();
402     }
403 }