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 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;
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();
47 private static AbstractNormalizedNodePruner prunerFullSchema(final YangInstanceIdentifier path) {
48 final ReusableNormalizedNodePruner pruner = ReusableNormalizedNodePruner.forSchemaContext(FULL_SCHEMA);
49 pruner.initializeForPath(path);
53 private static AbstractNormalizedNodePruner prunerNoAugSchema(final YangInstanceIdentifier path) {
54 final ReusableNormalizedNodePruner pruner = ReusableNormalizedNodePruner.forSchemaContext(NO_AUG_SCHEMA);
55 pruner.initializeForPath(path);
59 private static AbstractNormalizedNodePruner prunerNoTestSchema(final YangInstanceIdentifier path) {
60 final ReusableNormalizedNodePruner pruner = ReusableNormalizedNodePruner.forSchemaContext(NO_TEST_SCHEMA);
61 pruner.initializeForPath(path);
66 public void testNodesNotPrunedWhenSchemaPresent() throws IOException {
67 AbstractNormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH);
69 NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
71 NormalizedNode expected = createTestContainer();
73 normalizedNodeWriter.write(expected);
75 NormalizedNode actual = pruner.getResult().orElseThrow();
77 assertEquals(expected, actual);
81 @Test(expected = IllegalStateException.class)
82 public void testReusePruner() throws IOException {
83 AbstractNormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH);
85 NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
87 NormalizedNode expected = createTestContainer();
89 normalizedNodeWriter.write(expected);
91 NormalizedNode actual = pruner.getResult().orElseThrow();
93 assertEquals(expected, actual);
95 NormalizedNodeWriter.forStreamWriter(pruner).write(expected);
101 public void testNodesPrunedWhenAugmentationSchemaMissing() throws IOException {
102 AbstractNormalizedNodePruner pruner = prunerNoAugSchema(TestModel.TEST_PATH);
104 NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
106 NormalizedNode expected = createTestContainer();
108 normalizedNodeWriter.write(expected);
110 NormalizedNode actual = pruner.getResult().orElseThrow();
112 assertNotEquals(expected, actual);
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);
117 // All nodes from the augmentation module are gone from the resulting node
118 assertEquals(0, countNodes(actual, "store:aug"));
122 public void testNodesPrunedWhenTestSchemaMissing() throws IOException {
123 AbstractNormalizedNodePruner pruner = prunerNoTestSchema(TestModel.TEST_PATH);
125 NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
127 NormalizedNode expected = createTestContainer();
129 normalizedNodeWriter.write(expected);
131 // Since top level schema is missing empty is returned
132 assertEquals(Optional.empty(), pruner.getResult());
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);
139 private static int countNodes(final NormalizedNode normalizedNode, final String namespaceFilter) {
140 if (normalizedNode == null) {
143 final AtomicInteger count = new AtomicInteger();
144 new NormalizedNodeNavigator((level, parentPath, normalizedNode1) -> {
145 if (normalizedNode1.name().getNodeType().getNamespace().toString().contains(namespaceFilter)) {
146 count.incrementAndGet();
148 }).navigate(YangInstanceIdentifier.of().toString(), normalizedNode);
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);
160 assertEquals("normalizedNode", input, pruner.getResult().orElseThrow());
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);
169 assertEquals(Optional.empty(), pruner.getResult());
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);
179 NormalizedNode actual = pruner.getResult().orElseThrow();
180 assertEquals("normalizedNode", input, actual);
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);
192 NormalizedNode actual = pruner.getResult().orElseThrow();
193 assertEquals("normalizedNode", input, actual);
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);
203 assertEquals(Optional.empty(), pruner.getResult());
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);
215 assertEquals(Optional.empty(), pruner.getResult());
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);
225 NormalizedNode actual = pruner.getResult().orElseThrow();
226 assertEquals("normalizedNode", input, actual);
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);
238 assertEquals("normalizedNode", input, pruner.getResult().orElseThrow());
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);
248 assertEquals(Optional.empty(), pruner.getResult());
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);
259 NormalizedNode input = ImmutableNodes.containerNode(TestModel.INNER_CONTAINER_QNAME);
260 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
262 NormalizedNode actual = pruner.getResult().orElseThrow();
263 assertEquals("normalizedNode", input, actual);
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);
274 ContainerNode input = ImmutableNodes.containerNode(TestModel.INVALID_QNAME);
275 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
277 assertEquals(Optional.empty(), pruner.getResult());
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)
285 AbstractNormalizedNodePruner pruner = prunerFullSchema(path);
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);
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);
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);
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);
313 NormalizedNode actual = pruner.getResult().orElseThrow();
314 assertEquals("normalizedNode", input, actual);
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);
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);
329 assertEquals(Optional.empty(), pruner.getResult());
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)
337 AbstractNormalizedNodePruner pruner = prunerFullSchema(path);
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);
346 NormalizedNode expected = mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1);
347 NormalizedNode actual = pruner.getResult().orElseThrow();
348 assertEquals("normalizedNode", expected, actual);
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))
359 LeafSetEntryNode<Object> entry2 = Builders.leafSetEntryBuilder()
360 .withNodeIdentifier(new NodeWithValue<>(TestModel.BINARY_LEAF_LIST_QNAME, bytes2))
361 .withValue(bytes2).build();
363 return TestModel.createBaseTestContainerBuilder()
364 .withChild(Builders.leafSetBuilder()
365 .withNodeIdentifier(new NodeIdentifier(TestModel.BINARY_LEAF_LIST_QNAME))
369 .withChild(ImmutableNodes.leafNode(TestModel.SOME_BINARY_DATA_QNAME, new byte[]{1, 2, 3, 4}))