2 * Copyright (c) 2018 Pantheon Technologies, s.ro.. 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.adapter.test;
10 import static org.junit.Assert.assertEquals;
11 import static org.mockito.ArgumentMatchers.any;
12 import static org.mockito.Mockito.doNothing;
13 import static org.mockito.Mockito.mock;
14 import static org.mockito.Mockito.reset;
15 import static org.mockito.Mockito.verify;
16 import static org.opendaylight.mdsal.common.api.LogicalDatastoreType.CONFIGURATION;
18 import com.google.common.collect.ImmutableList;
19 import java.util.Collection;
20 import java.util.Collections;
21 import java.util.Iterator;
22 import java.util.concurrent.ExecutionException;
23 import org.junit.Test;
24 import org.mockito.ArgumentCaptor;
25 import org.opendaylight.mdsal.binding.api.DataObjectModification;
26 import org.opendaylight.mdsal.binding.api.DataObjectModification.ModificationType;
27 import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
28 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
29 import org.opendaylight.mdsal.binding.api.DataTreeModification;
30 import org.opendaylight.mdsal.binding.api.WriteTransaction;
31 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
32 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.AddressableCont;
33 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.AddressableContBuilder;
34 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.Container;
35 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.ContainerBuilder;
36 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.UnaddressableCont;
37 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.UnaddressableContBuilder;
38 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.WithChoice;
39 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.WithChoiceBuilder;
40 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.addressable.cont.AddressableChild;
41 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.addressable.cont.AddressableChildBuilder;
42 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.container.Keyed;
43 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.container.KeyedBuilder;
44 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.container.KeyedKey;
45 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.container.Unkeyed;
46 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.container.UnkeyedBuilder;
47 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.with.choice.Foo;
48 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.with.choice.foo.addressable._case.Addressable;
49 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.with.choice.foo.addressable._case.AddressableBuilder;
50 import org.opendaylight.yangtools.yang.binding.DataObject;
51 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
52 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
53 import org.opendaylight.yangtools.yang.common.QName;
54 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
55 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
56 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
57 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
58 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
60 public class Mdsal298Test extends AbstractDataBrokerTest {
61 private static final InstanceIdentifier<Container> CONTAINER = InstanceIdentifier.create(Container.class);
62 private static final DataTreeIdentifier<Container> CONTAINER_TID = DataTreeIdentifier.create(CONFIGURATION,
64 private static final NodeIdentifier CONTAINER_NID = new NodeIdentifier(Container.QNAME);
65 private static final QName FOO_QNAME = QName.create(Container.QNAME, "foo");
66 private static final QName BAZ_QNAME = QName.create(UnaddressableCont.QNAME, "baz");
68 private static final InstanceIdentifier<WithChoice> CHOICE_CONTAINER = InstanceIdentifier.create(WithChoice.class);
69 private static final DataTreeIdentifier<WithChoice> CHOICE_CONTAINER_TID = DataTreeIdentifier.create(CONFIGURATION,
71 private static final NodeIdentifier CHOICE_CONTAINER_NID = new NodeIdentifier(WithChoice.QNAME);
72 private static final NodeIdentifier CHOICE_NID = new NodeIdentifier(Foo.QNAME);
73 private static final InstanceIdentifier<Addressable> ADDRESSABLE_CASE = CHOICE_CONTAINER
74 .child((Class)Addressable.class);
76 private static final InstanceIdentifier<AddressableCont> ADDRESSABLE_CONTAINER =
77 InstanceIdentifier.create(AddressableCont.class);
78 private static final DataTreeIdentifier<AddressableCont> ADDRESSABLE_CONTAINER_TID = DataTreeIdentifier.create(
79 CONFIGURATION, ADDRESSABLE_CONTAINER);
80 private static final NodeIdentifier ADDRESSABLE_CONTAINER_NID = new NodeIdentifier(AddressableCont.QNAME);
82 private static final InstanceIdentifier<UnaddressableCont> UNADDRESSABLE_CONTAINER =
83 InstanceIdentifier.create(UnaddressableCont.class);
84 private static final DataTreeIdentifier<UnaddressableCont> UNADDRESSABLE_CONTAINER_TID = DataTreeIdentifier.create(
85 CONFIGURATION, UNADDRESSABLE_CONTAINER);
86 private static final NodeIdentifier UNADDRESSABLE_CONTAINER_NID = new NodeIdentifier(UnaddressableCont.QNAME);
89 public void testKeyedDataTreeModification() throws InterruptedException, ExecutionException {
90 final DataTreeChangeListener<Container> listener = assertWrittenContainer(Container.QNAME, Container.class,
91 new ContainerBuilder().build());
93 final DOMDataTreeWriteTransaction domTx = getDomBroker().newWriteOnlyTransaction();
94 domTx.put(CONFIGURATION, YangInstanceIdentifier.create(CONTAINER_NID).node(Keyed.QNAME),
95 Builders.orderedMapBuilder()
96 .withNodeIdentifier(new NodeIdentifier(Keyed.QNAME))
97 .addChild(Builders.mapEntryBuilder()
98 .withNodeIdentifier(NodeIdentifierWithPredicates.of(Keyed.QNAME, FOO_QNAME, "foo"))
99 .addChild(ImmutableNodes.leafNode(FOO_QNAME, "foo"))
101 .addChild(Builders.mapEntryBuilder()
102 .withNodeIdentifier(NodeIdentifierWithPredicates.of(Keyed.QNAME, FOO_QNAME, "bar"))
103 .addChild(ImmutableNodes.leafNode(FOO_QNAME, "bar"))
106 domTx.commit().get();
108 final ArgumentCaptor<Collection> captor = ArgumentCaptor.forClass(Collection.class);
109 verify(listener).onDataTreeChanged(captor.capture());
110 Collection<DataTreeModification<Container>> capture = captor.getValue();
111 assertEquals(1, capture.size());
113 final DataTreeModification<Container> change = capture.iterator().next();
114 assertEquals(CONTAINER_TID, change.getRootPath());
115 final DataObjectModification<Container> changedContainer = change.getRootNode();
116 assertEquals(Item.of(Container.class), changedContainer.getIdentifier());
117 assertEquals(ModificationType.SUBTREE_MODIFIED, changedContainer.getModificationType());
119 final Container containerAfter = changedContainer.getDataAfter();
120 assertEquals(new ContainerBuilder()
121 .setKeyed(ImmutableList.of(
122 new KeyedBuilder().setFoo("foo").withKey(new KeyedKey("foo")).build(),
123 new KeyedBuilder().setFoo("bar").withKey(new KeyedKey("bar")).build()))
124 .build(), containerAfter);
126 final Collection<? extends DataObjectModification<?>> changedChildren = changedContainer.getModifiedChildren();
127 assertEquals(2, changedChildren.size());
129 final Iterator<? extends DataObjectModification<?>> it = changedChildren.iterator();
130 final DataObjectModification<?> changedChild1 = it.next();
131 assertEquals(ModificationType.WRITE, changedChild1.getModificationType());
132 assertEquals(Collections.emptyList(), changedChild1.getModifiedChildren());
133 final Keyed child1After = (Keyed) changedChild1.getDataAfter();
134 assertEquals("foo", child1After.getFoo());
136 final DataObjectModification<?> changedChild2 = it.next();
137 assertEquals(ModificationType.WRITE, changedChild2.getModificationType());
138 assertEquals(Collections.emptyList(), changedChild2.getModifiedChildren());
139 final Keyed child2After = (Keyed) changedChild2.getDataAfter();
140 assertEquals("bar", child2After.getFoo());
144 public void testUnkeyedDataTreeModification() throws InterruptedException, ExecutionException {
145 final DataTreeChangeListener<Container> listener = assertWrittenContainer(Container.QNAME, Container.class,
146 new ContainerBuilder().build());
148 final DOMDataTreeWriteTransaction domTx = getDomBroker().newWriteOnlyTransaction();
149 domTx.put(CONFIGURATION, YangInstanceIdentifier.create(CONTAINER_NID).node(Unkeyed.QNAME),
150 Builders.unkeyedListBuilder()
151 .withNodeIdentifier(new NodeIdentifier(Unkeyed.QNAME))
152 .withChild(Builders.unkeyedListEntryBuilder()
153 .withNodeIdentifier(new NodeIdentifier(Unkeyed.QNAME))
154 .addChild(ImmutableNodes.leafNode(FOO_QNAME, "foo"))
156 .withChild(Builders.unkeyedListEntryBuilder()
157 .withNodeIdentifier(new NodeIdentifier(Unkeyed.QNAME))
158 .addChild(ImmutableNodes.leafNode(FOO_QNAME, "bar"))
161 domTx.commit().get();
163 final ArgumentCaptor<Collection> captor = ArgumentCaptor.forClass(Collection.class);
164 verify(listener).onDataTreeChanged(captor.capture());
165 Collection<DataTreeModification<Container>> capture = captor.getValue();
166 assertEquals(1, capture.size());
168 final DataTreeModification<Container> change = capture.iterator().next();
169 assertEquals(CONTAINER_TID, change.getRootPath());
170 final DataObjectModification<Container> changedContainer = change.getRootNode();
171 assertEquals(Item.of(Container.class), changedContainer.getIdentifier());
172 assertEquals(ModificationType.WRITE, changedContainer.getModificationType());
174 final Container containerAfter = changedContainer.getDataAfter();
175 assertEquals(new ContainerBuilder()
176 .setUnkeyed(ImmutableList.of(
177 new UnkeyedBuilder().setFoo("foo").build(),
178 new UnkeyedBuilder().setFoo("bar").build()))
179 .build(), containerAfter);
181 final Collection<? extends DataObjectModification<?>> changedChildren = changedContainer.getModifiedChildren();
182 assertEquals(0, changedChildren.size());
186 public void testChoiceDataTreeModificationAddressable() throws InterruptedException, ExecutionException {
187 final DataTreeChangeListener<WithChoice> listener = assertWrittenWithChoice();
189 doNothing().when(listener).onDataTreeChanged(any(Collection.class));
191 final WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
192 writeTx.put(CONFIGURATION, ADDRESSABLE_CASE, new AddressableBuilder().build());
193 writeTx.commit().get();
195 final ArgumentCaptor<Collection> captor = ArgumentCaptor.forClass(Collection.class);
196 verify(listener).onDataTreeChanged(captor.capture());
197 Collection<DataTreeModification<WithChoice>> capture = captor.getValue();
198 assertEquals(1, capture.size());
200 final DataTreeModification<WithChoice> choiceChange = capture.iterator().next();
201 assertEquals(CHOICE_CONTAINER_TID, choiceChange.getRootPath());
202 final DataObjectModification<WithChoice> changedContainer = choiceChange.getRootNode();
203 assertEquals(ModificationType.SUBTREE_MODIFIED, changedContainer.getModificationType());
204 assertEquals(Item.of(WithChoice.class), changedContainer.getIdentifier());
206 final Collection<? extends DataObjectModification<?>> choiceChildren = changedContainer.getModifiedChildren();
207 assertEquals(1, choiceChildren.size());
209 final DataObjectModification<Addressable> changedCase = (DataObjectModification<Addressable>) choiceChildren
211 assertEquals(ModificationType.WRITE, changedCase.getModificationType());
212 assertEquals(Item.of(Addressable.class), changedCase.getIdentifier());
213 assertEquals(new AddressableBuilder().build(), changedCase.getDataAfter());
217 public void testDataTreeModificationAddressable() throws InterruptedException, ExecutionException {
218 final DataTreeChangeListener<AddressableCont> listener = assertWrittenContainer(AddressableCont.QNAME,
219 AddressableCont.class, new AddressableContBuilder().build());
221 doNothing().when(listener).onDataTreeChanged(any(Collection.class));
223 final WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
224 writeTx.put(CONFIGURATION, ADDRESSABLE_CONTAINER.child(AddressableChild.class),
225 new AddressableChildBuilder().build());
226 writeTx.commit().get();
228 final ArgumentCaptor<Collection> captor = ArgumentCaptor.forClass(Collection.class);
229 verify(listener).onDataTreeChanged(captor.capture());
230 Collection<DataTreeModification<AddressableCont>> capture = captor.getValue();
231 assertEquals(1, capture.size());
233 final DataTreeModification<AddressableCont> contChange = capture.iterator().next();
234 assertEquals(ADDRESSABLE_CONTAINER_TID, contChange.getRootPath());
235 final DataObjectModification<AddressableCont> changedContainer = contChange.getRootNode();
236 assertEquals(ModificationType.SUBTREE_MODIFIED, changedContainer.getModificationType());
237 assertEquals(Item.of(AddressableCont.class), changedContainer.getIdentifier());
239 final Collection<? extends DataObjectModification<?>> contChildren = changedContainer.getModifiedChildren();
240 assertEquals(1, contChildren.size());
242 final DataObjectModification<Addressable> changedChild = (DataObjectModification<Addressable>) contChildren
244 assertEquals(ModificationType.WRITE, changedChild.getModificationType());
245 assertEquals(Item.of(AddressableChild.class), changedChild.getIdentifier());
246 assertEquals(new AddressableChildBuilder().build(), changedChild.getDataAfter());
250 public void testDataTreeModificationUnaddressable() throws InterruptedException, ExecutionException {
251 final DataTreeChangeListener<UnaddressableCont> listener = assertWrittenContainer(UnaddressableCont.QNAME,
252 UnaddressableCont.class, new UnaddressableContBuilder().build());
254 doNothing().when(listener).onDataTreeChanged(any(Collection.class));
256 final DOMDataTreeWriteTransaction domTx = getDomBroker().newWriteOnlyTransaction();
257 domTx.put(CONFIGURATION, YangInstanceIdentifier.create(UNADDRESSABLE_CONTAINER_NID)
258 .node(QName.create(UnaddressableCont.QNAME, "baz")),
259 ImmutableNodes.leafNode(BAZ_QNAME, "baz"));
260 domTx.commit().get();
262 final ArgumentCaptor<Collection> captor = ArgumentCaptor.forClass(Collection.class);
263 verify(listener).onDataTreeChanged(captor.capture());
264 Collection<DataTreeModification<UnaddressableCont>> capture = captor.getValue();
265 assertEquals(1, capture.size());
267 final DataTreeModification<UnaddressableCont> contChange = capture.iterator().next();
268 assertEquals(UNADDRESSABLE_CONTAINER_TID, contChange.getRootPath());
269 final DataObjectModification<UnaddressableCont> changedContainer = contChange.getRootNode();
270 assertEquals(ModificationType.WRITE, changedContainer.getModificationType());
271 assertEquals(Item.of(UnaddressableCont.class), changedContainer.getIdentifier());
273 final Collection<? extends DataObjectModification<?>> contChildren = changedContainer.getModifiedChildren();
274 assertEquals(0, contChildren.size());
278 public void testChoiceDataTreeModificationUnaddressable() throws InterruptedException, ExecutionException {
279 final DataTreeChangeListener<WithChoice> listener = assertWrittenWithChoice();
281 doNothing().when(listener).onDataTreeChanged(any(Collection.class));
283 final DOMDataTreeWriteTransaction domTx = getDomBroker().newWriteOnlyTransaction();
284 domTx.put(CONFIGURATION, YangInstanceIdentifier.create(CHOICE_CONTAINER_NID).node(Foo.QNAME),
285 Builders.choiceBuilder()
286 .withNodeIdentifier(new NodeIdentifier(Foo.QNAME))
287 .withChild(Builders.leafSetBuilder()
288 .withNodeIdentifier(new NodeIdentifier(QName.create(Foo.QNAME, "unaddressable")))
289 .withChildValue("foo")
292 domTx.commit().get();
294 final ArgumentCaptor<Collection> captor = ArgumentCaptor.forClass(Collection.class);
295 verify(listener).onDataTreeChanged(captor.capture());
296 Collection<DataTreeModification<WithChoice>> capture = captor.getValue();
297 assertEquals(1, capture.size());
299 final DataTreeModification<WithChoice> choiceChange = capture.iterator().next();
300 assertEquals(CHOICE_CONTAINER_TID, choiceChange.getRootPath());
301 final DataObjectModification<WithChoice> changedContainer = choiceChange.getRootNode();
304 assertEquals(ModificationType.WRITE, changedContainer.getModificationType());
305 assertEquals(Item.of(WithChoice.class), changedContainer.getIdentifier());
307 final Collection<? extends DataObjectModification<?>> choiceChildren = changedContainer.getModifiedChildren();
308 assertEquals(0, choiceChildren.size());
311 private <T extends DataObject> DataTreeChangeListener<T> assertWrittenContainer(final QName qname,
312 final Class<T> bindingClass, final T expected)
313 throws InterruptedException, ExecutionException {
314 final DataTreeChangeListener<T> listener = mock(DataTreeChangeListener.class);
315 doNothing().when(listener).onDataTreeChanged(any(Collection.class));
317 final DataTreeIdentifier<T> dti = DataTreeIdentifier.create(CONFIGURATION,
318 InstanceIdentifier.create(bindingClass));
319 getDataBroker().registerDataTreeChangeListener(dti, listener);
321 final DOMDataTreeWriteTransaction domTx = getDomBroker().newWriteOnlyTransaction();
322 domTx.put(CONFIGURATION, YangInstanceIdentifier.create(new NodeIdentifier(qname)),
323 ImmutableNodes.containerNode(qname));
324 domTx.commit().get();
326 final ArgumentCaptor<Collection> captor = ArgumentCaptor.forClass(Collection.class);
327 verify(listener).onDataTreeChanged(captor.capture());
328 Collection<DataTreeModification<T>> capture = captor.getValue();
329 assertEquals(1, capture.size());
331 final DataTreeModification<T> change = capture.iterator().next();
332 assertEquals(dti, change.getRootPath());
333 final DataObjectModification<T> changedContainer = change.getRootNode();
334 assertEquals(ModificationType.WRITE, changedContainer.getModificationType());
335 assertEquals(Item.of(bindingClass), changedContainer.getIdentifier());
337 final T containerAfter = changedContainer.getDataAfter();
338 assertEquals(expected, containerAfter);
340 // No further modifications should occur
341 assertEquals(Collections.emptyList(), changedContainer.getModifiedChildren());
344 doNothing().when(listener).onDataTreeChanged(any(Collection.class));
348 private DataTreeChangeListener<WithChoice> assertWrittenWithChoice() throws InterruptedException,
350 final DataTreeChangeListener<WithChoice> listener = mock(DataTreeChangeListener.class);
351 doNothing().when(listener).onDataTreeChanged(any(Collection.class));
352 getDataBroker().registerDataTreeChangeListener(CHOICE_CONTAINER_TID, listener);
354 final DOMDataTreeWriteTransaction domTx = getDomBroker().newWriteOnlyTransaction();
355 domTx.put(CONFIGURATION, YangInstanceIdentifier.create(CHOICE_CONTAINER_NID),
356 Builders.containerBuilder()
357 .withNodeIdentifier(CHOICE_CONTAINER_NID)
358 .withChild(Builders.choiceBuilder().withNodeIdentifier(CHOICE_NID).build())
360 domTx.commit().get();
362 final ArgumentCaptor<Collection> captor = ArgumentCaptor.forClass(Collection.class);
363 verify(listener).onDataTreeChanged(captor.capture());
364 Collection<DataTreeModification<WithChoice>> capture = captor.getValue();
365 assertEquals(1, capture.size());
367 final DataTreeModification<WithChoice> change = capture.iterator().next();
368 assertEquals(CHOICE_CONTAINER_TID, change.getRootPath());
369 final DataObjectModification<WithChoice> changedContainer = change.getRootNode();
370 assertEquals(ModificationType.WRITE, changedContainer.getModificationType());
371 assertEquals(Item.of(WithChoice.class), changedContainer.getIdentifier());
373 final WithChoice containerAfter = changedContainer.getDataAfter();
374 assertEquals(new WithChoiceBuilder().build(), containerAfter);
376 // No further modifications should occur
377 assertEquals(Collections.emptyList(), changedContainer.getModifiedChildren());
380 doNothing().when(listener).onDataTreeChanged(any(Collection.class));