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