Bind RestconfStrategy to EffectiveModelContext
[netconf.git] / restconf / restconf-nb / src / test / java / org / opendaylight / restconf / nb / rfc8040 / rests / transactions / MdsalRestconfStrategyTest.java
1 /*
2  * Copyright (c) 2023 PANTHEON.tech, s.r.o. 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.restconf.nb.rfc8040.rests.transactions;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.mockito.Mockito.doNothing;
12 import static org.mockito.Mockito.doReturn;
13 import static org.mockito.Mockito.verify;
14 import static org.mockito.Mockito.when;
15 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFailedFluentFuture;
16 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFalseFluentFuture;
17 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
18 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateTrueFluentFuture;
19
20 import java.util.Optional;
21 import org.junit.AfterClass;
22 import org.junit.Before;
23 import org.junit.BeforeClass;
24 import org.junit.Test;
25 import org.junit.runner.RunWith;
26 import org.mockito.Mock;
27 import org.mockito.junit.MockitoJUnitRunner;
28 import org.opendaylight.mdsal.common.api.CommitInfo;
29 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
30 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
31 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
32 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
33 import org.opendaylight.restconf.api.query.ContentParam;
34 import org.opendaylight.restconf.api.query.WithDefaultsParam;
35 import org.opendaylight.restconf.common.patch.PatchStatusContext;
36 import org.opendaylight.yangtools.yang.common.ErrorTag;
37 import org.opendaylight.yangtools.yang.common.ErrorType;
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.schema.MapEntryNode;
42 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
43 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
44 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
45 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
46 import org.w3c.dom.DOMException;
47
48 @RunWith(MockitoJUnitRunner.StrictStubs.class)
49 public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTest {
50     private static EffectiveModelContext MODULES_SCHEMA;
51
52     @Mock
53     private DOMDataTreeReadWriteTransaction readWrite;
54     @Mock
55     private DOMDataBroker mockDataBroker;
56     @Mock
57     private DOMDataTreeReadTransaction read;
58
59     @BeforeClass
60     public static void setupModulesSchema() {
61         MODULES_SCHEMA = YangParserTestUtils.parseYangResourceDirectory("/modules");
62     }
63
64     @AfterClass
65     public static void dropModulesSchema() {
66         MODULES_SCHEMA = null;
67     }
68
69     @Before
70     public void before() {
71         doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
72         doReturn(readWrite).when(mockDataBroker).newReadWriteTransaction();
73     }
74
75     @Override
76     RestconfStrategy testDeleteDataStrategy() {
77         // assert that data to delete exists
78         when(readWrite.exists(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.of()))
79             .thenReturn(immediateTrueFluentFuture());
80         return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker);
81     }
82
83     @Override
84     RestconfStrategy testNegativeDeleteDataStrategy() {
85         // assert that data to delete does NOT exist
86         when(readWrite.exists(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.of()))
87             .thenReturn(immediateFalseFluentFuture());
88         return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker);
89     }
90
91     @Override
92     RestconfStrategy testPostListDataStrategy(final MapEntryNode entryNode, final YangInstanceIdentifier node) {
93         doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, node);
94         doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, node, entryNode);
95         doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
96         return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker);
97     }
98
99     @Override
100     RestconfStrategy testPostDataFailStrategy(final DOMException domException) {
101         doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
102         doReturn(immediateFailedFluentFuture(domException)).when(readWrite).commit();
103         doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX);
104         return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker);
105     }
106
107     @Test
108     public void testPutContainerData() {
109         doReturn(readWrite).when(mockDataBroker).newReadWriteTransaction();
110         doReturn(read).when(mockDataBroker).newReadOnlyTransaction();
111         doReturn(immediateFalseFluentFuture()).when(read).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
112         doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX);
113         doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
114
115         new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker).putData(JUKEBOX_IID, EMPTY_JUKEBOX, null);
116         verify(read).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
117         verify(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX);
118     }
119
120     @Test
121     public void testPutLeafData() {
122         doReturn(readWrite).when(mockDataBroker).newReadWriteTransaction();
123         doReturn(read).when(mockDataBroker).newReadOnlyTransaction();
124         doReturn(immediateFalseFluentFuture()).when(read).exists(LogicalDatastoreType.CONFIGURATION, GAP_IID);
125         doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF);
126         doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
127
128         new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker).putData(GAP_IID, GAP_LEAF, null);
129         verify(read).exists(LogicalDatastoreType.CONFIGURATION, GAP_IID);
130         verify(readWrite).put(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF);
131     }
132
133
134     @Test
135     public void testPutListData() {
136         doReturn(readWrite).when(mockDataBroker).newReadWriteTransaction();
137         doReturn(read).when(mockDataBroker).newReadOnlyTransaction();
138         doReturn(immediateFalseFluentFuture())
139                 .when(read).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
140         doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS);
141         doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
142
143         new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker).putData(JUKEBOX_IID, JUKEBOX_WITH_BANDS, null);
144         verify(read).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
145         verify(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS);
146     }
147
148     @Override
149     RestconfStrategy testPostContainerDataStrategy() {
150         doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
151         doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX);
152         doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
153         return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker);
154     }
155
156     @Override
157     RestconfStrategy testPatchContainerDataStrategy() {
158         doReturn(readWrite).when(mockDataBroker).newReadWriteTransaction();
159         doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
160         return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker);
161     }
162
163     @Override
164     RestconfStrategy testPatchLeafDataStrategy() {
165         doReturn(readWrite).when(mockDataBroker).newReadWriteTransaction();
166         doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
167         return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker);
168     }
169
170     @Override
171     RestconfStrategy testPatchListDataStrategy() {
172         doReturn(readWrite).when(mockDataBroker).newReadWriteTransaction();
173         doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
174         return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker);
175     }
176
177     @Override
178     RestconfStrategy testPatchDataReplaceMergeAndRemoveStrategy() {
179         return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker);
180     }
181
182     @Override
183     RestconfStrategy testPatchDataCreateAndDeleteStrategy() {
184         doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, PLAYER_IID);
185         doReturn(immediateTrueFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION,
186             CREATE_AND_DELETE_TARGET);
187         return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker);
188     }
189
190     @Override
191     RestconfStrategy testPatchMergePutContainerStrategy() {
192         return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker);
193     }
194
195     @Override
196     RestconfStrategy deleteNonexistentDataTestStrategy() {
197         doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION,
198             CREATE_AND_DELETE_TARGET);
199         return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker);
200     }
201
202     @Override
203     void assertTestDeleteNonexistentData(final PatchStatusContext status) {
204         final var editCollection = status.editCollection();
205         assertEquals(1, editCollection.size());
206         final var editErrors = editCollection.get(0).getEditErrors();
207         assertEquals(1, editErrors.size());
208         final var editError = editErrors.get(0);
209         assertEquals(ErrorType.PROTOCOL, editError.getErrorType());
210         assertEquals(ErrorTag.DATA_MISSING, editError.getErrorTag());
211     }
212
213     @Override
214     RestconfStrategy readDataConfigTestStrategy() {
215         doReturn(read).when(mockDataBroker).newReadOnlyTransaction();
216         doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(read)
217             .read(LogicalDatastoreType.CONFIGURATION, PATH);
218         return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker);
219     }
220
221     @Override
222     RestconfStrategy readAllHavingOnlyConfigTestStrategy() {
223         doReturn(read).when(mockDataBroker).newReadOnlyTransaction();
224         doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(read)
225             .read(LogicalDatastoreType.CONFIGURATION, PATH);
226         doReturn(immediateFluentFuture(Optional.empty())).when(read)
227             .read(LogicalDatastoreType.OPERATIONAL, PATH);
228         return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker);
229     }
230
231     @Override
232     RestconfStrategy readAllHavingOnlyNonConfigTestStrategy() {
233         doReturn(read).when(mockDataBroker).newReadOnlyTransaction();
234         doReturn(immediateFluentFuture(Optional.of(DATA_2))).when(read)
235             .read(LogicalDatastoreType.OPERATIONAL, PATH_2);
236         doReturn(immediateFluentFuture(Optional.empty())).when(read)
237             .read(LogicalDatastoreType.CONFIGURATION, PATH_2);
238         return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker);
239     }
240
241     @Override
242     RestconfStrategy readDataNonConfigTestStrategy() {
243         doReturn(read).when(mockDataBroker).newReadOnlyTransaction();
244         doReturn(immediateFluentFuture(Optional.of(DATA_2))).when(read)
245             .read(LogicalDatastoreType.OPERATIONAL, PATH_2);
246         return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker);
247     }
248
249     @Override
250     RestconfStrategy readContainerDataAllTestStrategy() {
251         doReturn(read).when(mockDataBroker).newReadOnlyTransaction();
252         doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(read)
253             .read(LogicalDatastoreType.CONFIGURATION, PATH);
254         doReturn(immediateFluentFuture(Optional.of(DATA_4))).when(read)
255             .read(LogicalDatastoreType.OPERATIONAL, PATH);
256         return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker);
257     }
258
259     @Override
260     RestconfStrategy readContainerDataConfigNoValueOfContentTestStrategy() {
261         doReturn(read).when(mockDataBroker).newReadOnlyTransaction();
262         doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(read)
263             .read(LogicalDatastoreType.CONFIGURATION, PATH);
264         doReturn(immediateFluentFuture(Optional.of(DATA_4))).when(read)
265             .read(LogicalDatastoreType.OPERATIONAL, PATH);
266         return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker);
267     }
268
269     @Override
270     RestconfStrategy readListDataAllTestStrategy() {
271         doReturn(read).when(mockDataBroker).newReadOnlyTransaction();
272         doReturn(immediateFluentFuture(Optional.of(LIST_DATA))).when(read)
273             .read(LogicalDatastoreType.OPERATIONAL, PATH_3);
274         doReturn(immediateFluentFuture(Optional.of(LIST_DATA_2))).when(read)
275             .read(LogicalDatastoreType.CONFIGURATION, PATH_3);
276         return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker);
277     }
278
279     @Override
280     RestconfStrategy readOrderedListDataAllTestStrategy() {
281         doReturn(read).when(mockDataBroker).newReadOnlyTransaction();
282         doReturn(immediateFluentFuture(Optional.of(ORDERED_MAP_NODE_1))).when(read)
283             .read(LogicalDatastoreType.OPERATIONAL, PATH_3);
284         doReturn(immediateFluentFuture(Optional.of(ORDERED_MAP_NODE_2))).when(read)
285             .read(LogicalDatastoreType.CONFIGURATION, PATH_3);
286         return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker);
287     }
288
289     @Override
290     RestconfStrategy readUnkeyedListDataAllTestStrategy() {
291         doReturn(read).when(mockDataBroker).newReadOnlyTransaction();
292         doReturn(immediateFluentFuture(Optional.of(UNKEYED_LIST_NODE_1))).when(read)
293             .read(LogicalDatastoreType.OPERATIONAL, PATH_3);
294         doReturn(immediateFluentFuture(Optional.of(UNKEYED_LIST_NODE_2))).when(read)
295             .read(LogicalDatastoreType.CONFIGURATION, PATH_3);
296         return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker);
297     }
298
299     @Override
300     RestconfStrategy readLeafListDataAllTestStrategy() {
301         doReturn(read).when(mockDataBroker).newReadOnlyTransaction();
302         doReturn(immediateFluentFuture(Optional.of(LEAF_SET_NODE_1))).when(read)
303             .read(LogicalDatastoreType.OPERATIONAL, LEAF_SET_NODE_PATH);
304         doReturn(immediateFluentFuture(Optional.of(LEAF_SET_NODE_2))).when(read)
305             .read(LogicalDatastoreType.CONFIGURATION, LEAF_SET_NODE_PATH);
306         return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker);
307     }
308
309     @Override
310     RestconfStrategy readOrderedLeafListDataAllTestStrategy() {
311         doReturn(read).when(mockDataBroker).newReadOnlyTransaction();
312         doReturn(immediateFluentFuture(Optional.of(ORDERED_LEAF_SET_NODE_1))).when(read)
313             .read(LogicalDatastoreType.OPERATIONAL, LEAF_SET_NODE_PATH);
314         doReturn(immediateFluentFuture(Optional.of(ORDERED_LEAF_SET_NODE_2))).when(read)
315             .read(LogicalDatastoreType.CONFIGURATION, LEAF_SET_NODE_PATH);
316         return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker);
317     }
318
319     @Override
320     RestconfStrategy readDataWrongPathOrNoContentTestStrategy() {
321         doReturn(read).when(mockDataBroker).newReadOnlyTransaction();
322         doReturn(immediateFluentFuture(Optional.empty())).when(read).read(LogicalDatastoreType.CONFIGURATION, PATH_2);
323         return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker);
324     }
325
326     @Test
327     public void readLeafWithDefaultParameters() {
328         final var data = Builders.containerBuilder()
329             .withNodeIdentifier(new NodeIdentifier(CONT_QNAME))
330             .withChild(ImmutableNodes.leafNode(QName.create(BASE, "exampleLeaf"), "i am leaf"))
331             .build();
332         final var path = YangInstanceIdentifier.of(CONT_QNAME);
333         doReturn(read).when(mockDataBroker).newReadOnlyTransaction();
334         doReturn(immediateFluentFuture(Optional.of(data))).when(read)
335                 .read(LogicalDatastoreType.CONFIGURATION, path);
336         doReturn(immediateFluentFuture(Optional.of(data))).when(read)
337                 .read(LogicalDatastoreType.OPERATIONAL, path);
338
339         assertEquals(data, new MdsalRestconfStrategy(MODULES_SCHEMA, mockDataBroker).readData(ContentParam.ALL, path,
340             WithDefaultsParam.TRIM));
341     }
342
343     @Test
344     public void readContainerWithDefaultParameters() {
345         final var exampleList = new NodeIdentifier(QName.create(BASE, "exampleList"));
346         final var data = Builders.containerBuilder()
347             .withNodeIdentifier(new NodeIdentifier(CONT_QNAME))
348             .withChild(Builders.unkeyedListBuilder()
349                 .withNodeIdentifier(exampleList)
350                 .withChild(Builders.unkeyedListEntryBuilder()
351                     .withNodeIdentifier(exampleList)
352                     .withChild(Builders.containerBuilder()
353                         .withNodeIdentifier(new NodeIdentifier(QName.create(BASE, "containerBool")))
354                         .withChild(ImmutableNodes.leafNode(QName.create(BASE, "leafBool"), true))
355                         .build())
356                     .addChild(Builders.containerBuilder()
357                         .withNodeIdentifier(new NodeIdentifier(QName.create(BASE, "containerInt")))
358                         .withChild(ImmutableNodes.leafNode(QName.create(BASE, "leafInt"), 12))
359                         .build())
360                     .build())
361                 .build())
362             .build();
363         final var path = YangInstanceIdentifier.of(CONT_QNAME);
364         doReturn(read).when(mockDataBroker).newReadOnlyTransaction();
365         doReturn(immediateFluentFuture(Optional.of(data))).when(read)
366                 .read(LogicalDatastoreType.CONFIGURATION, path);
367         doReturn(immediateFluentFuture(Optional.of(data))).when(read)
368                 .read(LogicalDatastoreType.OPERATIONAL, path);
369
370         assertEquals(data, new MdsalRestconfStrategy(MODULES_SCHEMA, mockDataBroker).readData(ContentParam.ALL, path,
371             WithDefaultsParam.TRIM));
372     }
373
374     @Test
375     public void readLeafInListWithDefaultParameters() {
376         final var exampleList = new NodeIdentifier(QName.create(BASE, "exampleList"));
377         final var content = Builders.containerBuilder()
378             .withNodeIdentifier(new NodeIdentifier(CONT_QNAME))
379             .withChild(Builders.unkeyedListBuilder()
380                 .withNodeIdentifier(exampleList)
381                 .withChild(Builders.unkeyedListEntryBuilder()
382                     .withNodeIdentifier(exampleList)
383                     .addChild(ImmutableNodes.leafNode(QName.create(BASE, "leafInList"), "I am leaf in list"))
384                     .build())
385                 .build())
386             .build();
387         final var path = YangInstanceIdentifier.of(CONT_QNAME);
388         doReturn(read).when(mockDataBroker).newReadOnlyTransaction();
389         doReturn(immediateFluentFuture(Optional.of(content))).when(read)
390                 .read(LogicalDatastoreType.CONFIGURATION, path);
391         doReturn(immediateFluentFuture(Optional.of(content))).when(read)
392                 .read(LogicalDatastoreType.OPERATIONAL, path);
393
394         assertEquals(content, new MdsalRestconfStrategy(MODULES_SCHEMA, mockDataBroker).readData(ContentParam.ALL, path,
395             WithDefaultsParam.TRIM));
396     }
397 }