2 * Copyright (c) 2023 PANTHEON.tech, s.r.o. 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.restconf.nb.rfc8040.rests.transactions;
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;
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;
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"));
53 private DOMDataTreeReadWriteTransaction readWrite;
55 private DOMDataBroker mockDataBroker;
57 private DOMDataTreeReadTransaction read;
59 private DOMRpcService rpcService;
61 private DatabindContext mockDatabind;
64 public void before() {
65 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
66 doReturn(readWrite).when(mockDataBroker).newReadWriteTransaction();
67 mockDatabind = DatabindContext.ofModel(mockSchemaContext);
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);
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);
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);
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);
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();
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);
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();
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);
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();
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);
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);
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);
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);
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);
175 RestconfStrategy testPatchDataReplaceMergeAndRemoveStrategy() {
176 return new MdsalRestconfStrategy(JUKEBOX_DATABIND, mockDataBroker, null, null);
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);
188 RestconfStrategy testPatchMergePutContainerStrategy() {
189 return new MdsalRestconfStrategy(JUKEBOX_DATABIND, mockDataBroker, null, null);
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);
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());
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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"))
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);
336 assertEquals(data, new MdsalRestconfStrategy(MODULES_DATABIND, mockDataBroker, null, null)
337 .readData(ContentParam.ALL, path, WithDefaultsParam.TRIM));
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))
353 .addChild(Builders.containerBuilder()
354 .withNodeIdentifier(new NodeIdentifier(QName.create(BASE, "containerInt")))
355 .withChild(ImmutableNodes.leafNode(QName.create(BASE, "leafInt"), 12))
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);
367 assertEquals(data, new MdsalRestconfStrategy(MODULES_DATABIND, mockDataBroker, null, null)
368 .readData(ContentParam.ALL, path, WithDefaultsParam.TRIM));
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"))
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);
391 assertEquals(content, new MdsalRestconfStrategy(MODULES_DATABIND, mockDataBroker, null, null)
392 .readData(ContentParam.ALL, path, WithDefaultsParam.TRIM));