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