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.assertThrows;
14 import static org.mockito.Mockito.doNothing;
15 import static org.mockito.Mockito.doReturn;
16 import static org.mockito.Mockito.verify;
17 import static org.mockito.Mockito.when;
18 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFailedFluentFuture;
19 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFalseFluentFuture;
20 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
21 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateTrueFluentFuture;
23 import java.util.Optional;
24 import org.eclipse.jdt.annotation.NonNull;
25 import org.junit.Before;
26 import org.junit.Test;
27 import org.junit.runner.RunWith;
28 import org.mockito.Mock;
29 import org.mockito.junit.MockitoJUnitRunner;
30 import org.opendaylight.mdsal.common.api.CommitInfo;
31 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
32 import org.opendaylight.mdsal.dom.api.DOMActionService;
33 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
34 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
35 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
36 import org.opendaylight.mdsal.dom.api.DOMMountPoint;
37 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
38 import org.opendaylight.mdsal.dom.api.DOMRpcService;
39 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
40 import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
41 import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
42 import org.opendaylight.restconf.api.ApiPath;
43 import org.opendaylight.restconf.api.query.ContentParam;
44 import org.opendaylight.restconf.api.query.WithDefaultsParam;
45 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
46 import org.opendaylight.restconf.common.patch.PatchStatusContext;
47 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy.StrategyAndTail;
48 import org.opendaylight.restconf.server.api.DatabindContext;
49 import org.opendaylight.yangtools.yang.common.ErrorTag;
50 import org.opendaylight.yangtools.yang.common.ErrorType;
51 import org.opendaylight.yangtools.yang.common.QName;
52 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
53 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
54 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
55 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
56 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
57 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
58 import org.w3c.dom.DOMException;
60 @RunWith(MockitoJUnitRunner.StrictStubs.class)
61 public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTest {
62 private static final DatabindContext MODULES_DATABIND = DatabindContext.ofModel(
63 YangParserTestUtils.parseYangResourceDirectory("/modules"));
66 private DOMDataTreeReadWriteTransaction readWrite;
68 private DOMDataBroker dataBroker;
70 private DOMDataTreeReadTransaction read;
72 private DOMRpcService rpcService;
74 private DOMSchemaService schemaService;
76 private DOMMountPointService mountPointService;
78 private DOMMountPoint mountPoint;
80 private NetconfDataTreeService netconfService;
83 public void before() {
84 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
85 doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
89 RestconfStrategy newStrategy(final DatabindContext databind) {
90 return new MdsalRestconfStrategy(databind, dataBroker, rpcService, null, null, mountPointService);
93 private @NonNull RestconfStrategy modulesStrategy() {
94 return newStrategy(MODULES_DATABIND);
98 RestconfStrategy testDeleteDataStrategy() {
99 // assert that data to delete exists
100 when(readWrite.exists(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.of()))
101 .thenReturn(immediateTrueFluentFuture());
102 return jukeboxStrategy();
106 RestconfStrategy testNegativeDeleteDataStrategy() {
107 // assert that data to delete does NOT exist
108 when(readWrite.exists(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.of()))
109 .thenReturn(immediateFalseFluentFuture());
110 return jukeboxStrategy();
114 RestconfStrategy testPostListDataStrategy(final MapEntryNode entryNode, final YangInstanceIdentifier node) {
115 doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, node);
116 doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, node, entryNode);
117 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
118 return jukeboxStrategy();
122 RestconfStrategy testPostDataFailStrategy(final DOMException domException) {
123 doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
124 doReturn(immediateFailedFluentFuture(domException)).when(readWrite).commit();
125 doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX);
126 return jukeboxStrategy();
130 public void testPutContainerData() {
131 doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
132 doReturn(read).when(dataBroker).newReadOnlyTransaction();
133 doReturn(immediateFalseFluentFuture()).when(read).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
134 doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX);
135 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
137 jukeboxStrategy().putData(JUKEBOX_IID, EMPTY_JUKEBOX, null);
138 verify(read).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
139 verify(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX);
143 public void testPutLeafData() {
144 doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
145 doReturn(read).when(dataBroker).newReadOnlyTransaction();
146 doReturn(immediateFalseFluentFuture()).when(read).exists(LogicalDatastoreType.CONFIGURATION, GAP_IID);
147 doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF);
148 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
150 jukeboxStrategy().putData(GAP_IID, GAP_LEAF, null);
151 verify(read).exists(LogicalDatastoreType.CONFIGURATION, GAP_IID);
152 verify(readWrite).put(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF);
157 public void testPutListData() {
158 doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
159 doReturn(read).when(dataBroker).newReadOnlyTransaction();
160 doReturn(immediateFalseFluentFuture())
161 .when(read).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
162 doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS);
163 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
165 jukeboxStrategy().putData(JUKEBOX_IID, JUKEBOX_WITH_BANDS, null);
166 verify(read).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
167 verify(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS);
171 RestconfStrategy testPostContainerDataStrategy() {
172 doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
173 doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX);
174 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
175 return jukeboxStrategy();
179 RestconfStrategy testPatchContainerDataStrategy() {
180 doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
181 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
182 return jukeboxStrategy();
186 RestconfStrategy testPatchLeafDataStrategy() {
187 doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
188 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
189 return jukeboxStrategy();
193 RestconfStrategy testPatchListDataStrategy() {
194 doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
195 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
196 return jukeboxStrategy();
200 RestconfStrategy testPatchDataReplaceMergeAndRemoveStrategy() {
201 return jukeboxStrategy();
205 RestconfStrategy testPatchDataCreateAndDeleteStrategy() {
206 doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, PLAYER_IID);
207 doReturn(immediateTrueFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION,
208 CREATE_AND_DELETE_TARGET);
209 return jukeboxStrategy();
213 RestconfStrategy testPatchMergePutContainerStrategy() {
214 return jukeboxStrategy();
218 RestconfStrategy deleteNonexistentDataTestStrategy() {
219 doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION,
220 CREATE_AND_DELETE_TARGET);
221 return jukeboxStrategy();
225 void assertTestDeleteNonexistentData(final PatchStatusContext status) {
226 final var editCollection = status.editCollection();
227 assertEquals(1, editCollection.size());
228 final var editErrors = editCollection.get(0).getEditErrors();
229 assertEquals(1, editErrors.size());
230 final var editError = editErrors.get(0);
231 assertEquals(ErrorType.PROTOCOL, editError.getErrorType());
232 assertEquals(ErrorTag.DATA_MISSING, editError.getErrorTag());
236 RestconfStrategy readDataConfigTestStrategy() {
237 doReturn(read).when(dataBroker).newReadOnlyTransaction();
238 doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(read)
239 .read(LogicalDatastoreType.CONFIGURATION, PATH);
240 return mockStrategy();
244 RestconfStrategy readAllHavingOnlyConfigTestStrategy() {
245 doReturn(read).when(dataBroker).newReadOnlyTransaction();
246 doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(read)
247 .read(LogicalDatastoreType.CONFIGURATION, PATH);
248 doReturn(immediateFluentFuture(Optional.empty())).when(read)
249 .read(LogicalDatastoreType.OPERATIONAL, PATH);
250 return mockStrategy();
254 RestconfStrategy readAllHavingOnlyNonConfigTestStrategy() {
255 doReturn(read).when(dataBroker).newReadOnlyTransaction();
256 doReturn(immediateFluentFuture(Optional.of(DATA_2))).when(read)
257 .read(LogicalDatastoreType.OPERATIONAL, PATH_2);
258 doReturn(immediateFluentFuture(Optional.empty())).when(read)
259 .read(LogicalDatastoreType.CONFIGURATION, PATH_2);
260 return mockStrategy();
264 RestconfStrategy readDataNonConfigTestStrategy() {
265 doReturn(read).when(dataBroker).newReadOnlyTransaction();
266 doReturn(immediateFluentFuture(Optional.of(DATA_2))).when(read)
267 .read(LogicalDatastoreType.OPERATIONAL, PATH_2);
268 return mockStrategy();
272 RestconfStrategy readContainerDataAllTestStrategy() {
273 doReturn(read).when(dataBroker).newReadOnlyTransaction();
274 doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(read)
275 .read(LogicalDatastoreType.CONFIGURATION, PATH);
276 doReturn(immediateFluentFuture(Optional.of(DATA_4))).when(read)
277 .read(LogicalDatastoreType.OPERATIONAL, PATH);
278 return mockStrategy();
282 RestconfStrategy readContainerDataConfigNoValueOfContentTestStrategy() {
283 doReturn(read).when(dataBroker).newReadOnlyTransaction();
284 doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(read)
285 .read(LogicalDatastoreType.CONFIGURATION, PATH);
286 doReturn(immediateFluentFuture(Optional.of(DATA_4))).when(read)
287 .read(LogicalDatastoreType.OPERATIONAL, PATH);
288 return mockStrategy();
292 RestconfStrategy readListDataAllTestStrategy() {
293 doReturn(read).when(dataBroker).newReadOnlyTransaction();
294 doReturn(immediateFluentFuture(Optional.of(LIST_DATA))).when(read)
295 .read(LogicalDatastoreType.OPERATIONAL, PATH_3);
296 doReturn(immediateFluentFuture(Optional.of(LIST_DATA_2))).when(read)
297 .read(LogicalDatastoreType.CONFIGURATION, PATH_3);
298 return mockStrategy();
302 RestconfStrategy readOrderedListDataAllTestStrategy() {
303 doReturn(read).when(dataBroker).newReadOnlyTransaction();
304 doReturn(immediateFluentFuture(Optional.of(ORDERED_MAP_NODE_1))).when(read)
305 .read(LogicalDatastoreType.OPERATIONAL, PATH_3);
306 doReturn(immediateFluentFuture(Optional.of(ORDERED_MAP_NODE_2))).when(read)
307 .read(LogicalDatastoreType.CONFIGURATION, PATH_3);
308 return mockStrategy();
312 RestconfStrategy readUnkeyedListDataAllTestStrategy() {
313 doReturn(read).when(dataBroker).newReadOnlyTransaction();
314 doReturn(immediateFluentFuture(Optional.of(UNKEYED_LIST_NODE_1))).when(read)
315 .read(LogicalDatastoreType.OPERATIONAL, PATH_3);
316 doReturn(immediateFluentFuture(Optional.of(UNKEYED_LIST_NODE_2))).when(read)
317 .read(LogicalDatastoreType.CONFIGURATION, PATH_3);
318 return mockStrategy();
322 RestconfStrategy readLeafListDataAllTestStrategy() {
323 doReturn(read).when(dataBroker).newReadOnlyTransaction();
324 doReturn(immediateFluentFuture(Optional.of(LEAF_SET_NODE_1))).when(read)
325 .read(LogicalDatastoreType.OPERATIONAL, LEAF_SET_NODE_PATH);
326 doReturn(immediateFluentFuture(Optional.of(LEAF_SET_NODE_2))).when(read)
327 .read(LogicalDatastoreType.CONFIGURATION, LEAF_SET_NODE_PATH);
328 return mockStrategy();
332 RestconfStrategy readOrderedLeafListDataAllTestStrategy() {
333 doReturn(read).when(dataBroker).newReadOnlyTransaction();
334 doReturn(immediateFluentFuture(Optional.of(ORDERED_LEAF_SET_NODE_1))).when(read)
335 .read(LogicalDatastoreType.OPERATIONAL, LEAF_SET_NODE_PATH);
336 doReturn(immediateFluentFuture(Optional.of(ORDERED_LEAF_SET_NODE_2))).when(read)
337 .read(LogicalDatastoreType.CONFIGURATION, LEAF_SET_NODE_PATH);
338 return mockStrategy();
342 RestconfStrategy readDataWrongPathOrNoContentTestStrategy() {
343 doReturn(read).when(dataBroker).newReadOnlyTransaction();
344 doReturn(immediateFluentFuture(Optional.empty())).when(read).read(LogicalDatastoreType.CONFIGURATION, PATH_2);
345 return mockStrategy();
349 public void readLeafWithDefaultParameters() {
350 final var data = Builders.containerBuilder()
351 .withNodeIdentifier(new NodeIdentifier(CONT_QNAME))
352 .withChild(ImmutableNodes.leafNode(QName.create(BASE, "exampleLeaf"), "i am leaf"))
354 final var path = YangInstanceIdentifier.of(CONT_QNAME);
355 doReturn(read).when(dataBroker).newReadOnlyTransaction();
356 doReturn(immediateFluentFuture(Optional.of(data))).when(read)
357 .read(LogicalDatastoreType.CONFIGURATION, path);
358 doReturn(immediateFluentFuture(Optional.of(data))).when(read)
359 .read(LogicalDatastoreType.OPERATIONAL, path);
361 assertEquals(data, modulesStrategy().readData(ContentParam.ALL, path, WithDefaultsParam.TRIM));
365 public void readContainerWithDefaultParameters() {
366 final var exampleList = new NodeIdentifier(QName.create(BASE, "exampleList"));
367 final var data = Builders.containerBuilder()
368 .withNodeIdentifier(new NodeIdentifier(CONT_QNAME))
369 .withChild(Builders.unkeyedListBuilder()
370 .withNodeIdentifier(exampleList)
371 .withChild(Builders.unkeyedListEntryBuilder()
372 .withNodeIdentifier(exampleList)
373 .withChild(Builders.containerBuilder()
374 .withNodeIdentifier(new NodeIdentifier(QName.create(BASE, "containerBool")))
375 .withChild(ImmutableNodes.leafNode(QName.create(BASE, "leafBool"), true))
377 .addChild(Builders.containerBuilder()
378 .withNodeIdentifier(new NodeIdentifier(QName.create(BASE, "containerInt")))
379 .withChild(ImmutableNodes.leafNode(QName.create(BASE, "leafInt"), 12))
384 final var path = YangInstanceIdentifier.of(CONT_QNAME);
385 doReturn(read).when(dataBroker).newReadOnlyTransaction();
386 doReturn(immediateFluentFuture(Optional.of(data))).when(read)
387 .read(LogicalDatastoreType.CONFIGURATION, path);
388 doReturn(immediateFluentFuture(Optional.of(data))).when(read)
389 .read(LogicalDatastoreType.OPERATIONAL, path);
391 assertEquals(data, modulesStrategy().readData(ContentParam.ALL, path, WithDefaultsParam.TRIM));
395 public void readLeafInListWithDefaultParameters() {
396 final var exampleList = new NodeIdentifier(QName.create(BASE, "exampleList"));
397 final var content = Builders.containerBuilder()
398 .withNodeIdentifier(new NodeIdentifier(CONT_QNAME))
399 .withChild(Builders.unkeyedListBuilder()
400 .withNodeIdentifier(exampleList)
401 .withChild(Builders.unkeyedListEntryBuilder()
402 .withNodeIdentifier(exampleList)
403 .addChild(ImmutableNodes.leafNode(QName.create(BASE, "leafInList"), "I am leaf in list"))
407 final var path = YangInstanceIdentifier.of(CONT_QNAME);
408 doReturn(read).when(dataBroker).newReadOnlyTransaction();
409 doReturn(immediateFluentFuture(Optional.of(content))).when(read)
410 .read(LogicalDatastoreType.CONFIGURATION, path);
411 doReturn(immediateFluentFuture(Optional.of(content))).when(read)
412 .read(LogicalDatastoreType.OPERATIONAL, path);
414 assertEquals(content, modulesStrategy().readData(ContentParam.ALL, path, WithDefaultsParam.TRIM));
418 public void testGetRestconfStrategyLocal() {
419 final var strategy = jukeboxStrategy();
420 assertEquals(new StrategyAndTail(strategy, ApiPath.empty()), strategy.resolveStrategy(ApiPath.empty()));
424 public void testGetRestconfStrategyMountDataBroker() throws Exception {
425 doReturn(Optional.empty()).when(mountPoint).getService(NetconfDataTreeService.class);
426 doReturn(Optional.of(dataBroker)).when(mountPoint).getService(DOMDataBroker.class);
427 doReturn(Optional.of(rpcService)).when(mountPoint).getService(DOMRpcService.class);
428 doReturn(Optional.of(FixedDOMSchemaService.of(JUKEBOX_SCHEMA))).when(mountPoint)
429 .getService(DOMSchemaService.class);
430 doReturn(Optional.empty()).when(mountPoint).getService(DOMMountPointService.class);
431 doReturn(Optional.empty()).when(mountPoint).getService(DOMActionService.class);
432 doReturn(Optional.of(mountPoint)).when(mountPointService).getMountPoint(YangInstanceIdentifier.of());
434 final var strategy = jukeboxStrategy();
435 final var result = strategy.resolveStrategy(ApiPath.parse("yang-ext:mount"));
436 assertEquals(ApiPath.empty(), result.tail());
437 assertNotSame(strategy, assertInstanceOf(MdsalRestconfStrategy.class, result.strategy()));
441 public void testGetRestconfStrategyMountNetconfService() throws Exception {
442 doReturn(Optional.of(netconfService)).when(mountPoint).getService(NetconfDataTreeService.class);
443 doReturn(Optional.of(rpcService)).when(mountPoint).getService(DOMRpcService.class);
444 doReturn(Optional.of(FixedDOMSchemaService.of(JUKEBOX_SCHEMA))).when(mountPoint)
445 .getService(DOMSchemaService.class);
446 doReturn(Optional.empty()).when(mountPoint).getService(DOMMountPointService.class);
447 doReturn(Optional.empty()).when(mountPoint).getService(DOMActionService.class);
448 doReturn(Optional.of(mountPoint)).when(mountPointService).getMountPoint(YangInstanceIdentifier.of());
450 final var strategy = jukeboxStrategy();
451 final var result = strategy.resolveStrategy(ApiPath.parse("yang-ext:mount"));
452 assertEquals(ApiPath.empty(), result.tail());
453 assertInstanceOf(NetconfRestconfStrategy.class, result.strategy());
457 public void testGetRestconfStrategyMountNone() throws Exception {
458 doReturn(JUKEBOX_IID).when(mountPoint).getIdentifier();
459 doReturn(Optional.empty()).when(mountPoint).getService(NetconfDataTreeService.class);
460 doReturn(Optional.empty()).when(mountPoint).getService(DOMDataBroker.class);
461 doReturn(Optional.empty()).when(mountPoint).getService(DOMMountPointService.class);
462 doReturn(Optional.empty()).when(mountPoint).getService(DOMActionService.class);
463 doReturn(Optional.of(rpcService)).when(mountPoint).getService(DOMRpcService.class);
464 doReturn(Optional.of(FixedDOMSchemaService.of(JUKEBOX_SCHEMA))).when(mountPoint)
465 .getService(DOMSchemaService.class);
466 doReturn(Optional.of(mountPoint)).when(mountPointService).getMountPoint(YangInstanceIdentifier.of());
468 final var strategy = jukeboxStrategy();
469 final var mountPath = ApiPath.parse("yang-ext:mount");
471 final var ex = assertThrows(RestconfDocumentedException.class, () -> strategy.resolveStrategy(mountPath));
472 final var errors = ex.getErrors();
473 assertEquals(1, errors.size());
474 final var error = errors.get(0);
475 assertEquals(ErrorType.APPLICATION, error.getErrorType());
476 assertEquals(ErrorTag.OPERATION_FAILED, error.getErrorTag());
477 assertEquals("Could not find a supported access interface in mount point", error.getErrorMessage());
478 assertEquals(JUKEBOX_IID, error.getErrorPath());