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