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.model.api.EffectiveModelContext;
42 @RunWith(MockitoJUnitRunner.StrictStubs.class)
43 public class NormalizedNodePrunerTest {
44 private static final EffectiveModelContext NO_TEST_SCHEMA = TestModel.createTestContextWithoutTestSchema();
45 private static final EffectiveModelContext NO_AUG_SCHEMA = TestModel.createTestContextWithoutAugmentationSchema();
46 private static final EffectiveModelContext FULL_SCHEMA = TestModel.createTestContext();
48 private static AbstractNormalizedNodePruner prunerFullSchema(final YangInstanceIdentifier path) {
49 final ReusableNormalizedNodePruner pruner = ReusableNormalizedNodePruner.forSchemaContext(FULL_SCHEMA);
50 pruner.initializeForPath(path);
54 private static AbstractNormalizedNodePruner prunerNoAugSchema(final YangInstanceIdentifier path) {
55 final ReusableNormalizedNodePruner pruner = ReusableNormalizedNodePruner.forSchemaContext(NO_AUG_SCHEMA);
56 pruner.initializeForPath(path);
60 private static AbstractNormalizedNodePruner prunerNoTestSchema(final YangInstanceIdentifier path) {
61 final ReusableNormalizedNodePruner pruner = ReusableNormalizedNodePruner.forSchemaContext(NO_TEST_SCHEMA);
62 pruner.initializeForPath(path);
67 public void testNodesNotPrunedWhenSchemaPresent() throws IOException {
68 AbstractNormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH);
70 NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
72 NormalizedNode expected = createTestContainer();
74 normalizedNodeWriter.write(expected);
76 NormalizedNode actual = pruner.getResult().orElseThrow();
78 assertEquals(expected, actual);
82 @Test(expected = IllegalStateException.class)
83 public void testReusePruner() throws IOException {
84 AbstractNormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH);
86 NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
88 NormalizedNode expected = createTestContainer();
90 normalizedNodeWriter.write(expected);
92 NormalizedNode actual = pruner.getResult().orElseThrow();
94 assertEquals(expected, actual);
96 NormalizedNodeWriter.forStreamWriter(pruner).write(expected);
102 public void testNodesPrunedWhenAugmentationSchemaMissing() throws IOException {
103 AbstractNormalizedNodePruner pruner = prunerNoAugSchema(TestModel.TEST_PATH);
105 NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
107 NormalizedNode expected = createTestContainer();
109 normalizedNodeWriter.write(expected);
111 NormalizedNode actual = pruner.getResult().orElseThrow();
113 assertNotEquals(expected, actual);
115 // Asserting true here instead of checking actual value because I don't want this assertion to be fragile
116 assertTrue(countNodes(expected, "store:aug") > 0);
118 // All nodes from the augmentation module are gone from the resulting node
119 assertEquals(0, countNodes(actual, "store:aug"));
123 public void testNodesPrunedWhenTestSchemaMissing() throws IOException {
124 AbstractNormalizedNodePruner pruner = prunerNoTestSchema(TestModel.TEST_PATH);
126 NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
128 NormalizedNode expected = createTestContainer();
130 normalizedNodeWriter.write(expected);
132 // Since top level schema is missing empty is returned
133 assertEquals(Optional.empty(), pruner.getResult());
135 // Asserting true here instead of checking actual value because I don't want this assertion to be fragile
136 assertTrue(countNodes(expected, "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test") > 0);
140 private static int countNodes(final NormalizedNode normalizedNode, final String namespaceFilter) {
141 if (normalizedNode == null) {
144 final AtomicInteger count = new AtomicInteger();
145 new NormalizedNodeNavigator((level, parentPath, normalizedNode1) -> {
146 if (!(normalizedNode1.getIdentifier() instanceof AugmentationIdentifier)) {
147 if (normalizedNode1.getIdentifier().getNodeType().getNamespace().toString().contains(namespaceFilter)) {
148 count.incrementAndGet();
151 }).navigate(YangInstanceIdentifier.empty().toString(), normalizedNode);
157 public void testLeafNodeNotPrunedWhenHasNoParent() throws IOException {
158 AbstractNormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.DESC_QNAME));
159 NormalizedNode input = Builders.leafBuilder().withNodeIdentifier(
160 new NodeIdentifier(TestModel.DESC_QNAME)).withValue("test").build();
161 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
163 assertEquals("normalizedNode", input, pruner.getResult().orElseThrow());
167 public void testLeafNodePrunedWhenHasAugmentationParentAndSchemaMissing() throws IOException {
168 AugmentationIdentifier augId = new AugmentationIdentifier(Sets.newHashSet(TestModel.AUG_CONT_QNAME));
169 AbstractNormalizedNodePruner pruner = prunerFullSchema(YangInstanceIdentifier.builder()
170 .node(TestModel.TEST_QNAME).node(TestModel.AUGMENTED_LIST_QNAME)
171 .node(TestModel.AUGMENTED_LIST_QNAME).node(augId).build());
172 LeafNode<Object> child = Builders.leafBuilder().withNodeIdentifier(
173 new NodeIdentifier(TestModel.INVALID_QNAME)).withValue("test").build();
174 NormalizedNode input = Builders.augmentationBuilder().withNodeIdentifier(augId).withChild(child).build();
175 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
177 NormalizedNode actual = pruner.getResult().orElseThrow();
178 assertEquals("normalizedNode", Builders.augmentationBuilder().withNodeIdentifier(augId).build(), actual);
182 public void testLeafNodePrunedWhenHasNoParentAndSchemaMissing() throws IOException {
183 AbstractNormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.INVALID_QNAME));
184 NormalizedNode input = Builders.leafBuilder().withNodeIdentifier(
185 new NodeIdentifier(TestModel.INVALID_QNAME)).withValue("test").build();
186 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
188 assertEquals(Optional.empty(), pruner.getResult());
192 public void testLeafSetEntryNodeNotPrunedWhenHasNoParent() throws IOException {
193 AbstractNormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.SHOE_QNAME));
194 NormalizedNode input = Builders.leafSetEntryBuilder().withValue("puma").withNodeIdentifier(
195 new NodeWithValue<>(TestModel.SHOE_QNAME, "puma")).build();
196 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
198 NormalizedNode actual = pruner.getResult().orElseThrow();
199 assertEquals("normalizedNode", input, actual);
203 public void testLeafSetEntryNodeNotPrunedWhenHasParent() throws IOException {
204 AbstractNormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.SHOE_QNAME));
205 LeafSetEntryNode<Object> child = Builders.leafSetEntryBuilder().withValue("puma").withNodeIdentifier(
206 new NodeWithValue<>(TestModel.SHOE_QNAME, "puma")).build();
207 NormalizedNode input = Builders.leafSetBuilder().withNodeIdentifier(
208 new NodeIdentifier(TestModel.SHOE_QNAME)).withChild(child).build();
209 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
211 NormalizedNode actual = pruner.getResult().orElseThrow();
212 assertEquals("normalizedNode", input, actual);
216 public void testLeafSetEntryNodePrunedWhenHasNoParentAndSchemaMissing() throws IOException {
217 AbstractNormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.INVALID_QNAME));
218 NormalizedNode input = Builders.leafSetEntryBuilder().withValue("test").withNodeIdentifier(
219 new NodeWithValue<>(TestModel.INVALID_QNAME, "test")).build();
220 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
222 assertEquals(Optional.empty(), pruner.getResult());
226 public void testLeafSetEntryNodePrunedWhenHasParentAndSchemaMissing() throws IOException {
227 AbstractNormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.INVALID_QNAME));
228 LeafSetEntryNode<Object> child = Builders.leafSetEntryBuilder().withValue("test").withNodeIdentifier(
229 new NodeWithValue<>(TestModel.INVALID_QNAME, "test")).build();
230 NormalizedNode input = Builders.leafSetBuilder().withNodeIdentifier(
231 new NodeIdentifier(TestModel.INVALID_QNAME)).withChild(child).build();
232 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
234 assertEquals(Optional.empty(), pruner.getResult());
238 public void testAnyXMLNodeNotPrunedWhenHasNoParent() throws IOException {
239 AbstractNormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.ANY_XML_QNAME));
240 NormalizedNode input = Builders.anyXmlBuilder().withNodeIdentifier(
241 new NodeIdentifier(TestModel.ANY_XML_QNAME)).withValue(mock(DOMSource.class)).build();
242 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
244 NormalizedNode actual = pruner.getResult().orElseThrow();
245 assertEquals("normalizedNode", input, actual);
249 public void testAnyXMLNodeNotPrunedWhenHasParent() throws IOException {
250 AbstractNormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH);
251 DOMSourceAnyxmlNode child = Builders.anyXmlBuilder().withNodeIdentifier(
252 new NodeIdentifier(TestModel.ANY_XML_QNAME)).withValue(mock(DOMSource.class)).build();
253 NormalizedNode input = Builders.containerBuilder().withNodeIdentifier(
254 new NodeIdentifier(TestModel.TEST_QNAME)).withChild(child).build();
255 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
257 NormalizedNode actual = pruner.getResult().orElseThrow();
258 assertEquals("normalizedNode", input, actual);
262 public void testAnyXmlNodePrunedWhenHasNoParentAndSchemaMissing() throws IOException {
263 AbstractNormalizedNodePruner pruner = prunerNoTestSchema(TestModel.TEST_PATH.node(TestModel.ANY_XML_QNAME));
264 NormalizedNode input = Builders.anyXmlBuilder().withNodeIdentifier(
265 new NodeIdentifier(TestModel.ANY_XML_QNAME)).withValue(mock(DOMSource.class)).build();
266 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
268 assertEquals(Optional.empty(), pruner.getResult());
272 public void testInnerContainerNodeWithFullPathPathNotPruned() throws IOException {
273 YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
274 .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
275 .node(TestModel.INNER_LIST_QNAME).nodeWithKey(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "one")
276 .node(TestModel.INNER_CONTAINER_QNAME).build();
277 AbstractNormalizedNodePruner pruner = prunerFullSchema(path);
279 NormalizedNode input = ImmutableNodes.containerNode(TestModel.INNER_CONTAINER_QNAME);
280 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
282 NormalizedNode actual = pruner.getResult().orElseThrow();
283 assertEquals("normalizedNode", input, actual);
287 public void testInnerContainerNodeWithFullPathPrunedWhenSchemaMissing() throws IOException {
288 YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
289 .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
290 .node(TestModel.INNER_LIST_QNAME).nodeWithKey(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "one")
291 .node(TestModel.INVALID_QNAME).build();
292 AbstractNormalizedNodePruner pruner = prunerFullSchema(path);
294 NormalizedNode input = ImmutableNodes.containerNode(TestModel.INVALID_QNAME);
295 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
297 assertEquals(Optional.empty(), pruner.getResult());
301 public void testInnerContainerNodeWithParentPathPrunedWhenSchemaMissing() throws IOException {
302 YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
303 .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
305 AbstractNormalizedNodePruner pruner = prunerFullSchema(path);
307 MapNode innerList = mapNodeBuilder(TestModel.INNER_LIST_QNAME).withChild(mapEntryBuilder(
308 TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "one").withChild(
309 ImmutableNodes.containerNode(TestModel.INVALID_QNAME)).build()).build();
310 NormalizedNode input = mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
311 .withChild(innerList).build();
312 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
314 NormalizedNode expected = mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
315 .withChild(mapNodeBuilder(TestModel.INNER_LIST_QNAME).withChild(mapEntryBuilder(
316 TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "one").build()).build()).build();
317 NormalizedNode actual = pruner.getResult().orElseThrow();
318 assertEquals("normalizedNode", expected, actual);
322 public void testInnerListNodeWithFullPathNotPruned() throws IOException {
323 YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
324 .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
325 .node(TestModel.INNER_LIST_QNAME).build();
326 AbstractNormalizedNodePruner pruner = prunerFullSchema(path);
328 MapNode input = mapNodeBuilder(TestModel.INNER_LIST_QNAME).withChild(mapEntryBuilder(
329 TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "one").withChild(
330 ImmutableNodes.containerNode(TestModel.INNER_CONTAINER_QNAME)).build()).build();
331 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
333 NormalizedNode actual = pruner.getResult().orElseThrow();
334 assertEquals("normalizedNode", input, actual);
338 public void testInnerListNodeWithFullPathPrunedWhenSchemaMissing() throws IOException {
339 YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
340 .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
341 .node(TestModel.INVALID_QNAME).build();
342 AbstractNormalizedNodePruner pruner = prunerFullSchema(path);
344 MapNode input = mapNodeBuilder(TestModel.INVALID_QNAME).withChild(mapEntryBuilder(
345 TestModel.INVALID_QNAME, TestModel.NAME_QNAME, "one").withChild(
346 ImmutableNodes.containerNode(TestModel.INNER_CONTAINER_QNAME)).build()).build();
347 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
349 assertEquals(Optional.empty(), pruner.getResult());
353 public void testInnerListNodeWithParentPathPrunedWhenSchemaMissing() throws IOException {
354 YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
355 .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
357 AbstractNormalizedNodePruner pruner = prunerFullSchema(path);
359 MapNode innerList = mapNodeBuilder(TestModel.INVALID_QNAME).withChild(mapEntryBuilder(
360 TestModel.INVALID_QNAME, TestModel.NAME_QNAME, "one").withChild(
361 ImmutableNodes.containerNode(TestModel.INNER_CONTAINER_QNAME)).build()).build();
362 NormalizedNode input = mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
363 .withChild(innerList).build();
364 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
366 NormalizedNode expected = mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1);
367 NormalizedNode actual = pruner.getResult().orElseThrow();
368 assertEquals("normalizedNode", expected, actual);
371 private static NormalizedNode createTestContainer() {
372 byte[] bytes1 = {1, 2, 3};
373 LeafSetEntryNode<Object> entry1 = Builders.leafSetEntryBuilder()
374 .withNodeIdentifier(new NodeWithValue<>(TestModel.BINARY_LEAF_LIST_QNAME, bytes1))
379 LeafSetEntryNode<Object> entry2 = Builders.leafSetEntryBuilder()
380 .withNodeIdentifier(new NodeWithValue<>(TestModel.BINARY_LEAF_LIST_QNAME, bytes2))
381 .withValue(bytes2).build();
383 return TestModel.createBaseTestContainerBuilder()
384 .withChild(Builders.leafSetBuilder()
385 .withNodeIdentifier(new NodeIdentifier(TestModel.BINARY_LEAF_LIST_QNAME))
389 .withChild(ImmutableNodes.leafNode(TestModel.SOME_BINARY_DATA_QNAME, new byte[]{1, 2, 3, 4}))