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