Refactor ServerRequest
[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.jupiter.api.Assertions.assertEquals;
11 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
12 import static org.junit.jupiter.api.Assertions.assertNotNull;
13 import static org.junit.jupiter.api.Assertions.assertNotSame;
14 import static org.junit.jupiter.api.Assertions.assertNull;
15 import static org.junit.jupiter.api.Assertions.assertThrows;
16 import static org.mockito.ArgumentMatchers.any;
17 import static org.mockito.Mockito.doNothing;
18 import static org.mockito.Mockito.doReturn;
19 import static org.mockito.Mockito.verify;
20 import static org.mockito.Mockito.when;
21 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFailedFluentFuture;
22 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFalseFluentFuture;
23 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
24 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateTrueFluentFuture;
25
26 import com.google.common.collect.ImmutableMap;
27 import java.util.Optional;
28 import org.eclipse.jdt.annotation.NonNull;
29 import org.junit.jupiter.api.Test;
30 import org.junit.jupiter.api.extension.ExtendWith;
31 import org.mockito.Mock;
32 import org.mockito.junit.jupiter.MockitoExtension;
33 import org.opendaylight.mdsal.common.api.CommitInfo;
34 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
35 import org.opendaylight.mdsal.dom.api.DOMActionService;
36 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
37 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
38 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
39 import org.opendaylight.mdsal.dom.api.DOMMountPoint;
40 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
41 import org.opendaylight.mdsal.dom.api.DOMRpcService;
42 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
43 import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
44 import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
45 import org.opendaylight.restconf.api.ApiPath;
46 import org.opendaylight.restconf.api.ErrorMessage;
47 import org.opendaylight.restconf.api.query.ContentParam;
48 import org.opendaylight.restconf.api.query.WithDefaultsParam;
49 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy.StrategyAndTail;
50 import org.opendaylight.restconf.server.api.DataPutResult;
51 import org.opendaylight.restconf.server.api.DatabindContext;
52 import org.opendaylight.restconf.server.api.PatchStatusContext;
53 import org.opendaylight.restconf.server.api.PatchStatusEntity;
54 import org.opendaylight.restconf.server.api.ServerException;
55 import org.opendaylight.yangtools.yang.common.ErrorTag;
56 import org.opendaylight.yangtools.yang.common.ErrorType;
57 import org.opendaylight.yangtools.yang.common.QName;
58 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
59 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
60 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
61 import org.opendaylight.yangtools.yang.data.spi.node.ImmutableNodes;
62 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
63 import org.w3c.dom.DOMException;
64
65 @ExtendWith(MockitoExtension.class)
66 final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTest {
67     private static final DatabindContext MODULES_DATABIND = DatabindContext.ofModel(
68         YangParserTestUtils.parseYangResourceDirectory("/modules"));
69
70     @Mock
71     private DOMDataTreeReadWriteTransaction readWrite;
72     @Mock
73     private DOMDataBroker dataBroker;
74     @Mock
75     private DOMDataTreeReadTransaction read;
76     @Mock
77     private DOMRpcService rpcService;
78     @Mock
79     private DOMSchemaService schemaService;
80     @Mock
81     private DOMMountPointService mountPointService;
82     @Mock
83     private DOMMountPoint mountPoint;
84     @Mock
85     private NetconfDataTreeService netconfService;
86
87     @Override
88     RestconfStrategy newStrategy(final DatabindContext databind) {
89         return new MdsalRestconfStrategy(databind, dataBroker, ImmutableMap.of(), rpcService, null, null,
90             mountPointService);
91     }
92
93     private @NonNull RestconfStrategy modulesStrategy() {
94         return newStrategy(MODULES_DATABIND);
95     }
96
97     @Override
98     RestconfStrategy testDeleteDataStrategy() {
99         // assert that data to delete exists
100         doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
101         doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
102         when(readWrite.exists(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.of()))
103             .thenReturn(immediateTrueFluentFuture());
104         return jukeboxStrategy();
105     }
106
107     @Override
108     RestconfStrategy testNegativeDeleteDataStrategy() {
109         // assert that data to delete does NOT exist
110         doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
111         when(readWrite.exists(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.of()))
112             .thenReturn(immediateFalseFluentFuture());
113         return jukeboxStrategy();
114     }
115
116     @Override
117     RestconfStrategy testPostListDataStrategy(final MapEntryNode entryNode, final YangInstanceIdentifier node) {
118         doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
119         doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, node);
120         doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, node, entryNode);
121         doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
122         return jukeboxStrategy();
123     }
124
125     @Override
126     RestconfStrategy testPostDataFailStrategy(final DOMException domException) {
127         doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
128         doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
129         doReturn(immediateFailedFluentFuture(domException)).when(readWrite).commit();
130         doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX);
131         return jukeboxStrategy();
132     }
133
134     @Test
135     void testPutContainerData() {
136         doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
137         doReturn(read).when(dataBroker).newReadOnlyTransaction();
138         doReturn(immediateFalseFluentFuture()).when(read).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
139         doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX);
140         doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
141
142         jukeboxStrategy().putData(dataPutRequest, JUKEBOX_IID, EMPTY_JUKEBOX, null);
143         verify(read).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
144         verify(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX);
145         verify(dataPutRequest).completeWith(any(DataPutResult.class));
146     }
147
148     @Test
149     void testPutLeafData() {
150         doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
151         doReturn(read).when(dataBroker).newReadOnlyTransaction();
152         doReturn(immediateFalseFluentFuture()).when(read).exists(LogicalDatastoreType.CONFIGURATION, GAP_IID);
153         doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF);
154         doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
155
156         jukeboxStrategy().putData(dataPutRequest, GAP_IID, GAP_LEAF, null);
157         verify(read).exists(LogicalDatastoreType.CONFIGURATION, GAP_IID);
158         verify(readWrite).put(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF);
159         verify(dataPutRequest).completeWith(any(DataPutResult.class));
160     }
161
162     @Test
163     void testPutListData() {
164         doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
165         doReturn(read).when(dataBroker).newReadOnlyTransaction();
166         doReturn(immediateFalseFluentFuture())
167                 .when(read).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
168         doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS);
169         doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
170
171         jukeboxStrategy().putData(dataPutRequest, JUKEBOX_IID, JUKEBOX_WITH_BANDS, null);
172         verify(read).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
173         verify(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS);
174         verify(dataPutRequest).completeWith(any(DataPutResult.class));
175     }
176
177     @Override
178     RestconfStrategy testPostContainerDataStrategy() {
179         doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
180         doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
181         doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX);
182         doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
183         return jukeboxStrategy();
184     }
185
186     @Override
187     RestconfStrategy testPatchContainerDataStrategy() {
188         doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
189         doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
190         return jukeboxStrategy();
191     }
192
193     @Override
194     RestconfStrategy testPatchLeafDataStrategy() {
195         doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
196         doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
197         return jukeboxStrategy();
198     }
199
200     @Override
201     RestconfStrategy testPatchListDataStrategy() {
202         doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
203         doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
204         return jukeboxStrategy();
205     }
206
207     @Override
208     RestconfStrategy testPatchDataReplaceMergeAndRemoveStrategy() {
209         doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
210         doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
211         return jukeboxStrategy();
212     }
213
214     @Override
215     RestconfStrategy testPatchDataCreateAndDeleteStrategy() {
216         doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
217         doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
218         doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, PLAYER_IID);
219         doReturn(immediateTrueFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION,
220             CREATE_AND_DELETE_TARGET);
221         return jukeboxStrategy();
222     }
223
224     @Override
225     RestconfStrategy testPatchMergePutContainerStrategy() {
226         doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
227         doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
228         return jukeboxStrategy();
229     }
230
231     @Override
232     RestconfStrategy deleteNonexistentDataTestStrategy() {
233         doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
234         doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION,
235             CREATE_AND_DELETE_TARGET);
236         return jukeboxStrategy();
237     }
238
239     @Override
240     void assertTestDeleteNonexistentData(final PatchStatusContext status, final PatchStatusEntity edit) {
241         assertNull(status.globalErrors());
242         final var editErrors = edit.getEditErrors();
243         assertEquals(1, editErrors.size());
244         final var editError = editErrors.get(0);
245         assertEquals(new ErrorMessage("Data does not exist"), editError.message());
246         assertEquals(ErrorType.PROTOCOL, editError.type());
247         assertEquals(ErrorTag.DATA_MISSING, editError.tag());
248     }
249
250     @Override
251     RestconfStrategy readDataConfigTestStrategy() {
252         doReturn(read).when(dataBroker).newReadOnlyTransaction();
253         doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(read)
254             .read(LogicalDatastoreType.CONFIGURATION, PATH);
255         return mockStrategy();
256     }
257
258     @Override
259     RestconfStrategy readAllHavingOnlyConfigTestStrategy() {
260         doReturn(read).when(dataBroker).newReadOnlyTransaction();
261         doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(read)
262             .read(LogicalDatastoreType.CONFIGURATION, PATH);
263         doReturn(immediateFluentFuture(Optional.empty())).when(read)
264             .read(LogicalDatastoreType.OPERATIONAL, PATH);
265         return mockStrategy();
266     }
267
268     @Override
269     RestconfStrategy readAllHavingOnlyNonConfigTestStrategy() {
270         doReturn(read).when(dataBroker).newReadOnlyTransaction();
271         doReturn(immediateFluentFuture(Optional.of(DATA_2))).when(read)
272             .read(LogicalDatastoreType.OPERATIONAL, PATH_2);
273         doReturn(immediateFluentFuture(Optional.empty())).when(read)
274             .read(LogicalDatastoreType.CONFIGURATION, PATH_2);
275         return mockStrategy();
276     }
277
278     @Override
279     RestconfStrategy readDataNonConfigTestStrategy() {
280         doReturn(read).when(dataBroker).newReadOnlyTransaction();
281         doReturn(immediateFluentFuture(Optional.of(DATA_2))).when(read)
282             .read(LogicalDatastoreType.OPERATIONAL, PATH_2);
283         return mockStrategy();
284     }
285
286     @Override
287     RestconfStrategy readContainerDataAllTestStrategy() {
288         doReturn(read).when(dataBroker).newReadOnlyTransaction();
289         doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(read)
290             .read(LogicalDatastoreType.CONFIGURATION, PATH);
291         doReturn(immediateFluentFuture(Optional.of(DATA_4))).when(read)
292             .read(LogicalDatastoreType.OPERATIONAL, PATH);
293         return mockStrategy();
294     }
295
296     @Override
297     RestconfStrategy readContainerDataConfigNoValueOfContentTestStrategy() {
298         doReturn(read).when(dataBroker).newReadOnlyTransaction();
299         doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(read)
300             .read(LogicalDatastoreType.CONFIGURATION, PATH);
301         doReturn(immediateFluentFuture(Optional.of(DATA_4))).when(read)
302             .read(LogicalDatastoreType.OPERATIONAL, PATH);
303         return mockStrategy();
304     }
305
306     @Override
307     RestconfStrategy readListDataAllTestStrategy() {
308         doReturn(read).when(dataBroker).newReadOnlyTransaction();
309         doReturn(immediateFluentFuture(Optional.of(LIST_DATA))).when(read)
310             .read(LogicalDatastoreType.OPERATIONAL, PATH_3);
311         doReturn(immediateFluentFuture(Optional.of(LIST_DATA_2))).when(read)
312             .read(LogicalDatastoreType.CONFIGURATION, PATH_3);
313         return mockStrategy();
314     }
315
316     @Override
317     RestconfStrategy readOrderedListDataAllTestStrategy() {
318         doReturn(read).when(dataBroker).newReadOnlyTransaction();
319         doReturn(immediateFluentFuture(Optional.of(ORDERED_MAP_NODE_1))).when(read)
320             .read(LogicalDatastoreType.OPERATIONAL, PATH_3);
321         doReturn(immediateFluentFuture(Optional.of(ORDERED_MAP_NODE_2))).when(read)
322             .read(LogicalDatastoreType.CONFIGURATION, PATH_3);
323         return mockStrategy();
324     }
325
326     @Override
327     RestconfStrategy readUnkeyedListDataAllTestStrategy() {
328         doReturn(read).when(dataBroker).newReadOnlyTransaction();
329         doReturn(immediateFluentFuture(Optional.of(UNKEYED_LIST_NODE_1))).when(read)
330             .read(LogicalDatastoreType.OPERATIONAL, PATH_3);
331         doReturn(immediateFluentFuture(Optional.of(UNKEYED_LIST_NODE_2))).when(read)
332             .read(LogicalDatastoreType.CONFIGURATION, PATH_3);
333         return mockStrategy();
334     }
335
336     @Override
337     RestconfStrategy readLeafListDataAllTestStrategy() {
338         doReturn(read).when(dataBroker).newReadOnlyTransaction();
339         doReturn(immediateFluentFuture(Optional.of(LEAF_SET_NODE_1))).when(read)
340             .read(LogicalDatastoreType.OPERATIONAL, LEAF_SET_NODE_PATH);
341         doReturn(immediateFluentFuture(Optional.of(LEAF_SET_NODE_2))).when(read)
342             .read(LogicalDatastoreType.CONFIGURATION, LEAF_SET_NODE_PATH);
343         return mockStrategy();
344     }
345
346     @Override
347     RestconfStrategy readOrderedLeafListDataAllTestStrategy() {
348         doReturn(read).when(dataBroker).newReadOnlyTransaction();
349         doReturn(immediateFluentFuture(Optional.of(ORDERED_LEAF_SET_NODE_1))).when(read)
350             .read(LogicalDatastoreType.OPERATIONAL, LEAF_SET_NODE_PATH);
351         doReturn(immediateFluentFuture(Optional.of(ORDERED_LEAF_SET_NODE_2))).when(read)
352             .read(LogicalDatastoreType.CONFIGURATION, LEAF_SET_NODE_PATH);
353         return mockStrategy();
354     }
355
356     @Override
357     RestconfStrategy readDataWrongPathOrNoContentTestStrategy() {
358         doReturn(read).when(dataBroker).newReadOnlyTransaction();
359         doReturn(immediateFluentFuture(Optional.empty())).when(read).read(LogicalDatastoreType.CONFIGURATION, PATH_2);
360         return mockStrategy();
361     }
362
363     @Test
364     void readLeafWithDefaultParameters() {
365         final var data = ImmutableNodes.newContainerBuilder()
366             .withNodeIdentifier(new NodeIdentifier(CONT_QNAME))
367             .withChild(ImmutableNodes.leafNode(QName.create(BASE, "exampleLeaf"), "i am leaf"))
368             .build();
369         final var path = YangInstanceIdentifier.of(CONT_QNAME);
370         doReturn(read).when(dataBroker).newReadOnlyTransaction();
371         doReturn(immediateFluentFuture(Optional.of(data))).when(read)
372                 .read(LogicalDatastoreType.CONFIGURATION, path);
373         doReturn(immediateFluentFuture(Optional.of(data))).when(read)
374                 .read(LogicalDatastoreType.OPERATIONAL, path);
375
376         assertEquals(data, modulesStrategy().readData(ContentParam.ALL, path, WithDefaultsParam.TRIM));
377     }
378
379     @Test
380     void readContainerWithDefaultParameters() {
381         final var exampleList = new NodeIdentifier(QName.create(BASE, "exampleList"));
382         final var data = ImmutableNodes.newContainerBuilder()
383             .withNodeIdentifier(new NodeIdentifier(CONT_QNAME))
384             .withChild(ImmutableNodes.newUnkeyedListBuilder()
385                 .withNodeIdentifier(exampleList)
386                 .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
387                     .withNodeIdentifier(exampleList)
388                     .withChild(ImmutableNodes.newContainerBuilder()
389                         .withNodeIdentifier(new NodeIdentifier(QName.create(BASE, "containerBool")))
390                         .withChild(ImmutableNodes.leafNode(QName.create(BASE, "leafBool"), true))
391                         .build())
392                     .addChild(ImmutableNodes.newContainerBuilder()
393                         .withNodeIdentifier(new NodeIdentifier(QName.create(BASE, "containerInt")))
394                         .withChild(ImmutableNodes.leafNode(QName.create(BASE, "leafInt"), 12))
395                         .build())
396                     .build())
397                 .build())
398             .build();
399         final var path = YangInstanceIdentifier.of(CONT_QNAME);
400         doReturn(read).when(dataBroker).newReadOnlyTransaction();
401         doReturn(immediateFluentFuture(Optional.of(data))).when(read)
402                 .read(LogicalDatastoreType.CONFIGURATION, path);
403         doReturn(immediateFluentFuture(Optional.of(data))).when(read)
404                 .read(LogicalDatastoreType.OPERATIONAL, path);
405
406         assertEquals(data, modulesStrategy().readData(ContentParam.ALL, path, WithDefaultsParam.TRIM));
407     }
408
409     @Test
410     void readLeafInListWithDefaultParameters() {
411         final var exampleList = new NodeIdentifier(QName.create(BASE, "exampleList"));
412         final var content = ImmutableNodes.newContainerBuilder()
413             .withNodeIdentifier(new NodeIdentifier(CONT_QNAME))
414             .withChild(ImmutableNodes.newUnkeyedListBuilder()
415                 .withNodeIdentifier(exampleList)
416                 .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
417                     .withNodeIdentifier(exampleList)
418                     .addChild(ImmutableNodes.leafNode(QName.create(BASE, "leafInList"), "I am leaf in list"))
419                     .build())
420                 .build())
421             .build();
422         final var path = YangInstanceIdentifier.of(CONT_QNAME);
423         doReturn(read).when(dataBroker).newReadOnlyTransaction();
424         doReturn(immediateFluentFuture(Optional.of(content))).when(read)
425                 .read(LogicalDatastoreType.CONFIGURATION, path);
426         doReturn(immediateFluentFuture(Optional.of(content))).when(read)
427                 .read(LogicalDatastoreType.OPERATIONAL, path);
428
429         assertEquals(content, modulesStrategy().readData(ContentParam.ALL, path, WithDefaultsParam.TRIM));
430     }
431
432     @Test
433     void testGetRestconfStrategyLocal() throws Exception {
434         final var strategy = jukeboxStrategy();
435         assertEquals(new StrategyAndTail(strategy, ApiPath.empty()), strategy.resolveStrategy(ApiPath.empty()));
436     }
437
438     @Test
439     void testGetRestconfStrategyMountDataBroker() throws Exception {
440         doReturn(Optional.empty()).when(mountPoint).getService(NetconfDataTreeService.class);
441         doReturn(Optional.of(dataBroker)).when(mountPoint).getService(DOMDataBroker.class);
442         doReturn(Optional.of(rpcService)).when(mountPoint).getService(DOMRpcService.class);
443         doReturn(Optional.of(new FixedDOMSchemaService(JUKEBOX_SCHEMA))).when(mountPoint)
444             .getService(DOMSchemaService.class);
445         doReturn(Optional.empty()).when(mountPoint).getService(DOMMountPointService.class);
446         doReturn(Optional.empty()).when(mountPoint).getService(DOMActionService.class);
447         doReturn(Optional.of(mountPoint)).when(mountPointService).getMountPoint(YangInstanceIdentifier.of());
448
449         final var strategy = jukeboxStrategy();
450         final var result = strategy.resolveStrategy(ApiPath.parse("yang-ext:mount"));
451         assertEquals(ApiPath.empty(), result.tail());
452         assertNotSame(strategy, assertInstanceOf(MdsalRestconfStrategy.class, result.strategy()));
453     }
454
455     @Test
456     void testGetRestconfStrategyMountNetconfService() throws Exception {
457         doReturn(Optional.of(netconfService)).when(mountPoint).getService(NetconfDataTreeService.class);
458         doReturn(Optional.of(rpcService)).when(mountPoint).getService(DOMRpcService.class);
459         doReturn(Optional.of(new FixedDOMSchemaService(JUKEBOX_SCHEMA))).when(mountPoint)
460             .getService(DOMSchemaService.class);
461         doReturn(Optional.empty()).when(mountPoint).getService(DOMMountPointService.class);
462         doReturn(Optional.empty()).when(mountPoint).getService(DOMActionService.class);
463         doReturn(Optional.of(mountPoint)).when(mountPointService).getMountPoint(YangInstanceIdentifier.of());
464
465         final var strategy = jukeboxStrategy();
466         final var result = strategy.resolveStrategy(ApiPath.parse("yang-ext:mount"));
467         assertEquals(ApiPath.empty(), result.tail());
468         assertInstanceOf(NetconfRestconfStrategy.class, result.strategy());
469     }
470
471     @Test
472     void testGetRestconfStrategyMountNone() throws Exception {
473         doReturn(JUKEBOX_IID).when(mountPoint).getIdentifier();
474         doReturn(Optional.empty()).when(mountPoint).getService(NetconfDataTreeService.class);
475         doReturn(Optional.empty()).when(mountPoint).getService(DOMDataBroker.class);
476         doReturn(Optional.empty()).when(mountPoint).getService(DOMMountPointService.class);
477         doReturn(Optional.empty()).when(mountPoint).getService(DOMActionService.class);
478         doReturn(Optional.of(rpcService)).when(mountPoint).getService(DOMRpcService.class);
479         doReturn(Optional.of(new FixedDOMSchemaService(JUKEBOX_SCHEMA))).when(mountPoint)
480             .getService(DOMSchemaService.class);
481         doReturn(Optional.of(mountPoint)).when(mountPointService).getMountPoint(YangInstanceIdentifier.of());
482
483         final var strategy = jukeboxStrategy();
484         final var mountPath = ApiPath.parse("yang-ext:mount");
485
486         final var errors = assertThrows(ServerException.class, () -> strategy.resolveStrategy(mountPath)).errors();
487         assertEquals(1, errors.size());
488         final var error = errors.get(0);
489         assertEquals(ErrorType.APPLICATION, error.type());
490         assertEquals(ErrorTag.OPERATION_FAILED, error.tag());
491         assertEquals(new ErrorMessage("Could not find a supported access interface in mount point"), error.message());
492         final var path = error.path();
493         assertNotNull(path);
494         assertEquals(JUKEBOX_IID, path.path());
495     }
496 }