2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.mdsal.binding.dom.codec.impl;
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;
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.binding.rev140701.Top;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.two.level.list.TopLevelList;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.two.level.list.TopLevelListKey;
28 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.aug.norev.cont.cont.choice.ContAug;
29 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.aug.norev.root.RootAug;
30 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.base.norev.Cont;
31 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.base.norev.Root;
32 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.base.norev.cont.ContChoice;
33 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.base.norev.cont.cont.choice.ContBase;
34 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.base.norev.grp.GrpCont;
35 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.base.norev.root.RootBase;
36 import org.opendaylight.yangtools.yang.binding.Identifier;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38 import org.opendaylight.yangtools.yang.common.QName;
39 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
40 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
41 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
42 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
44 public class InstanceIdentifierSerializeDeserializeTest extends AbstractBindingCodecTest {
45 public static final String TOP_LEVEL_LIST_KEY_VALUE = "foo";
47 private static final TopLevelListKey TOP_FOO_KEY = new TopLevelListKey("foo");
48 private static final InstanceIdentifier<TopLevelList> BA_TOP_LEVEL_LIST = InstanceIdentifier
49 .builder(Top.class).child(TopLevelList.class, TOP_FOO_KEY).build();
51 public static final QName TOP_QNAME = Top.QNAME;
52 public static final QName TOP_LEVEL_LIST_QNAME = QName.create(TOP_QNAME, "top-level-list");
53 public static final QName TOP_LEVEL_LIST_KEY = QName.create(TOP_QNAME, "name");
55 public static final YangInstanceIdentifier BI_TOP_PATH = YangInstanceIdentifier.of(TOP_QNAME);
56 public static final YangInstanceIdentifier BI_TOP_LEVEL_LIST_PATH = BI_TOP_PATH.node(TOP_LEVEL_LIST_QNAME);
57 public static final YangInstanceIdentifier BI_TOP_LEVEL_LIST_1_PATH = BI_TOP_LEVEL_LIST_PATH
58 .node(NodeIdentifierWithPredicates.of(TOP_LEVEL_LIST_QNAME, TOP_LEVEL_LIST_KEY,
59 TOP_LEVEL_LIST_KEY_VALUE));
62 public void testYangIIToBindingAwareII() {
63 final InstanceIdentifier<?> instanceIdentifier = codecContext.fromYangInstanceIdentifier(BI_TOP_PATH);
64 assertEquals(Top.class, instanceIdentifier.getTargetType());
68 public void testYangIIToBindingAwareIIListWildcarded() {
69 final InstanceIdentifier<?> instanceIdentifier = codecContext.fromYangInstanceIdentifier(
70 BI_TOP_LEVEL_LIST_PATH);
71 assertNull(instanceIdentifier);
75 public void testYangIIToBindingAwareIIListWithKey() {
76 final InstanceIdentifier<?> instanceIdentifier = codecContext.fromYangInstanceIdentifier(
77 BI_TOP_LEVEL_LIST_1_PATH);
78 final InstanceIdentifier.PathArgument last = Iterables.getLast(instanceIdentifier.getPathArguments());
79 assertEquals(TopLevelList.class, instanceIdentifier.getTargetType());
80 assertFalse(instanceIdentifier.isWildcarded());
81 assertTrue(last instanceof InstanceIdentifier.IdentifiableItem);
82 final Identifier<?> key = ((InstanceIdentifier.IdentifiableItem<?, ?>) last).getKey();
83 assertEquals(TopLevelListKey.class, key.getClass());
84 assertEquals(TOP_LEVEL_LIST_KEY_VALUE, ((TopLevelListKey)key).getName());
88 public void testBindingAwareIIToYangIContainer() {
89 final YangInstanceIdentifier yangInstanceIdentifier = codecContext.toYangInstanceIdentifier(
90 InstanceIdentifier.create(Top.class).child(TopLevelList.class));
91 final PathArgument lastPathArgument = yangInstanceIdentifier.getLastPathArgument();
92 assertTrue(lastPathArgument instanceof NodeIdentifier);
93 assertEquals(TopLevelList.QNAME, lastPathArgument.getNodeType());
97 public void testBindingAwareIIToYangIIWildcard() {
98 final YangInstanceIdentifier yangInstanceIdentifier = codecContext.toYangInstanceIdentifier(
99 InstanceIdentifier.create(Top.class).child(TopLevelList.class));
100 final PathArgument lastPathArgument = yangInstanceIdentifier.getLastPathArgument();
101 assertTrue(lastPathArgument instanceof NodeIdentifier);
102 assertEquals(TopLevelList.QNAME, lastPathArgument.getNodeType());
106 public void testBindingAwareIIToYangIIListWithKey() {
107 final YangInstanceIdentifier yangInstanceIdentifier = codecContext.toYangInstanceIdentifier(
108 InstanceIdentifier.create(Top.class).child(TopLevelList.class, TOP_FOO_KEY));
109 final PathArgument lastPathArgument = yangInstanceIdentifier.getLastPathArgument();
110 assertTrue(lastPathArgument instanceof NodeIdentifierWithPredicates);
111 assertTrue(((NodeIdentifierWithPredicates) lastPathArgument).values().contains(TOP_LEVEL_LIST_KEY_VALUE));
112 assertEquals(TopLevelList.QNAME, lastPathArgument.getNodeType());
116 public void testChoiceCaseGroupingFromBinding() {
117 final YangInstanceIdentifier contBase = codecContext.toYangInstanceIdentifier(
118 InstanceIdentifier.builder(Cont.class).child(ContBase.class, GrpCont.class).build());
119 assertEquals(YangInstanceIdentifier.create(NodeIdentifier.create(Cont.QNAME),
120 NodeIdentifier.create(ContChoice.QNAME), NodeIdentifier.create(GrpCont.QNAME)), contBase);
122 final YangInstanceIdentifier contAug = codecContext.toYangInstanceIdentifier(
123 InstanceIdentifier.builder(Cont.class).child(ContAug.class, GrpCont.class).build());
124 assertEquals(YangInstanceIdentifier.create(NodeIdentifier.create(Cont.QNAME),
125 NodeIdentifier.create(ContChoice.QNAME),
126 NodeIdentifier.create(GrpCont.QNAME.bindTo(ContAug.QNAME.getModule()))), contAug);
128 // Legacy: downcast the child to Class, losing type safety but still working. Faced with ambiguity, it will
129 // select the lexically-lower class
130 assertEquals(1, ContBase.class.getCanonicalName().compareTo(ContAug.class.getCanonicalName()));
131 final YangInstanceIdentifier contAugLegacy = codecContext.toYangInstanceIdentifier(
132 InstanceIdentifier.builder(Cont.class).child((Class) GrpCont.class).build());
133 assertEquals(contAug, contAugLegacy);
135 final YangInstanceIdentifier rootBase = codecContext.toYangInstanceIdentifier(
136 InstanceIdentifier.builder(RootBase.class, GrpCont.class).build());
137 assertEquals(YangInstanceIdentifier.create(NodeIdentifier.create(Root.QNAME),
138 NodeIdentifier.create(GrpCont.QNAME)), rootBase);
140 final YangInstanceIdentifier rootAug = codecContext.toYangInstanceIdentifier(
141 InstanceIdentifier.builder(RootAug.class, GrpCont.class).build());
142 assertEquals(YangInstanceIdentifier.create(NodeIdentifier.create(Root.QNAME),
143 NodeIdentifier.create(GrpCont.QNAME.bindTo(RootAug.QNAME.getModule()))), rootAug);
147 public void testChoiceCaseGroupingToBinding() {
148 final InstanceIdentifier<?> contBase = codecContext.fromYangInstanceIdentifier(
149 YangInstanceIdentifier.create(NodeIdentifier.create(Cont.QNAME),
150 NodeIdentifier.create(ContChoice.QNAME), NodeIdentifier.create(GrpCont.QNAME)));
151 assertEquals(InstanceIdentifier.builder(Cont.class).child(ContBase.class, GrpCont.class).build(), contBase);
153 final InstanceIdentifier<?> contAug = codecContext.fromYangInstanceIdentifier(
154 YangInstanceIdentifier.create(NodeIdentifier.create(Cont.QNAME), NodeIdentifier.create(ContChoice.QNAME),
155 NodeIdentifier.create(GrpCont.QNAME.bindTo(ContAug.QNAME.getModule()))));
156 assertEquals(InstanceIdentifier.builder(Cont.class).child(ContAug.class, GrpCont.class).build(), contAug);
158 final InstanceIdentifier<?> rootBase = codecContext.fromYangInstanceIdentifier(
159 YangInstanceIdentifier.create(NodeIdentifier.create(Root.QNAME), NodeIdentifier.create(GrpCont.QNAME)));
160 assertEquals(InstanceIdentifier.builder(RootBase.class, GrpCont.class).build(), rootBase);
162 final InstanceIdentifier<?> rootAug = codecContext.fromYangInstanceIdentifier(
163 YangInstanceIdentifier.create(NodeIdentifier.create(Root.QNAME),
164 NodeIdentifier.create(GrpCont.QNAME.bindTo(RootAug.QNAME.getModule()))));
165 assertEquals(InstanceIdentifier.builder(RootAug.class, GrpCont.class).build(), rootAug);
169 public void testRejectNotificationQName() {
170 // A purposely-wrong YangInstanceIdentifier
171 final var yiid = YangInstanceIdentifier.create(NodeIdentifier.create(OutOfPixieDustNotification.QNAME));
172 final var ex = assertThrows(IncorrectNestingException.class,
173 () -> codecContext.fromYangInstanceIdentifier(yiid));
174 assertThat(ex.getMessage(),
175 startsWith("Argument (urn:opendaylight:params:xml:ns:yang:controller:md:sal:test:bi:ba:notification"
176 + "?revision=2015-02-05)out-of-pixie-dust-notification is not valid data tree child of "));
180 public void testRejectRpcQName() {
181 // A purposely-wrong YangInstanceIdentifier
182 final var yiid = YangInstanceIdentifier.create(NodeIdentifier.create(
183 // TODO: use the RPC interface once we are generating it
184 QName.create(KnockKnockInput.QNAME, "knock-knock")));
185 final var ex = assertThrows(IncorrectNestingException.class,
186 () -> codecContext.fromYangInstanceIdentifier(yiid));
187 assertThat(ex.getMessage(), startsWith("Argument (urn:opendaylight:params:xml:ns:yang:md:sal:knock-knock"
188 + "?revision=2018-07-23)knock-knock is not valid data tree child of "));
192 public void testRejectActionQName() {
193 // A purposely-wrong YangInstanceIdentifier
194 final var yiid = YangInstanceIdentifier.create(
195 NodeIdentifier.create(Lst.QNAME),
196 NodeIdentifierWithPredicates.of(Lst.QNAME, QName.create(Lst.QNAME, "key"), "foo"),
197 NodeIdentifier.create(Foo.QNAME));
198 final var ex = assertThrows(IncorrectNestingException.class,
199 () -> codecContext.fromYangInstanceIdentifier(yiid));
200 assertEquals("Argument (urn:odl:actions)foo is not valid child of "
201 + "EmptyListEffectiveStatement{argument=(urn:odl:actions)lst}", ex.getMessage());