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
8 package org.opendaylight.controller.cluster.datastore.node.utils.transformer;
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;
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.SchemaContext;
44 @RunWith(MockitoJUnitRunner.StrictStubs.class)
45 public class NormalizedNodePrunerTest {
46 private static final SchemaContext NO_TEST_SCHEMA = TestModel.createTestContextWithoutTestSchema();
47 private static final SchemaContext NO_AUG_SCHEMA = TestModel.createTestContextWithoutAugmentationSchema();
48 private static final SchemaContext FULL_SCHEMA = TestModel.createTestContext();
50 private static AbstractNormalizedNodePruner prunerFullSchema(final YangInstanceIdentifier path) {
51 final ReusableNormalizedNodePruner pruner = ReusableNormalizedNodePruner.forSchemaContext(FULL_SCHEMA);
52 pruner.initializeForPath(path);
56 private static AbstractNormalizedNodePruner prunerNoAugSchema(final YangInstanceIdentifier path) {
57 final ReusableNormalizedNodePruner pruner = ReusableNormalizedNodePruner.forSchemaContext(NO_AUG_SCHEMA);
58 pruner.initializeForPath(path);
62 private static AbstractNormalizedNodePruner prunerNoTestSchema(final YangInstanceIdentifier path) {
63 final ReusableNormalizedNodePruner pruner = ReusableNormalizedNodePruner.forSchemaContext(NO_TEST_SCHEMA);
64 pruner.initializeForPath(path);
69 public void testNodesNotPrunedWhenSchemaPresent() throws IOException {
70 AbstractNormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH);
72 NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
74 NormalizedNode<?, ?> expected = createTestContainer();
76 normalizedNodeWriter.write(expected);
78 NormalizedNode<?, ?> actual = pruner.getResult().orElseThrow();
80 assertEquals(expected, actual);
84 @Test(expected = IllegalStateException.class)
85 public void testReusePruner() throws IOException {
86 AbstractNormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH);
88 NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
90 NormalizedNode<?, ?> expected = createTestContainer();
92 normalizedNodeWriter.write(expected);
94 NormalizedNode<?, ?> actual = pruner.getResult().orElseThrow();
96 assertEquals(expected, actual);
98 NormalizedNodeWriter.forStreamWriter(pruner).write(expected);
104 public void testNodesPrunedWhenAugmentationSchemaMissing() throws IOException {
105 AbstractNormalizedNodePruner pruner = prunerNoAugSchema(TestModel.TEST_PATH);
107 NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
109 NormalizedNode<?, ?> expected = createTestContainer();
111 normalizedNodeWriter.write(expected);
113 NormalizedNode<?, ?> actual = pruner.getResult().orElseThrow();
115 assertNotEquals(expected, actual);
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);
120 // All nodes from the augmentation module are gone from the resulting node
121 assertEquals(0, countNodes(actual, "store:aug"));
125 public void testNodesPrunedWhenTestSchemaMissing() throws IOException {
126 AbstractNormalizedNodePruner pruner = prunerNoTestSchema(TestModel.TEST_PATH);
128 NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
130 NormalizedNode<?, ?> expected = createTestContainer();
132 normalizedNodeWriter.write(expected);
134 // Since top level schema is missing empty is returned
135 assertEquals(Optional.empty(), pruner.getResult());
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);
142 private static int countNodes(final NormalizedNode<?,?> normalizedNode, final String namespaceFilter) {
143 if (normalizedNode == null) {
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();
153 }).navigate(YangInstanceIdentifier.empty().toString(), normalizedNode);
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);
165 assertEquals("normalizedNode", input, pruner.getResult().orElseThrow());
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);
179 NormalizedNode<?, ?> actual = pruner.getResult().orElseThrow();
180 assertEquals("normalizedNode", Builders.augmentationBuilder().withNodeIdentifier(augId).build(), actual);
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);
190 assertEquals(Optional.empty(), pruner.getResult());
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);
200 NormalizedNode<?, ?> actual = pruner.getResult().orElseThrow();
201 assertEquals("normalizedNode", input, actual);
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);
213 NormalizedNode<?, ?> actual = pruner.getResult().orElseThrow();
214 assertEquals("normalizedNode", input, actual);
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);
224 assertEquals(Optional.empty(), pruner.getResult());
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);
236 assertEquals(Optional.empty(), pruner.getResult());
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);
246 NormalizedNode<?, ?> actual = pruner.getResult().orElseThrow();
247 assertEquals("normalizedNode", input, actual);
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);
259 NormalizedNode<?, ?> actual = pruner.getResult().orElseThrow();
260 assertEquals("normalizedNode", input, actual);
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);
270 assertEquals(Optional.empty(), pruner.getResult());
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);
281 NormalizedNode<?, ?> input = ImmutableNodes.containerNode(TestModel.INNER_CONTAINER_QNAME);
282 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
284 NormalizedNode<?, ?> actual = pruner.getResult().orElseThrow();
285 assertEquals("normalizedNode", input, actual);
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);
296 NormalizedNode<?, ?> input = ImmutableNodes.containerNode(TestModel.INVALID_QNAME);
297 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
299 assertEquals(Optional.empty(), pruner.getResult());
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)
307 AbstractNormalizedNodePruner pruner = prunerFullSchema(path);
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);
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);
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);
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);
335 NormalizedNode<?, ?> actual = pruner.getResult().orElseThrow();
336 assertEquals("normalizedNode", input, actual);
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);
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);
351 assertEquals(Optional.empty(), pruner.getResult());
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)
359 AbstractNormalizedNodePruner pruner = prunerFullSchema(path);
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);
368 NormalizedNode<?, ?> expected = mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1);
369 NormalizedNode<?, ?> actual = pruner.getResult().orElseThrow();
370 assertEquals("normalizedNode", expected, actual);
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();
379 LeafSetEntryNode<Object> entry2 = ImmutableLeafSetEntryNodeBuilder.create().withNodeIdentifier(
380 new NodeWithValue<>(TestModel.BINARY_LEAF_LIST_QNAME, bytes2)).withValue(bytes2).build();
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}))