c42d0dc5316e9f0f094069797699ec8fc1e9140f
[netconf.git] / restconf / restconf-nb-rfc8040 / 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.assertTrue;
15 import static org.mockito.ArgumentMatchers.any;
16 import static org.mockito.Mockito.doNothing;
17 import static org.mockito.Mockito.doReturn;
18 import static org.opendaylight.restconf.common.patch.PatchEditOperation.CREATE;
19 import static org.opendaylight.restconf.common.patch.PatchEditOperation.DELETE;
20 import static org.opendaylight.restconf.common.patch.PatchEditOperation.REMOVE;
21 import static org.opendaylight.restconf.common.patch.PatchEditOperation.REPLACE;
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 java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.Collections;
29 import java.util.HashSet;
30 import java.util.List;
31 import java.util.Optional;
32 import javax.ws.rs.core.MultivaluedHashMap;
33 import javax.ws.rs.core.MultivaluedMap;
34 import javax.ws.rs.core.Response;
35 import javax.ws.rs.core.UriBuilder;
36 import javax.ws.rs.core.UriInfo;
37 import org.junit.Before;
38 import org.junit.Test;
39 import org.mockito.Mock;
40 import org.mockito.Mockito;
41 import org.mockito.MockitoAnnotations;
42 import org.opendaylight.mdsal.common.api.CommitInfo;
43 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
44 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
45 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
46 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
47 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
48 import org.opendaylight.mdsal.dom.api.DOMMountPoint;
49 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
50 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
51 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
52 import org.opendaylight.mdsal.dom.api.DOMTransactionChainListener;
53 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
54 import org.opendaylight.restconf.common.context.NormalizedNodeContext;
55 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
56 import org.opendaylight.restconf.common.patch.PatchContext;
57 import org.opendaylight.restconf.common.patch.PatchEntity;
58 import org.opendaylight.restconf.common.patch.PatchStatusContext;
59 import org.opendaylight.restconf.nb.rfc8040.TestRestconfUtils;
60 import org.opendaylight.restconf.nb.rfc8040.handlers.DOMMountPointServiceHandler;
61 import org.opendaylight.restconf.nb.rfc8040.handlers.SchemaContextHandler;
62 import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
63 import org.opendaylight.restconf.nb.rfc8040.references.SchemaContextRef;
64 import org.opendaylight.restconf.nb.rfc8040.rests.services.api.RestconfStreamsSubscriptionService;
65 import org.opendaylight.yangtools.yang.common.QName;
66 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
67 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
68 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
69 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
70 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
71 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
72 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
73 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
74 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
75 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
76 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
77 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
78 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
79 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
80 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
81 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
82 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
83
84 public class RestconfDataServiceImplTest {
85
86     private static final String PATH_FOR_NEW_SCHEMA_CONTEXT = "/jukebox";
87
88     private ContainerNode buildBaseCont;
89     private ContainerNode buildBaseContConfig;
90     private ContainerNode buildBaseContOperational;
91     private SchemaContextRef contextRef;
92     private YangInstanceIdentifier iidBase;
93     private DataSchemaNode schemaNode;
94     private RestconfDataServiceImpl dataService;
95     private QName baseQName;
96     private QName containerPlayerQname;
97     private QName leafQname;
98     private ContainerNode buildPlayerCont;
99     private ContainerNode buildLibraryCont;
100     private MapNode buildPlaylistList;
101     private TransactionChainHandler transactionChainHandler;
102
103     @Mock
104     private DOMTransactionChain domTransactionChain;
105     @Mock
106     private UriInfo uriInfo;
107     @Mock
108     private DOMDataTreeReadWriteTransaction readWrite;
109     @Mock
110     private DOMDataTreeReadTransaction read;
111     @Mock
112     private DOMDataTreeWriteTransaction write;
113     @Mock
114     private DOMMountPointService mountPointService;
115     @Mock
116     private DOMMountPoint mountPoint;
117     @Mock
118     private DOMDataBroker mountDataBroker;
119     @Mock
120     private DOMTransactionChain mountTransactionChain;
121     @Mock
122     private RestconfStreamsSubscriptionService delegRestconfSubscrService;
123
124     @Before
125     public void setUp() throws Exception {
126         MockitoAnnotations.initMocks(this);
127
128         final MultivaluedMap<String, String> value = Mockito.mock(MultivaluedMap.class);
129         Mockito.when(value.entrySet()).thenReturn(new HashSet<>());
130         Mockito.when(this.uriInfo.getQueryParameters()).thenReturn(value);
131
132         this.baseQName = QName.create("http://example.com/ns/example-jukebox", "2015-04-04", "jukebox");
133         this.containerPlayerQname = QName.create(this.baseQName, "player");
134         this.leafQname = QName.create(this.baseQName, "gap");
135
136         final QName containerLibraryQName = QName.create(this.baseQName, "library");
137         final QName listPlaylistQName = QName.create(this.baseQName, "playlist");
138
139         final LeafNode buildLeaf = Builders.leafBuilder()
140                 .withNodeIdentifier(new NodeIdentifier(this.leafQname))
141                 .withValue(0.2)
142                 .build();
143
144         this.buildPlayerCont = Builders.containerBuilder()
145                 .withNodeIdentifier(new NodeIdentifier(this.containerPlayerQname))
146                 .withChild(buildLeaf)
147                 .build();
148
149         this.buildLibraryCont = Builders.containerBuilder()
150                 .withNodeIdentifier(new NodeIdentifier(containerLibraryQName))
151                 .build();
152
153         this.buildPlaylistList = Builders.mapBuilder()
154                 .withNodeIdentifier(new NodeIdentifier(listPlaylistQName))
155                 .build();
156
157         this.buildBaseCont = Builders.containerBuilder()
158                 .withNodeIdentifier(new NodeIdentifier(this.baseQName))
159                 .withChild(this.buildPlayerCont)
160                 .build();
161
162         // config contains one child the same as in operational and one additional
163         this.buildBaseContConfig = Builders.containerBuilder()
164                 .withNodeIdentifier(new NodeIdentifier(this.baseQName))
165                 .withChild(this.buildPlayerCont)
166                 .withChild(this.buildLibraryCont)
167                 .build();
168
169         // operational contains one child the same as in config and one additional
170         this.buildBaseContOperational = Builders.containerBuilder()
171                 .withNodeIdentifier(new NodeIdentifier(this.baseQName))
172                 .withChild(this.buildPlayerCont)
173                 .withChild(this.buildPlaylistList)
174                 .build();
175
176         this.iidBase = YangInstanceIdentifier.builder()
177                 .node(this.baseQName)
178                 .build();
179
180         this.contextRef = new SchemaContextRef(
181                 YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles(PATH_FOR_NEW_SCHEMA_CONTEXT)));
182         this.schemaNode = DataSchemaContextTree.from(this.contextRef.get()).getChild(this.iidBase).getDataSchemaNode();
183
184         doReturn(CommitInfo.emptyFluentFuture()).when(this.write).commit();
185         doReturn(CommitInfo.emptyFluentFuture()).when(this.readWrite).commit();
186
187         doReturn(this.read).when(domTransactionChain).newReadOnlyTransaction();
188         doReturn(this.readWrite).when(domTransactionChain).newReadWriteTransaction();
189         doReturn(this.write).when(domTransactionChain).newWriteOnlyTransaction();
190
191         DOMDataBroker mockDataBroker = Mockito.mock(DOMDataBroker.class);
192         Mockito.doReturn(domTransactionChain).when(mockDataBroker).createTransactionChain(Mockito.any());
193
194         transactionChainHandler = new TransactionChainHandler(mockDataBroker);
195
196         final SchemaContextHandler schemaContextHandler = SchemaContextHandler.newInstance(transactionChainHandler,
197                 Mockito.mock(DOMSchemaService.class));
198
199         schemaContextHandler.onGlobalContextUpdated(this.contextRef.get());
200         this.dataService = new RestconfDataServiceImpl(schemaContextHandler, this.transactionChainHandler,
201                 DOMMountPointServiceHandler.newInstance(mountPointService), this.delegRestconfSubscrService);
202         doReturn(Optional.of(this.mountPoint)).when(this.mountPointService)
203                 .getMountPoint(any(YangInstanceIdentifier.class));
204         doReturn(this.contextRef.get()).when(this.mountPoint).getSchemaContext();
205         doReturn(Optional.of(this.mountDataBroker)).when(this.mountPoint).getService(DOMDataBroker.class);
206         doReturn(this.mountTransactionChain).when(this.mountDataBroker)
207                 .createTransactionChain(any(DOMTransactionChainListener.class));
208         doReturn(this.read).when(this.mountTransactionChain).newReadOnlyTransaction();
209         doReturn(this.readWrite).when(this.mountTransactionChain).newReadWriteTransaction();
210     }
211
212     @Test
213     public void testReadData() {
214         doReturn(new MultivaluedHashMap<String, String>()).when(this.uriInfo).getQueryParameters();
215         doReturn(immediateFluentFuture(Optional.of(this.buildBaseCont))).when(this.read)
216                 .read(LogicalDatastoreType.CONFIGURATION, this.iidBase);
217         doReturn(immediateFluentFuture(Optional.empty()))
218                 .when(this.read).read(LogicalDatastoreType.OPERATIONAL, this.iidBase);
219         final Response response = this.dataService.readData("example-jukebox:jukebox", this.uriInfo);
220         assertNotNull(response);
221         assertEquals(200, response.getStatus());
222         assertEquals(this.buildBaseCont, ((NormalizedNodeContext) response.getEntity()).getData());
223     }
224
225     @Test
226     public void testReadRootData() {
227         doReturn(new MultivaluedHashMap<String, String>()).when(this.uriInfo).getQueryParameters();
228         doReturn(immediateFluentFuture(Optional.of(wrapNodeByDataRootContainer(this.buildBaseContConfig))))
229                 .when(this.read)
230                 .read(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.EMPTY);
231         doReturn(immediateFluentFuture(Optional.of(wrapNodeByDataRootContainer(this.buildBaseContOperational))))
232                 .when(this.read)
233                 .read(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.EMPTY);
234         final Response response = this.dataService.readData(this.uriInfo);
235         assertNotNull(response);
236         assertEquals(200, response.getStatus());
237
238         final NormalizedNode<?, ?> data = ((NormalizedNodeContext) response.getEntity()).getData();
239         assertTrue(data instanceof ContainerNode);
240         final Collection<DataContainerChild<? extends PathArgument, ?>> rootNodes = ((ContainerNode) data).getValue();
241         assertEquals(1, rootNodes.size());
242         final Collection<DataContainerChild<? extends PathArgument, ?>> allDataChildren
243                 = ((ContainerNode) rootNodes.iterator().next()).getValue();
244         assertEquals(3, allDataChildren.size());
245     }
246
247     private static ContainerNode wrapNodeByDataRootContainer(final DataContainerChild<?, ?> data) {
248         return ImmutableContainerNodeBuilder.create()
249                 .withNodeIdentifier(NodeIdentifier.create(SchemaContext.NAME))
250                 .withChild(data)
251                 .build();
252     }
253
254     /**
255      * Test read data from mount point when both {@link LogicalDatastoreType#CONFIGURATION} and
256      * {@link LogicalDatastoreType#OPERATIONAL} contains the same data and some additional data to be merged.
257      */
258     @Test
259     public void testReadDataMountPoint() {
260         doReturn(new MultivaluedHashMap<String, String>()).when(this.uriInfo).getQueryParameters();
261         doReturn(immediateFluentFuture(Optional.of(this.buildBaseContConfig))).when(this.read)
262                 .read(LogicalDatastoreType.CONFIGURATION, this.iidBase);
263         doReturn(immediateFluentFuture(Optional.of(this.buildBaseContOperational))).when(this.read)
264                 .read(LogicalDatastoreType.OPERATIONAL, this.iidBase);
265
266         final Response response = this.dataService.readData(
267                 "example-jukebox:jukebox/yang-ext:mount/example-jukebox:jukebox", this.uriInfo);
268
269         assertNotNull(response);
270         assertEquals(200, response.getStatus());
271
272         // response must contain all child nodes from config and operational containers merged in one container
273         final NormalizedNode<?, ?> data = ((NormalizedNodeContext) response.getEntity()).getData();
274         assertTrue(data instanceof ContainerNode);
275         assertEquals(3, ((ContainerNode) data).getValue().size());
276         assertTrue(((ContainerNode) data).getChild(this.buildPlayerCont.getIdentifier()).isPresent());
277         assertTrue(((ContainerNode) data).getChild(this.buildLibraryCont.getIdentifier()).isPresent());
278         assertTrue(((ContainerNode) data).getChild(this.buildPlaylistList.getIdentifier()).isPresent());
279     }
280
281     @Test(expected = RestconfDocumentedException.class)
282     public void testReadDataNoData() {
283         doReturn(new MultivaluedHashMap<String, String>()).when(this.uriInfo).getQueryParameters();
284         doReturn(immediateFluentFuture(Optional.empty()))
285                 .when(this.read).read(LogicalDatastoreType.CONFIGURATION, this.iidBase);
286         doReturn(immediateFluentFuture(Optional.empty()))
287                 .when(this.read).read(LogicalDatastoreType.OPERATIONAL, this.iidBase);
288         this.dataService.readData("example-jukebox:jukebox", this.uriInfo);
289     }
290
291     /**
292      * Read data from config datastore according to content parameter.
293      */
294     @Test
295     public void testReadDataConfigTest() {
296         final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
297         parameters.put("content", Collections.singletonList("config"));
298
299         doReturn(parameters).when(this.uriInfo).getQueryParameters();
300         doReturn(immediateFluentFuture(Optional.of(this.buildBaseContConfig))).when(this.read)
301                 .read(LogicalDatastoreType.CONFIGURATION, this.iidBase);
302         doReturn(immediateFluentFuture(Optional.of(this.buildBaseContOperational))).when(this.read)
303                 .read(LogicalDatastoreType.OPERATIONAL, this.iidBase);
304
305         final Response response = this.dataService.readData("example-jukebox:jukebox", this.uriInfo);
306
307         assertNotNull(response);
308         assertEquals(200, response.getStatus());
309
310         // response must contain only config data
311         final NormalizedNode<?, ?> data = ((NormalizedNodeContext) response.getEntity()).getData();
312
313         // config data present
314         assertTrue(((ContainerNode) data).getChild(this.buildPlayerCont.getIdentifier()).isPresent());
315         assertTrue(((ContainerNode) data).getChild(this.buildLibraryCont.getIdentifier()).isPresent());
316
317         // state data absent
318         assertFalse(((ContainerNode) data).getChild(this.buildPlaylistList.getIdentifier()).isPresent());
319     }
320
321     /**
322      * Read data from operational datastore according to content parameter.
323      */
324     @Test
325     public void testReadDataOperationalTest() {
326         final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
327         parameters.put("content", Collections.singletonList("nonconfig"));
328
329         doReturn(parameters).when(this.uriInfo).getQueryParameters();
330         doReturn(immediateFluentFuture(Optional.of(this.buildBaseContConfig))).when(this.read)
331                 .read(LogicalDatastoreType.CONFIGURATION, this.iidBase);
332         doReturn(immediateFluentFuture(Optional.of(this.buildBaseContOperational))).when(this.read)
333                 .read(LogicalDatastoreType.OPERATIONAL, this.iidBase);
334
335         final Response response = this.dataService.readData("example-jukebox:jukebox", this.uriInfo);
336
337         assertNotNull(response);
338         assertEquals(200, response.getStatus());
339
340         // response must contain only operational data
341         final NormalizedNode<?, ?> data = ((NormalizedNodeContext) response.getEntity()).getData();
342
343         // state data present
344         assertTrue(((ContainerNode) data).getChild(this.buildPlayerCont.getIdentifier()).isPresent());
345         assertTrue(((ContainerNode) data).getChild(this.buildPlaylistList.getIdentifier()).isPresent());
346
347         // config data absent
348         assertFalse(((ContainerNode) data).getChild(this.buildLibraryCont.getIdentifier()).isPresent());
349     }
350
351     @Test
352     public void testPutData() {
353         final InstanceIdentifierContext<DataSchemaNode> iidContext =
354                 new InstanceIdentifierContext<>(this.iidBase, this.schemaNode, null, this.contextRef.get());
355         final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildBaseCont);
356
357         doReturn(immediateTrueFluentFuture()).when(this.readWrite)
358                 .exists(LogicalDatastoreType.CONFIGURATION, this.iidBase);
359         doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION, this.iidBase, payload.getData());
360         final Response response = this.dataService.putData(null, payload, this.uriInfo);
361         assertNotNull(response);
362         assertEquals(Response.Status.NO_CONTENT.getStatusCode(), response.getStatus());
363     }
364
365     @Test
366     public void testPutDataWithMountPoint() {
367 //        final DOMDataBroker dataBroker = Mockito.mock(DOMDataBroker.class);
368 //        doReturn(Optional.of(dataBroker)).when(mountPoint).getService(DOMDataBroker.class);
369 //        doReturn(this.transactionChainHandler.get()).when(dataBroker)
370 //                .createTransactionChain(RestConnectorProvider.TRANSACTION_CHAIN_LISTENER);
371         final InstanceIdentifierContext<DataSchemaNode> iidContext =
372                 new InstanceIdentifierContext<>(this.iidBase, this.schemaNode, mountPoint, this.contextRef.get());
373         final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildBaseCont);
374
375         doReturn(immediateTrueFluentFuture()).when(this.readWrite)
376                 .exists(LogicalDatastoreType.CONFIGURATION, this.iidBase);
377         doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION, this.iidBase, payload.getData());
378         final Response response = this.dataService.putData(null, payload, this.uriInfo);
379         assertNotNull(response);
380         assertEquals(Response.Status.NO_CONTENT.getStatusCode(), response.getStatus());
381     }
382
383     @Test
384     public void testPostData() {
385         final QName listQname = QName.create(this.baseQName, "playlist");
386         final QName listKeyQname = QName.create(this.baseQName, "name");
387         final NodeIdentifierWithPredicates nodeWithKey =
388                 NodeIdentifierWithPredicates.of(listQname, listKeyQname, "name of band");
389         final LeafNode<Object> content = Builders.leafBuilder()
390                 .withNodeIdentifier(new NodeIdentifier(QName.create(this.baseQName, "name")))
391                 .withValue("name of band")
392                 .build();
393         final LeafNode<Object> content2 = Builders.leafBuilder()
394             .withNodeIdentifier(new NodeIdentifier(QName.create(this.baseQName, "description")))
395             .withValue("band description")
396             .build();
397         final MapEntryNode mapEntryNode = Builders.mapEntryBuilder()
398                 .withNodeIdentifier(nodeWithKey)
399                 .withChild(content)
400                 .withChild(content2)
401                 .build();
402         final MapNode buildList = Builders.mapBuilder()
403                 .withNodeIdentifier(new NodeIdentifier(listQname))
404                 .withChild(mapEntryNode)
405                 .build();
406
407         doReturn(new MultivaluedHashMap<String, String>()).when(this.uriInfo).getQueryParameters();
408         final InstanceIdentifierContext<? extends SchemaNode> iidContext =
409                 new InstanceIdentifierContext<>(this.iidBase, null, null, this.contextRef.get());
410         final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, buildList);
411         doReturn(immediateFluentFuture(Optional.empty()))
412                 .when(this.read).read(LogicalDatastoreType.CONFIGURATION, this.iidBase);
413         final MapNode data = (MapNode) payload.getData();
414         final NodeIdentifierWithPredicates identifier =
415                 data.getValue().iterator().next().getIdentifier();
416         final YangInstanceIdentifier node =
417                 payload.getInstanceIdentifierContext().getInstanceIdentifier().node(identifier);
418         doReturn(immediateFalseFluentFuture())
419                 .when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, node);
420         doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION, node, payload.getData());
421         doReturn(UriBuilder.fromUri("http://localhost:8181/restconf/15/")).when(this.uriInfo).getBaseUriBuilder();
422
423         final Response response = this.dataService.postData(null, payload, this.uriInfo);
424         assertEquals(201, response.getStatus());
425     }
426
427     @Test
428     public void testDeleteData() {
429         doNothing().when(this.readWrite).delete(LogicalDatastoreType.CONFIGURATION, this.iidBase);
430         doReturn(immediateTrueFluentFuture())
431                 .when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, this.iidBase);
432         final Response response = this.dataService.deleteData("example-jukebox:jukebox");
433         assertNotNull(response);
434         assertEquals(Response.Status.NO_CONTENT.getStatusCode(), response.getStatus());
435     }
436
437     /**
438      * Test of deleting data on mount point.
439      */
440     @Test
441     public void testDeleteDataMountPoint() {
442         doNothing().when(this.readWrite).delete(LogicalDatastoreType.CONFIGURATION, this.iidBase);
443         doReturn(immediateTrueFluentFuture())
444                 .when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, this.iidBase);
445         final Response response =
446                 this.dataService.deleteData("example-jukebox:jukebox/yang-ext:mount/example-jukebox:jukebox");
447         assertNotNull(response);
448         assertEquals(Response.Status.NO_CONTENT.getStatusCode(), response.getStatus());
449     }
450
451     @Test
452     public void testPatchData() throws Exception {
453         final InstanceIdentifierContext<? extends SchemaNode> iidContext =
454                 new InstanceIdentifierContext<>(this.iidBase, this.schemaNode, null, this.contextRef.get());
455         final List<PatchEntity> entity = new ArrayList<>();
456         final YangInstanceIdentifier iidleaf = YangInstanceIdentifier.builder(this.iidBase)
457                 .node(this.containerPlayerQname)
458                 .node(this.leafQname)
459                 .build();
460         entity.add(new PatchEntity("create data", CREATE, this.iidBase, this.buildBaseCont));
461         entity.add(new PatchEntity("replace data", REPLACE, this.iidBase, this.buildBaseCont));
462         entity.add(new PatchEntity("delete data", DELETE, iidleaf));
463         final PatchContext patch = new PatchContext(iidContext, entity, "test patch id");
464
465         doReturn(immediateFluentFuture(Optional.of(this.buildBaseCont))).when(this.read)
466                 .read(LogicalDatastoreType.CONFIGURATION, this.iidBase);
467         doNothing().when(this.write).put(LogicalDatastoreType.CONFIGURATION, this.iidBase, this.buildBaseCont);
468         doNothing().when(this.readWrite).delete(LogicalDatastoreType.CONFIGURATION, iidleaf);
469         doReturn(immediateFalseFluentFuture())
470                 .when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, this.iidBase);
471         doReturn(immediateTrueFluentFuture())
472                 .when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, iidleaf);
473         final PatchStatusContext status = this.dataService.patchData(patch, this.uriInfo);
474         assertTrue(status.isOk());
475         assertEquals(3, status.getEditCollection().size());
476         assertEquals("replace data", status.getEditCollection().get(1).getEditId());
477     }
478
479     @Test
480     public void testPatchDataMountPoint() throws Exception {
481         final InstanceIdentifierContext<? extends SchemaNode> iidContext = new InstanceIdentifierContext<>(
482                 this.iidBase, this.schemaNode, this.mountPoint, this.contextRef.get());
483         final List<PatchEntity> entity = new ArrayList<>();
484         final YangInstanceIdentifier iidleaf = YangInstanceIdentifier.builder(this.iidBase)
485                 .node(this.containerPlayerQname)
486                 .node(this.leafQname)
487                 .build();
488         entity.add(new PatchEntity("create data", CREATE, this.iidBase, this.buildBaseCont));
489         entity.add(new PatchEntity("replace data", REPLACE, this.iidBase, this.buildBaseCont));
490         entity.add(new PatchEntity("delete data", DELETE, iidleaf));
491         final PatchContext patch = new PatchContext(iidContext, entity, "test patch id");
492
493         doReturn(immediateFluentFuture(Optional.of(this.buildBaseCont))).when(this.read)
494                 .read(LogicalDatastoreType.CONFIGURATION, this.iidBase);
495         doNothing().when(this.write).put(LogicalDatastoreType.CONFIGURATION, this.iidBase, this.buildBaseCont);
496         doNothing().when(this.readWrite).delete(LogicalDatastoreType.CONFIGURATION, iidleaf);
497         doReturn(immediateFalseFluentFuture())
498                 .when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, this.iidBase);
499         doReturn(immediateTrueFluentFuture()).when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, iidleaf);
500
501         final PatchStatusContext status = this.dataService.patchData(patch, this.uriInfo);
502         assertTrue(status.isOk());
503         assertEquals(3, status.getEditCollection().size());
504         assertNull(status.getGlobalErrors());
505     }
506
507     @Test
508     public void testPatchDataDeleteNotExist() throws Exception {
509         final InstanceIdentifierContext<? extends SchemaNode> iidContext =
510                 new InstanceIdentifierContext<>(this.iidBase, this.schemaNode, null, this.contextRef.get());
511         final List<PatchEntity> entity = new ArrayList<>();
512         final YangInstanceIdentifier iidleaf = YangInstanceIdentifier.builder(this.iidBase)
513                 .node(this.containerPlayerQname)
514                 .node(this.leafQname)
515                 .build();
516         entity.add(new PatchEntity("create data", CREATE, this.iidBase, this.buildBaseCont));
517         entity.add(new PatchEntity("remove data", REMOVE, iidleaf));
518         entity.add(new PatchEntity("delete data", DELETE, iidleaf));
519         final PatchContext patch = new PatchContext(iidContext, entity, "test patch id");
520
521         doReturn(immediateFluentFuture(Optional.of(this.buildBaseCont))).when(this.read)
522                 .read(LogicalDatastoreType.CONFIGURATION, this.iidBase);
523         doNothing().when(this.write).put(LogicalDatastoreType.CONFIGURATION, this.iidBase, this.buildBaseCont);
524         doNothing().when(this.readWrite).delete(LogicalDatastoreType.CONFIGURATION, iidleaf);
525         doReturn(immediateFalseFluentFuture())
526                 .when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, this.iidBase);
527         doReturn(immediateFalseFluentFuture())
528                 .when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, iidleaf);
529         doReturn(true).when(this.readWrite).cancel();
530         final PatchStatusContext status = this.dataService.patchData(patch, this.uriInfo);
531
532         assertFalse(status.isOk());
533         assertEquals(3, status.getEditCollection().size());
534         assertTrue(status.getEditCollection().get(0).isOk());
535         assertTrue(status.getEditCollection().get(1).isOk());
536         assertFalse(status.getEditCollection().get(2).isOk());
537         assertFalse(status.getEditCollection().get(2).getEditErrors().isEmpty());
538         final String errorMessage = status.getEditCollection().get(2).getEditErrors().get(0).getErrorMessage();
539         assertEquals("Data does not exist", errorMessage);
540     }
541 }