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.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;
48 @RunWith(MockitoJUnitRunner.StrictStubs.class)
49 public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTest {
50 private static EffectiveModelContext MODULES_SCHEMA;
53 private DOMDataTreeReadWriteTransaction readWrite;
55 private DOMDataBroker mockDataBroker;
57 private DOMDataTreeReadTransaction read;
60 public static void setupModulesSchema() {
61 MODULES_SCHEMA = YangParserTestUtils.parseYangResourceDirectory("/modules");
65 public static void dropModulesSchema() {
66 MODULES_SCHEMA = null;
70 public void before() {
71 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
72 doReturn(readWrite).when(mockDataBroker).newReadWriteTransaction();
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);
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);
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);
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);
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();
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);
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();
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);
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();
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);
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);
157 RestconfStrategy testPatchContainerDataStrategy() {
158 doReturn(readWrite).when(mockDataBroker).newReadWriteTransaction();
159 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
160 return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker);
164 RestconfStrategy testPatchLeafDataStrategy() {
165 doReturn(readWrite).when(mockDataBroker).newReadWriteTransaction();
166 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
167 return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker);
171 RestconfStrategy testPatchListDataStrategy() {
172 doReturn(readWrite).when(mockDataBroker).newReadWriteTransaction();
173 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
174 return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker);
178 RestconfStrategy testPatchDataReplaceMergeAndRemoveStrategy() {
179 return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker);
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);
191 RestconfStrategy testPatchMergePutContainerStrategy() {
192 return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker);
196 RestconfStrategy deleteNonexistentDataTestStrategy() {
197 doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION,
198 CREATE_AND_DELETE_TARGET);
199 return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker);
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());
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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"))
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);
339 assertEquals(data, new MdsalRestconfStrategy(MODULES_SCHEMA, mockDataBroker).readData(ContentParam.ALL, path,
340 WithDefaultsParam.TRIM));
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))
356 .addChild(Builders.containerBuilder()
357 .withNodeIdentifier(new NodeIdentifier(QName.create(BASE, "containerInt")))
358 .withChild(ImmutableNodes.leafNode(QName.create(BASE, "leafInt"), 12))
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);
370 assertEquals(data, new MdsalRestconfStrategy(MODULES_SCHEMA, mockDataBroker).readData(ContentParam.ALL, path,
371 WithDefaultsParam.TRIM));
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"))
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);
394 assertEquals(content, new MdsalRestconfStrategy(MODULES_SCHEMA, mockDataBroker).readData(ContentParam.ALL, path,
395 WithDefaultsParam.TRIM));