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