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