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