Merge "Fixed concurrency bug in DOMTransactionChainTest"
[controller.git] / opendaylight / md-sal / sal-common-impl / src / test / java / org / opendaylight / controller / md / sal / common / impl / util / compat / DataNormalizerTest.java
1 /*
2  * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.md.sal.common.impl.util.compat;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotNull;
12 import static org.junit.Assert.assertNull;
13 import static org.junit.Assert.assertTrue;
14 import static org.junit.Assert.fail;
15
16 import com.google.common.collect.ImmutableList;
17 import com.google.common.collect.Lists;
18 import com.google.common.collect.Maps;
19 import com.google.common.collect.Sets;
20 import java.util.AbstractMap;
21 import java.util.Arrays;
22 import java.util.Collections;
23 import java.util.Comparator;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Map.Entry;
27 import java.util.Set;
28 import org.junit.Test;
29 import org.opendaylight.yangtools.yang.common.QName;
30 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
31 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
32 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
33 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
34 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
35 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeWithValue;
36 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
37 import org.opendaylight.yangtools.yang.data.api.Node;
38 import org.opendaylight.yangtools.yang.data.api.SimpleNode;
39 import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
40 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
41 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
42 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
43 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
44 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
45 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
46 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
47 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
48 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
49 import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
50 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
51 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
52 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
53 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
54 import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
55 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
56 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
57 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
58 import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder;
59 import org.opendaylight.yangtools.yang.model.api.Module;
60 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
61 import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
62
63 public class DataNormalizerTest {
64
65     static class NormalizedNodeData {
66         PathArgument nodeID;
67         Class<?> nodeClass;
68         Object nodeData; // List for a container, value Object for a leaf
69
70         NormalizedNodeData(PathArgument nodeID, Class<?> nodeClass, Object nodeData) {
71             this.nodeID = nodeID;
72             this.nodeClass = nodeClass;
73             this.nodeData = nodeData;
74         }
75     }
76
77     static class LegacyNodeData {
78         QName nodeKey;
79         Object nodeData; // List for a CompositeNode, value Object for a
80                          // SimpeNode
81
82         LegacyNodeData(QName nodeKey, Object nodeData) {
83             this.nodeKey = nodeKey;
84             this.nodeData = nodeData;
85         }
86
87         @Override
88         public String toString() {
89             return nodeKey.toString();
90         }
91     }
92
93     static final QName TEST_QNAME = QName.create(
94             "urn:opendaylight:params:xml:ns:yang:controller:md:sal:normalization:test", "2014-03-13", "test");
95     static final QName OUTER_LIST_QNAME = QName.create(TEST_QNAME, "outer-list");
96     static final QName INNER_LIST_QNAME = QName.create(TEST_QNAME, "inner-list");
97     static final QName OUTER_CHOICE_QNAME = QName.create(TEST_QNAME, "outer-choice");
98     static final QName ID_QNAME = QName.create(TEST_QNAME, "id");
99     static final QName NAME_QNAME = QName.create(TEST_QNAME, "name");
100     static final QName VALUE_QNAME = QName.create(TEST_QNAME, "value");
101
102     static final InstanceIdentifier TEST_PATH = InstanceIdentifier.of(TEST_QNAME);
103     static final InstanceIdentifier OUTER_LIST_PATH = InstanceIdentifier.builder(TEST_PATH).node(OUTER_LIST_QNAME)
104             .build();
105     static final QName ONE_QNAME = QName.create(TEST_QNAME, "one");
106     static final QName TWO_QNAME = QName.create(TEST_QNAME, "two");
107     static final QName THREE_QNAME = QName.create(TEST_QNAME, "three");
108
109     static final QName ANY_XML_DATA_QNAME = QName.create(TEST_QNAME, "any-xml-data");
110     static final QName OUTER_CONTAINER_QNAME = QName.create(TEST_QNAME, "outer-container");
111     static final QName AUGMENTED_LEAF_QNAME = QName.create(TEST_QNAME, "augmented-leaf");
112     static final QName UNKEYED_LIST_QNAME = QName.create(TEST_QNAME, "unkeyed-list");
113     static final QName UNORDERED_LEAF_LIST_QNAME = QName.create(TEST_QNAME, "unordered-leaf-list");
114     static final QName ORDERED_LEAF_LIST_QNAME = QName.create(TEST_QNAME, "ordered-leaf-list");
115
116     static final Short OUTER_LIST_ID = (short) 10;
117
118     static final InstanceIdentifier OUTER_LIST_PATH_LEGACY = InstanceIdentifier.builder(TEST_QNAME)
119             .nodeWithKey(OUTER_LIST_QNAME, ID_QNAME, OUTER_LIST_ID).build();
120
121     static final InstanceIdentifier LEAF_TWO_PATH_LEGACY = InstanceIdentifier.builder(OUTER_LIST_PATH_LEGACY)
122             .node(TWO_QNAME).build();
123
124     static final QName ANY_XML_LEAF_QNAME = QName.create(TEST_QNAME, "leaf");;
125     static final QName ANY_XML_INNER_QNAME = QName.create(TEST_QNAME, "inner");
126     static final QName ANY_XML_INNER_LEAF_QNAME = QName.create(TEST_QNAME, "inner-leaf");
127
128     SchemaContext createTestContext() {
129         YangParserImpl parser = new YangParserImpl();
130         Set<Module> modules = parser.parseYangModelsFromStreams(Collections.singletonList(DataNormalizerTest.class
131                 .getResourceAsStream("/normalization-test.yang")));
132         return parser.resolveSchemaContext(modules);
133     }
134
135     @Test
136     public void testToNormalizedInstanceIdentifier() {
137         SchemaContext testCtx = createTestContext();
138         DataNormalizer normalizer = new DataNormalizer(testCtx);
139
140         InstanceIdentifier normalizedPath = normalizer.toNormalized(LEAF_TWO_PATH_LEGACY);
141
142         verifyNormalizedInstanceIdentifier(normalizedPath, TEST_QNAME, OUTER_LIST_QNAME, new Object[] {
143                 OUTER_LIST_QNAME, ID_QNAME, OUTER_LIST_ID }, OUTER_CHOICE_QNAME, TWO_QNAME);
144     }
145
146     private void verifyNormalizedInstanceIdentifier(InstanceIdentifier actual, Object... expPath) {
147
148         assertNotNull("Actual InstanceIdentifier is null", actual);
149         assertEquals("InstanceIdentifier path length", expPath.length, actual.getPath().size());
150
151         for (int i = 0; i < expPath.length; i++) {
152             PathArgument actualArg = actual.getPath().get(i);
153             if (expPath[i] instanceof Object[]) { // NodeIdentifierWithPredicates
154                 Object[] exp = (Object[]) expPath[i];
155                 assertEquals("Actual path arg " + (i + 1) + " class", NodeIdentifierWithPredicates.class,
156                         actualArg.getClass());
157                 NodeIdentifierWithPredicates actualNode = (NodeIdentifierWithPredicates) actualArg;
158                 assertEquals("Actual path arg " + (i + 1) + " node type", exp[0], actualNode.getNodeType());
159                 assertEquals("Actual path arg " + (i + 1) + " key values map size", 1, actualNode.getKeyValues().size());
160                 Entry<QName, Object> keyValuesEntry = actualNode.getKeyValues().entrySet().iterator().next();
161                 assertEquals("Actual path arg " + (i + 1) + " key values map key", exp[1], keyValuesEntry.getKey());
162                 assertEquals("Actual path arg " + (i + 1) + " key values map value", exp[2], keyValuesEntry.getValue());
163             } else if (expPath[i] instanceof Set) { // AugmentationIdentifier
164                 assertEquals("Actual path arg " + (i + 1) + " class", AugmentationIdentifier.class,
165                         actualArg.getClass());
166                 AugmentationIdentifier actualNode = (AugmentationIdentifier) actualArg;
167                 assertEquals("Actual path arg " + (i + 1) + " PossibleChildNames", expPath[i],
168                         actualNode.getPossibleChildNames());
169             } else {
170                 assertEquals("Actual path arg " + (i + 1) + " node type", expPath[i], actualArg.getNodeType());
171             }
172         }
173     }
174
175     @Test
176     public void testToLegacyInstanceIdentifier() throws DataNormalizationException {
177
178         DataNormalizer normalizer = new DataNormalizer(createTestContext());
179
180         InstanceIdentifier normalized = InstanceIdentifier.builder().node(TEST_QNAME).node(OUTER_LIST_QNAME)
181                 .nodeWithKey(OUTER_LIST_QNAME, ID_QNAME, OUTER_LIST_ID).node(OUTER_CHOICE_QNAME).node(TWO_QNAME)
182                 .build();
183
184         InstanceIdentifier legacy = normalizer.toLegacy(normalized);
185
186         assertEquals("Legacy InstanceIdentifier", LEAF_TWO_PATH_LEGACY, legacy);
187     }
188
189     @Test
190     public void testToLegacyNormalizedNode() {
191
192         ChoiceNode choiceNode1 = Builders.choiceBuilder().withNodeIdentifier(new NodeIdentifier(OUTER_CHOICE_QNAME))
193                 .withChild(ImmutableNodes.leafNode(TWO_QNAME, "two"))
194                 .withChild(ImmutableNodes.leafNode(THREE_QNAME, "three")).build();
195
196         MapEntryNode innerListEntryNode1 = Builders.mapEntryBuilder()
197                 .withNodeIdentifier(new NodeIdentifierWithPredicates(INNER_LIST_QNAME, NAME_QNAME, "inner-name1"))
198                 .withChild(ImmutableNodes.leafNode(NAME_QNAME, "inner-name1"))
199                 .withChild(ImmutableNodes.leafNode(VALUE_QNAME, "inner-value1")).build();
200
201         MapEntryNode innerListEntryNode2 = Builders.mapEntryBuilder()
202                 .withNodeIdentifier(new NodeIdentifierWithPredicates(INNER_LIST_QNAME, NAME_QNAME, "inner-name2"))
203                 .withChild(ImmutableNodes.leafNode(NAME_QNAME, "inner-name2"))
204                 .withChild(ImmutableNodes.leafNode(VALUE_QNAME, "inner-value2")).build();
205
206         OrderedMapNode innerListNode = Builders.orderedMapBuilder()
207                 .withNodeIdentifier(new NodeIdentifier(INNER_LIST_QNAME)).withChild(innerListEntryNode1)
208                 .withChild(innerListEntryNode2).build();
209
210         Short outerListID1 = Short.valueOf((short) 10);
211         MapEntryNode outerListEntryNode1 = Builders.mapEntryBuilder()
212                 .withNodeIdentifier(new NodeIdentifierWithPredicates(OUTER_LIST_QNAME, ID_QNAME, outerListID1))
213                 .withChild(ImmutableNodes.leafNode(ID_QNAME, outerListID1)).withChild(choiceNode1)
214                 .withChild(innerListNode).build();
215
216         ChoiceNode choiceNode2 = Builders.choiceBuilder().withNodeIdentifier(new NodeIdentifier(OUTER_CHOICE_QNAME))
217                 .withChild(ImmutableNodes.leafNode(ONE_QNAME, "one")).build();
218
219         Short outerListID2 = Short.valueOf((short) 20);
220         MapEntryNode outerListEntryNode2 = Builders.mapEntryBuilder()
221                 .withNodeIdentifier(new NodeIdentifierWithPredicates(OUTER_LIST_QNAME, ID_QNAME, outerListID2))
222                 .withChild(ImmutableNodes.leafNode(ID_QNAME, outerListID2)).withChild(choiceNode2).build();
223
224         MapNode outerListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(OUTER_LIST_QNAME))
225                 .withChild(outerListEntryNode1).withChild(outerListEntryNode2).build();
226
227         UnkeyedListEntryNode unkeyedListEntryNode1 = Builders.unkeyedListEntryBuilder()
228                 .withNodeIdentifier(new NodeIdentifier(UNKEYED_LIST_QNAME))
229                 .withChild(ImmutableNodes.leafNode(NAME_QNAME, "unkeyed1")).build();
230
231         UnkeyedListEntryNode unkeyedListEntryNode2 = Builders.unkeyedListEntryBuilder()
232                 .withNodeIdentifier(new NodeIdentifier(UNKEYED_LIST_QNAME))
233                 .withChild(ImmutableNodes.leafNode(NAME_QNAME, "unkeyed2")).build();
234
235         UnkeyedListNode unkeyedListNode = Builders.unkeyedListBuilder()
236                 .withNodeIdentifier(new NodeIdentifier(UNKEYED_LIST_QNAME)).withChild(unkeyedListEntryNode1)
237                 .withChild(unkeyedListEntryNode2).build();
238
239         ContainerNode testContainerNode = Builders.containerBuilder()
240                 .withNodeIdentifier(new NodeIdentifier(TEST_QNAME)).withChild(outerListNode).withChild(unkeyedListNode)
241                 .build();
242
243         Node<?> legacyNode = DataNormalizer.toLegacy(testContainerNode);
244
245         verifyLegacyNode(
246                 legacyNode,
247                 expectCompositeNode(
248                         TEST_QNAME,
249                         expectCompositeNode(
250                                 OUTER_LIST_QNAME,
251                                 expectSimpleNode(ID_QNAME, outerListID1),
252                                 expectSimpleNode(TWO_QNAME, "two"),
253                                 expectSimpleNode(THREE_QNAME, "three"),
254
255                                 expectCompositeNode(INNER_LIST_QNAME, expectSimpleNode(NAME_QNAME, "inner-name1"),
256                                         expectSimpleNode(VALUE_QNAME, "inner-value1")),
257
258                                 expectCompositeNode(INNER_LIST_QNAME, expectSimpleNode(NAME_QNAME, "inner-name2"),
259                                         expectSimpleNode(VALUE_QNAME, "inner-value2"))),
260                         expectCompositeNode(OUTER_LIST_QNAME, expectSimpleNode(ID_QNAME, outerListID2),
261                                 expectSimpleNode(ONE_QNAME, "one")),
262                         expectCompositeNode(UNKEYED_LIST_QNAME, expectSimpleNode(NAME_QNAME, "unkeyed1")),
263                         expectCompositeNode(UNKEYED_LIST_QNAME, expectSimpleNode(NAME_QNAME, "unkeyed2"))));
264
265         // Conversion of Mixin type nodes is not supported.
266
267         assertNull("Expected null returned for Mixin type node", DataNormalizer.toLegacy(outerListNode));
268     }
269
270     /**
271      * Following data are constructed: <any-xml-data> <inner>
272      * <inner-leaf>inner-leaf-value</inner-leaf> </inner>
273      * <leaf>leaf-value</leaf> <any-xml-data>
274      */
275     @Test
276     public void testToLegacyNormalizedNodeWithAnyXml() {
277
278         Node<?> innerLeafChild = NodeFactory.createImmutableSimpleNode(ANY_XML_INNER_LEAF_QNAME, null,
279                 "inner-leaf-value");
280         CompositeNode innerContainer = NodeFactory.createImmutableCompositeNode(ANY_XML_INNER_QNAME, null,
281                 Collections.<Node<?>> singletonList(innerLeafChild));
282
283         Node<?> leafChild = NodeFactory.createImmutableSimpleNode(ANY_XML_LEAF_QNAME, null, "leaf-value");
284         CompositeNode anyXmlNodeValue = NodeFactory.createImmutableCompositeNode(ANY_XML_DATA_QNAME, null,
285                 Arrays.asList(leafChild, innerContainer));
286
287         AnyXmlNode testAnyXmlNode = Builders.anyXmlBuilder().withNodeIdentifier(new NodeIdentifier(TEST_QNAME))
288                 .withValue(anyXmlNodeValue).build();
289
290         ContainerNode testContainerNode = Builders.containerBuilder()
291                 .withNodeIdentifier(new NodeIdentifier(TEST_QNAME)).withChild(testAnyXmlNode).build();
292
293         DataNormalizer normalizer = new DataNormalizer(createTestContext());
294         Node<?> legacyNode = normalizer.toLegacy(InstanceIdentifier.builder(TEST_QNAME).build(), testContainerNode);
295
296         verifyLegacyNode(
297                 legacyNode,
298                 expectCompositeNode(
299                         TEST_QNAME,
300                         expectCompositeNode(
301                                 ANY_XML_DATA_QNAME,
302                                 expectSimpleNode(ANY_XML_LEAF_QNAME, "leaf-value"),
303                                 expectCompositeNode(ANY_XML_INNER_QNAME,
304                                         expectSimpleNode(ANY_XML_INNER_LEAF_QNAME, "inner-leaf-value")))));
305     }
306
307     @Test
308     public void testToLegacyNormalizedNodeWithLeafLists() {
309
310         CompositeNodeBuilder<ImmutableCompositeNode> testBuilder = ImmutableCompositeNode.builder();
311         testBuilder.setQName(TEST_QNAME);
312
313         ListNodeBuilder<Object, LeafSetEntryNode<Object>> leafSetBuilder = Builders.leafSetBuilder()
314                 .withNodeIdentifier(new NodeIdentifier(UNORDERED_LEAF_LIST_QNAME));
315         for (int i = 1; i <= 3; i++) {
316             leafSetBuilder.withChildValue("unordered-value" + i);
317         }
318
319         ListNodeBuilder<Object, LeafSetEntryNode<Object>> orderedLeafSetBuilder = Builders.orderedLeafSetBuilder()
320                 .withNodeIdentifier(new NodeIdentifier(ORDERED_LEAF_LIST_QNAME));
321         for (int i = 3; i > 0; i--) {
322             orderedLeafSetBuilder.withChildValue("ordered-value" + i);
323         }
324
325         ContainerNode testContainerNode = Builders.containerBuilder()
326                 .withNodeIdentifier(new NodeIdentifier(TEST_QNAME)).withChild(leafSetBuilder.build())
327                 .withChild(orderedLeafSetBuilder.build()).build();
328
329         DataNormalizer normalizer = new DataNormalizer(createTestContext());
330
331         Node<?> legacyNode = normalizer.toLegacy(InstanceIdentifier.builder(TEST_QNAME).build(), testContainerNode);
332
333         verifyLegacyNode(
334                 legacyNode,
335                 expectCompositeNode(TEST_QNAME, expectSimpleNode(UNORDERED_LEAF_LIST_QNAME, "unordered-value1"),
336                         expectSimpleNode(UNORDERED_LEAF_LIST_QNAME, "unordered-value2"),
337                         expectSimpleNode(UNORDERED_LEAF_LIST_QNAME, "unordered-value3"),
338                         expectSimpleNode(ORDERED_LEAF_LIST_QNAME, "ordered-value3"),
339                         expectSimpleNode(ORDERED_LEAF_LIST_QNAME, "ordered-value2"),
340                         expectSimpleNode(ORDERED_LEAF_LIST_QNAME, "ordered-value1")));
341     }
342
343     @Test
344     public void testToLegacyNormalizedNodeWithAugmentation() {
345
346         AugmentationNode augmentationNode = Builders.augmentationBuilder()
347                 .withNodeIdentifier(new AugmentationIdentifier(Sets.newHashSet(AUGMENTED_LEAF_QNAME)))
348                 .withChild(ImmutableNodes.leafNode(AUGMENTED_LEAF_QNAME, "augmented-value")).build();
349
350         ContainerNode outerContainerNode = Builders.containerBuilder()
351                 .withNodeIdentifier(new NodeIdentifier(OUTER_CONTAINER_QNAME)).withChild(augmentationNode).build();
352
353         ContainerNode testContainerNode = Builders.containerBuilder()
354                 .withNodeIdentifier(new NodeIdentifier(TEST_QNAME)).withChild(outerContainerNode).build();
355
356         DataNormalizer normalizer = new DataNormalizer(createTestContext());
357
358         Node<?> legacyNode = normalizer.toLegacy(InstanceIdentifier.builder(TEST_QNAME).build(), testContainerNode);
359
360         verifyLegacyNode(
361                 legacyNode,
362                 expectCompositeNode(
363                         TEST_QNAME,
364                         expectCompositeNode(OUTER_CONTAINER_QNAME,
365                                 expectSimpleNode(AUGMENTED_LEAF_QNAME, "augmented-value"))));
366     }
367
368     private boolean isOrdered(QName nodeName) {
369         return ORDERED_LEAF_LIST_QNAME.equals(nodeName) || INNER_LIST_QNAME.equals(nodeName);
370     }
371
372     @SuppressWarnings("unchecked")
373     private void verifyLegacyNode(Node<?> actual, LegacyNodeData expNodeData) {
374
375         assertNotNull("Actual Node is null", actual);
376         assertTrue("Expected CompositeNode instance", actual instanceof CompositeNode);
377         CompositeNode actualCN = (CompositeNode) actual;
378         assertEquals("Node key", expNodeData.nodeKey, actualCN.getKey());
379
380         List<LegacyNodeData> expChildData = Lists.newArrayList();
381         List<LegacyNodeData> unorderdChildData = Lists.newArrayList();
382         for (LegacyNodeData data : (List<LegacyNodeData>) expNodeData.nodeData) {
383             if (isOrdered(data.nodeKey)) {
384                 expChildData.add(data);
385             } else {
386                 unorderdChildData.add(data);
387             }
388         }
389
390         Collections.sort(unorderdChildData, new Comparator<LegacyNodeData>() {
391             @Override
392             public int compare(LegacyNodeData arg1, LegacyNodeData arg2) {
393                 String str1 = arg1.nodeKey.getLocalName();
394                 if (!(arg1.nodeData instanceof List))
395                     str1 += arg1.nodeData; // add simple node value
396
397                 String str2 = arg2.nodeKey.getLocalName();
398                 if (!(arg2.nodeData instanceof List))
399                     str2 += arg2.nodeData; // add simple node value
400
401                 return str1.compareTo(str2);
402             }
403         });
404
405         expChildData.addAll(unorderdChildData);
406
407         List<Node<?>> actualChildNodes = Lists.newArrayList();
408         List<Node<?>> unorderedChildNodes = Lists.newArrayList();
409         for (Node<?> node : actualCN.getValue()) {
410             if (isOrdered(node.getKey())) {
411                 actualChildNodes.add(node);
412             } else {
413                 unorderedChildNodes.add(node);
414             }
415         }
416
417         Collections.sort(unorderedChildNodes, new Comparator<Node<?>>() {
418             @Override
419             public int compare(Node<?> n1, Node<?> n2) {
420                 String str1 = n1.getKey().getLocalName();
421                 if (n1 instanceof SimpleNode)
422                     str1 += ((SimpleNode<?>) n1).getValue();
423
424                 String str2 = n2.getKey().getLocalName();
425                 if (n2 instanceof SimpleNode)
426                     str2 += ((SimpleNode<?>) n2).getValue();
427
428                 return str1.compareTo(str2);
429             }
430         });
431
432         actualChildNodes.addAll(unorderedChildNodes);
433
434         for (Node<?> actualChild : actualChildNodes) {
435             LegacyNodeData expData = expChildData.isEmpty() ? null : expChildData.remove(0);
436             assertNotNull("Unexpected child node with key " + actualChild.getKey(), expData);
437             assertEquals("Child node QName", expData.nodeKey, actualChild.getKey());
438
439             if (expData.nodeData instanceof List) { // List represents a
440                                                     // composite node
441                 verifyLegacyNode(actualChild, expData);
442             } else { // else a simple node
443                 assertTrue("Expected SimpleNode instance", actualChild instanceof SimpleNode);
444                 assertEquals("Child node value with key " + actualChild.getKey(), expData.nodeData,
445                         ((SimpleNode<?>) actualChild).getValue());
446             }
447         }
448
449         if (!expChildData.isEmpty()) {
450             fail("Missing child nodes: " + expChildData);
451         }
452     }
453
454     private LegacyNodeData expectCompositeNode(QName key, LegacyNodeData... childData) {
455         return new LegacyNodeData(key, Lists.newArrayList(childData));
456     }
457
458     private LegacyNodeData expectSimpleNode(QName key, Object value) {
459         return new LegacyNodeData(key, value);
460     }
461
462     @Test
463     public void testToNormalizedCompositeNode() {
464         SchemaContext testCtx = createTestContext();
465         DataNormalizer normalizer = new DataNormalizer(testCtx);
466
467         CompositeNodeBuilder<ImmutableCompositeNode> testBuilder = ImmutableCompositeNode.builder();
468         testBuilder.setQName(TEST_QNAME);
469
470         CompositeNodeBuilder<ImmutableCompositeNode> outerListBuilder = ImmutableCompositeNode.builder();
471         outerListBuilder.setQName(OUTER_LIST_QNAME);
472         outerListBuilder.addLeaf(ID_QNAME, 10);
473         outerListBuilder.addLeaf(ONE_QNAME, "one");
474
475         for (int i = 3; i > 0; i--) {
476             CompositeNodeBuilder<ImmutableCompositeNode> innerListBuilder = ImmutableCompositeNode.builder();
477             innerListBuilder.setQName(INNER_LIST_QNAME);
478             innerListBuilder.addLeaf(NAME_QNAME, "inner-name" + i);
479             innerListBuilder.addLeaf(VALUE_QNAME, "inner-value" + i);
480             outerListBuilder.add(innerListBuilder.toInstance());
481         }
482
483         testBuilder.add(outerListBuilder.toInstance());
484
485         outerListBuilder = ImmutableCompositeNode.builder();
486         outerListBuilder.setQName(OUTER_LIST_QNAME);
487         outerListBuilder.addLeaf(ID_QNAME, 20);
488         outerListBuilder.addLeaf(TWO_QNAME, "two");
489         outerListBuilder.addLeaf(THREE_QNAME, "three");
490         testBuilder.add(outerListBuilder.toInstance());
491
492         for (int i = 1; i <= 2; i++) {
493             CompositeNodeBuilder<ImmutableCompositeNode> unkeyedListBuilder = ImmutableCompositeNode.builder();
494             unkeyedListBuilder.setQName(UNKEYED_LIST_QNAME);
495             unkeyedListBuilder.addLeaf(NAME_QNAME, "unkeyed-name" + i);
496             testBuilder.add(unkeyedListBuilder.toInstance());
497         }
498
499         Entry<InstanceIdentifier, NormalizedNode<?, ?>> normalizedNodeEntry = normalizer
500                 .toNormalized(new AbstractMap.SimpleEntry<InstanceIdentifier, CompositeNode>(new InstanceIdentifier(
501                         ImmutableList.<PathArgument> of(new NodeIdentifier(TEST_QNAME))), testBuilder.toInstance()));
502
503         verifyNormalizedInstanceIdentifier(normalizedNodeEntry.getKey(), TEST_QNAME);
504
505         verifyNormalizedNode(
506                 normalizedNodeEntry.getValue(),
507                 expectContainerNode(
508                         TEST_QNAME,
509                         expectMapNode(
510                                 OUTER_LIST_QNAME,
511                                 expectMapEntryNode(
512                                         OUTER_LIST_QNAME,
513                                         ID_QNAME,
514                                         10,
515                                         expectLeafNode(ID_QNAME, 10),
516                                         expectChoiceNode(OUTER_CHOICE_QNAME, expectLeafNode(ONE_QNAME, "one")),
517                                         expectOrderedMapNode(
518                                                 INNER_LIST_QNAME,
519                                                 expectMapEntryNode(INNER_LIST_QNAME, NAME_QNAME, "inner-name3",
520                                                         expectLeafNode(NAME_QNAME, "inner-name3"),
521                                                         expectLeafNode(VALUE_QNAME, "inner-value3")),
522                                                 expectMapEntryNode(INNER_LIST_QNAME, NAME_QNAME, "inner-name2",
523                                                         expectLeafNode(NAME_QNAME, "inner-name2"),
524                                                         expectLeafNode(VALUE_QNAME, "inner-value2")),
525                                                 expectMapEntryNode(INNER_LIST_QNAME, NAME_QNAME, "inner-name1",
526                                                         expectLeafNode(NAME_QNAME, "inner-name1"),
527                                                         expectLeafNode(VALUE_QNAME, "inner-value1")))),
528                                 expectMapEntryNode(
529                                         OUTER_LIST_QNAME,
530                                         ID_QNAME,
531                                         20,
532                                         expectLeafNode(ID_QNAME, 20),
533                                         expectChoiceNode(OUTER_CHOICE_QNAME, expectLeafNode(TWO_QNAME, "two"),
534                                                 expectLeafNode(THREE_QNAME, "three")))),
535                         expectUnkeyedListNode(
536                                 UNKEYED_LIST_QNAME,
537                                 expectUnkeyedListEntryNode(UNKEYED_LIST_QNAME,
538                                         expectLeafNode(NAME_QNAME, "unkeyed-name1")),
539                                 expectUnkeyedListEntryNode(UNKEYED_LIST_QNAME,
540                                         expectLeafNode(NAME_QNAME, "unkeyed-name2")))));
541     }
542
543     @Test
544     public void testToNormalizedCompositeNodeWithAnyXml() {
545         SchemaContext testCtx = createTestContext();
546         DataNormalizer normalizer = new DataNormalizer(testCtx);
547
548         CompositeNodeBuilder<ImmutableCompositeNode> testBuilder = ImmutableCompositeNode.builder();
549         testBuilder.setQName(TEST_QNAME);
550
551         CompositeNodeBuilder<ImmutableCompositeNode> anyXmlBuilder = ImmutableCompositeNode.builder();
552         anyXmlBuilder.setQName(ANY_XML_DATA_QNAME);
553         anyXmlBuilder.addLeaf(ANY_XML_LEAF_QNAME, "leaf-value");
554
555         CompositeNodeBuilder<ImmutableCompositeNode> innerBuilder = ImmutableCompositeNode.builder();
556         innerBuilder.setQName(ANY_XML_INNER_QNAME);
557         innerBuilder.addLeaf(ANY_XML_INNER_LEAF_QNAME, "inner-leaf-value");
558
559         anyXmlBuilder.add(innerBuilder.toInstance());
560         CompositeNode anyXmlLegacy = anyXmlBuilder.toInstance();
561         testBuilder.add(anyXmlLegacy);
562
563         Entry<InstanceIdentifier, NormalizedNode<?, ?>> normalizedNodeEntry = normalizer
564                 .toNormalized(new AbstractMap.SimpleEntry<InstanceIdentifier, CompositeNode>(new InstanceIdentifier(
565                         ImmutableList.<PathArgument> of(new NodeIdentifier(TEST_QNAME))), testBuilder.toInstance()));
566
567         verifyNormalizedInstanceIdentifier(normalizedNodeEntry.getKey(), TEST_QNAME);
568
569         verifyNormalizedNode(normalizedNodeEntry.getValue(),
570                 expectContainerNode(TEST_QNAME, expectAnyXmlNode(ANY_XML_DATA_QNAME, anyXmlLegacy)));
571     }
572
573     @Test
574     public void testToNormalizedCompositeNodeWithAugmentation() {
575         SchemaContext testCtx = createTestContext();
576         DataNormalizer normalizer = new DataNormalizer(testCtx);
577
578         CompositeNodeBuilder<ImmutableCompositeNode> testBuilder = ImmutableCompositeNode.builder();
579         testBuilder.setQName(TEST_QNAME);
580
581         CompositeNodeBuilder<ImmutableCompositeNode> outerContBuilder = ImmutableCompositeNode.builder();
582         outerContBuilder.setQName(OUTER_CONTAINER_QNAME);
583         outerContBuilder.addLeaf(AUGMENTED_LEAF_QNAME, "augmented-value");
584
585         testBuilder.add(outerContBuilder.toInstance());
586
587         Entry<InstanceIdentifier, NormalizedNode<?, ?>> normalizedNodeEntry = normalizer
588                 .toNormalized(new AbstractMap.SimpleEntry<InstanceIdentifier, CompositeNode>(new InstanceIdentifier(
589                         ImmutableList.<PathArgument> of(new NodeIdentifier(TEST_QNAME))), testBuilder.toInstance()));
590
591         verifyNormalizedInstanceIdentifier(normalizedNodeEntry.getKey(), TEST_QNAME);
592
593         NormalizedNodeData expAugmentation = expectAugmentation(AUGMENTED_LEAF_QNAME,
594                 expectLeafNode(AUGMENTED_LEAF_QNAME, "augmented-value"));
595
596         verifyNormalizedNode(normalizedNodeEntry.getValue(),
597                 expectContainerNode(TEST_QNAME, expectContainerNode(OUTER_CONTAINER_QNAME, expAugmentation)));
598
599         normalizedNodeEntry = normalizer.toNormalized(new AbstractMap.SimpleEntry<InstanceIdentifier, CompositeNode>(
600                 new InstanceIdentifier(Lists.newArrayList(new NodeIdentifier(TEST_QNAME), new NodeIdentifier(
601                         OUTER_CONTAINER_QNAME))), outerContBuilder.toInstance()));
602
603         verifyNormalizedInstanceIdentifier(normalizedNodeEntry.getKey(), TEST_QNAME, OUTER_CONTAINER_QNAME,
604                 Sets.newHashSet(AUGMENTED_LEAF_QNAME));
605
606         verifyNormalizedNode(normalizedNodeEntry.getValue(), expAugmentation);
607     }
608
609     @Test
610     public void testToNormalizedCompositeNodeWithLeafLists() {
611         SchemaContext testCtx = createTestContext();
612         DataNormalizer normalizer = new DataNormalizer(testCtx);
613
614         CompositeNodeBuilder<ImmutableCompositeNode> testBuilder = ImmutableCompositeNode.builder();
615         testBuilder.setQName(TEST_QNAME);
616
617         for (int i = 1; i <= 3; i++) {
618             testBuilder.addLeaf(UNORDERED_LEAF_LIST_QNAME, "unordered-value" + i);
619         }
620
621         for (int i = 3; i > 0; i--) {
622             testBuilder.addLeaf(ORDERED_LEAF_LIST_QNAME, "ordered-value" + i);
623         }
624
625         Entry<InstanceIdentifier, NormalizedNode<?, ?>> normalizedNodeEntry = normalizer
626                 .toNormalized(new AbstractMap.SimpleEntry<InstanceIdentifier, CompositeNode>(new InstanceIdentifier(
627                         ImmutableList.<PathArgument> of(new NodeIdentifier(TEST_QNAME))), testBuilder.toInstance()));
628
629         verifyNormalizedInstanceIdentifier(normalizedNodeEntry.getKey(), TEST_QNAME);
630
631         verifyNormalizedNode(
632                 normalizedNodeEntry.getValue(),
633                 expectContainerNode(
634                         TEST_QNAME,
635                         expectLeafSetNode(UNORDERED_LEAF_LIST_QNAME,
636                                 expectLeafSetEntryNode(UNORDERED_LEAF_LIST_QNAME, "unordered-value1"),
637                                 expectLeafSetEntryNode(UNORDERED_LEAF_LIST_QNAME, "unordered-value2"),
638                                 expectLeafSetEntryNode(UNORDERED_LEAF_LIST_QNAME, "unordered-value3")),
639                         expectOrderedLeafSetNode(ORDERED_LEAF_LIST_QNAME,
640                                 expectLeafSetEntryNode(ORDERED_LEAF_LIST_QNAME, "ordered-value3"),
641                                 expectLeafSetEntryNode(ORDERED_LEAF_LIST_QNAME, "ordered-value2"),
642                                 expectLeafSetEntryNode(ORDERED_LEAF_LIST_QNAME, "ordered-value1"))));
643     }
644
645     @SuppressWarnings("unchecked")
646     private void verifyNormalizedNode(NormalizedNode<?, ?> actual, NormalizedNodeData expNodeData) {
647
648         Class<?> expNodeClass = expNodeData.nodeClass;
649         PathArgument expNodeID = expNodeData.nodeID;
650
651         assertNotNull("Actual NormalizedNode is null", actual);
652         assertTrue("NormalizedNode instance " + actual.getClass() + " is not derived from " + expNodeClass,
653                 expNodeClass.isAssignableFrom(actual.getClass()));
654         assertEquals("NormalizedNode identifier", expNodeID, actual.getIdentifier());
655
656         if (expNodeData.nodeData instanceof List) {
657             Map<PathArgument, Integer> orderingMap = null;
658             if (expNodeClass.equals(OrderedMapNode.class) || expNodeClass.equals(OrderedLeafSetNode.class)) {
659                 orderingMap = Maps.newHashMap();
660             }
661
662             int i = 1;
663             Map<PathArgument, NormalizedNodeData> expChildDataMap = Maps.newHashMap();
664             List<NormalizedNodeData> expChildDataList = (List<NormalizedNodeData>) expNodeData.nodeData;
665             for (NormalizedNodeData data : expChildDataList) {
666                 expChildDataMap.put(data.nodeID, data);
667
668                 if (orderingMap != null) {
669                     orderingMap.put(data.nodeID, i++);
670                 }
671             }
672
673             assertNotNull("Actual value is null for node " + actual.getIdentifier(), actual.getValue());
674             assertTrue("Expected value instance Iterable for node " + actual.getIdentifier(),
675                     Iterable.class.isAssignableFrom(actual.getValue().getClass()));
676
677             i = 1;
678             for (NormalizedNode<?, ?> actualChild : (Iterable<NormalizedNode<?, ?>>) actual.getValue()) {
679                 NormalizedNodeData expChildData = expNodeClass.equals(UnkeyedListNode.class) ? expChildDataList
680                         .remove(0) : expChildDataMap.remove(actualChild.getIdentifier());
681
682                 assertNotNull(
683                         "Unexpected child node " + actualChild.getClass() + " with identifier "
684                                 + actualChild.getIdentifier() + " for parent node " + actual.getClass()
685                                 + " with identifier " + actual.getIdentifier(), expChildData);
686
687                 if (orderingMap != null) {
688                     assertEquals("Order index for child node " + actualChild.getIdentifier(),
689                             orderingMap.get(actualChild.getIdentifier()), Integer.valueOf(i));
690                 }
691
692                 verifyNormalizedNode(actualChild, expChildData);
693                 i++;
694             }
695
696             if (expNodeClass.equals(UnkeyedListNode.class)) {
697                 if (expChildDataList.size() > 0) {
698                     fail("Missing " + expChildDataList.size() + " child nodes for parent " + actual.getIdentifier());
699                 }
700             } else {
701                 if (!expChildDataMap.isEmpty()) {
702                     fail("Missing child nodes for parent " + actual.getIdentifier() + ": " + expChildDataMap.keySet());
703                 }
704             }
705         } else {
706             assertEquals("Leaf value for node " + actual.getIdentifier(), expNodeData.nodeData, actual.getValue());
707         }
708     }
709
710     private NormalizedNodeData expectOrderedLeafSetNode(QName nodeName, NormalizedNodeData... childData) {
711         return new NormalizedNodeData(new NodeIdentifier(nodeName), OrderedLeafSetNode.class,
712                 Lists.newArrayList(childData));
713     }
714
715     private NormalizedNodeData expectLeafSetNode(QName nodeName, NormalizedNodeData... childData) {
716         return new NormalizedNodeData(new NodeIdentifier(nodeName), LeafSetNode.class, Lists.newArrayList(childData));
717     }
718
719     private NormalizedNodeData expectLeafSetEntryNode(QName nodeName, Object value) {
720         return new NormalizedNodeData(new NodeWithValue(nodeName, value), LeafSetEntryNode.class, value);
721     }
722
723     private NormalizedNodeData expectUnkeyedListNode(QName nodeName, NormalizedNodeData... childData) {
724         return new NormalizedNodeData(new NodeIdentifier(nodeName), UnkeyedListNode.class,
725                 Lists.newArrayList(childData));
726     }
727
728     private NormalizedNodeData expectUnkeyedListEntryNode(QName nodeName, NormalizedNodeData... childData) {
729         return new NormalizedNodeData(new NodeIdentifier(nodeName), UnkeyedListEntryNode.class,
730                 Lists.newArrayList(childData));
731     }
732
733     private NormalizedNodeData expectAugmentation(QName augmentedNodeName, NormalizedNodeData... childData) {
734         return new NormalizedNodeData(new AugmentationIdentifier(Sets.newHashSet(augmentedNodeName)),
735                 AugmentationNode.class, Lists.newArrayList(childData));
736     }
737
738     private NormalizedNodeData expectAnyXmlNode(QName nodeName, Object value) {
739         return new NormalizedNodeData(new NodeIdentifier(nodeName), AnyXmlNode.class, value);
740     }
741
742     private NormalizedNodeData expectContainerNode(QName nodeName, NormalizedNodeData... childData) {
743         return new NormalizedNodeData(new NodeIdentifier(nodeName), ContainerNode.class, Lists.newArrayList(childData));
744     }
745
746     private NormalizedNodeData expectChoiceNode(QName nodeName, NormalizedNodeData... childData) {
747         return new NormalizedNodeData(new NodeIdentifier(nodeName), ChoiceNode.class, Lists.newArrayList(childData));
748     }
749
750     private NormalizedNodeData expectLeafNode(QName nodeName, Object value) {
751         return new NormalizedNodeData(new NodeIdentifier(nodeName), LeafNode.class, value);
752
753     }
754
755     private NormalizedNodeData expectMapEntryNode(QName nodeName, QName key, Object value,
756             NormalizedNodeData... childData) {
757         return new NormalizedNodeData(new NodeIdentifierWithPredicates(nodeName, key, value), MapEntryNode.class,
758                 Lists.newArrayList(childData));
759     }
760
761     private NormalizedNodeData expectMapNode(QName key, NormalizedNodeData... childData) {
762         return new NormalizedNodeData(new NodeIdentifier(key), MapNode.class, Lists.newArrayList(childData));
763     }
764
765     private NormalizedNodeData expectOrderedMapNode(QName key, NormalizedNodeData... childData) {
766         return new NormalizedNodeData(new NodeIdentifier(key), OrderedMapNode.class, Lists.newArrayList(childData));
767     }
768 }