Create NetconfDataTreeService with base and additional operations for netconf
[netconf.git] / restconf / restconf-nb-rfc8040 / src / test / java / org / opendaylight / restconf / nb / rfc8040 / rests / utils / PutDataTransactionUtilTest.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.utils;
9
10 import static org.mockito.Mockito.doNothing;
11 import static org.mockito.Mockito.doReturn;
12 import static org.mockito.Mockito.mock;
13 import static org.mockito.Mockito.verify;
14 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFalseFluentFuture;
15 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
16
17 import java.util.Optional;
18 import org.junit.Before;
19 import org.junit.Test;
20 import org.mockito.Mock;
21 import org.mockito.Mockito;
22 import org.mockito.MockitoAnnotations;
23 import org.opendaylight.mdsal.common.api.CommitInfo;
24 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
25 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
26 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
27 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
28 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
29 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
30 import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
31 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
32 import org.opendaylight.restconf.common.context.NormalizedNodeContext;
33 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
34 import org.opendaylight.restconf.nb.rfc8040.TestRestconfUtils;
35 import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
36 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.MdsalRestconfStrategy;
37 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.NetconfRestconfStrategy;
38 import org.opendaylight.yangtools.yang.common.QName;
39 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
40 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
41 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
42 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
43 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
44 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
45 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
46 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
47 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
48 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
49 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
50 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
51 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
52
53 public class PutDataTransactionUtilTest {
54     private static final String PATH_FOR_NEW_SCHEMA_CONTEXT = "/jukebox";
55     @Mock
56     private DOMTransactionChain transactionChain;
57     @Mock
58     private DOMDataTreeReadWriteTransaction readWrite;
59     @Mock
60     private DOMDataTreeReadTransaction read;
61     @Mock
62     private DOMDataTreeWriteTransaction write;
63     @Mock
64     private DOMDataBroker mockDataBroker;
65     @Mock
66     private NetconfDataTreeService netconfService;
67
68     private TransactionChainHandler transactionChainHandler;
69     private LeafNode<?> buildLeaf;
70     private ContainerNode buildBaseCont;
71     private ContainerNode buildBaseContWithList;
72     private MapEntryNode buildListEntry;
73     private EffectiveModelContext schema;
74     private DataSchemaNode schemaNode;
75     private YangInstanceIdentifier iid;
76     private DataSchemaNode schemaNode2;
77     private YangInstanceIdentifier iid2;
78     private DataSchemaNode schemaNode3;
79     private YangInstanceIdentifier iid3;
80
81     @Before
82     public void setUp() throws Exception {
83         MockitoAnnotations.initMocks(this);
84         this.schema =
85                 YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles(PATH_FOR_NEW_SCHEMA_CONTEXT));
86
87         final QName baseQName = QName.create("http://example.com/ns/example-jukebox", "2015-04-04", "jukebox");
88         final QName containerQname = QName.create(baseQName, "player");
89         final QName leafQname = QName.create(baseQName, "gap");
90         final QName listQname = QName.create(baseQName, "playlist");
91         final QName listKeyQname = QName.create(baseQName, "name");
92
93         final NodeIdentifierWithPredicates nodeWithKey =
94                 NodeIdentifierWithPredicates.of(listQname, listKeyQname, "name of band");
95         final NodeIdentifierWithPredicates nodeWithKey2 =
96                 NodeIdentifierWithPredicates.of(listQname, listKeyQname, "name of band 2");
97
98         this.iid = YangInstanceIdentifier.builder()
99                 .node(baseQName)
100                 .node(containerQname)
101                 .node(leafQname)
102                 .build();
103         this.schemaNode = DataSchemaContextTree.from(this.schema).getChild(this.iid).getDataSchemaNode();
104
105         this.iid2 = YangInstanceIdentifier.builder()
106                 .node(baseQName)
107                 .build();
108         this.schemaNode2 = DataSchemaContextTree.from(this.schema).getChild(this.iid2).getDataSchemaNode();
109
110         this.iid3 = YangInstanceIdentifier.builder()
111                 .node(baseQName)
112                 .node(listQname)
113                 .node(nodeWithKey)
114                 .build();
115         this.schemaNode3 = DataSchemaContextTree.from(this.schema).getChild(this.iid3).getDataSchemaNode();
116
117         this.buildLeaf = Builders.leafBuilder()
118                 .withNodeIdentifier(new NodeIdentifier(leafQname))
119                 .withValue(0.2)
120                 .build();
121         final ContainerNode buildPlayerCont = Builders.containerBuilder()
122                 .withNodeIdentifier(new NodeIdentifier(containerQname))
123                 .withChild(this.buildLeaf)
124                 .build();
125         this.buildBaseCont = Builders.containerBuilder()
126                 .withNodeIdentifier(new NodeIdentifier(baseQName))
127                 .withChild(buildPlayerCont)
128                 .build();
129         final LeafNode<Object> content = Builders.leafBuilder()
130                 .withNodeIdentifier(new NodeIdentifier(QName.create(baseQName, "name")))
131                 .withValue("name of band")
132                 .build();
133         final LeafNode<Object> content2 = Builders.leafBuilder()
134                 .withNodeIdentifier(new NodeIdentifier(QName.create(baseQName, "description")))
135                 .withValue("band description")
136                 .build();
137         this.buildListEntry = Builders.mapEntryBuilder()
138                 .withNodeIdentifier(nodeWithKey)
139                 .withChild(content)
140                 .withChild(content2)
141                 .build();
142         final LeafNode<Object> content3 = Builders.leafBuilder()
143                 .withNodeIdentifier(new NodeIdentifier(QName.create(baseQName, "name")))
144                 .withValue("name of band 2")
145                 .build();
146         final LeafNode<Object> content4 = Builders.leafBuilder()
147                 .withNodeIdentifier(new NodeIdentifier(QName.create(baseQName, "description")))
148                 .withValue("band description 2")
149                 .build();
150         final MapEntryNode buildListEntry2 = Builders.mapEntryBuilder()
151                 .withNodeIdentifier(nodeWithKey2)
152                 .withChild(content3)
153                 .withChild(content4)
154                 .build();
155         final MapNode buildList = Builders.mapBuilder()
156                 .withNodeIdentifier(new NodeIdentifier(listQname))
157                 .withChild(this.buildListEntry)
158                 .withChild(buildListEntry2)
159                 .build();
160         this.buildBaseContWithList = Builders.containerBuilder()
161                 .withNodeIdentifier(new NodeIdentifier(baseQName))
162                 .withChild(buildList)
163                 .build();
164
165         Mockito.doReturn(transactionChain).when(mockDataBroker).createTransactionChain(Mockito.any());
166         transactionChainHandler = new TransactionChainHandler(mockDataBroker);
167     }
168
169     @Test
170     public void testValidInputData() {
171         final InstanceIdentifierContext<DataSchemaNode> iidContext =
172                 new InstanceIdentifierContext<>(this.iid, this.schemaNode, null, this.schema);
173         final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildLeaf);
174         PutDataTransactionUtil.validInputData(iidContext.getSchemaNode(), payload);
175     }
176
177     @Test
178     public void testValidTopLevelNodeName() {
179         InstanceIdentifierContext<DataSchemaNode> iidContext =
180                 new InstanceIdentifierContext<>(this.iid, this.schemaNode, null, this.schema);
181         NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildLeaf);
182         PutDataTransactionUtil.validTopLevelNodeName(iidContext.getInstanceIdentifier(), payload);
183
184         iidContext = new InstanceIdentifierContext<>(this.iid2, this.schemaNode2, null, this.schema);
185         payload = new NormalizedNodeContext(iidContext, this.buildBaseCont);
186         PutDataTransactionUtil.validTopLevelNodeName(iidContext.getInstanceIdentifier(), payload);
187     }
188
189     @Test(expected = RestconfDocumentedException.class)
190     public void testValidTopLevelNodeNamePathEmpty() {
191         final InstanceIdentifierContext<DataSchemaNode> iidContext =
192                 new InstanceIdentifierContext<>(this.iid, this.schemaNode, null, this.schema);
193         final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildLeaf);
194         PutDataTransactionUtil.validTopLevelNodeName(YangInstanceIdentifier.empty(), payload);
195     }
196
197     @Test(expected = RestconfDocumentedException.class)
198     public void testValidTopLevelNodeNameWrongTopIdentifier() {
199         final InstanceIdentifierContext<DataSchemaNode> iidContext =
200                 new InstanceIdentifierContext<>(this.iid, this.schemaNode, null, this.schema);
201         final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildLeaf);
202         PutDataTransactionUtil.validTopLevelNodeName(this.iid.getAncestor(1), payload);
203     }
204
205     @Test
206     public void testValidateListKeysEqualityInPayloadAndUri() {
207         final InstanceIdentifierContext<DataSchemaNode> iidContext =
208                 new InstanceIdentifierContext<>(this.iid3, this.schemaNode3, null, this.schema);
209         final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildListEntry);
210         PutDataTransactionUtil.validateListKeysEqualityInPayloadAndUri(payload);
211     }
212
213     @Test
214     public void testPutContainerData() {
215         final InstanceIdentifierContext<DataSchemaNode> iidContext =
216                 new InstanceIdentifierContext<>(this.iid2, this.schemaNode2, null, this.schema);
217         final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildBaseCont);
218
219         doReturn(this.readWrite).when(this.transactionChain).newReadWriteTransaction();
220         doReturn(this.read).when(this.transactionChain).newReadOnlyTransaction();
221         doReturn(this.write).when(this.transactionChain).newWriteOnlyTransaction();
222         doReturn(immediateFalseFluentFuture())
223                 .when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, this.iid2);
224         doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION,
225                 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
226         doReturn(CommitInfo.emptyFluentFuture()).when(this.readWrite).commit();
227
228         PutDataTransactionUtil.putData(payload, this.schema,
229                 new MdsalRestconfStrategy(iidContext, transactionChainHandler), null, null);
230         verify(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION,
231                 payload.getInstanceIdentifierContext().getInstanceIdentifier());
232         verify(this.readWrite).put(LogicalDatastoreType.CONFIGURATION,
233                 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
234     }
235
236     @Test
237     public void testPutCreateContainerData() {
238         final InstanceIdentifierContext<DataSchemaNode> iidContext =
239                 new InstanceIdentifierContext<>(this.iid2, this.schemaNode2, null, this.schema);
240         final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildBaseCont);
241
242         doReturn(immediateFluentFuture(Optional.empty())).when(this.netconfService).getConfig(this.iid2);
243         doReturn(CommitInfo.emptyFluentFuture()).when(this.netconfService).commit(Mockito.any());
244
245         PutDataTransactionUtil.putData(payload, this.schema,
246                 new NetconfRestconfStrategy(netconfService, iidContext), null, null);
247         verify(this.netconfService).getConfig(payload.getInstanceIdentifierContext().getInstanceIdentifier());
248         verify(this.netconfService).create(LogicalDatastoreType.CONFIGURATION,
249                 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(), Optional.empty());
250     }
251
252     @Test
253     public void testPutReplaceContainerData() {
254         final InstanceIdentifierContext<DataSchemaNode> iidContext =
255                 new InstanceIdentifierContext<>(this.iid2, this.schemaNode2, null, this.schema);
256         final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildBaseCont);
257
258         doReturn(immediateFluentFuture(Optional.of(mock(NormalizedNode.class))))
259                 .when(this.netconfService).getConfig(this.iid2);
260         doReturn(CommitInfo.emptyFluentFuture()).when(this.netconfService).commit(Mockito.any());
261
262         PutDataTransactionUtil.putData(payload, this.schema,
263                 new NetconfRestconfStrategy(netconfService, iidContext), null, null);
264         verify(this.netconfService).getConfig(payload.getInstanceIdentifierContext().getInstanceIdentifier());
265         verify(this.netconfService).replace(LogicalDatastoreType.CONFIGURATION,
266                 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(), Optional.empty());
267     }
268
269     @Test
270     public void testPutLeafData() {
271         final InstanceIdentifierContext<DataSchemaNode> iidContext =
272                 new InstanceIdentifierContext<>(this.iid, this.schemaNode, null, this.schema);
273         final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildLeaf);
274
275         doReturn(this.readWrite).when(this.transactionChain).newReadWriteTransaction();
276         doReturn(this.read).when(this.transactionChain).newReadOnlyTransaction();
277         doReturn(this.write).when(this.transactionChain).newWriteOnlyTransaction();
278         doReturn(immediateFalseFluentFuture())
279                 .when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, this.iid);
280         doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION,
281                 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
282         doReturn(CommitInfo.emptyFluentFuture()).when(this.readWrite).commit();
283
284         PutDataTransactionUtil.putData(payload, this.schema,
285                 new MdsalRestconfStrategy(iidContext, transactionChainHandler), null, null);
286         verify(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION,
287                 payload.getInstanceIdentifierContext().getInstanceIdentifier());
288         verify(this.readWrite).put(LogicalDatastoreType.CONFIGURATION,
289                 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
290     }
291
292     @Test
293     public void testPutCreateLeafData() {
294         final InstanceIdentifierContext<DataSchemaNode> iidContext =
295                 new InstanceIdentifierContext<>(this.iid, this.schemaNode, null, this.schema);
296         final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildLeaf);
297
298         doReturn(immediateFluentFuture(Optional.empty())).when(this.netconfService).getConfig(this.iid);
299         doReturn(CommitInfo.emptyFluentFuture()).when(this.netconfService).commit(Mockito.any());
300
301         PutDataTransactionUtil.putData(payload, this.schema,
302                 new NetconfRestconfStrategy(netconfService, iidContext), null, null);
303         verify(this.netconfService).getConfig(payload.getInstanceIdentifierContext().getInstanceIdentifier());
304         verify(this.netconfService).create(LogicalDatastoreType.CONFIGURATION,
305                 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(), Optional.empty());
306     }
307
308     @Test
309     public void testPutReplaceLeafData() {
310         final InstanceIdentifierContext<DataSchemaNode> iidContext =
311                 new InstanceIdentifierContext<>(this.iid, this.schemaNode, null, this.schema);
312         final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildLeaf);
313
314         doReturn(immediateFluentFuture(Optional.of(mock(NormalizedNode.class))))
315                 .when(this.netconfService).getConfig(this.iid);
316         doReturn(CommitInfo.emptyFluentFuture()).when(this.netconfService).commit(Mockito.any());
317
318         PutDataTransactionUtil.putData(payload, this.schema,
319                 new NetconfRestconfStrategy(netconfService, iidContext), null, null);
320         verify(this.netconfService).getConfig(payload.getInstanceIdentifierContext().getInstanceIdentifier());
321         verify(this.netconfService).replace(LogicalDatastoreType.CONFIGURATION,
322                 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(), Optional.empty());
323     }
324
325     @Test
326     public void testPutListData() {
327         final InstanceIdentifierContext<DataSchemaNode> iidContext =
328                 new InstanceIdentifierContext<>(this.iid2, this.schemaNode2, null, this.schema);
329         final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildBaseContWithList);
330
331         doReturn(this.readWrite).when(this.transactionChain).newReadWriteTransaction();
332         doReturn(this.read).when(this.transactionChain).newReadOnlyTransaction();
333         doReturn(this.write).when(this.transactionChain).newWriteOnlyTransaction();
334         doReturn(immediateFalseFluentFuture())
335                 .when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, this.iid2);
336         doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION,
337                 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
338         doReturn(CommitInfo.emptyFluentFuture()).when(this.readWrite).commit();
339         PutDataTransactionUtil.putData(payload, this.schema,
340                 new MdsalRestconfStrategy(iidContext, transactionChainHandler), null, null);
341         verify(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, this.iid2);
342         verify(this.readWrite).put(LogicalDatastoreType.CONFIGURATION, this.iid2, payload.getData());
343     }
344
345     @Test
346     public void testPutCreateListData() {
347         final InstanceIdentifierContext<DataSchemaNode> iidContext =
348                 new InstanceIdentifierContext<>(this.iid2, this.schemaNode2, null, this.schema);
349         final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildBaseContWithList);
350
351         doReturn(immediateFluentFuture(Optional.empty())).when(this.netconfService)
352                 .getConfig(this.iid2);
353         doReturn(CommitInfo.emptyFluentFuture()).when(this.netconfService).commit(Mockito.any());
354
355         PutDataTransactionUtil.putData(payload, this.schema,
356                 new NetconfRestconfStrategy(netconfService, iidContext), null, null);
357         verify(this.netconfService).getConfig(this.iid2);
358         verify(this.netconfService).create(LogicalDatastoreType.CONFIGURATION, this.iid2,
359                 payload.getData(), Optional.empty());
360     }
361
362     @Test
363     public void testPutReplaceListData() {
364         final InstanceIdentifierContext<DataSchemaNode> iidContext =
365                 new InstanceIdentifierContext<>(this.iid2, this.schemaNode2, null, this.schema);
366         final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildBaseContWithList);
367
368         doReturn(immediateFluentFuture(Optional.of(mock(NormalizedNode.class)))).when(this.netconfService)
369                 .getConfig(this.iid2);
370         doReturn(CommitInfo.emptyFluentFuture()).when(this.netconfService).commit(Mockito.any());
371
372         PutDataTransactionUtil.putData(payload, this.schema,
373                 new NetconfRestconfStrategy(netconfService, iidContext), null, null);
374         verify(this.netconfService).getConfig(this.iid2);
375         verify(this.netconfService).replace(LogicalDatastoreType.CONFIGURATION, this.iid2,
376                 payload.getData(), Optional.empty());
377     }
378 }