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