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 / PlainPatchDataTransactionUtilTest.java
1 /*
2  * Copyright (c) 2020 Lumina Networks, Inc. and others. All rights reserved.
3  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
4  *
5  * This program and the accompanying materials are made available under the
6  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7  * and is available at http://www.eclipse.org/legal/epl-v10.html
8  */
9 package org.opendaylight.restconf.nb.rfc8040.rests.utils;
10
11 import static org.mockito.Mockito.doNothing;
12 import static org.mockito.Mockito.doReturn;
13 import static org.mockito.Mockito.verify;
14 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFalseFluentFuture;
15
16 import java.util.Optional;
17 import org.junit.Before;
18 import org.junit.Test;
19 import org.mockito.Mock;
20 import org.mockito.Mockito;
21 import org.mockito.MockitoAnnotations;
22 import org.opendaylight.mdsal.common.api.CommitInfo;
23 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
24 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
25 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
26 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
27 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
28 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
29 import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
30 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
31 import org.opendaylight.restconf.common.context.NormalizedNodeContext;
32 import org.opendaylight.restconf.nb.rfc8040.TestRestconfUtils;
33 import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
34 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.MdsalRestconfStrategy;
35 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.NetconfRestconfStrategy;
36 import org.opendaylight.yangtools.yang.common.QName;
37 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
38 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
39 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
40 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
41 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
42 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
43 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
44 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
45 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
46 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
47 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
48 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
49
50 public class PlainPatchDataTransactionUtilTest {
51     private static final String PATH_FOR_NEW_SCHEMA_CONTEXT = "/jukebox";
52     @Mock
53     private DOMTransactionChain transactionChain;
54     @Mock
55     private DOMDataTreeReadWriteTransaction readWrite;
56     @Mock
57     private DOMDataTreeReadTransaction read;
58     @Mock
59     private DOMDataTreeWriteTransaction write;
60     @Mock
61     private DOMDataBroker mockDataBroker;
62     @Mock
63     private NetconfDataTreeService netconfService;
64
65     private TransactionChainHandler transactionChainHandler;
66     private LeafNode<?> leafGap;
67     private ContainerNode jukeboxContainerWithPlayer;
68     private ContainerNode jukeboxContainerWithPlaylist;
69     private EffectiveModelContext schema;
70     private DataSchemaNode schemaNodeForGap;
71     private YangInstanceIdentifier iidGap;
72     private DataSchemaNode schemaNodeForJukebox;
73     private YangInstanceIdentifier iidJukebox;
74
75     @Before
76     public void setUp() throws Exception {
77         MockitoAnnotations.initMocks(this);
78         this.schema = YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles(PATH_FOR_NEW_SCHEMA_CONTEXT));
79
80         final QName qnJukebox = QName.create("http://example.com/ns/example-jukebox", "2015-04-04", "jukebox");
81         final QName qnPlayer = QName.create(qnJukebox, "player");
82         final QName qnGap = QName.create(qnJukebox, "gap");
83         final QName qnPlaylist = QName.create(qnJukebox, "playlist");
84         final QName qnPlaylistKey = QName.create(qnJukebox, "name");
85
86         final NodeIdentifierWithPredicates nidBandA =
87                 NodeIdentifierWithPredicates.of(qnPlaylist, qnPlaylistKey, "MyFavoriteBand-A");
88         final NodeIdentifierWithPredicates nidBandB =
89                 NodeIdentifierWithPredicates.of(qnPlaylist, qnPlaylistKey, "MyFavoriteBand-B");
90
91         this.iidGap = YangInstanceIdentifier.builder()
92                 .node(qnJukebox)
93                 .node(qnPlayer)
94                 .node(qnGap)
95                 .build();
96         this.schemaNodeForGap = DataSchemaContextTree.from(this.schema).getChild(this.iidGap).getDataSchemaNode();
97
98         this.iidJukebox = YangInstanceIdentifier.builder()
99                 .node(qnJukebox)
100                 .build();
101         this.schemaNodeForJukebox = DataSchemaContextTree.from(this.schema)
102                 .getChild(this.iidJukebox).getDataSchemaNode();
103
104         this.leafGap = Builders.leafBuilder()
105                 .withNodeIdentifier(new NodeIdentifier(qnGap))
106                 .withValue(0.2)
107                 .build();
108         final ContainerNode playerContainer = Builders.containerBuilder()
109                 .withNodeIdentifier(new NodeIdentifier(qnPlayer))
110                 .withChild(this.leafGap)
111                 .build();
112         this.jukeboxContainerWithPlayer = Builders.containerBuilder()
113                 .withNodeIdentifier(new NodeIdentifier(qnJukebox))
114                 .withChild(playerContainer)
115                 .build();
116
117         // ----------
118
119         final LeafNode<Object> leafBandA = Builders.leafBuilder()
120                 .withNodeIdentifier(new NodeIdentifier(QName.create(qnJukebox, "name")))
121                 .withValue("MyFavoriteBand-A")
122                 .build();
123         final LeafNode<Object> leafDescriptionA = Builders.leafBuilder()
124                 .withNodeIdentifier(new NodeIdentifier(QName.create(qnJukebox, "description")))
125                 .withValue("band description A")
126                 .build();
127         final MapEntryNode entryBandA = Builders.mapEntryBuilder()
128                 .withNodeIdentifier(nidBandA)
129                 .withChild(leafBandA)
130                 .withChild(leafDescriptionA)
131                 .build();
132
133         final LeafNode<Object> leafBandB = Builders.leafBuilder()
134                 .withNodeIdentifier(new NodeIdentifier(QName.create(qnJukebox, "name")))
135                 .withValue("MyFavoriteBand-B")
136                 .build();
137         final LeafNode<Object> leafDescriptionB = Builders.leafBuilder()
138                 .withNodeIdentifier(new NodeIdentifier(QName.create(qnJukebox, "description")))
139                 .withValue("band description B")
140                 .build();
141         final MapEntryNode entryBandB = Builders.mapEntryBuilder()
142                 .withNodeIdentifier(nidBandB)
143                 .withChild(leafBandB)
144                 .withChild(leafDescriptionB)
145                 .build();
146
147         final MapNode listBands = Builders.mapBuilder()
148                 .withNodeIdentifier(new NodeIdentifier(qnPlaylist))
149                 .withChild(entryBandA)
150                 .withChild(entryBandB)
151                 .build();
152         this.jukeboxContainerWithPlaylist = Builders.containerBuilder()
153                 .withNodeIdentifier(new NodeIdentifier(qnJukebox))
154                 .withChild(listBands)
155                 .build();
156
157         Mockito.doReturn(transactionChain).when(mockDataBroker).createTransactionChain(Mockito.any());
158         transactionChainHandler = new TransactionChainHandler(mockDataBroker);
159     }
160
161     @Test
162     public void testPatchContainerData() {
163         final InstanceIdentifierContext<DataSchemaNode> iidContext =
164                 new InstanceIdentifierContext<>(this.iidJukebox, this.schemaNodeForJukebox, null, this.schema);
165         final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.jukeboxContainerWithPlayer);
166
167         doReturn(this.readWrite).when(this.transactionChain).newReadWriteTransaction();
168         doReturn(this.read).when(this.transactionChain).newReadOnlyTransaction();
169         doReturn(this.write).when(this.transactionChain).newWriteOnlyTransaction();
170         doReturn(immediateFalseFluentFuture())
171                 .when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, this.iidJukebox);
172         doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION,
173                 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
174         doReturn(CommitInfo.emptyFluentFuture()).when(this.readWrite).commit();
175         doReturn(CommitInfo.emptyFluentFuture()).when(this.netconfService).commit(Mockito.any());
176
177         PlainPatchDataTransactionUtil.patchData(payload,
178                 new MdsalRestconfStrategy(iidContext, transactionChainHandler),
179                 this.schema);
180         verify(this.readWrite).merge(LogicalDatastoreType.CONFIGURATION,
181                 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
182
183         PlainPatchDataTransactionUtil.patchData(payload,
184                 new NetconfRestconfStrategy(netconfService, iidContext),
185                 this.schema);
186         verify(this.netconfService).merge(LogicalDatastoreType.CONFIGURATION,
187                 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(), Optional.empty());
188     }
189
190     @Test
191     public void testPatchLeafData() {
192         final InstanceIdentifierContext<DataSchemaNode> iidContext =
193                 new InstanceIdentifierContext<>(this.iidGap, this.schemaNodeForGap, null, this.schema);
194         final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.leafGap);
195
196         doReturn(this.readWrite).when(this.transactionChain).newReadWriteTransaction();
197         doReturn(this.read).when(this.transactionChain).newReadOnlyTransaction();
198         doReturn(this.write).when(this.transactionChain).newWriteOnlyTransaction();
199         doReturn(immediateFalseFluentFuture())
200                 .when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, this.iidGap);
201         doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION,
202                 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
203         doReturn(CommitInfo.emptyFluentFuture()).when(this.readWrite).commit();
204         doReturn(CommitInfo.emptyFluentFuture()).when(this.netconfService).commit(Mockito.any());
205
206         PlainPatchDataTransactionUtil.patchData(payload, new MdsalRestconfStrategy(iidContext, transactionChainHandler),
207                 this.schema);
208         verify(this.readWrite).merge(LogicalDatastoreType.CONFIGURATION,
209                 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
210
211         PlainPatchDataTransactionUtil.patchData(payload, new NetconfRestconfStrategy(netconfService, iidContext),
212                 this.schema);
213         verify(this.netconfService).merge(LogicalDatastoreType.CONFIGURATION,
214                 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(), Optional.empty());
215     }
216
217     @Test
218     public void testPatchListData() {
219         final InstanceIdentifierContext<DataSchemaNode> iidContext =
220                 new InstanceIdentifierContext<>(this.iidJukebox, this.schemaNodeForJukebox, null, this.schema);
221         final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.jukeboxContainerWithPlaylist);
222
223         doReturn(this.readWrite).when(this.transactionChain).newReadWriteTransaction();
224         doReturn(this.read).when(this.transactionChain).newReadOnlyTransaction();
225         doReturn(this.write).when(this.transactionChain).newWriteOnlyTransaction();
226         doReturn(immediateFalseFluentFuture())
227                 .when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, this.iidJukebox);
228         doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION,
229                 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
230         doReturn(CommitInfo.emptyFluentFuture()).when(this.readWrite).commit();
231         doReturn(CommitInfo.emptyFluentFuture()).when(this.netconfService).commit(Mockito.any());
232
233         PlainPatchDataTransactionUtil.patchData(payload,
234                 new MdsalRestconfStrategy(iidContext, transactionChainHandler),
235                 this.schema);
236         verify(this.readWrite).merge(LogicalDatastoreType.CONFIGURATION, this.iidJukebox, payload.getData());
237
238         PlainPatchDataTransactionUtil.patchData(payload, new NetconfRestconfStrategy(netconfService, iidContext),
239                 this.schema);
240         verify(this.netconfService).merge(LogicalDatastoreType.CONFIGURATION, this.iidJukebox, payload.getData(),
241                 Optional.empty());
242     }
243 }