Refactor NormalizedNodePayload
[netconf.git] / restconf / restconf-nb / src / test / java / org / opendaylight / restconf / nb / rfc8040 / rests / services / impl / RestconfDataServiceImplTest.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. 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.services.impl;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertFalse;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertNull;
14 import static org.junit.Assert.assertThrows;
15 import static org.junit.Assert.assertTrue;
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.mock;
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;
23
24 import java.io.ByteArrayInputStream;
25 import java.io.InputStream;
26 import java.net.URI;
27 import java.nio.charset.StandardCharsets;
28 import java.util.Collection;
29 import java.util.List;
30 import java.util.Optional;
31 import java.util.Set;
32 import javax.ws.rs.container.AsyncResponse;
33 import javax.ws.rs.core.MultivaluedHashMap;
34 import javax.ws.rs.core.MultivaluedMap;
35 import javax.ws.rs.core.Response;
36 import javax.ws.rs.core.UriBuilder;
37 import javax.ws.rs.core.UriInfo;
38 import org.junit.Before;
39 import org.junit.Test;
40 import org.junit.runner.RunWith;
41 import org.mockito.ArgumentCaptor;
42 import org.mockito.Mock;
43 import org.mockito.junit.MockitoJUnitRunner;
44 import org.opendaylight.mdsal.common.api.CommitInfo;
45 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
46 import org.opendaylight.mdsal.dom.api.DOMActionService;
47 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
48 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
49 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
50 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
51 import org.opendaylight.mdsal.dom.api.DOMMountPoint;
52 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
53 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
54 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
55 import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
56 import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
57 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
58 import org.opendaylight.restconf.common.patch.PatchContext;
59 import org.opendaylight.restconf.common.patch.PatchEntity;
60 import org.opendaylight.restconf.common.patch.PatchStatusContext;
61 import org.opendaylight.restconf.nb.rfc8040.AbstractJukeboxTest;
62 import org.opendaylight.restconf.nb.rfc8040.databind.DatabindContext;
63 import org.opendaylight.restconf.nb.rfc8040.legacy.NormalizedNodePayload;
64 import org.opendaylight.restconf.nb.rfc8040.rests.services.api.RestconfStreamsSubscriptionService;
65 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.MdsalRestconfStrategy;
66 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.NetconfRestconfStrategy;
67 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
68 import org.opendaylight.restconf.nb.rfc8040.streams.StreamsConfiguration;
69 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.patch.rev170222.yang.patch.yang.patch.Edit.Operation;
70 import org.opendaylight.yangtools.yang.common.ErrorTag;
71 import org.opendaylight.yangtools.yang.common.ErrorType;
72 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
73 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
74 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
75 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
76 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
77 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
78 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
79
80 @RunWith(MockitoJUnitRunner.StrictStubs.class)
81 public class RestconfDataServiceImplTest extends AbstractJukeboxTest {
82     private static final NodeIdentifier PLAYLIST_NID = new NodeIdentifier(PLAYLIST_QNAME);
83     private static final NodeIdentifier LIBRARY_NID = new NodeIdentifier(LIBRARY_QNAME);
84
85     // config contains one child the same as in operational and one additional
86     private static final ContainerNode CONFIG_JUKEBOX = Builders.containerBuilder()
87             .withNodeIdentifier(new NodeIdentifier(JUKEBOX_QNAME))
88             .withChild(CONT_PLAYER)
89             .withChild(Builders.containerBuilder().withNodeIdentifier(LIBRARY_NID).build())
90             .build();
91     // operational contains one child the same as in config and one additional
92     private static final ContainerNode OPER_JUKEBOX = Builders.containerBuilder()
93             .withNodeIdentifier(new NodeIdentifier(JUKEBOX_QNAME))
94             .withChild(CONT_PLAYER)
95             .withChild(Builders.mapBuilder().withNodeIdentifier(PLAYLIST_NID).build())
96             .build();
97
98     private RestconfDataServiceImpl dataService;
99
100     @Mock
101     private DOMTransactionChain domTransactionChain;
102     @Mock
103     private UriInfo uriInfo;
104     @Mock
105     private DOMDataTreeReadWriteTransaction readWrite;
106     @Mock
107     private DOMDataTreeReadTransaction read;
108     @Mock
109     private DOMDataTreeWriteTransaction write;
110     @Mock
111     private DOMMountPointService mountPointService;
112     @Mock
113     private DOMMountPoint mountPoint;
114     @Mock
115     private DOMDataBroker mountDataBroker;
116     @Mock
117     private NetconfDataTreeService netconfService;
118     @Mock
119     private DOMActionService actionService;
120     @Mock
121     private RestconfStreamsSubscriptionService delegRestconfSubscrService;
122     @Mock
123     private MultivaluedMap<String, String> queryParamenters;
124     @Mock
125     private AsyncResponse asyncResponse;
126
127     @Before
128     public void setUp() throws Exception {
129         doReturn(Set.of()).when(queryParamenters).entrySet();
130         doReturn(queryParamenters).when(uriInfo).getQueryParameters();
131
132         doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
133
134         final var dataBroker = mock(DOMDataBroker.class);
135         doReturn(read).when(dataBroker).newReadOnlyTransaction();
136         doReturn(readWrite).when(dataBroker).newReadWriteTransaction();
137
138         dataService = new RestconfDataServiceImpl(() -> DatabindContext.ofModel(JUKEBOX_SCHEMA), dataBroker,
139                 mountPointService, delegRestconfSubscrService, actionService, new StreamsConfiguration(0, 1, 0, false));
140         doReturn(Optional.of(mountPoint)).when(mountPointService)
141                 .getMountPoint(any(YangInstanceIdentifier.class));
142         doReturn(Optional.of(FixedDOMSchemaService.of(JUKEBOX_SCHEMA))).when(mountPoint)
143                 .getService(DOMSchemaService.class);
144         doReturn(Optional.of(mountDataBroker)).when(mountPoint).getService(DOMDataBroker.class);
145         doReturn(Optional.empty()).when(mountPoint).getService(NetconfDataTreeService.class);
146         doReturn(read).when(mountDataBroker).newReadOnlyTransaction();
147         doReturn(readWrite).when(mountDataBroker).newReadWriteTransaction();
148     }
149
150     @Test
151     public void testReadData() {
152         doReturn(new MultivaluedHashMap<>()).when(uriInfo).getQueryParameters();
153         doReturn(immediateFluentFuture(Optional.of(EMPTY_JUKEBOX))).when(read)
154                 .read(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
155         doReturn(immediateFluentFuture(Optional.empty()))
156                 .when(read).read(LogicalDatastoreType.OPERATIONAL, JUKEBOX_IID);
157         final Response response = dataService.readData("example-jukebox:jukebox", uriInfo);
158         assertNotNull(response);
159         assertEquals(200, response.getStatus());
160         assertEquals(EMPTY_JUKEBOX, ((NormalizedNodePayload) response.getEntity()).data());
161     }
162
163     @Test
164     public void testReadRootData() {
165         doReturn(new MultivaluedHashMap<>()).when(uriInfo).getQueryParameters();
166         doReturn(immediateFluentFuture(Optional.of(wrapNodeByDataRootContainer(CONFIG_JUKEBOX))))
167                 .when(read)
168                 .read(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.of());
169         doReturn(immediateFluentFuture(Optional.of(wrapNodeByDataRootContainer(OPER_JUKEBOX))))
170                 .when(read)
171                 .read(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.of());
172         final Response response = dataService.readData(uriInfo);
173         assertNotNull(response);
174         assertEquals(200, response.getStatus());
175
176         final NormalizedNode data = ((NormalizedNodePayload) response.getEntity()).data();
177         assertTrue(data instanceof ContainerNode);
178         final Collection<DataContainerChild> rootNodes = ((ContainerNode) data).body();
179         assertEquals(1, rootNodes.size());
180         final Collection<DataContainerChild> allDataChildren = ((ContainerNode) rootNodes.iterator().next()).body();
181         assertEquals(3, allDataChildren.size());
182     }
183
184     private static ContainerNode wrapNodeByDataRootContainer(final DataContainerChild data) {
185         return Builders.containerBuilder()
186             .withNodeIdentifier(NodeIdentifier.create(SchemaContext.NAME))
187             .withChild(data)
188             .build();
189     }
190
191     /**
192      * Test read data from mount point when both {@link LogicalDatastoreType#CONFIGURATION} and
193      * {@link LogicalDatastoreType#OPERATIONAL} contains the same data and some additional data to be merged.
194      */
195     @Test
196     public void testReadDataMountPoint() {
197         doReturn(new MultivaluedHashMap<>()).when(uriInfo).getQueryParameters();
198         doReturn(immediateFluentFuture(Optional.of(CONFIG_JUKEBOX))).when(read)
199                 .read(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
200         doReturn(immediateFluentFuture(Optional.of(OPER_JUKEBOX))).when(read)
201                 .read(LogicalDatastoreType.OPERATIONAL, JUKEBOX_IID);
202
203         final Response response = dataService.readData(
204                 "example-jukebox:jukebox/yang-ext:mount/example-jukebox:jukebox", uriInfo);
205
206         assertNotNull(response);
207         assertEquals(200, response.getStatus());
208
209         // response must contain all child nodes from config and operational containers merged in one container
210         final NormalizedNode data = ((NormalizedNodePayload) response.getEntity()).data();
211         assertTrue(data instanceof ContainerNode);
212         assertEquals(3, ((ContainerNode) data).size());
213         assertNotNull(((ContainerNode) data).childByArg(CONT_PLAYER.name()));
214         assertNotNull(((ContainerNode) data).childByArg(LIBRARY_NID));
215         assertNotNull(((ContainerNode) data).childByArg(PLAYLIST_NID));
216     }
217
218     @Test
219     public void testReadDataNoData() {
220         doReturn(new MultivaluedHashMap<>()).when(uriInfo).getQueryParameters();
221         doReturn(immediateFluentFuture(Optional.empty()))
222                 .when(read).read(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
223         doReturn(immediateFluentFuture(Optional.empty()))
224                 .when(read).read(LogicalDatastoreType.OPERATIONAL, JUKEBOX_IID);
225
226         final var errors = assertThrows(RestconfDocumentedException.class,
227             () -> dataService.readData("example-jukebox:jukebox", uriInfo)).getErrors();
228         assertEquals(1, errors.size());
229         final var error = errors.get(0);
230         assertEquals(ErrorType.PROTOCOL, error.getErrorType());
231         assertEquals(ErrorTag.DATA_MISSING, error.getErrorTag());
232         assertEquals("Request could not be completed because the relevant data model content does not exist",
233             error.getErrorMessage());
234     }
235
236     /**
237      * Read data from config datastore according to content parameter.
238      */
239     @Test
240     public void testReadDataConfigTest() {
241         final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
242         parameters.put("content", List.of("config"));
243
244         doReturn(parameters).when(uriInfo).getQueryParameters();
245         doReturn(immediateFluentFuture(Optional.of(CONFIG_JUKEBOX))).when(read)
246                 .read(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
247
248         final Response response = dataService.readData("example-jukebox:jukebox", uriInfo);
249
250         assertNotNull(response);
251         assertEquals(200, response.getStatus());
252
253         // response must contain only config data
254         final NormalizedNode data = ((NormalizedNodePayload) response.getEntity()).data();
255
256         // config data present
257         assertNotNull(((ContainerNode) data).childByArg(CONT_PLAYER.name()));
258         assertNotNull(((ContainerNode) data).childByArg(LIBRARY_NID));
259
260         // state data absent
261         assertNull(((ContainerNode) data).childByArg(PLAYLIST_NID));
262     }
263
264     /**
265      * Read data from operational datastore according to content parameter.
266      */
267     @Test
268     public void testReadDataOperationalTest() {
269         final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
270         parameters.put("content", List.of("nonconfig"));
271
272         doReturn(parameters).when(uriInfo).getQueryParameters();
273         doReturn(immediateFluentFuture(Optional.of(OPER_JUKEBOX))).when(read)
274                 .read(LogicalDatastoreType.OPERATIONAL, JUKEBOX_IID);
275
276         final Response response = dataService.readData("example-jukebox:jukebox", uriInfo);
277
278         assertNotNull(response);
279         assertEquals(200, response.getStatus());
280
281         // response must contain only operational data
282         final NormalizedNode data = ((NormalizedNodePayload) response.getEntity()).data();
283
284         // state data present
285         assertNotNull(((ContainerNode) data).childByArg(CONT_PLAYER.name()));
286         assertNotNull(((ContainerNode) data).childByArg(PLAYLIST_NID));
287
288         // config data absent
289         assertNull(((ContainerNode) data).childByArg(LIBRARY_NID));
290     }
291
292     @Test
293     public void testPutData() {
294         doReturn(immediateTrueFluentFuture()).when(read)
295                 .exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
296         doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX);
297         final var response = dataService.putDataJSON("example-jukebox:jukebox", uriInfo, stringInputStream("""
298             {
299               "example-jukebox:jukebox" : {
300                  "player": {
301                    "gap": "0.2"
302                  }
303               }
304             }"""));
305         assertNotNull(response);
306         assertEquals(Response.Status.NO_CONTENT.getStatusCode(), response.getStatus());
307     }
308
309     @Test
310     public void testPutDataWithMountPoint() {
311         doReturn(immediateTrueFluentFuture()).when(read)
312                 .exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
313         doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX);
314         final var response = dataService.putDataXML("example-jukebox:jukebox/yang-ext:mount/example-jukebox:jukebox",
315             uriInfo, stringInputStream("""
316                 <jukebox xmlns="http://example.com/ns/example-jukebox">
317                   <player>
318                     <gap>0.2</gap>
319                   </player>
320                 </jukebox>"""));
321         assertNotNull(response);
322         assertEquals(Response.Status.NO_CONTENT.getStatusCode(), response.getStatus());
323     }
324
325     private static InputStream stringInputStream(final String str) {
326         return new ByteArrayInputStream(str.getBytes(StandardCharsets.UTF_8));
327     }
328
329     @Test
330     public void testPostData() {
331         doReturn(new MultivaluedHashMap<>()).when(uriInfo).getQueryParameters();
332         doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
333         doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID,
334             Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(JUKEBOX_QNAME)).build());
335         doReturn(UriBuilder.fromUri("http://localhost:8181/rests/")).when(uriInfo).getBaseUriBuilder();
336
337         final var response = dataService.postDataJSON(new ByteArrayInputStream("""
338             {
339               "example-jukebox:jukebox" : {
340               }
341             }""".getBytes(StandardCharsets.UTF_8)), uriInfo);
342         assertEquals(201, response.getStatus());
343         assertEquals(URI.create("http://localhost:8181/rests/data/example-jukebox:jukebox"), response.getLocation());
344     }
345
346     @Test
347     public void testPostMapEntryData() {
348         doReturn(new MultivaluedHashMap<>()).when(uriInfo).getQueryParameters();
349         final var node = PLAYLIST_IID.node(BAND_ENTRY.name());
350         doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, node);
351         doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, node, BAND_ENTRY);
352         doReturn(UriBuilder.fromUri("http://localhost:8181/rests/")).when(uriInfo).getBaseUriBuilder();
353
354         final var response = dataService.postDataJSON("example-jukebox:jukebox", new ByteArrayInputStream("""
355             {
356               "example-jukebox:playlist" : {
357                 "name" : "name of band",
358                 "description" : "band description"
359               }
360             }""".getBytes(StandardCharsets.UTF_8)),
361             uriInfo);
362         assertEquals(201, response.getStatus());
363         assertEquals(URI.create("http://localhost:8181/rests/data/example-jukebox:jukebox/playlist=name%20of%20band"),
364             response.getLocation());
365     }
366
367     @Test
368     public void testDeleteData() {
369         doNothing().when(readWrite).delete(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
370         doReturn(immediateTrueFluentFuture())
371                 .when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
372         final var captor = ArgumentCaptor.forClass(Response.class);
373         doReturn(true).when(asyncResponse).resume(captor.capture());
374         dataService.deleteData("example-jukebox:jukebox", asyncResponse);
375
376         assertEquals(204, captor.getValue().getStatus());
377     }
378
379     @Test
380     public void testDeleteDataNotExisting() {
381         doReturn(immediateFalseFluentFuture())
382                 .when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
383         final var captor = ArgumentCaptor.forClass(RestconfDocumentedException.class);
384         doReturn(true).when(asyncResponse).resume(captor.capture());
385         dataService.deleteData("example-jukebox:jukebox", asyncResponse);
386
387         final var errors = captor.getValue().getErrors();
388         assertEquals(1, errors.size());
389         final var error = errors.get(0);
390         assertEquals(ErrorType.PROTOCOL, error.getErrorType());
391         assertEquals(ErrorTag.DATA_MISSING, error.getErrorTag());
392     }
393
394     /**
395      * Test of deleting data on mount point.
396      */
397     @Test
398     public void testDeleteDataMountPoint() {
399         doNothing().when(readWrite).delete(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
400         doReturn(immediateTrueFluentFuture())
401                 .when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
402         final var captor = ArgumentCaptor.forClass(Response.class);
403         doReturn(true).when(asyncResponse).resume(captor.capture());
404         dataService.deleteData("example-jukebox:jukebox/yang-ext:mount/example-jukebox:jukebox", asyncResponse);
405
406         assertEquals(204, captor.getValue().getStatus());
407     }
408
409     @Test
410     public void testPatchData() {
411         final var patch = new PatchContext("test patch id", List.of(
412             new PatchEntity("create data", Operation.Create, JUKEBOX_IID, EMPTY_JUKEBOX),
413             new PatchEntity("replace data", Operation.Replace, JUKEBOX_IID, EMPTY_JUKEBOX),
414             new PatchEntity("delete data", Operation.Delete, GAP_IID)));
415
416         doNothing().when(readWrite).delete(LogicalDatastoreType.CONFIGURATION, GAP_IID);
417         doReturn(immediateFalseFluentFuture())
418                 .when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
419         doReturn(immediateTrueFluentFuture())
420                 .when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, GAP_IID);
421         final var status = dataService.yangPatchData(JUKEBOX_SCHEMA, patch, null);
422         assertTrue(status.ok());
423         assertEquals(3, status.editCollection().size());
424         assertEquals("replace data", status.editCollection().get(1).getEditId());
425     }
426
427     @Test
428     public void testPatchDataMountPoint() throws Exception {
429         final var patch = new PatchContext("test patch id", List.of(
430             new PatchEntity("create data", Operation.Create, JUKEBOX_IID, EMPTY_JUKEBOX),
431             new PatchEntity("replace data", Operation.Replace, JUKEBOX_IID, EMPTY_JUKEBOX),
432             new PatchEntity("delete data", Operation.Delete, GAP_IID)));
433
434         doNothing().when(readWrite).delete(LogicalDatastoreType.CONFIGURATION, GAP_IID);
435         doReturn(immediateFalseFluentFuture())
436                 .when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
437         doReturn(immediateTrueFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, GAP_IID);
438
439         final var status = dataService.yangPatchData(JUKEBOX_SCHEMA, patch, mountPoint);
440         assertTrue(status.ok());
441         assertEquals(3, status.editCollection().size());
442         assertNull(status.globalErrors());
443     }
444
445     @Test
446     public void testPatchDataDeleteNotExist() {
447         final PatchContext patch = new PatchContext("test patch id", List.of(
448             new PatchEntity("create data", Operation.Create, JUKEBOX_IID, EMPTY_JUKEBOX),
449             new PatchEntity("remove data", Operation.Remove, GAP_IID),
450             new PatchEntity("delete data", Operation.Delete, GAP_IID)));
451
452         doNothing().when(readWrite).delete(LogicalDatastoreType.CONFIGURATION, GAP_IID);
453         doReturn(immediateFalseFluentFuture())
454                 .when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
455         doReturn(immediateFalseFluentFuture())
456                 .when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, GAP_IID);
457         doReturn(true).when(readWrite).cancel();
458
459         final PatchStatusContext status = dataService.yangPatchData(JUKEBOX_SCHEMA, patch, null);
460
461         assertFalse(status.ok());
462         assertEquals(3, status.editCollection().size());
463         assertTrue(status.editCollection().get(0).isOk());
464         assertTrue(status.editCollection().get(1).isOk());
465         assertFalse(status.editCollection().get(2).isOk());
466         assertFalse(status.editCollection().get(2).getEditErrors().isEmpty());
467         final String errorMessage = status.editCollection().get(2).getEditErrors().get(0).getErrorMessage();
468         assertEquals("Data does not exist", errorMessage);
469     }
470
471     @Test
472     public void testGetRestconfStrategy() {
473         RestconfStrategy restconfStrategy = dataService.getRestconfStrategy(mountPoint);
474         assertTrue(restconfStrategy instanceof MdsalRestconfStrategy);
475
476         doReturn(Optional.of(netconfService)).when(mountPoint).getService(NetconfDataTreeService.class);
477         restconfStrategy = dataService.getRestconfStrategy(mountPoint);
478         assertTrue(restconfStrategy instanceof NetconfRestconfStrategy);
479     }
480 }