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.containerNode;
15 import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntry;
16 import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntryBuilder;
17 import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapNodeBuilder;
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.NodeIdentifier;
30 import org.opendaylight.yangtools.yang.data.api.schema.AnyxmlNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
34 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
35 import org.opendaylight.yangtools.yang.data.api.schema.SystemLeafSetNode;
36 import org.opendaylight.yangtools.yang.data.api.schema.SystemMapNode;
37 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
38 import org.opendaylight.yangtools.yang.data.spi.node.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);
80 @Test(expected = IllegalStateException.class)
81 public void testReusePruner() throws IOException {
82 AbstractNormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH);
84 NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
86 NormalizedNode expected = createTestContainer();
88 normalizedNodeWriter.write(expected);
90 NormalizedNode actual = pruner.getResult().orElseThrow();
92 assertEquals(expected, actual);
94 NormalizedNodeWriter.forStreamWriter(pruner).write(expected);
98 public void testNodesPrunedWhenAugmentationSchemaMissing() throws IOException {
99 AbstractNormalizedNodePruner pruner = prunerNoAugSchema(TestModel.TEST_PATH);
101 NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
103 NormalizedNode expected = createTestContainer();
105 normalizedNodeWriter.write(expected);
107 NormalizedNode actual = pruner.getResult().orElseThrow();
109 assertNotEquals(expected, actual);
111 // Asserting true here instead of checking actual value because I don't want this assertion to be fragile
112 assertTrue(countNodes(expected, "store:aug") > 0);
114 // All nodes from the augmentation module are gone from the resulting node
115 assertEquals(0, countNodes(actual, "store:aug"));
119 public void testNodesPrunedWhenTestSchemaMissing() throws IOException {
120 AbstractNormalizedNodePruner pruner = prunerNoTestSchema(TestModel.TEST_PATH);
122 NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
124 NormalizedNode expected = createTestContainer();
126 normalizedNodeWriter.write(expected);
128 // Since top level schema is missing empty is returned
129 assertEquals(Optional.empty(), pruner.getResult());
131 // Asserting true here instead of checking actual value because I don't want this assertion to be fragile
132 assertTrue(countNodes(expected, "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test") > 0);
135 private static int countNodes(final NormalizedNode normalizedNode, final String namespaceFilter) {
136 if (normalizedNode == null) {
139 final AtomicInteger count = new AtomicInteger();
140 new NormalizedNodeNavigator((level, parentPath, normalizedNode1) -> {
141 if (normalizedNode1.name().getNodeType().getNamespace().toString().contains(namespaceFilter)) {
142 count.incrementAndGet();
144 }).navigate(YangInstanceIdentifier.of().toString(), normalizedNode);
150 public void testLeafNodeNotPrunedWhenHasNoParent() throws IOException {
151 AbstractNormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.DESC_QNAME));
152 NormalizedNode input = ImmutableNodes.leafNode(TestModel.DESC_QNAME, "test");
153 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
155 assertEquals("normalizedNode", input, pruner.getResult().orElseThrow());
159 public void testLeafNodePrunedWhenHasNoParentAndSchemaMissing() throws IOException {
160 AbstractNormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.INVALID_QNAME));
161 LeafNode<String> input = ImmutableNodes.leafNode(TestModel.INVALID_QNAME, "test");
162 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
164 assertEquals(Optional.empty(), pruner.getResult());
168 public void testLeafSetEntryNodeNotPrunedWhenHasNoParent() throws IOException {
169 AbstractNormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.SHOE_QNAME));
170 LeafSetEntryNode<?> input = ImmutableNodes.leafSetEntry(TestModel.SHOE_QNAME, "puma");
171 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
173 NormalizedNode actual = pruner.getResult().orElseThrow();
174 assertEquals("normalizedNode", input, actual);
178 public void testLeafSetEntryNodeNotPrunedWhenHasParent() throws IOException {
179 AbstractNormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.SHOE_QNAME));
180 SystemLeafSetNode<?> input = ImmutableNodes.<String>newSystemLeafSetBuilder()
181 .withNodeIdentifier(new NodeIdentifier(TestModel.SHOE_QNAME))
182 .withChildValue("puma")
184 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
186 NormalizedNode actual = pruner.getResult().orElseThrow();
187 assertEquals("normalizedNode", input, actual);
191 public void testLeafSetEntryNodePrunedWhenHasNoParentAndSchemaMissing() throws IOException {
192 AbstractNormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.INVALID_QNAME));
193 LeafSetEntryNode<?> input = ImmutableNodes.leafSetEntry(TestModel.INVALID_QNAME, "test");
194 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
196 assertEquals(Optional.empty(), pruner.getResult());
200 public void testLeafSetEntryNodePrunedWhenHasParentAndSchemaMissing() throws IOException {
201 AbstractNormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.INVALID_QNAME));
202 NormalizedNodeWriter.forStreamWriter(pruner).write(ImmutableNodes.<String>newSystemLeafSetBuilder()
203 .withNodeIdentifier(new NodeIdentifier(TestModel.INVALID_QNAME))
204 .withChildValue("test")
207 assertEquals(Optional.empty(), pruner.getResult());
211 public void testAnyXMLNodeNotPrunedWhenHasNoParent() throws IOException {
212 AbstractNormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.ANY_XML_QNAME));
213 AnyxmlNode<DOMSource> input = ImmutableNodes.newAnyxmlBuilder(DOMSource.class)
214 .withNodeIdentifier(new NodeIdentifier(TestModel.ANY_XML_QNAME))
215 .withValue(mock(DOMSource.class))
217 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
219 assertEquals(input, pruner.getResult().orElseThrow());
223 public void testAnyXMLNodeNotPrunedWhenHasParent() throws IOException {
224 final var pruner = prunerFullSchema(TestModel.TEST_PATH);
225 final var input = ImmutableNodes.newContainerBuilder()
226 .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
227 .withChild(ImmutableNodes.newAnyxmlBuilder(DOMSource.class)
228 .withNodeIdentifier(new NodeIdentifier(TestModel.ANY_XML_QNAME))
229 .withValue(mock(DOMSource.class))
232 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
234 assertEquals(input, pruner.getResult().orElseThrow());
238 public void testAnyXmlNodePrunedWhenHasNoParentAndSchemaMissing() throws IOException {
239 AbstractNormalizedNodePruner pruner = prunerNoTestSchema(TestModel.TEST_PATH.node(TestModel.ANY_XML_QNAME));
240 NormalizedNodeWriter.forStreamWriter(pruner).write(ImmutableNodes.newAnyxmlBuilder(DOMSource.class)
241 .withNodeIdentifier(new NodeIdentifier(TestModel.ANY_XML_QNAME))
242 .withValue(mock(DOMSource.class))
245 assertEquals(Optional.empty(), pruner.getResult());
249 public void testInnerContainerNodeWithFullPathPathNotPruned() throws IOException {
250 YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
251 .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
252 .node(TestModel.INNER_LIST_QNAME).nodeWithKey(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "one")
253 .node(TestModel.INNER_CONTAINER_QNAME).build();
254 AbstractNormalizedNodePruner pruner = prunerFullSchema(path);
256 ContainerNode input = containerNode(TestModel.INNER_CONTAINER_QNAME);
257 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
259 assertEquals(input, pruner.getResult().orElseThrow());
263 public void testInnerContainerNodeWithFullPathPrunedWhenSchemaMissing() throws IOException {
264 YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
265 .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
266 .node(TestModel.INNER_LIST_QNAME).nodeWithKey(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "one")
267 .node(TestModel.INVALID_QNAME).build();
268 AbstractNormalizedNodePruner pruner = prunerFullSchema(path);
270 NormalizedNodeWriter.forStreamWriter(pruner).write(containerNode(TestModel.INVALID_QNAME));
272 assertEquals(Optional.empty(), pruner.getResult());
276 public void testInnerContainerNodeWithParentPathPrunedWhenSchemaMissing() throws IOException {
277 YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
278 .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
280 AbstractNormalizedNodePruner pruner = prunerFullSchema(path);
282 NormalizedNodeWriter.forStreamWriter(pruner)
283 .write(mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
284 .withChild(mapNodeBuilder(TestModel.INNER_LIST_QNAME)
285 .withChild(mapEntryBuilder(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "one")
286 .withChild(containerNode(TestModel.INVALID_QNAME))
291 assertEquals(mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
292 .withChild(mapNodeBuilder(TestModel.INNER_LIST_QNAME)
293 .withChild(mapEntryBuilder(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "one").build())
295 .build(), pruner.getResult().orElseThrow());
299 public void testInnerListNodeWithFullPathNotPruned() throws IOException {
300 YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
301 .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
302 .node(TestModel.INNER_LIST_QNAME).build();
303 AbstractNormalizedNodePruner pruner = prunerFullSchema(path);
305 SystemMapNode input = mapNodeBuilder(TestModel.INNER_LIST_QNAME)
306 .withChild(mapEntryBuilder(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "one")
307 .withChild(containerNode(TestModel.INNER_CONTAINER_QNAME))
310 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
312 assertEquals(input, pruner.getResult().orElseThrow());
316 public void testInnerListNodeWithFullPathPrunedWhenSchemaMissing() throws IOException {
317 YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
318 .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
319 .node(TestModel.INVALID_QNAME).build();
320 AbstractNormalizedNodePruner pruner = prunerFullSchema(path);
322 NormalizedNodeWriter.forStreamWriter(pruner).write(mapNodeBuilder(TestModel.INVALID_QNAME)
323 .withChild(mapEntryBuilder(TestModel.INVALID_QNAME, TestModel.NAME_QNAME, "one")
324 .withChild(containerNode(TestModel.INNER_CONTAINER_QNAME))
328 assertEquals(Optional.empty(), pruner.getResult());
332 public void testInnerListNodeWithParentPathPrunedWhenSchemaMissing() throws IOException {
333 YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
334 .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
336 AbstractNormalizedNodePruner pruner = prunerFullSchema(path);
338 NormalizedNodeWriter.forStreamWriter(pruner)
339 .write(mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
340 .withChild(mapNodeBuilder(TestModel.INVALID_QNAME)
341 .withChild(mapEntryBuilder(TestModel.INVALID_QNAME, TestModel.NAME_QNAME, "one")
342 .withChild(containerNode(TestModel.INNER_CONTAINER_QNAME))
347 assertEquals(mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1),
348 pruner.getResult().orElseThrow());
351 private static ContainerNode createTestContainer() {
352 return TestModel.createBaseTestContainerBuilder()
353 .withChild(ImmutableNodes.newSystemLeafSetBuilder()
354 .withNodeIdentifier(new NodeIdentifier(TestModel.BINARY_LEAF_LIST_QNAME))
355 .withChildValue(new byte[] {1, 2, 3})
356 .withChildValue(new byte[0])
358 .withChild(ImmutableNodes.leafNode(TestModel.SOME_BINARY_DATA_QNAME, new byte[] {1, 2, 3, 4}))