Adopt odlparent-10.0.0/yangtools-8.0.0-SNAPSHOT
[mdsal.git] / binding / mdsal-binding-dom-codec / src / test / java / org / opendaylight / mdsal / binding / dom / codec / impl / InstanceIdentifierSerializeDeserializeTest.java
1 /*
2  * Copyright (c) 2014 Cisco 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.mdsal.binding.dom.codec.impl;
9
10 import static org.hamcrest.CoreMatchers.startsWith;
11 import static org.hamcrest.MatcherAssert.assertThat;
12 import static org.junit.Assert.assertEquals;
13 import static org.junit.Assert.assertFalse;
14 import static org.junit.Assert.assertNull;
15 import static org.junit.Assert.assertThrows;
16 import static org.junit.Assert.assertTrue;
17
18 import com.google.common.collect.Iterables;
19 import org.junit.Test;
20 import org.opendaylight.mdsal.binding.dom.codec.api.IncorrectNestingException;
21 import org.opendaylight.yang.gen.v1.urn.odl.actions.norev.Lst;
22 import org.opendaylight.yang.gen.v1.urn.odl.actions.norev.lst.Foo;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.bi.ba.notification.rev150205.OutOfPixieDustNotification;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.md.sal.knock.knock.rev180723.KnockKnockInput;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.TreeComplexUsesAugment;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.TreeLeafOnlyAugment;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.Top;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.two.level.list.TopLevelList;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.two.level.list.TopLevelListKey;
30 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.aug.norev.cont.cont.choice.ContAug;
31 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.aug.norev.root.RootAug;
32 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.base.norev.Cont;
33 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.base.norev.Root;
34 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.base.norev.cont.ContChoice;
35 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.base.norev.cont.cont.choice.ContBase;
36 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.base.norev.grp.GrpCont;
37 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.base.norev.root.RootBase;
38 import org.opendaylight.yangtools.yang.binding.Identifier;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
40 import org.opendaylight.yangtools.yang.common.QName;
41 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
42 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
43 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
44 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
45 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
46
47 public class InstanceIdentifierSerializeDeserializeTest extends AbstractBindingCodecTest {
48     public static final String TOP_LEVEL_LIST_KEY_VALUE = "foo";
49
50     private static final TopLevelListKey TOP_FOO_KEY = new TopLevelListKey("foo");
51     private static final InstanceIdentifier<TopLevelList> BA_TOP_LEVEL_LIST = InstanceIdentifier
52             .builder(Top.class).child(TopLevelList.class, TOP_FOO_KEY).build();
53     private static final InstanceIdentifier<TreeLeafOnlyAugment> BA_TREE_LEAF_ONLY =
54             BA_TOP_LEVEL_LIST.augmentation(TreeLeafOnlyAugment.class);
55     private static final InstanceIdentifier<TreeComplexUsesAugment> BA_TREE_COMPLEX_USES =
56             BA_TOP_LEVEL_LIST.augmentation(TreeComplexUsesAugment.class);
57
58     public static final QName TOP_QNAME = Top.QNAME;
59     public static final QName TOP_LEVEL_LIST_QNAME = QName.create(TOP_QNAME, "top-level-list");
60     public static final QName TOP_LEVEL_LIST_KEY = QName.create(TOP_QNAME, "name");
61     private static final QName SIMPLE_VALUE_QNAME = QName.create(TreeComplexUsesAugment.QNAME, "simple-value");
62
63     public static final YangInstanceIdentifier BI_TOP_PATH = YangInstanceIdentifier.of(TOP_QNAME);
64     public static final YangInstanceIdentifier BI_TOP_LEVEL_LIST_PATH = BI_TOP_PATH.node(TOP_LEVEL_LIST_QNAME);
65     public static final YangInstanceIdentifier BI_TOP_LEVEL_LIST_1_PATH = BI_TOP_LEVEL_LIST_PATH
66             .node(NodeIdentifierWithPredicates.of(TOP_LEVEL_LIST_QNAME, TOP_LEVEL_LIST_KEY,
67                 TOP_LEVEL_LIST_KEY_VALUE));
68
69     @Test
70     public void testYangIIToBindingAwareII() {
71         final InstanceIdentifier<?> instanceIdentifier = codecContext.fromYangInstanceIdentifier(BI_TOP_PATH);
72         assertEquals(Top.class, instanceIdentifier.getTargetType());
73     }
74
75     @Test
76     public void testYangIIToBindingAwareIIListWildcarded() {
77         final InstanceIdentifier<?> instanceIdentifier = codecContext.fromYangInstanceIdentifier(
78             BI_TOP_LEVEL_LIST_PATH);
79         assertNull(instanceIdentifier);
80     }
81
82     @Test
83     public void testYangIIToBindingAwareIIListWithKey() {
84         final InstanceIdentifier<?> instanceIdentifier = codecContext.fromYangInstanceIdentifier(
85             BI_TOP_LEVEL_LIST_1_PATH);
86         final InstanceIdentifier.PathArgument last = Iterables.getLast(instanceIdentifier.getPathArguments());
87         assertEquals(TopLevelList.class, instanceIdentifier.getTargetType());
88         assertFalse(instanceIdentifier.isWildcarded());
89         assertTrue(last instanceof InstanceIdentifier.IdentifiableItem);
90         final Identifier<?> key = ((InstanceIdentifier.IdentifiableItem<?, ?>) last).getKey();
91         assertEquals(TopLevelListKey.class, key.getClass());
92         assertEquals(TOP_LEVEL_LIST_KEY_VALUE, ((TopLevelListKey)key).getName());
93     }
94
95     @Test
96     public void testBindingAwareIIToYangIContainer() {
97         final YangInstanceIdentifier yangInstanceIdentifier = codecContext.toYangInstanceIdentifier(
98                 InstanceIdentifier.create(Top.class).child(TopLevelList.class));
99         final PathArgument lastPathArgument = yangInstanceIdentifier.getLastPathArgument();
100         assertTrue(lastPathArgument instanceof NodeIdentifier);
101         assertEquals(TopLevelList.QNAME, lastPathArgument.getNodeType());
102     }
103
104     @Test
105     public void testBindingAwareIIToYangIIWildcard() {
106         final YangInstanceIdentifier yangInstanceIdentifier = codecContext.toYangInstanceIdentifier(
107                 InstanceIdentifier.create(Top.class).child(TopLevelList.class));
108         final PathArgument lastPathArgument = yangInstanceIdentifier.getLastPathArgument();
109         assertTrue(lastPathArgument instanceof NodeIdentifier);
110         assertEquals(TopLevelList.QNAME, lastPathArgument.getNodeType());
111     }
112
113     @Test
114     public void testBindingAwareIIToYangIIListWithKey() {
115         final YangInstanceIdentifier yangInstanceIdentifier = codecContext.toYangInstanceIdentifier(
116                 InstanceIdentifier.create(Top.class).child(TopLevelList.class, TOP_FOO_KEY));
117         final PathArgument lastPathArgument = yangInstanceIdentifier.getLastPathArgument();
118         assertTrue(lastPathArgument instanceof NodeIdentifierWithPredicates);
119         assertTrue(((NodeIdentifierWithPredicates) lastPathArgument).values().contains(TOP_LEVEL_LIST_KEY_VALUE));
120         assertEquals(TopLevelList.QNAME, lastPathArgument.getNodeType());
121     }
122
123     @Test
124     public void testBindingAwareIIToYangIIAugmentation() {
125         final PathArgument lastArg = codecContext.toYangInstanceIdentifier(BA_TREE_COMPLEX_USES).getLastPathArgument();
126         assertTrue(lastArg instanceof AugmentationIdentifier);
127     }
128
129     @Test
130     public void testBindingAwareIIToYangIILeafOnlyAugmentation() {
131         final PathArgument leafOnlyLastArg = codecContext.toYangInstanceIdentifier(BA_TREE_LEAF_ONLY)
132                 .getLastPathArgument();
133         assertTrue(leafOnlyLastArg instanceof AugmentationIdentifier);
134         assertTrue(((AugmentationIdentifier) leafOnlyLastArg).getPossibleChildNames().contains(SIMPLE_VALUE_QNAME));
135     }
136
137     @Test
138     public void testChoiceCaseGroupingFromBinding() {
139         final YangInstanceIdentifier contBase = codecContext.toYangInstanceIdentifier(
140             InstanceIdentifier.builder(Cont.class).child(ContBase.class, GrpCont.class).build());
141         assertEquals(YangInstanceIdentifier.create(NodeIdentifier.create(Cont.QNAME),
142             NodeIdentifier.create(ContChoice.QNAME), NodeIdentifier.create(GrpCont.QNAME)), contBase);
143
144         final YangInstanceIdentifier contAug = codecContext.toYangInstanceIdentifier(
145             InstanceIdentifier.builder(Cont.class).child(ContAug.class, GrpCont.class).build());
146         assertEquals(YangInstanceIdentifier.create(NodeIdentifier.create(Cont.QNAME),
147             NodeIdentifier.create(ContChoice.QNAME),
148             NodeIdentifier.create(GrpCont.QNAME.bindTo(ContAug.QNAME.getModule()))), contAug);
149
150         // Legacy: downcast the child to Class, losing type safety but still working. Faced with ambiguity, it will
151         //         select the lexically-lower class
152         assertEquals(1, ContBase.class.getCanonicalName().compareTo(ContAug.class.getCanonicalName()));
153         final YangInstanceIdentifier contAugLegacy = codecContext.toYangInstanceIdentifier(
154             InstanceIdentifier.builder(Cont.class).child((Class) GrpCont.class).build());
155         assertEquals(contAug, contAugLegacy);
156
157         final YangInstanceIdentifier rootBase = codecContext.toYangInstanceIdentifier(
158             InstanceIdentifier.builder(RootBase.class, GrpCont.class).build());
159         assertEquals(YangInstanceIdentifier.create(NodeIdentifier.create(Root.QNAME),
160             NodeIdentifier.create(GrpCont.QNAME)), rootBase);
161
162         final YangInstanceIdentifier rootAug = codecContext.toYangInstanceIdentifier(
163             InstanceIdentifier.builder(RootAug.class, GrpCont.class).build());
164         assertEquals(YangInstanceIdentifier.create(NodeIdentifier.create(Root.QNAME),
165             NodeIdentifier.create(GrpCont.QNAME.bindTo(RootAug.QNAME.getModule()))), rootAug);
166     }
167
168     @Test
169     public void testChoiceCaseGroupingToBinding() {
170         final InstanceIdentifier<?> contBase = codecContext.fromYangInstanceIdentifier(
171             YangInstanceIdentifier.create(NodeIdentifier.create(Cont.QNAME),
172             NodeIdentifier.create(ContChoice.QNAME), NodeIdentifier.create(GrpCont.QNAME)));
173         assertEquals(InstanceIdentifier.builder(Cont.class).child(ContBase.class, GrpCont.class).build(), contBase);
174
175         final InstanceIdentifier<?> contAug = codecContext.fromYangInstanceIdentifier(
176             YangInstanceIdentifier.create(NodeIdentifier.create(Cont.QNAME), NodeIdentifier.create(ContChoice.QNAME),
177                 NodeIdentifier.create(GrpCont.QNAME.bindTo(ContAug.QNAME.getModule()))));
178         assertEquals(InstanceIdentifier.builder(Cont.class).child(ContAug.class, GrpCont.class).build(), contAug);
179
180         final InstanceIdentifier<?> rootBase = codecContext.fromYangInstanceIdentifier(
181             YangInstanceIdentifier.create(NodeIdentifier.create(Root.QNAME), NodeIdentifier.create(GrpCont.QNAME)));
182         assertEquals(InstanceIdentifier.builder(RootBase.class, GrpCont.class).build(), rootBase);
183
184         final InstanceIdentifier<?> rootAug = codecContext.fromYangInstanceIdentifier(
185             YangInstanceIdentifier.create(NodeIdentifier.create(Root.QNAME),
186                 NodeIdentifier.create(GrpCont.QNAME.bindTo(RootAug.QNAME.getModule()))));
187         assertEquals(InstanceIdentifier.builder(RootAug.class, GrpCont.class).build(), rootAug);
188     }
189
190     @Test
191     public void testRejectNotificationQName() {
192         // A purposely-wrong YangInstanceIdentifier
193         final var yiid = YangInstanceIdentifier.create(NodeIdentifier.create(OutOfPixieDustNotification.QNAME));
194         final var ex = assertThrows(IncorrectNestingException.class,
195             () -> codecContext.fromYangInstanceIdentifier(yiid));
196         assertThat(ex.getMessage(),
197             startsWith("Argument (urn:opendaylight:params:xml:ns:yang:controller:md:sal:test:bi:ba:notification"
198                 + "?revision=2015-02-05)out-of-pixie-dust-notification is not valid data tree child of "));
199     }
200
201     @Test
202     public void testRejectRpcQName() {
203         // A purposely-wrong YangInstanceIdentifier
204         final var yiid = YangInstanceIdentifier.create(NodeIdentifier.create(
205             // TODO: use the RPC interface once we are generating it
206             QName.create(KnockKnockInput.QNAME, "knock-knock")));
207         final var ex = assertThrows(IncorrectNestingException.class,
208             () -> codecContext.fromYangInstanceIdentifier(yiid));
209         assertThat(ex.getMessage(), startsWith("Argument (urn:opendaylight:params:xml:ns:yang:md:sal:knock-knock"
210             + "?revision=2018-07-23)knock-knock is not valid child of "));
211     }
212
213     @Test
214     public void testRejectActionQName() {
215         // A purposely-wrong YangInstanceIdentifier
216         final var yiid = YangInstanceIdentifier.create(
217             NodeIdentifier.create(Lst.QNAME),
218             NodeIdentifierWithPredicates.of(Lst.QNAME, QName.create(Lst.QNAME, "key"), "foo"),
219             NodeIdentifier.create(Foo.QNAME));
220         final var ex = assertThrows(IncorrectNestingException.class,
221             () -> codecContext.fromYangInstanceIdentifier(yiid));
222         assertEquals("Argument (urn:odl:actions)foo is not valid child of "
223             + "EmptyListEffectiveStatement{argument=(urn:odl:actions)lst}", ex.getMessage());
224     }
225 }