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.jupiter.api.Assertions.assertEquals;
11 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
12 import static org.junit.jupiter.api.Assertions.assertNotSame;
13 import static org.junit.jupiter.api.Assertions.assertNull;
14 import static org.junit.jupiter.api.Assertions.assertThrows;
15 import static org.mockito.Mockito.doNothing;
16 import static org.mockito.Mockito.doReturn;
17 import static org.mockito.Mockito.verify;
18 import static org.mockito.Mockito.when;
19 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFailedFluentFuture;
20 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFalseFluentFuture;
21 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
22 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateTrueFluentFuture;
24 import java.util.Optional;
25 import org.eclipse.jdt.annotation.NonNull;
26 import org.junit.Before;
27 import org.junit.Test;
28 import org.junit.runner.RunWith;
29 import org.mockito.Mock;
30 import org.mockito.junit.MockitoJUnitRunner;
31 import org.opendaylight.mdsal.common.api.CommitInfo;
32 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
33 import org.opendaylight.mdsal.dom.api.DOMActionService;
34 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
35 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
36 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
37 import org.opendaylight.mdsal.dom.api.DOMMountPoint;
38 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
39 import org.opendaylight.mdsal.dom.api.DOMRpcService;
40 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
41 import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
42 import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
43 import org.opendaylight.restconf.api.ApiPath;
44 import org.opendaylight.restconf.api.query.ContentParam;
45 import org.opendaylight.restconf.api.query.WithDefaultsParam;
46 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
47 import org.opendaylight.restconf.common.patch.PatchStatusContext;
48 import org.opendaylight.restconf.common.patch.PatchStatusEntity;
49 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy.StrategyAndTail;
50 import org.opendaylight.restconf.server.api.DatabindContext;
51 import org.opendaylight.yangtools.yang.common.ErrorTag;
52 import org.opendaylight.yangtools.yang.common.ErrorType;
53 import org.opendaylight.yangtools.yang.common.QName;
54 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
55 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
56 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
57 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
58 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
59 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
60 import org.w3c.dom.DOMException;
62 @RunWith(MockitoJUnitRunner.StrictStubs.class)
63 public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTest {
64 private static final DatabindContext MODULES_DATABIND = DatabindContext.ofModel(
65 YangParserTestUtils.parseYangResourceDirectory("/modules"));
68 private DOMDataTreeReadWriteTransaction readWrite;
70 private DOMDataBroker dataBroker;
72 private DOMDataTreeReadTransaction read;
74 private DOMRpcService rpcService;
76 private DOMSchemaService schemaService;
78 private DOMMountPointService mountPointService;
80 private DOMMountPoint mountPoint;
82 private NetconfDataTreeService netconfService;
85 public void before() {
86 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
87 doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
91 RestconfStrategy newStrategy(final DatabindContext databind) {
92 return new MdsalRestconfStrategy(databind, dataBroker, rpcService, null, null, mountPointService);
95 private @NonNull RestconfStrategy modulesStrategy() {
96 return newStrategy(MODULES_DATABIND);
100 RestconfStrategy testDeleteDataStrategy() {
101 // assert that data to delete exists
102 when(readWrite.exists(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.of()))
103 .thenReturn(immediateTrueFluentFuture());
104 return jukeboxStrategy();
108 RestconfStrategy testNegativeDeleteDataStrategy() {
109 // assert that data to delete does NOT exist
110 when(readWrite.exists(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.of()))
111 .thenReturn(immediateFalseFluentFuture());
112 return jukeboxStrategy();
116 RestconfStrategy testPostListDataStrategy(final MapEntryNode entryNode, final YangInstanceIdentifier node) {
117 doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, node);
118 doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, node, entryNode);
119 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
120 return jukeboxStrategy();
124 RestconfStrategy testPostDataFailStrategy(final DOMException domException) {
125 doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
126 doReturn(immediateFailedFluentFuture(domException)).when(readWrite).commit();
127 doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX);
128 return jukeboxStrategy();
132 public void testPutContainerData() {
133 doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
134 doReturn(read).when(dataBroker).newReadOnlyTransaction();
135 doReturn(immediateFalseFluentFuture()).when(read).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
136 doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX);
137 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
139 jukeboxStrategy().putData(JUKEBOX_IID, EMPTY_JUKEBOX, null);
140 verify(read).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
141 verify(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX);
145 public void testPutLeafData() {
146 doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
147 doReturn(read).when(dataBroker).newReadOnlyTransaction();
148 doReturn(immediateFalseFluentFuture()).when(read).exists(LogicalDatastoreType.CONFIGURATION, GAP_IID);
149 doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF);
150 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
152 jukeboxStrategy().putData(GAP_IID, GAP_LEAF, null);
153 verify(read).exists(LogicalDatastoreType.CONFIGURATION, GAP_IID);
154 verify(readWrite).put(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF);
159 public void testPutListData() {
160 doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
161 doReturn(read).when(dataBroker).newReadOnlyTransaction();
162 doReturn(immediateFalseFluentFuture())
163 .when(read).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
164 doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS);
165 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
167 jukeboxStrategy().putData(JUKEBOX_IID, JUKEBOX_WITH_BANDS, null);
168 verify(read).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
169 verify(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS);
173 RestconfStrategy testPostContainerDataStrategy() {
174 doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
175 doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX);
176 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
177 return jukeboxStrategy();
181 RestconfStrategy testPatchContainerDataStrategy() {
182 doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
183 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
184 return jukeboxStrategy();
188 RestconfStrategy testPatchLeafDataStrategy() {
189 doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
190 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
191 return jukeboxStrategy();
195 RestconfStrategy testPatchListDataStrategy() {
196 doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
197 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
198 return jukeboxStrategy();
202 RestconfStrategy testPatchDataReplaceMergeAndRemoveStrategy() {
203 return jukeboxStrategy();
207 RestconfStrategy testPatchDataCreateAndDeleteStrategy() {
208 doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, PLAYER_IID);
209 doReturn(immediateTrueFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION,
210 CREATE_AND_DELETE_TARGET);
211 return jukeboxStrategy();
215 RestconfStrategy testPatchMergePutContainerStrategy() {
216 return jukeboxStrategy();
220 RestconfStrategy deleteNonexistentDataTestStrategy() {
221 doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION,
222 CREATE_AND_DELETE_TARGET);
223 return jukeboxStrategy();
227 void assertTestDeleteNonexistentData(final PatchStatusContext status, final PatchStatusEntity edit) {
228 assertNull(status.globalErrors());
229 final var editErrors = edit.getEditErrors();
230 assertEquals(1, editErrors.size());
231 final var editError = editErrors.get(0);
232 assertEquals("Data does not exist", editError.getErrorMessage());
233 assertEquals(ErrorType.PROTOCOL, editError.getErrorType());
234 assertEquals(ErrorTag.DATA_MISSING, editError.getErrorTag());
238 RestconfStrategy readDataConfigTestStrategy() {
239 doReturn(read).when(dataBroker).newReadOnlyTransaction();
240 doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(read)
241 .read(LogicalDatastoreType.CONFIGURATION, PATH);
242 return mockStrategy();
246 RestconfStrategy readAllHavingOnlyConfigTestStrategy() {
247 doReturn(read).when(dataBroker).newReadOnlyTransaction();
248 doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(read)
249 .read(LogicalDatastoreType.CONFIGURATION, PATH);
250 doReturn(immediateFluentFuture(Optional.empty())).when(read)
251 .read(LogicalDatastoreType.OPERATIONAL, PATH);
252 return mockStrategy();
256 RestconfStrategy readAllHavingOnlyNonConfigTestStrategy() {
257 doReturn(read).when(dataBroker).newReadOnlyTransaction();
258 doReturn(immediateFluentFuture(Optional.of(DATA_2))).when(read)
259 .read(LogicalDatastoreType.OPERATIONAL, PATH_2);
260 doReturn(immediateFluentFuture(Optional.empty())).when(read)
261 .read(LogicalDatastoreType.CONFIGURATION, PATH_2);
262 return mockStrategy();
266 RestconfStrategy readDataNonConfigTestStrategy() {
267 doReturn(read).when(dataBroker).newReadOnlyTransaction();
268 doReturn(immediateFluentFuture(Optional.of(DATA_2))).when(read)
269 .read(LogicalDatastoreType.OPERATIONAL, PATH_2);
270 return mockStrategy();
274 RestconfStrategy readContainerDataAllTestStrategy() {
275 doReturn(read).when(dataBroker).newReadOnlyTransaction();
276 doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(read)
277 .read(LogicalDatastoreType.CONFIGURATION, PATH);
278 doReturn(immediateFluentFuture(Optional.of(DATA_4))).when(read)
279 .read(LogicalDatastoreType.OPERATIONAL, PATH);
280 return mockStrategy();
284 RestconfStrategy readContainerDataConfigNoValueOfContentTestStrategy() {
285 doReturn(read).when(dataBroker).newReadOnlyTransaction();
286 doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(read)
287 .read(LogicalDatastoreType.CONFIGURATION, PATH);
288 doReturn(immediateFluentFuture(Optional.of(DATA_4))).when(read)
289 .read(LogicalDatastoreType.OPERATIONAL, PATH);
290 return mockStrategy();
294 RestconfStrategy readListDataAllTestStrategy() {
295 doReturn(read).when(dataBroker).newReadOnlyTransaction();
296 doReturn(immediateFluentFuture(Optional.of(LIST_DATA))).when(read)
297 .read(LogicalDatastoreType.OPERATIONAL, PATH_3);
298 doReturn(immediateFluentFuture(Optional.of(LIST_DATA_2))).when(read)
299 .read(LogicalDatastoreType.CONFIGURATION, PATH_3);
300 return mockStrategy();
304 RestconfStrategy readOrderedListDataAllTestStrategy() {
305 doReturn(read).when(dataBroker).newReadOnlyTransaction();
306 doReturn(immediateFluentFuture(Optional.of(ORDERED_MAP_NODE_1))).when(read)
307 .read(LogicalDatastoreType.OPERATIONAL, PATH_3);
308 doReturn(immediateFluentFuture(Optional.of(ORDERED_MAP_NODE_2))).when(read)
309 .read(LogicalDatastoreType.CONFIGURATION, PATH_3);
310 return mockStrategy();
314 RestconfStrategy readUnkeyedListDataAllTestStrategy() {
315 doReturn(read).when(dataBroker).newReadOnlyTransaction();
316 doReturn(immediateFluentFuture(Optional.of(UNKEYED_LIST_NODE_1))).when(read)
317 .read(LogicalDatastoreType.OPERATIONAL, PATH_3);
318 doReturn(immediateFluentFuture(Optional.of(UNKEYED_LIST_NODE_2))).when(read)
319 .read(LogicalDatastoreType.CONFIGURATION, PATH_3);
320 return mockStrategy();
324 RestconfStrategy readLeafListDataAllTestStrategy() {
325 doReturn(read).when(dataBroker).newReadOnlyTransaction();
326 doReturn(immediateFluentFuture(Optional.of(LEAF_SET_NODE_1))).when(read)
327 .read(LogicalDatastoreType.OPERATIONAL, LEAF_SET_NODE_PATH);
328 doReturn(immediateFluentFuture(Optional.of(LEAF_SET_NODE_2))).when(read)
329 .read(LogicalDatastoreType.CONFIGURATION, LEAF_SET_NODE_PATH);
330 return mockStrategy();
334 RestconfStrategy readOrderedLeafListDataAllTestStrategy() {
335 doReturn(read).when(dataBroker).newReadOnlyTransaction();
336 doReturn(immediateFluentFuture(Optional.of(ORDERED_LEAF_SET_NODE_1))).when(read)
337 .read(LogicalDatastoreType.OPERATIONAL, LEAF_SET_NODE_PATH);
338 doReturn(immediateFluentFuture(Optional.of(ORDERED_LEAF_SET_NODE_2))).when(read)
339 .read(LogicalDatastoreType.CONFIGURATION, LEAF_SET_NODE_PATH);
340 return mockStrategy();
344 RestconfStrategy readDataWrongPathOrNoContentTestStrategy() {
345 doReturn(read).when(dataBroker).newReadOnlyTransaction();
346 doReturn(immediateFluentFuture(Optional.empty())).when(read).read(LogicalDatastoreType.CONFIGURATION, PATH_2);
347 return mockStrategy();
351 public void readLeafWithDefaultParameters() {
352 final var data = Builders.containerBuilder()
353 .withNodeIdentifier(new NodeIdentifier(CONT_QNAME))
354 .withChild(ImmutableNodes.leafNode(QName.create(BASE, "exampleLeaf"), "i am leaf"))
356 final var path = YangInstanceIdentifier.of(CONT_QNAME);
357 doReturn(read).when(dataBroker).newReadOnlyTransaction();
358 doReturn(immediateFluentFuture(Optional.of(data))).when(read)
359 .read(LogicalDatastoreType.CONFIGURATION, path);
360 doReturn(immediateFluentFuture(Optional.of(data))).when(read)
361 .read(LogicalDatastoreType.OPERATIONAL, path);
363 assertEquals(data, modulesStrategy().readData(ContentParam.ALL, path, WithDefaultsParam.TRIM));
367 public void readContainerWithDefaultParameters() {
368 final var exampleList = new NodeIdentifier(QName.create(BASE, "exampleList"));
369 final var data = Builders.containerBuilder()
370 .withNodeIdentifier(new NodeIdentifier(CONT_QNAME))
371 .withChild(Builders.unkeyedListBuilder()
372 .withNodeIdentifier(exampleList)
373 .withChild(Builders.unkeyedListEntryBuilder()
374 .withNodeIdentifier(exampleList)
375 .withChild(Builders.containerBuilder()
376 .withNodeIdentifier(new NodeIdentifier(QName.create(BASE, "containerBool")))
377 .withChild(ImmutableNodes.leafNode(QName.create(BASE, "leafBool"), true))
379 .addChild(Builders.containerBuilder()
380 .withNodeIdentifier(new NodeIdentifier(QName.create(BASE, "containerInt")))
381 .withChild(ImmutableNodes.leafNode(QName.create(BASE, "leafInt"), 12))
386 final var path = YangInstanceIdentifier.of(CONT_QNAME);
387 doReturn(read).when(dataBroker).newReadOnlyTransaction();
388 doReturn(immediateFluentFuture(Optional.of(data))).when(read)
389 .read(LogicalDatastoreType.CONFIGURATION, path);
390 doReturn(immediateFluentFuture(Optional.of(data))).when(read)
391 .read(LogicalDatastoreType.OPERATIONAL, path);
393 assertEquals(data, modulesStrategy().readData(ContentParam.ALL, path, WithDefaultsParam.TRIM));
397 public void readLeafInListWithDefaultParameters() {
398 final var exampleList = new NodeIdentifier(QName.create(BASE, "exampleList"));
399 final var content = Builders.containerBuilder()
400 .withNodeIdentifier(new NodeIdentifier(CONT_QNAME))
401 .withChild(Builders.unkeyedListBuilder()
402 .withNodeIdentifier(exampleList)
403 .withChild(Builders.unkeyedListEntryBuilder()
404 .withNodeIdentifier(exampleList)
405 .addChild(ImmutableNodes.leafNode(QName.create(BASE, "leafInList"), "I am leaf in list"))
409 final var path = YangInstanceIdentifier.of(CONT_QNAME);
410 doReturn(read).when(dataBroker).newReadOnlyTransaction();
411 doReturn(immediateFluentFuture(Optional.of(content))).when(read)
412 .read(LogicalDatastoreType.CONFIGURATION, path);
413 doReturn(immediateFluentFuture(Optional.of(content))).when(read)
414 .read(LogicalDatastoreType.OPERATIONAL, path);
416 assertEquals(content, modulesStrategy().readData(ContentParam.ALL, path, WithDefaultsParam.TRIM));
420 public void testGetRestconfStrategyLocal() {
421 final var strategy = jukeboxStrategy();
422 assertEquals(new StrategyAndTail(strategy, ApiPath.empty()), strategy.resolveStrategy(ApiPath.empty()));
426 public void testGetRestconfStrategyMountDataBroker() throws Exception {
427 doReturn(Optional.empty()).when(mountPoint).getService(NetconfDataTreeService.class);
428 doReturn(Optional.of(dataBroker)).when(mountPoint).getService(DOMDataBroker.class);
429 doReturn(Optional.of(rpcService)).when(mountPoint).getService(DOMRpcService.class);
430 doReturn(Optional.of(new FixedDOMSchemaService(JUKEBOX_SCHEMA))).when(mountPoint)
431 .getService(DOMSchemaService.class);
432 doReturn(Optional.empty()).when(mountPoint).getService(DOMMountPointService.class);
433 doReturn(Optional.empty()).when(mountPoint).getService(DOMActionService.class);
434 doReturn(Optional.of(mountPoint)).when(mountPointService).getMountPoint(YangInstanceIdentifier.of());
436 final var strategy = jukeboxStrategy();
437 final var result = strategy.resolveStrategy(ApiPath.parse("yang-ext:mount"));
438 assertEquals(ApiPath.empty(), result.tail());
439 assertNotSame(strategy, assertInstanceOf(MdsalRestconfStrategy.class, result.strategy()));
443 public void testGetRestconfStrategyMountNetconfService() throws Exception {
444 doReturn(Optional.of(netconfService)).when(mountPoint).getService(NetconfDataTreeService.class);
445 doReturn(Optional.of(rpcService)).when(mountPoint).getService(DOMRpcService.class);
446 doReturn(Optional.of(new FixedDOMSchemaService(JUKEBOX_SCHEMA))).when(mountPoint)
447 .getService(DOMSchemaService.class);
448 doReturn(Optional.empty()).when(mountPoint).getService(DOMMountPointService.class);
449 doReturn(Optional.empty()).when(mountPoint).getService(DOMActionService.class);
450 doReturn(Optional.of(mountPoint)).when(mountPointService).getMountPoint(YangInstanceIdentifier.of());
452 final var strategy = jukeboxStrategy();
453 final var result = strategy.resolveStrategy(ApiPath.parse("yang-ext:mount"));
454 assertEquals(ApiPath.empty(), result.tail());
455 assertInstanceOf(NetconfRestconfStrategy.class, result.strategy());
459 public void testGetRestconfStrategyMountNone() throws Exception {
460 doReturn(JUKEBOX_IID).when(mountPoint).getIdentifier();
461 doReturn(Optional.empty()).when(mountPoint).getService(NetconfDataTreeService.class);
462 doReturn(Optional.empty()).when(mountPoint).getService(DOMDataBroker.class);
463 doReturn(Optional.empty()).when(mountPoint).getService(DOMMountPointService.class);
464 doReturn(Optional.empty()).when(mountPoint).getService(DOMActionService.class);
465 doReturn(Optional.of(rpcService)).when(mountPoint).getService(DOMRpcService.class);
466 doReturn(Optional.of(new FixedDOMSchemaService(JUKEBOX_SCHEMA))).when(mountPoint)
467 .getService(DOMSchemaService.class);
468 doReturn(Optional.of(mountPoint)).when(mountPointService).getMountPoint(YangInstanceIdentifier.of());
470 final var strategy = jukeboxStrategy();
471 final var mountPath = ApiPath.parse("yang-ext:mount");
473 final var ex = assertThrows(RestconfDocumentedException.class, () -> strategy.resolveStrategy(mountPath));
474 final var errors = ex.getErrors();
475 assertEquals(1, errors.size());
476 final var error = errors.get(0);
477 assertEquals(ErrorType.APPLICATION, error.getErrorType());
478 assertEquals(ErrorTag.OPERATION_FAILED, error.getErrorTag());
479 assertEquals("Could not find a supported access interface in mount point", error.getErrorMessage());
480 assertEquals(JUKEBOX_IID, error.getErrorPath());