BUG 2970 : Create a utility class which can prune a normalized node based on the...
[controller.git] / opendaylight / md-sal / sal-clustering-commons / src / test / java / org / opendaylight / controller / cluster / datastore / node / utils / transformer / NormalizedNodePrunerTest.java
1 package org.opendaylight.controller.cluster.datastore.node.utils.transformer;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.assertNull;
5 import static org.junit.Assert.assertTrue;
6 import static org.mockito.Matchers.any;
7 import static org.mockito.Mockito.doReturn;
8 import static org.mockito.Mockito.mock;
9 import static org.mockito.Mockito.never;
10 import static org.mockito.Mockito.verify;
11 import com.google.common.collect.ImmutableMap;
12 import com.google.common.collect.ImmutableSet;
13 import java.io.IOException;
14 import java.util.concurrent.atomic.AtomicInteger;
15 import javax.xml.transform.dom.DOMSource;
16 import org.junit.Assert;
17 import org.junit.Before;
18 import org.junit.Test;
19 import org.mockito.ArgumentCaptor;
20 import org.mockito.Mock;
21 import org.mockito.MockitoAnnotations;
22 import org.opendaylight.controller.cluster.datastore.node.utils.NormalizedNodeNavigator;
23 import org.opendaylight.controller.cluster.datastore.node.utils.NormalizedNodeVisitor;
24 import org.opendaylight.controller.cluster.datastore.util.TestModel;
25 import org.opendaylight.yangtools.yang.common.QName;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
27 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
30 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
31 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
32 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
33 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
34 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
35 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
36 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
37 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetEntryNodeBuilder;
38 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
39
40 public class NormalizedNodePrunerTest {
41
42     private NormalizedNodePruner prunerFullSchema;
43
44     private NormalizedNodePruner prunerNoAugSchema;
45
46     @Mock
47     private NormalizedNodeBuilderWrapper normalizedNodeBuilderWrapper;
48
49     @Mock
50     private NormalizedNodeContainerBuilder normalizedNodeContainerBuilder;
51
52     @Mock
53     private NormalizedNode<?,?> normalizedNode;
54
55     @Before
56     public void setUp(){
57         MockitoAnnotations.initMocks(this);
58         prunerFullSchema = new NormalizedNodePruner(TestModel.createTestContext());
59         prunerNoAugSchema = new NormalizedNodePruner(TestModel.createTestContextWithoutAugmentationSchema());
60         doReturn(normalizedNodeContainerBuilder).when(normalizedNodeBuilderWrapper).builder();
61         doReturn(TestModel.BOOLEAN_LEAF_QNAME).when(normalizedNodeBuilderWrapper).nodeType();
62         doReturn(normalizedNode).when(normalizedNodeContainerBuilder).build();
63         doReturn(new YangInstanceIdentifier.NodeIdentifier(TestModel.BOOLEAN_LEAF_QNAME)).when(normalizedNodeBuilderWrapper).identifier();
64     }
65
66     @Test
67     public void testNodesNotPrunedWhenSchemaPresent() throws IOException {
68         NormalizedNodePruner pruner = prunerFullSchema;
69
70         NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
71
72         NormalizedNode<?, ?> expected = createTestContainer();
73
74         normalizedNodeWriter.write(expected);
75
76         NormalizedNode actual = pruner.normalizedNode();
77
78         assertEquals(expected, actual);
79
80     }
81
82     @Test(expected = IllegalStateException.class)
83     public void testReusePruner() throws IOException {
84         NormalizedNodePruner pruner = prunerFullSchema;
85
86         NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
87
88         NormalizedNode<?, ?> expected = createTestContainer();
89
90         normalizedNodeWriter.write(expected);
91
92         NormalizedNode actual = pruner.normalizedNode();
93
94         assertEquals(expected, actual);
95
96         NormalizedNodeWriter.forStreamWriter(pruner).write(expected);
97
98     }
99
100
101     @Test
102     public void testNodesPrunedWhenAugmentationSchemaNotPresent() throws IOException {
103         NormalizedNodePruner pruner = prunerNoAugSchema;
104
105         NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
106
107         NormalizedNode<?, ?> expected = createTestContainer();
108
109         normalizedNodeWriter.write(expected);
110
111         NormalizedNode actual = pruner.normalizedNode();
112
113         Assert.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 testNodesPrunedWhenTestSchemaNotPresent() throws IOException {
124         NormalizedNodePruner pruner = new NormalizedNodePruner(TestModel.createTestContextWithoutTestSchema());
125
126         NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
127
128         NormalizedNode<?, ?> expected = createTestContainer();
129
130         normalizedNodeWriter.write(expected);
131
132         NormalizedNode actual = pruner.normalizedNode();
133
134         // Since top level schema is missing null is returned
135         assertNull(actual);
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
143     private int countNodes(NormalizedNode<?,?> normalizedNode, final String namespaceFilter){
144         if(normalizedNode == null){
145             return 0;
146         }
147         final AtomicInteger count = new AtomicInteger();
148         new NormalizedNodeNavigator(new NormalizedNodeVisitor() {
149
150             @Override
151             public void visitNode(int level, String parentPath, NormalizedNode<?, ?> normalizedNode) {
152                 if(!(normalizedNode.getIdentifier() instanceof YangInstanceIdentifier.AugmentationIdentifier)) {
153                     if (normalizedNode.getIdentifier().getNodeType().getNamespace().toString().contains(namespaceFilter)) {
154                         count.incrementAndGet();
155                     }
156                 }
157             }
158         }).navigate(YangInstanceIdentifier.builder().build().toString(), normalizedNode);
159
160         return count.get();
161     }
162
163     @Test(expected = IllegalStateException.class)
164     public void testLeafNodeHasNoParent() throws IOException {
165         prunerFullSchema.leafNode(new YangInstanceIdentifier.NodeIdentifier(TestModel.BOOLEAN_LEAF_QNAME), mock(Object.class));
166     }
167
168     @Test
169     public void testLeafNodeHasParent() throws IOException {
170         prunerFullSchema.stack().push(normalizedNodeBuilderWrapper);
171         Object o = mock(Object.class);
172         prunerFullSchema.leafNode(new YangInstanceIdentifier.NodeIdentifier(TestModel.BOOLEAN_LEAF_QNAME), o);
173
174         ArgumentCaptor<NormalizedNode> captor = ArgumentCaptor.forClass(NormalizedNode.class);
175
176         verify(normalizedNodeContainerBuilder).addChild(captor.capture());
177
178         NormalizedNode value = captor.getValue();
179         assertEquals(normalizedNodeBuilderWrapper.identifier().getNodeType(), value.getNodeType());
180         assertEquals(normalizedNodeBuilderWrapper.identifier(), value.getIdentifier());
181         assertEquals(o, value.getValue());
182
183     }
184
185     @Test
186     public void testLeafNodeSchemaMissing() throws IOException {
187         prunerNoAugSchema.stack().push(normalizedNodeBuilderWrapper);
188         prunerNoAugSchema.leafNode(new YangInstanceIdentifier.NodeIdentifier(TestModel.AUG_CONT_QNAME), mock(Object.class));
189         verify(normalizedNodeContainerBuilder, never()).addChild(any(NormalizedNode.class));
190     }
191
192     @Test(expected = IllegalStateException.class)
193     public void testLeafSetEntryNodeHasNoParent() throws IOException {
194         prunerFullSchema.leafSetEntryNode(mock(Object.class));
195     }
196
197     @Test
198     public void testLeafSetEntryNodeHasParent() throws IOException {
199         prunerFullSchema.stack().push(normalizedNodeBuilderWrapper);
200         Object o = mock(Object.class);
201         YangInstanceIdentifier.PathArgument nodeIdentifier
202                 = new YangInstanceIdentifier.NodeWithValue(normalizedNodeBuilderWrapper.identifier().getNodeType(), o);
203         prunerFullSchema.leafSetEntryNode(o);
204
205         ArgumentCaptor<NormalizedNode> captor = ArgumentCaptor.forClass(NormalizedNode.class);
206
207         verify(normalizedNodeContainerBuilder).addChild(captor.capture());
208
209         NormalizedNode value = captor.getValue();
210         assertEquals(nodeIdentifier.getNodeType(), value.getNodeType());
211         assertEquals(nodeIdentifier, value.getIdentifier());
212         assertEquals(o, value.getValue());
213
214     }
215
216     @Test
217     public void testLeafSetEntryNodeSchemaMissing() throws IOException {
218         doReturn(new YangInstanceIdentifier.NodeIdentifier(TestModel.AUG_CONT_QNAME)).when(normalizedNodeBuilderWrapper).identifier();
219
220         prunerNoAugSchema.stack().push(normalizedNodeBuilderWrapper);
221         prunerNoAugSchema.leafSetEntryNode(new YangInstanceIdentifier.NodeIdentifier(TestModel.AUG_CONT_QNAME));
222
223         verify(normalizedNodeContainerBuilder, never()).addChild(any(NormalizedNode.class));
224     }
225
226     @Test(expected = IllegalStateException.class)
227     public void testAnyXMLNodeHasNoParent() throws IOException {
228         prunerFullSchema.anyxmlNode(new YangInstanceIdentifier.NodeIdentifier(TestModel.BOOLEAN_LEAF_QNAME), mock(Object.class));
229     }
230
231     @Test
232     public void testAnyXMLNodeHasParent() throws IOException {
233         prunerFullSchema.stack().push(normalizedNodeBuilderWrapper);
234         YangInstanceIdentifier.NodeIdentifier nodeIdentifier = new YangInstanceIdentifier.NodeIdentifier(TestModel.BOOLEAN_LEAF_QNAME);
235         DOMSource o = mock(DOMSource.class);
236         prunerFullSchema.anyxmlNode(nodeIdentifier, o);
237
238         ArgumentCaptor<NormalizedNode> captor = ArgumentCaptor.forClass(NormalizedNode.class);
239
240         verify(normalizedNodeContainerBuilder).addChild(captor.capture());
241
242         NormalizedNode value = captor.getValue();
243         assertEquals(nodeIdentifier.getNodeType(), value.getNodeType());
244         assertEquals(nodeIdentifier, value.getIdentifier());
245         assertEquals(o, value.getValue());
246     }
247
248     @Test
249     public void testAnyXmlNodeSchemaMissing() throws IOException {
250         prunerNoAugSchema.stack().push(normalizedNodeBuilderWrapper);
251         prunerNoAugSchema.anyxmlNode(new YangInstanceIdentifier.NodeIdentifier(TestModel.AUG_CONT_QNAME), mock(DOMSource.class));
252
253         verify(normalizedNodeContainerBuilder, never()).addChild(any(NormalizedNode.class));
254
255
256     }
257
258
259     @Test
260     public void testLeafSetPushesBuilderToStack() throws IOException {
261         prunerFullSchema.startLeafSet(new YangInstanceIdentifier.NodeIdentifier(TestModel.BOOLEAN_LEAF_QNAME), 10);
262
263         assertEquals(1, prunerFullSchema.stack().size());
264         assertTrue(prunerFullSchema.stack().peek().toString(), prunerFullSchema.stack().peek() instanceof NormalizedNodeBuilderWrapper);
265         assertTrue(prunerFullSchema.stack().peek().builder().toString(), prunerFullSchema.stack().peek().builder() instanceof ListNodeBuilder);
266     }
267
268     @Test
269     public void testStartContainerNodePushesBuilderToStack() throws IOException {
270         prunerFullSchema.startContainerNode(new YangInstanceIdentifier.NodeIdentifier(TestModel.BOOLEAN_LEAF_QNAME), 10);
271
272         assertEquals(1, prunerFullSchema.stack().size());
273         assertTrue(prunerFullSchema.stack().peek().toString(), prunerFullSchema.stack().peek() instanceof NormalizedNodeBuilderWrapper);
274         assertTrue(prunerFullSchema.stack().peek().builder().toString(), prunerFullSchema.stack().peek().builder() instanceof DataContainerNodeAttrBuilder);
275     }
276
277     @Test
278     public void testStartUnkeyedListPushesBuilderToStack() throws IOException {
279         prunerFullSchema.startUnkeyedList(new YangInstanceIdentifier.NodeIdentifier(TestModel.BOOLEAN_LEAF_QNAME), 10);
280
281         assertEquals(1, prunerFullSchema.stack().size());
282         assertTrue(prunerFullSchema.stack().peek().toString(), prunerFullSchema.stack().peek() instanceof NormalizedNodeBuilderWrapper);
283         assertTrue(prunerFullSchema.stack().peek().builder().toString(), prunerFullSchema.stack().peek().builder() instanceof CollectionNodeBuilder);
284     }
285
286     @Test
287     public void testStartUnkeyedListItemPushesBuilderToStack() throws IOException {
288         prunerFullSchema.startUnkeyedListItem(new YangInstanceIdentifier.NodeIdentifier(TestModel.BOOLEAN_LEAF_QNAME), 10);
289
290         assertEquals(1, prunerFullSchema.stack().size());
291         assertTrue(prunerFullSchema.stack().peek().toString(), prunerFullSchema.stack().peek() instanceof NormalizedNodeBuilderWrapper);
292         assertTrue(prunerFullSchema.stack().peek().builder().toString(), prunerFullSchema.stack().peek().builder() instanceof DataContainerNodeAttrBuilder);
293     }
294
295     @Test
296     public void testStartMapNodePushesBuilderToStack() throws IOException {
297         prunerFullSchema.startMapNode(new YangInstanceIdentifier.NodeIdentifier(TestModel.BOOLEAN_LEAF_QNAME), 10);
298
299         assertEquals(1, prunerFullSchema.stack().size());
300         assertTrue(prunerFullSchema.stack().peek().toString(), prunerFullSchema.stack().peek() instanceof NormalizedNodeBuilderWrapper);
301         assertTrue(prunerFullSchema.stack().peek().builder().toString(), prunerFullSchema.stack().peek().builder() instanceof CollectionNodeBuilder);
302     }
303
304     @Test
305     public void testStartMapEntryNodePushesBuilderToStack() throws IOException {
306         prunerFullSchema.startMapEntryNode(
307                 new YangInstanceIdentifier.NodeIdentifierWithPredicates(TestModel.BOOLEAN_LEAF_QNAME,
308                         ImmutableMap.<QName, Object>of(TestModel.BOOLEAN_LEAF_QNAME, "value")), 10);
309
310         assertEquals(1, prunerFullSchema.stack().size());
311         assertTrue(prunerFullSchema.stack().peek().toString(), prunerFullSchema.stack().peek() instanceof NormalizedNodeBuilderWrapper);
312         assertTrue(prunerFullSchema.stack().peek().builder().toString(), prunerFullSchema.stack().peek().builder() instanceof DataContainerNodeAttrBuilder);
313     }
314
315     @Test
316     public void testStartOrderedMapNodePushesBuilderToStack() throws IOException {
317         prunerFullSchema.startOrderedMapNode(new YangInstanceIdentifier.NodeIdentifier(TestModel.BOOLEAN_LEAF_QNAME), 10);
318
319         assertEquals(1, prunerFullSchema.stack().size());
320         assertTrue(prunerFullSchema.stack().peek().toString(), prunerFullSchema.stack().peek() instanceof NormalizedNodeBuilderWrapper);
321         assertTrue(prunerFullSchema.stack().peek().builder().toString(), prunerFullSchema.stack().peek().builder() instanceof CollectionNodeBuilder);
322     }
323
324     @Test
325     public void testStartChoiceNodePushesBuilderToStack() throws IOException {
326         prunerFullSchema.startChoiceNode(new YangInstanceIdentifier.NodeIdentifier(TestModel.BOOLEAN_LEAF_QNAME), 10);
327
328         assertEquals(1, prunerFullSchema.stack().size());
329         assertTrue(prunerFullSchema.stack().peek().toString(), prunerFullSchema.stack().peek() instanceof NormalizedNodeBuilderWrapper);
330         assertTrue(prunerFullSchema.stack().peek().builder().toString(), prunerFullSchema.stack().peek().builder() instanceof DataContainerNodeBuilder);
331     }
332
333     @Test
334     public void testStartAugmentationPushesBuilderToStack() throws IOException {
335         prunerFullSchema.startAugmentationNode(new YangInstanceIdentifier.AugmentationIdentifier(ImmutableSet.of(TestModel.AUG_CONT_QNAME)));
336
337         assertEquals(1, prunerFullSchema.stack().size());
338         assertTrue(prunerFullSchema.stack().peek().toString(), prunerFullSchema.stack().peek() instanceof NormalizedNodeBuilderWrapper);
339         assertTrue(prunerFullSchema.stack().peek().builder().toString(), prunerFullSchema.stack().peek().builder() instanceof DataContainerNodeBuilder);
340     }
341
342     @Test(expected = IllegalStateException.class)
343     public void testEndNodeWhenNoBuildersOnStack() throws IOException {
344         prunerFullSchema.endNode();
345     }
346
347     @Test
348     public void testEndNodeWhenOneBuildersOnStack() throws IOException {
349         prunerFullSchema.stack().push(normalizedNodeBuilderWrapper);
350         prunerFullSchema.endNode();
351         assertEquals(normalizedNode, prunerFullSchema.normalizedNode());
352     }
353
354     @Test
355     public void testEndNodeSchemaMissing() throws IOException {
356         doReturn(new YangInstanceIdentifier.NodeIdentifier(TestModel.AUG_CONT_QNAME)).when(normalizedNodeBuilderWrapper).identifier();
357
358         prunerNoAugSchema.stack().push(normalizedNodeBuilderWrapper);
359         prunerNoAugSchema.endNode();
360
361         assertEquals(null, prunerNoAugSchema.normalizedNode());
362     }
363
364     @Test
365     public void testEndNodeWhenMoreThanOneBuilderOnStack() throws IOException {
366         // A little lazy in adding the "parent" builder
367         prunerFullSchema.stack().push(normalizedNodeBuilderWrapper);
368         prunerFullSchema.stack().push(normalizedNodeBuilderWrapper);
369         prunerFullSchema.endNode();
370         assertEquals(null, prunerFullSchema.normalizedNode());
371
372         verify(normalizedNodeContainerBuilder).addChild(any(NormalizedNode.class));
373     }
374
375     private NormalizedNode<?, ?> createTestContainer() {
376         byte[] bytes1 = {1,2,3};
377         LeafSetEntryNode<Object> entry1 = ImmutableLeafSetEntryNodeBuilder.create().withNodeIdentifier(
378                 new YangInstanceIdentifier.NodeWithValue(TestModel.BINARY_LEAF_LIST_QNAME, bytes1)).
379                 withValue(bytes1).build();
380
381         byte[] bytes2 = {};
382         LeafSetEntryNode<Object> entry2 = ImmutableLeafSetEntryNodeBuilder.create().withNodeIdentifier(
383                 new YangInstanceIdentifier.NodeWithValue(TestModel.BINARY_LEAF_LIST_QNAME, bytes2)).
384                 withValue(bytes2).build();
385
386         LeafSetEntryNode<Object> entry3 = ImmutableLeafSetEntryNodeBuilder.create().withNodeIdentifier(
387                 new YangInstanceIdentifier.NodeWithValue(TestModel.BINARY_LEAF_LIST_QNAME, null)).
388                 withValue(null).build();
389
390
391         return TestModel.createBaseTestContainerBuilder().
392                 withChild(ImmutableLeafSetNodeBuilder.create().withNodeIdentifier(
393                         new YangInstanceIdentifier.NodeIdentifier(TestModel.BINARY_LEAF_LIST_QNAME)).
394                         withChild(entry1).withChild(entry2).withChild(entry3).build()).
395                 withChild(ImmutableNodes.leafNode(TestModel.SOME_BINARY_DATA_QNAME, new byte[]{1, 2, 3, 4})).
396                 withChild(Builders.orderedMapBuilder().
397                         withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TestModel.ORDERED_LIST_QNAME)).
398                         withChild(ImmutableNodes.mapEntry(TestModel.ORDERED_LIST_ENTRY_QNAME,
399                                 TestModel.ID_QNAME, 11)).build()).
400                 build();
401     }
402 }