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.junit.Assert.assertNotNull;
12 import static org.junit.Assert.assertNull;
13 import static org.mockito.ArgumentMatchers.any;
14 import static org.mockito.Mockito.doReturn;
15 import static org.mockito.Mockito.mock;
16 import static org.mockito.Mockito.verify;
17 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFailedFluentFuture;
18 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
20 import com.google.common.util.concurrent.Futures;
21 import java.util.Optional;
22 import org.junit.Before;
23 import org.junit.Test;
24 import org.junit.runner.RunWith;
25 import org.mockito.Mock;
26 import org.mockito.junit.MockitoJUnitRunner;
27 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
28 import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
29 import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
30 import org.opendaylight.netconf.api.NetconfDocumentedException;
31 import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
32 import org.opendaylight.restconf.common.patch.PatchStatusContext;
33 import org.opendaylight.restconf.common.patch.PatchStatusEntity;
34 import org.opendaylight.restconf.server.api.DatabindContext;
35 import org.opendaylight.yangtools.yang.common.ErrorSeverity;
36 import org.opendaylight.yangtools.yang.common.ErrorTag;
37 import org.opendaylight.yangtools.yang.common.ErrorType;
38 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
39 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
40 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
41 import org.w3c.dom.DOMException;
43 @RunWith(MockitoJUnitRunner.StrictStubs.class)
44 public final class NetconfRestconfStrategyTest extends AbstractRestconfStrategyTest {
46 private NetconfDataTreeService netconfService;
49 public void before() {
50 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).commit();
51 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).discardChanges();
52 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).unlock();
53 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).lock();
54 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
55 .delete(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.of());
56 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).merge(any(), any(),
61 RestconfStrategy newStrategy(final DatabindContext databind) {
62 return new NetconfRestconfStrategy(databind, netconfService, null, null, null, null);
66 RestconfStrategy testDeleteDataStrategy() {
67 return jukeboxStrategy();
71 RestconfStrategy testNegativeDeleteDataStrategy() {
72 doReturn(Futures.immediateFailedFuture(new TransactionCommitFailedException(
73 "Commit of transaction " + this + " failed", new NetconfDocumentedException("id",
74 ErrorType.RPC, ErrorTag.DATA_MISSING, ErrorSeverity.ERROR)))).when(netconfService).commit();
75 return jukeboxStrategy();
79 RestconfStrategy testPostContainerDataStrategy() {
80 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).commit();
81 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
82 .create(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX, Optional.empty());
83 return jukeboxStrategy();
87 RestconfStrategy testPostListDataStrategy(final MapEntryNode entryNode, final YangInstanceIdentifier node) {
88 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
90 .merge(any(), any(), any(), any());
91 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).commit();
92 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).create(
93 LogicalDatastoreType.CONFIGURATION, node, entryNode, Optional.empty());
94 return jukeboxStrategy();
98 RestconfStrategy testPostDataFailStrategy(final DOMException domException) {
99 doReturn(immediateFailedFluentFuture(domException)).when(netconfService)
100 // FIXME: exact match
101 .create(any(), any(), any(), any());
102 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).discardChanges();
103 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).unlock();
104 return jukeboxStrategy();
108 RestconfStrategy testPatchContainerDataStrategy() {
109 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).merge(any(), any(),any(),
111 return jukeboxStrategy();
115 RestconfStrategy testPatchLeafDataStrategy() {
116 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
117 .merge(any(), any(), any(), any());
118 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).commit();
119 return jukeboxStrategy();
123 RestconfStrategy testPatchListDataStrategy() {
124 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).commit();
125 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
126 .merge(any(), any(),any(),any());
127 return jukeboxStrategy();
131 public void testPutCreateContainerData() {
132 doReturn(immediateFluentFuture(Optional.empty())).when(netconfService).getConfig(JUKEBOX_IID);
133 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).commit();
134 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
135 .replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX, Optional.empty());
137 jukeboxStrategy().putData(JUKEBOX_IID, EMPTY_JUKEBOX, null);
138 verify(netconfService).lock();
139 verify(netconfService).getConfig(JUKEBOX_IID);
140 verify(netconfService).replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX,
145 public void testPutReplaceContainerData() {
146 doReturn(immediateFluentFuture(Optional.of(mock(ContainerNode.class)))).when(netconfService)
147 .getConfig(JUKEBOX_IID);
148 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).commit();
149 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
150 .replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX, Optional.empty());
152 jukeboxStrategy().putData(JUKEBOX_IID, EMPTY_JUKEBOX, null);
153 verify(netconfService).getConfig(JUKEBOX_IID);
154 verify(netconfService).replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX,
159 public void testPutCreateLeafData() {
160 doReturn(immediateFluentFuture(Optional.empty())).when(netconfService).getConfig(GAP_IID);
161 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).commit();
162 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
163 .replace(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF, Optional.empty());
165 jukeboxStrategy().putData(GAP_IID, GAP_LEAF, null);
166 verify(netconfService).getConfig(GAP_IID);
167 verify(netconfService).replace(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF, Optional.empty());
171 public void testPutReplaceLeafData() {
172 doReturn(immediateFluentFuture(Optional.of(mock(ContainerNode.class)))).when(netconfService)
174 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).commit();
175 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
176 .replace(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF, Optional.empty());
178 jukeboxStrategy().putData(GAP_IID, GAP_LEAF, null);
179 verify(netconfService).getConfig(GAP_IID);
180 verify(netconfService).replace(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF, Optional.empty());
184 public void testPutCreateListData() {
185 doReturn(immediateFluentFuture(Optional.empty())).when(netconfService).getConfig(JUKEBOX_IID);
186 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).commit();
187 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
188 .replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS, Optional.empty());
190 jukeboxStrategy().putData(JUKEBOX_IID, JUKEBOX_WITH_BANDS, null);
191 verify(netconfService).getConfig(JUKEBOX_IID);
192 verify(netconfService).replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS,
197 public void testPutReplaceListData() {
198 doReturn(immediateFluentFuture(Optional.of(mock(ContainerNode.class)))).when(netconfService)
199 .getConfig(JUKEBOX_IID);
200 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).commit();
201 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
202 .replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS, Optional.empty());
204 jukeboxStrategy().putData(JUKEBOX_IID, JUKEBOX_WITH_BANDS, null);
205 verify(netconfService).getConfig(JUKEBOX_IID);
206 verify(netconfService).replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS,
211 RestconfStrategy testPatchDataReplaceMergeAndRemoveStrategy() {
212 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
213 .remove(LogicalDatastoreType.CONFIGURATION, ARTIST_IID);
214 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
215 // FIXME: exact match
216 .replace(any(), any(), any(), any());
217 return jukeboxStrategy();
221 RestconfStrategy testPatchDataCreateAndDeleteStrategy() {
222 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
223 .create(LogicalDatastoreType.CONFIGURATION, PLAYER_IID, EMPTY_JUKEBOX, Optional.empty());
224 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
225 .delete(LogicalDatastoreType.CONFIGURATION, CREATE_AND_DELETE_TARGET);
226 return jukeboxStrategy();
230 RestconfStrategy testPatchMergePutContainerStrategy() {
231 return jukeboxStrategy();
235 RestconfStrategy deleteNonexistentDataTestStrategy() {
236 doReturn(Futures.immediateFailedFuture(
237 new TransactionCommitFailedException("Commit of transaction " + this + " failed",
238 new NetconfDocumentedException("id", ErrorType.RPC, ErrorTag.DATA_MISSING, ErrorSeverity.ERROR))))
239 .when(netconfService).commit();
240 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
241 .delete(LogicalDatastoreType.CONFIGURATION, CREATE_AND_DELETE_TARGET);
242 return jukeboxStrategy();
246 void assertTestDeleteNonexistentData(final PatchStatusContext status, final PatchStatusEntity edit) {
247 assertNull(edit.getEditErrors());
248 final var globalErrors = status.globalErrors();
249 assertNotNull(globalErrors);
250 assertEquals(1, globalErrors.size());
251 final var globalError = globalErrors.get(0);
252 assertEquals("Data does not exist", globalError.getErrorMessage());
253 assertEquals(ErrorType.PROTOCOL, globalError.getErrorType());
254 assertEquals(ErrorTag.DATA_MISSING, globalError.getErrorTag());
258 RestconfStrategy readDataConfigTestStrategy() {
259 doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(netconfService).getConfig(PATH);
260 return mockStrategy();
264 RestconfStrategy readAllHavingOnlyConfigTestStrategy() {
265 doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(netconfService).getConfig(PATH);
266 doReturn(immediateFluentFuture(Optional.empty())).when(netconfService).get(PATH);
267 return mockStrategy();
271 RestconfStrategy readAllHavingOnlyNonConfigTestStrategy() {
272 doReturn(immediateFluentFuture(Optional.of(DATA_2))).when(netconfService).get(PATH_2);
273 doReturn(immediateFluentFuture(Optional.empty())).when(netconfService).getConfig(PATH_2);
274 return mockStrategy();
278 RestconfStrategy readDataNonConfigTestStrategy() {
279 doReturn(immediateFluentFuture(Optional.of(DATA_2))).when(netconfService).get(PATH_2);
280 return mockStrategy();
284 RestconfStrategy readContainerDataAllTestStrategy() {
285 doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(netconfService).getConfig(PATH);
286 doReturn(immediateFluentFuture(Optional.of(DATA_4))).when(netconfService).get(PATH);
287 return mockStrategy();
291 RestconfStrategy readContainerDataConfigNoValueOfContentTestStrategy() {
292 doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(netconfService).getConfig(PATH);
293 doReturn(immediateFluentFuture(Optional.of(DATA_4))).when(netconfService).get(PATH);
294 return mockStrategy();
298 RestconfStrategy readListDataAllTestStrategy() {
299 doReturn(immediateFluentFuture(Optional.of(LIST_DATA))).when(netconfService).get(PATH_3);
300 doReturn(immediateFluentFuture(Optional.of(LIST_DATA_2))).when(netconfService).getConfig(PATH_3);
301 return mockStrategy();
305 RestconfStrategy readOrderedListDataAllTestStrategy() {
306 doReturn(immediateFluentFuture(Optional.of(ORDERED_MAP_NODE_1))).when(netconfService).get(PATH_3);
307 doReturn(immediateFluentFuture(Optional.of(ORDERED_MAP_NODE_2))).when(netconfService).getConfig(PATH_3);
308 return mockStrategy();
312 RestconfStrategy readUnkeyedListDataAllTestStrategy() {
313 doReturn(immediateFluentFuture(Optional.of(UNKEYED_LIST_NODE_1))).when(netconfService).get(PATH_3);
314 doReturn(immediateFluentFuture(Optional.of(UNKEYED_LIST_NODE_2))).when(netconfService).getConfig(PATH_3);
315 return mockStrategy();
319 RestconfStrategy readLeafListDataAllTestStrategy() {
320 doReturn(immediateFluentFuture(Optional.of(LEAF_SET_NODE_1))).when(netconfService)
321 .get(LEAF_SET_NODE_PATH);
322 doReturn(immediateFluentFuture(Optional.of(LEAF_SET_NODE_2))).when(netconfService)
323 .getConfig(LEAF_SET_NODE_PATH);
324 return mockStrategy();
328 RestconfStrategy readOrderedLeafListDataAllTestStrategy() {
329 doReturn(immediateFluentFuture(Optional.of(ORDERED_LEAF_SET_NODE_1))).when(netconfService)
330 .get(LEAF_SET_NODE_PATH);
331 doReturn(immediateFluentFuture(Optional.of(ORDERED_LEAF_SET_NODE_2))).when(netconfService)
332 .getConfig(LEAF_SET_NODE_PATH);
333 return mockStrategy();
337 RestconfStrategy readDataWrongPathOrNoContentTestStrategy() {
338 doReturn(immediateFluentFuture(Optional.empty())).when(netconfService).getConfig(PATH_2);
339 return mockStrategy();