2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.controller.cluster.datastore.node.utils.transformer;
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;
54 public class NormalizedNodePrunerTest {
56 private NormalizedNodePruner prunerFullSchema;
58 private NormalizedNodePruner prunerNoAugSchema;
61 private NormalizedNodeBuilderWrapper normalizedNodeBuilderWrapper;
64 private NormalizedNodeContainerBuilder normalizedNodeContainerBuilder;
67 private NormalizedNode<?,?> normalizedNode;
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();
81 public void testNodesNotPrunedWhenSchemaPresent() throws IOException {
82 NormalizedNodePruner pruner = prunerFullSchema;
84 NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
86 NormalizedNode<?, ?> expected = createTestContainer();
88 normalizedNodeWriter.write(expected);
90 NormalizedNode<?, ?> actual = pruner.normalizedNode();
92 assertEquals(expected, actual);
96 @Test(expected = IllegalStateException.class)
97 public void testReusePruner() throws IOException {
98 NormalizedNodePruner pruner = prunerFullSchema;
100 NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
102 NormalizedNode<?, ?> expected = createTestContainer();
104 normalizedNodeWriter.write(expected);
106 NormalizedNode<?, ?> actual = pruner.normalizedNode();
108 assertEquals(expected, actual);
110 NormalizedNodeWriter.forStreamWriter(pruner).write(expected);
116 public void testNodesPrunedWhenAugmentationSchemaNotPresent() throws IOException {
117 NormalizedNodePruner pruner = prunerNoAugSchema;
119 NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
121 NormalizedNode<?, ?> expected = createTestContainer();
123 normalizedNodeWriter.write(expected);
125 NormalizedNode<?, ?> actual = pruner.normalizedNode();
127 Assert.assertNotEquals(expected, actual);
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);
132 // All nodes from the augmentation module are gone from the resulting node
133 assertEquals(0, countNodes(actual, "store:aug"));
137 public void testNodesPrunedWhenTestSchemaNotPresent() throws IOException {
138 NormalizedNodePruner pruner = new NormalizedNodePruner(TestModel.createTestContextWithoutTestSchema());
140 NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
142 NormalizedNode<?, ?> expected = createTestContainer();
144 normalizedNodeWriter.write(expected);
146 NormalizedNode<?, ?> actual = pruner.normalizedNode();
148 // Since top level schema is missing null is returned
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);
157 private static int countNodes(NormalizedNode<?,?> normalizedNode, final String namespaceFilter){
158 if(normalizedNode == null){
161 final AtomicInteger count = new AtomicInteger();
162 new NormalizedNodeNavigator(new NormalizedNodeVisitor() {
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();
172 }).navigate(YangInstanceIdentifier.EMPTY.toString(), normalizedNode);
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);
183 NormalizedNode<?, ?> actual = prunerFullSchema.normalizedNode();
184 assertEquals("normalizedNode", input, actual);
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);
195 NormalizedNode<?, ?> actual = prunerFullSchema.normalizedNode();
196 assertEquals("normalizedNode", input, actual);
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));
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);
212 NormalizedNode<?, ?> actual = prunerFullSchema.normalizedNode();
213 assertEquals("normalizedNode", input, actual);
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);
224 NormalizedNode<?, ?> actual = prunerFullSchema.normalizedNode();
225 assertEquals("normalizedNode", input, actual);
229 public void testLeafSetEntryNodeSchemaMissing() throws IOException {
230 doReturn(new NodeIdentifier(TestModel.AUG_CONT_QNAME)).when(normalizedNodeBuilderWrapper).identifier();
232 prunerNoAugSchema.stack().push(normalizedNodeBuilderWrapper);
233 prunerNoAugSchema.leafSetEntryNode(TestModel.AUG_CONT_QNAME, "");
235 verify(normalizedNodeContainerBuilder, never()).addChild(any(NormalizedNode.class));
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);
245 NormalizedNode<?, ?> actual = prunerFullSchema.normalizedNode();
246 assertEquals("normalizedNode", input, actual);
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);
258 NormalizedNode<?, ?> actual = prunerFullSchema.normalizedNode();
259 assertEquals("normalizedNode", input, actual);
263 public void testAnyXmlNodeSchemaMissing() throws IOException {
264 prunerNoAugSchema.stack().push(normalizedNodeBuilderWrapper);
265 prunerNoAugSchema.anyxmlNode(new NodeIdentifier(TestModel.AUG_CONT_QNAME), mock(DOMSource.class));
267 verify(normalizedNodeContainerBuilder, never()).addChild(any(NormalizedNode.class));
272 public void testLeafSetPushesBuilderToStack() throws IOException {
273 prunerFullSchema.startLeafSet(new NodeIdentifier(TestModel.BOOLEAN_LEAF_QNAME), 10);
275 assertEquals(1, prunerFullSchema.stack().size());
276 assertNotNull(prunerFullSchema.stack().peek());
277 assertTrue(prunerFullSchema.stack().peek().builder().toString(), prunerFullSchema.stack().peek().builder() instanceof ListNodeBuilder);
281 public void testStartContainerNodePushesBuilderToStack() throws IOException {
282 prunerFullSchema.startContainerNode(new NodeIdentifier(TestModel.BOOLEAN_LEAF_QNAME), 10);
284 assertEquals(1, prunerFullSchema.stack().size());
285 assertNotNull(prunerFullSchema.stack().peek());
286 assertTrue(prunerFullSchema.stack().peek().builder().toString(), prunerFullSchema.stack().peek().builder() instanceof DataContainerNodeAttrBuilder);
290 public void testStartUnkeyedListPushesBuilderToStack() throws IOException {
291 prunerFullSchema.startUnkeyedList(new NodeIdentifier(TestModel.BOOLEAN_LEAF_QNAME), 10);
293 assertEquals(1, prunerFullSchema.stack().size());
294 assertNotNull(prunerFullSchema.stack().peek());
295 assertTrue(prunerFullSchema.stack().peek().builder().toString(), prunerFullSchema.stack().peek().builder() instanceof CollectionNodeBuilder);
299 public void testStartUnkeyedListItemPushesBuilderToStack() throws IOException {
300 prunerFullSchema.startUnkeyedListItem(new NodeIdentifier(TestModel.BOOLEAN_LEAF_QNAME), 10);
302 assertEquals(1, prunerFullSchema.stack().size());
303 assertNotNull(prunerFullSchema.stack().peek());
304 assertTrue(prunerFullSchema.stack().peek().builder().toString(), prunerFullSchema.stack().peek().builder() instanceof DataContainerNodeAttrBuilder);
308 public void testStartMapNodePushesBuilderToStack() throws IOException {
309 prunerFullSchema.startMapNode(new NodeIdentifier(TestModel.BOOLEAN_LEAF_QNAME), 10);
311 assertEquals(1, prunerFullSchema.stack().size());
312 assertNotNull(prunerFullSchema.stack().peek());
313 assertTrue(prunerFullSchema.stack().peek().builder().toString(), prunerFullSchema.stack().peek().builder() instanceof CollectionNodeBuilder);
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);
322 assertEquals(1, prunerFullSchema.stack().size());
323 assertNotNull(prunerFullSchema.stack().peek());
324 assertTrue(prunerFullSchema.stack().peek().builder().toString(), prunerFullSchema.stack().peek().builder() instanceof DataContainerNodeAttrBuilder);
328 public void testStartOrderedMapNodePushesBuilderToStack() throws IOException {
329 prunerFullSchema.startOrderedMapNode(new NodeIdentifier(TestModel.BOOLEAN_LEAF_QNAME), 10);
331 assertEquals(1, prunerFullSchema.stack().size());
332 assertNotNull(prunerFullSchema.stack().peek());
333 assertTrue(prunerFullSchema.stack().peek().builder().toString(), prunerFullSchema.stack().peek().builder() instanceof CollectionNodeBuilder);
337 public void testStartChoiceNodePushesBuilderToStack() throws IOException {
338 prunerFullSchema.startChoiceNode(new NodeIdentifier(TestModel.BOOLEAN_LEAF_QNAME), 10);
340 assertEquals(1, prunerFullSchema.stack().size());
341 assertNotNull(prunerFullSchema.stack().peek());
342 assertTrue(prunerFullSchema.stack().peek().builder().toString(), prunerFullSchema.stack().peek().builder() instanceof DataContainerNodeBuilder);
346 public void testStartAugmentationPushesBuilderToStack() throws IOException {
347 prunerFullSchema.startAugmentationNode(new AugmentationIdentifier(ImmutableSet.of(TestModel.AUG_CONT_QNAME)));
349 assertEquals(1, prunerFullSchema.stack().size());
350 assertNotNull(prunerFullSchema.stack().peek());
351 assertTrue(prunerFullSchema.stack().peek().builder().toString(), prunerFullSchema.stack().peek().builder() instanceof DataContainerNodeBuilder);
354 @Test(expected = IllegalStateException.class)
355 public void testEndNodeWhenNoBuildersOnStack() throws IOException {
356 prunerFullSchema.endNode();
360 public void testEndNodeWhenOneBuildersOnStack() throws IOException {
361 prunerFullSchema.stack().push(normalizedNodeBuilderWrapper);
362 prunerFullSchema.endNode();
363 assertEquals(normalizedNode, prunerFullSchema.normalizedNode());
367 public void testEndNodeSchemaMissing() throws IOException {
368 doReturn(new NodeIdentifier(TestModel.AUG_CONT_QNAME)).when(normalizedNodeBuilderWrapper).identifier();
370 prunerNoAugSchema.stack().push(normalizedNodeBuilderWrapper);
371 prunerNoAugSchema.endNode();
373 assertEquals(null, prunerNoAugSchema.normalizedNode());
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());
384 verify(normalizedNodeContainerBuilder).addChild(any(NormalizedNode.class));
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();
394 LeafSetEntryNode<Object> entry2 = ImmutableLeafSetEntryNodeBuilder.create().withNodeIdentifier(
395 new NodeWithValue<>(TestModel.BINARY_LEAF_LIST_QNAME, bytes2)).
396 withValue(bytes2).build();
398 LeafSetEntryNode<Object> entry3 = ImmutableLeafSetEntryNodeBuilder.create().withNodeIdentifier(
399 new NodeWithValue<>(TestModel.BINARY_LEAF_LIST_QNAME, null)).withValue(null).build();
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()).