Migrate users of deprecated yang.common methods
[mdsal.git] / binding / mdsal-binding-dom-adapter / src / test / java / org / opendaylight / mdsal / binding / dom / adapter / Mdsal298Test.java
1 /*
2  * Copyright (c) 2018 Pantheon Technologies, s.ro.. 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.adapter;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.mockito.ArgumentMatchers.anyList;
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;
17
18 import java.util.List;
19 import java.util.concurrent.ExecutionException;
20 import org.junit.Test;
21 import org.mockito.ArgumentCaptor;
22 import org.opendaylight.mdsal.binding.api.DataObjectModification;
23 import org.opendaylight.mdsal.binding.api.DataObjectModification.ModificationType;
24 import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
25 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
26 import org.opendaylight.mdsal.binding.api.DataTreeModification;
27 import org.opendaylight.mdsal.binding.api.WriteTransaction;
28 import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractDataBrokerTest;
29 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
30 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.AddressableCont;
31 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.AddressableContBuilder;
32 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.Container;
33 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.ContainerBuilder;
34 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.UnaddressableCont;
35 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.UnaddressableContBuilder;
36 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.WithChoice;
37 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.WithChoiceBuilder;
38 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.addressable.cont.AddressableChild;
39 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.addressable.cont.AddressableChildBuilder;
40 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.container.Keyed;
41 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.container.KeyedBuilder;
42 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.container.KeyedKey;
43 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.container.Unkeyed;
44 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.container.UnkeyedBuilder;
45 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.with.choice.Foo;
46 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.with.choice.foo.addressable._case.Addressable;
47 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.with.choice.foo.addressable._case.AddressableBuilder;
48 import org.opendaylight.yangtools.yang.binding.ChildOf;
49 import org.opendaylight.yangtools.yang.binding.DataRoot;
50 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
51 import org.opendaylight.yangtools.yang.binding.NodeStep;
52 import org.opendaylight.yangtools.yang.common.QName;
53 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
54 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
55 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
56 import org.opendaylight.yangtools.yang.data.spi.node.ImmutableNodes;
57
58 public class Mdsal298Test extends AbstractDataBrokerTest {
59     private static final InstanceIdentifier<Container> CONTAINER = InstanceIdentifier.create(Container.class);
60     private static final DataTreeIdentifier<Container> CONTAINER_TID = DataTreeIdentifier.of(CONFIGURATION,
61         CONTAINER);
62     private static final NodeIdentifier CONTAINER_NID = new NodeIdentifier(Container.QNAME);
63     private static final QName FOO_QNAME = QName.create(Container.QNAME, "foo");
64     private static final QName BAZ_QNAME = QName.create(UnaddressableCont.QNAME, "baz");
65
66     private static final InstanceIdentifier<WithChoice> CHOICE_CONTAINER = InstanceIdentifier.create(WithChoice.class);
67     private static final DataTreeIdentifier<WithChoice> CHOICE_CONTAINER_TID = DataTreeIdentifier.of(CONFIGURATION,
68         CHOICE_CONTAINER);
69     private static final NodeIdentifier CHOICE_CONTAINER_NID = new NodeIdentifier(WithChoice.QNAME);
70     private static final NodeIdentifier CHOICE_NID = new NodeIdentifier(Foo.QNAME);
71     private static final InstanceIdentifier<Addressable> ADDRESSABLE_CASE = CHOICE_CONTAINER
72             .child((Class)Addressable.class);
73
74     private static final InstanceIdentifier<AddressableCont> ADDRESSABLE_CONTAINER =
75             InstanceIdentifier.create(AddressableCont.class);
76     private static final DataTreeIdentifier<AddressableCont> ADDRESSABLE_CONTAINER_TID = DataTreeIdentifier.of(
77         CONFIGURATION, ADDRESSABLE_CONTAINER);
78     private static final NodeIdentifier ADDRESSABLE_CONTAINER_NID = new NodeIdentifier(AddressableCont.QNAME);
79
80     private static final InstanceIdentifier<UnaddressableCont> UNADDRESSABLE_CONTAINER =
81             InstanceIdentifier.create(UnaddressableCont.class);
82     private static final DataTreeIdentifier<UnaddressableCont> UNADDRESSABLE_CONTAINER_TID = DataTreeIdentifier.of(
83         CONFIGURATION, UNADDRESSABLE_CONTAINER);
84     private static final NodeIdentifier UNADDRESSABLE_CONTAINER_NID = new NodeIdentifier(UnaddressableCont.QNAME);
85
86     @Test
87     public void testKeyedDataTreeModification() throws InterruptedException, ExecutionException {
88         final DataTreeChangeListener<Container> listener = assertWrittenContainer(Container.QNAME, Container.class,
89             new ContainerBuilder().build());
90
91         final DOMDataTreeWriteTransaction domTx = getDomBroker().newWriteOnlyTransaction();
92         domTx.put(CONFIGURATION, YangInstanceIdentifier.of(CONTAINER_NID).node(Keyed.QNAME),
93             ImmutableNodes.newUserMapBuilder()
94                 .withNodeIdentifier(new NodeIdentifier(Keyed.QNAME))
95                 .addChild(ImmutableNodes.newMapEntryBuilder()
96                     .withNodeIdentifier(NodeIdentifierWithPredicates.of(Keyed.QNAME, FOO_QNAME, "foo"))
97                     .addChild(ImmutableNodes.leafNode(FOO_QNAME, "foo"))
98                     .build())
99                 .addChild(ImmutableNodes.newMapEntryBuilder()
100                     .withNodeIdentifier(NodeIdentifierWithPredicates.of(Keyed.QNAME, FOO_QNAME, "bar"))
101                     .addChild(ImmutableNodes.leafNode(FOO_QNAME, "bar"))
102                     .build())
103                 .build());
104         domTx.commit().get();
105
106         final var captor = ArgumentCaptor.forClass(List.class);
107         verify(listener).onDataTreeChanged(captor.capture());
108         List<DataTreeModification<Container>> capture = captor.getValue();
109         assertEquals(1, capture.size());
110
111         final DataTreeModification<Container> change = capture.get(0);
112         assertEquals(CONTAINER_TID, change.getRootPath());
113         final DataObjectModification<Container> changedContainer = change.getRootNode();
114         assertEquals(new NodeStep<>(Container.class), changedContainer.step());
115         assertEquals(ModificationType.SUBTREE_MODIFIED, changedContainer.modificationType());
116
117         final Container containerAfter = changedContainer.dataAfter();
118         assertEquals(new ContainerBuilder()
119             .setKeyed(List.of(
120                 new KeyedBuilder().setFoo("foo").withKey(new KeyedKey("foo")).build(),
121                 new KeyedBuilder().setFoo("bar").withKey(new KeyedKey("bar")).build()))
122             .build(), containerAfter);
123
124         final var changedChildren = changedContainer.modifiedChildren();
125         assertEquals(2, changedChildren.size());
126
127         final var it = changedChildren.iterator();
128         final DataObjectModification<?> changedChild1 = it.next();
129         assertEquals(ModificationType.WRITE, changedChild1.modificationType());
130         assertEquals(List.of(), changedChild1.modifiedChildren());
131         final Keyed child1After = (Keyed) changedChild1.dataAfter();
132         assertEquals("foo", child1After.getFoo());
133
134         final DataObjectModification<?> changedChild2 = it.next();
135         assertEquals(ModificationType.WRITE, changedChild2.modificationType());
136         assertEquals(List.of(), changedChild2.modifiedChildren());
137         final Keyed child2After = (Keyed) changedChild2.dataAfter();
138         assertEquals("bar", child2After.getFoo());
139     }
140
141     @Test
142     public void testUnkeyedDataTreeModification() throws InterruptedException, ExecutionException {
143         final DataTreeChangeListener<Container> listener = assertWrittenContainer(Container.QNAME, Container.class,
144             new ContainerBuilder().build());
145
146         final DOMDataTreeWriteTransaction domTx = getDomBroker().newWriteOnlyTransaction();
147         domTx.put(CONFIGURATION, YangInstanceIdentifier.of(CONTAINER_NID).node(Unkeyed.QNAME),
148             ImmutableNodes.newUnkeyedListBuilder()
149                 .withNodeIdentifier(new NodeIdentifier(Unkeyed.QNAME))
150                 .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
151                     .withNodeIdentifier(new NodeIdentifier(Unkeyed.QNAME))
152                     .addChild(ImmutableNodes.leafNode(FOO_QNAME, "foo"))
153                     .build())
154                 .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
155                     .withNodeIdentifier(new NodeIdentifier(Unkeyed.QNAME))
156                     .addChild(ImmutableNodes.leafNode(FOO_QNAME, "bar"))
157                     .build())
158                 .build());
159         domTx.commit().get();
160
161         final var captor = ArgumentCaptor.forClass(List.class);
162         verify(listener).onDataTreeChanged(captor.capture());
163         List<DataTreeModification<Container>> capture = captor.getValue();
164         assertEquals(1, capture.size());
165
166         final DataTreeModification<Container> change = capture.get(0);
167         assertEquals(CONTAINER_TID, change.getRootPath());
168         final DataObjectModification<Container> changedContainer = change.getRootNode();
169         assertEquals(new NodeStep<>(Container.class), changedContainer.step());
170         assertEquals(ModificationType.WRITE, changedContainer.modificationType());
171
172         final Container containerAfter = changedContainer.dataAfter();
173         assertEquals(new ContainerBuilder()
174                 .setUnkeyed(List.of(
175                     new UnkeyedBuilder().setFoo("foo").build(),
176                     new UnkeyedBuilder().setFoo("bar").build()))
177                 .build(), containerAfter);
178
179         final var changedChildren = changedContainer.modifiedChildren();
180         assertEquals(0, changedChildren.size());
181     }
182
183     @Test
184     public void testChoiceDataTreeModificationAddressable() throws InterruptedException, ExecutionException {
185         final DataTreeChangeListener<WithChoice> listener = assertWrittenWithChoice();
186
187         doNothing().when(listener).onDataTreeChanged(anyList());
188
189         final WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
190         writeTx.put(CONFIGURATION, ADDRESSABLE_CASE, new AddressableBuilder().build());
191         writeTx.commit().get();
192
193         final var captor = ArgumentCaptor.forClass(List.class);
194         verify(listener).onDataTreeChanged(captor.capture());
195         List<DataTreeModification<WithChoice>> capture = captor.getValue();
196         assertEquals(1, capture.size());
197
198         final DataTreeModification<WithChoice> choiceChange = capture.iterator().next();
199         assertEquals(CHOICE_CONTAINER_TID, choiceChange.getRootPath());
200         final DataObjectModification<WithChoice> changedContainer = choiceChange.getRootNode();
201         assertEquals(ModificationType.SUBTREE_MODIFIED, changedContainer.modificationType());
202         assertEquals(new NodeStep<>(WithChoice.class), changedContainer.step());
203
204         final var choiceChildren = changedContainer.modifiedChildren();
205         assertEquals(1, choiceChildren.size());
206
207         final var changedCase = (DataObjectModification<Addressable>) choiceChildren.iterator().next();
208         assertEquals(ModificationType.WRITE, changedCase.modificationType());
209         assertEquals(new NodeStep<>(Addressable.class), changedCase.step());
210         assertEquals(new AddressableBuilder().build(), changedCase.dataAfter());
211     }
212
213     @Test
214     public void testDataTreeModificationAddressable() throws InterruptedException, ExecutionException {
215         final DataTreeChangeListener<AddressableCont> listener = assertWrittenContainer(AddressableCont.QNAME,
216             AddressableCont.class, new AddressableContBuilder().build());
217
218         doNothing().when(listener).onDataTreeChanged(anyList());
219
220         final WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
221         writeTx.put(CONFIGURATION, ADDRESSABLE_CONTAINER.child(AddressableChild.class),
222             new AddressableChildBuilder().build());
223         writeTx.commit().get();
224
225         final var captor = ArgumentCaptor.forClass(List.class);
226         verify(listener).onDataTreeChanged(captor.capture());
227         final List<DataTreeModification<AddressableCont>> capture = captor.getValue();
228         assertEquals(1, capture.size());
229
230         final DataTreeModification<AddressableCont> contChange = capture.iterator().next();
231         assertEquals(ADDRESSABLE_CONTAINER_TID, contChange.getRootPath());
232         final DataObjectModification<AddressableCont> changedContainer = contChange.getRootNode();
233         assertEquals(ModificationType.SUBTREE_MODIFIED, changedContainer.modificationType());
234         assertEquals(new NodeStep<>(AddressableCont.class), changedContainer.step());
235
236         final var contChildren = changedContainer.modifiedChildren();
237         assertEquals(1, contChildren.size());
238
239         final var changedChild = (DataObjectModification<Addressable>) contChildren.iterator().next();
240         assertEquals(ModificationType.WRITE, changedChild.modificationType());
241         assertEquals(new NodeStep<>(AddressableChild.class), changedChild.step());
242         assertEquals(new AddressableChildBuilder().build(), changedChild.dataAfter());
243     }
244
245     @Test
246     public void testDataTreeModificationUnaddressable() throws InterruptedException, ExecutionException {
247         final DataTreeChangeListener<UnaddressableCont> listener = assertWrittenContainer(UnaddressableCont.QNAME,
248             UnaddressableCont.class, new UnaddressableContBuilder().build());
249
250         doNothing().when(listener).onDataTreeChanged(anyList());
251
252         final DOMDataTreeWriteTransaction domTx = getDomBroker().newWriteOnlyTransaction();
253         domTx.put(CONFIGURATION, YangInstanceIdentifier.of(UNADDRESSABLE_CONTAINER_NID)
254             .node(QName.create(UnaddressableCont.QNAME, "baz")),
255             ImmutableNodes.leafNode(BAZ_QNAME, "baz"));
256         domTx.commit().get();
257
258         final var captor = ArgumentCaptor.forClass(List.class);
259         verify(listener).onDataTreeChanged(captor.capture());
260         List<DataTreeModification<UnaddressableCont>> capture = captor.getValue();
261         assertEquals(1, capture.size());
262
263         final DataTreeModification<UnaddressableCont> contChange = capture.iterator().next();
264         assertEquals(UNADDRESSABLE_CONTAINER_TID, contChange.getRootPath());
265         final DataObjectModification<UnaddressableCont> changedContainer = contChange.getRootNode();
266         assertEquals(ModificationType.WRITE, changedContainer.modificationType());
267         assertEquals(new NodeStep<>(UnaddressableCont.class), changedContainer.step());
268
269         final var contChildren = changedContainer.modifiedChildren();
270         assertEquals(0, contChildren.size());
271     }
272
273     @Test
274     public void testChoiceDataTreeModificationUnaddressable() throws InterruptedException, ExecutionException {
275         final DataTreeChangeListener<WithChoice> listener = assertWrittenWithChoice();
276
277         doNothing().when(listener).onDataTreeChanged(anyList());
278
279         final DOMDataTreeWriteTransaction domTx = getDomBroker().newWriteOnlyTransaction();
280         domTx.put(CONFIGURATION, YangInstanceIdentifier.of(CHOICE_CONTAINER_NID).node(Foo.QNAME),
281             ImmutableNodes.newChoiceBuilder()
282                 .withNodeIdentifier(new NodeIdentifier(Foo.QNAME))
283                 .withChild(ImmutableNodes.newSystemLeafSetBuilder()
284                     .withNodeIdentifier(new NodeIdentifier(QName.create(Foo.QNAME, "unaddressable")))
285                     .withChildValue("foo")
286                     .build())
287                 .build());
288         domTx.commit().get();
289
290         final var captor = ArgumentCaptor.forClass(List.class);
291         verify(listener).onDataTreeChanged(captor.capture());
292         List<DataTreeModification<WithChoice>> capture = captor.getValue();
293         assertEquals(1, capture.size());
294
295         final DataTreeModification<WithChoice> choiceChange = capture.get(0);
296         assertEquals(CHOICE_CONTAINER_TID, choiceChange.getRootPath());
297         final DataObjectModification<WithChoice> changedContainer = choiceChange.getRootNode();
298
299         // Should be write
300         assertEquals(ModificationType.WRITE, changedContainer.modificationType());
301         assertEquals(new NodeStep<>(WithChoice.class), changedContainer.step());
302
303         final var choiceChildren = changedContainer.modifiedChildren();
304         assertEquals(0, choiceChildren.size());
305     }
306
307     private <T extends ChildOf<? extends DataRoot>> DataTreeChangeListener<T> assertWrittenContainer(final QName qname,
308             final Class<T> bindingClass, final T expected)
309             throws InterruptedException, ExecutionException {
310         final DataTreeChangeListener<T> listener = mock(DataTreeChangeListener.class);
311         doNothing().when(listener).onDataTreeChanged(anyList());
312
313         final DataTreeIdentifier<T> dti = DataTreeIdentifier.of(CONFIGURATION, InstanceIdentifier.create(bindingClass));
314         getDataBroker().registerDataTreeChangeListener(dti, listener);
315
316         final DOMDataTreeWriteTransaction domTx = getDomBroker().newWriteOnlyTransaction();
317         domTx.put(CONFIGURATION, YangInstanceIdentifier.of(new NodeIdentifier(qname)),
318             ImmutableNodes.newContainerBuilder().withNodeIdentifier(new NodeIdentifier(qname)).build());
319         domTx.commit().get();
320
321         final var captor = ArgumentCaptor.forClass(List.class);
322         verify(listener).onDataTreeChanged(captor.capture());
323         List<DataTreeModification<T>> capture = captor.getValue();
324         assertEquals(1, capture.size());
325
326         final DataTreeModification<T> change = capture.iterator().next();
327         assertEquals(dti, change.getRootPath());
328         final DataObjectModification<T> changedContainer = change.getRootNode();
329         assertEquals(ModificationType.WRITE, changedContainer.modificationType());
330         assertEquals(new NodeStep<>(bindingClass), changedContainer.step());
331
332         final T containerAfter = changedContainer.dataAfter();
333         assertEquals(expected, containerAfter);
334
335         // No further modifications should occur
336         assertEquals(List.of(), changedContainer.modifiedChildren());
337
338         reset(listener);
339         doNothing().when(listener).onDataTreeChanged(anyList());
340         return listener;
341     }
342
343     private DataTreeChangeListener<WithChoice> assertWrittenWithChoice() throws InterruptedException,
344             ExecutionException {
345         final DataTreeChangeListener<WithChoice> listener = mock(DataTreeChangeListener.class);
346         doNothing().when(listener).onDataTreeChanged(anyList());
347         getDataBroker().registerDataTreeChangeListener(CHOICE_CONTAINER_TID, listener);
348
349         final DOMDataTreeWriteTransaction domTx = getDomBroker().newWriteOnlyTransaction();
350         domTx.put(CONFIGURATION, YangInstanceIdentifier.of(CHOICE_CONTAINER_NID), ImmutableNodes.newContainerBuilder()
351             .withNodeIdentifier(CHOICE_CONTAINER_NID)
352             .withChild(ImmutableNodes.newChoiceBuilder().withNodeIdentifier(CHOICE_NID).build())
353             .build());
354         domTx.commit().get();
355
356         final var captor = ArgumentCaptor.forClass(List.class);
357         verify(listener).onDataTreeChanged(captor.capture());
358         List<DataTreeModification<WithChoice>> capture = captor.getValue();
359         assertEquals(1, capture.size());
360
361         final DataTreeModification<WithChoice> change = capture.iterator().next();
362         assertEquals(CHOICE_CONTAINER_TID, change.getRootPath());
363         final DataObjectModification<WithChoice> changedContainer = change.getRootNode();
364         assertEquals(ModificationType.WRITE, changedContainer.modificationType());
365         assertEquals(new NodeStep<>(WithChoice.class), changedContainer.step());
366
367         final WithChoice containerAfter = changedContainer.dataAfter();
368         assertEquals(new WithChoiceBuilder().build(), containerAfter);
369
370         // No further modifications should occur
371         assertEquals(List.of(), changedContainer.modifiedChildren());
372
373         reset(listener);
374         doNothing().when(listener).onDataTreeChanged(anyList());
375
376         return listener;
377     }
378 }