Remove SchemaContextRef
[netconf.git] / restconf / restconf-nb-rfc8040 / src / test / java / org / opendaylight / restconf / nb / rfc8040 / rests / utils / PatchDataTransactionUtilTest.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.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertFalse;
12 import static org.junit.Assert.assertTrue;
13 import static org.mockito.ArgumentMatchers.any;
14 import static org.mockito.Mockito.doReturn;
15 import static org.mockito.MockitoAnnotations.initMocks;
16 import static org.opendaylight.restconf.common.patch.PatchEditOperation.CREATE;
17 import static org.opendaylight.restconf.common.patch.PatchEditOperation.DELETE;
18 import static org.opendaylight.restconf.common.patch.PatchEditOperation.MERGE;
19 import static org.opendaylight.restconf.common.patch.PatchEditOperation.REMOVE;
20 import static org.opendaylight.restconf.common.patch.PatchEditOperation.REPLACE;
21 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFalseFluentFuture;
22 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateTrueFluentFuture;
23
24 import java.util.ArrayList;
25 import java.util.List;
26 import org.junit.Before;
27 import org.junit.Test;
28 import org.mockito.Mock;
29 import org.opendaylight.mdsal.common.api.CommitInfo;
30 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
31 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
32 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
33 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
34 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
35 import org.opendaylight.restconf.common.errors.RestconfError;
36 import org.opendaylight.restconf.common.patch.PatchContext;
37 import org.opendaylight.restconf.common.patch.PatchEntity;
38 import org.opendaylight.restconf.common.patch.PatchStatusContext;
39 import org.opendaylight.restconf.common.patch.PatchStatusEntity;
40 import org.opendaylight.restconf.nb.rfc8040.TestRestconfUtils;
41 import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
42 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
43 import org.opendaylight.yangtools.yang.common.QName;
44 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
45 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
46 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
47 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
48 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
49 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
50 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
51 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
52 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
53 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
54 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
55
56 public class PatchDataTransactionUtilTest {
57
58     private static final String PATH_FOR_NEW_SCHEMA_CONTEXT = "/jukebox";
59
60     @Mock
61     private DOMTransactionChain transactionChain;
62
63     @Mock
64     private DOMDataTreeReadWriteTransaction rwTransaction;
65
66     @Mock
67     private DOMDataBroker mockDataBroker;
68
69     private TransactionChainHandler transactionChainHandler;
70     private EffectiveModelContext refSchemaCtx;
71     private YangInstanceIdentifier instanceIdContainer;
72     private YangInstanceIdentifier instanceIdCreateAndDelete;
73     private YangInstanceIdentifier instanceIdMerge;
74     private ContainerNode buildBaseContainerForTests;
75     private YangInstanceIdentifier targetNodeForCreateAndDelete;
76     private YangInstanceIdentifier targetNodeMerge;
77     private MapNode buildArtistList;
78
79     @Before
80     public void setUp() throws Exception {
81         initMocks(this);
82
83         doReturn(transactionChain).when(mockDataBroker).createTransactionChain(any());
84         transactionChainHandler = new TransactionChainHandler(mockDataBroker);
85
86         this.refSchemaCtx = YangParserTestUtils.parseYangFiles(
87             TestRestconfUtils.loadFiles(PATH_FOR_NEW_SCHEMA_CONTEXT));
88         final QName baseQName = QName.create("http://example.com/ns/example-jukebox", "2015-04-04", "jukebox");
89         final QName containerPlayerQName = QName.create(baseQName, "player");
90         final QName leafGapQName = QName.create(baseQName, "gap");
91         final QName containerLibraryQName = QName.create(baseQName, "library");
92         final QName listArtistQName = QName.create(baseQName, "artist");
93         final QName leafNameQName = QName.create(baseQName, "name");
94         final NodeIdentifierWithPredicates nodeWithKey = NodeIdentifierWithPredicates.of(listArtistQName, leafNameQName,
95             "name of artist");
96
97         /* instance identifier for accessing container node "player" */
98         this.instanceIdContainer = YangInstanceIdentifier.builder()
99                 .node(baseQName)
100                 .node(containerPlayerQName)
101                 .build();
102
103         /* instance identifier for accessing leaf node "gap" */
104         this.instanceIdCreateAndDelete = instanceIdContainer.node(leafGapQName);
105
106         /* values that are used for creating leaf for testPatchDataCreateAndDelete test */
107         final LeafNode<?> buildGapLeaf = Builders.leafBuilder()
108                 .withNodeIdentifier(new NodeIdentifier(leafGapQName))
109                 .withValue(0.2)
110                 .build();
111
112         final ContainerNode buildPlayerContainer = Builders.containerBuilder()
113                 .withNodeIdentifier(new NodeIdentifier(containerPlayerQName))
114                 .withChild(buildGapLeaf)
115                 .build();
116
117         this.buildBaseContainerForTests = Builders.containerBuilder()
118                 .withNodeIdentifier(new NodeIdentifier(baseQName))
119                 .withChild(buildPlayerContainer)
120                 .build();
121
122         this.targetNodeForCreateAndDelete = YangInstanceIdentifier.builder(this.instanceIdCreateAndDelete)
123                 .node(containerPlayerQName)
124                 .node(leafGapQName)
125                 .build();
126
127         /* instance identifier for accessing leaf node "name" in list "artist" */
128         this.instanceIdMerge = YangInstanceIdentifier.builder()
129                 .node(baseQName)
130                 .node(containerLibraryQName)
131                 .node(listArtistQName)
132                 .nodeWithKey(listArtistQName, QName.create(listArtistQName, "name"), "name of artist")
133                 .node(leafNameQName)
134                 .build();
135
136         /* values that are used for creating leaf for testPatchDataReplaceMergeAndRemove test */
137         final LeafNode<Object> contentName = Builders.leafBuilder()
138                 .withNodeIdentifier(new NodeIdentifier(QName.create(baseQName, "name")))
139                 .withValue("name of artist")
140                 .build();
141
142         final LeafNode<Object> contentDescription = Builders.leafBuilder()
143                 .withNodeIdentifier(new NodeIdentifier(QName.create(baseQName, "description")))
144                 .withValue("description of artist")
145                 .build();
146
147         final MapEntryNode mapEntryNode = Builders.mapEntryBuilder()
148                 .withNodeIdentifier(nodeWithKey)
149                 .withChild(contentName)
150                 .withChild(contentDescription)
151                 .build();
152
153         this.buildArtistList = Builders.mapBuilder()
154                 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(listArtistQName))
155                 .withChild(mapEntryNode)
156                 .build();
157
158         this.targetNodeMerge = YangInstanceIdentifier.builder()
159                 .node(baseQName)
160                 .node(containerLibraryQName)
161                 .node(listArtistQName)
162                 .nodeWithKey(listArtistQName, leafNameQName, "name of artist")
163                 .build();
164
165         /* Mocks */
166         doReturn(this.rwTransaction).when(this.transactionChain).newReadWriteTransaction();
167         doReturn(CommitInfo.emptyFluentFuture()).when(this.rwTransaction).commit();
168     }
169
170     @Test
171     public void testPatchDataReplaceMergeAndRemove() {
172         doReturn(immediateFalseFluentFuture()).doReturn(immediateTrueFluentFuture())
173                 .when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, this.targetNodeMerge);
174
175         final PatchEntity entityReplace =
176                 new PatchEntity("edit1", REPLACE, this.targetNodeMerge, this.buildArtistList);
177         final PatchEntity entityMerge = new PatchEntity("edit2", MERGE, this.targetNodeMerge, this.buildArtistList);
178         final PatchEntity entityRemove = new PatchEntity("edit3", REMOVE, this.targetNodeMerge);
179         final List<PatchEntity> entities = new ArrayList<>();
180
181         entities.add(entityReplace);
182         entities.add(entityMerge);
183         entities.add(entityRemove);
184
185         final InstanceIdentifierContext<? extends SchemaNode> iidContext =
186                 new InstanceIdentifierContext<>(this.instanceIdMerge, null, null, this.refSchemaCtx);
187         final PatchContext patchContext = new PatchContext(iidContext, entities, "patchRMRm");
188         final TransactionVarsWrapper wrapper = new TransactionVarsWrapper(iidContext, null, transactionChainHandler);
189         final PatchStatusContext patchStatusContext =
190                 PatchDataTransactionUtil.patchData(patchContext, wrapper, this.refSchemaCtx);
191
192         for (final PatchStatusEntity entity : patchStatusContext.getEditCollection()) {
193             assertTrue(entity.isOk());
194         }
195         assertTrue(patchStatusContext.isOk());
196     }
197
198     @Test
199     public void testPatchDataCreateAndDelete() throws Exception {
200         doReturn(immediateFalseFluentFuture()).when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION,
201             this.instanceIdContainer);
202         doReturn(immediateTrueFluentFuture()).when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION,
203             this.targetNodeForCreateAndDelete);
204
205         final PatchEntity entityCreate =
206                 new PatchEntity("edit1", CREATE, this.instanceIdContainer, this.buildBaseContainerForTests);
207         final PatchEntity entityDelete =
208                 new PatchEntity("edit2", DELETE, this.targetNodeForCreateAndDelete);
209         final List<PatchEntity> entities = new ArrayList<>();
210
211         entities.add(entityCreate);
212         entities.add(entityDelete);
213
214         final InstanceIdentifierContext<? extends SchemaNode> iidContext =
215                 new InstanceIdentifierContext<>(this.instanceIdCreateAndDelete, null, null, this.refSchemaCtx);
216         final PatchContext patchContext = new PatchContext(iidContext, entities, "patchCD");
217         final TransactionVarsWrapper wrapper = new TransactionVarsWrapper(iidContext, null, transactionChainHandler);
218         final PatchStatusContext patchStatusContext =
219                 PatchDataTransactionUtil.patchData(patchContext, wrapper, this.refSchemaCtx);
220
221         for (final PatchStatusEntity entity : patchStatusContext.getEditCollection()) {
222             assertTrue("Edit " + entity.getEditId() + " failed", entity.isOk());
223         }
224         assertTrue(patchStatusContext.isOk());
225     }
226
227     @Test
228     public void deleteNonexistentDataTest() {
229         doReturn(immediateFalseFluentFuture()).when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION,
230             this.targetNodeForCreateAndDelete);
231
232         final PatchEntity entityDelete = new PatchEntity("edit", DELETE, this.targetNodeForCreateAndDelete);
233         final List<PatchEntity> entities = new ArrayList<>();
234
235         entities.add(entityDelete);
236
237         final InstanceIdentifierContext<? extends SchemaNode> iidContext =
238                 new InstanceIdentifierContext<>(this.instanceIdCreateAndDelete, null, null, this.refSchemaCtx);
239         final PatchContext patchContext = new PatchContext(iidContext, entities, "patchD");
240         final TransactionVarsWrapper wrapper = new TransactionVarsWrapper(iidContext, null, transactionChainHandler);
241         final PatchStatusContext patchStatusContext =
242                 PatchDataTransactionUtil.patchData(patchContext, wrapper, this.refSchemaCtx);
243
244         assertFalse(patchStatusContext.isOk());
245         assertEquals(RestconfError.ErrorType.PROTOCOL,
246                 patchStatusContext.getEditCollection().get(0).getEditErrors().get(0).getErrorType());
247         assertEquals(RestconfError.ErrorTag.DATA_MISSING,
248                 patchStatusContext.getEditCollection().get(0).getEditErrors().get(0).getErrorTag());
249     }
250
251     @Test
252     public void testPatchMergePutContainer() throws Exception {
253         doReturn(immediateFalseFluentFuture()).doReturn(immediateTrueFluentFuture())
254                 .when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, this.targetNodeForCreateAndDelete);
255
256         final PatchEntity entityMerge =
257                 new PatchEntity("edit1", MERGE, this.instanceIdContainer, this.buildBaseContainerForTests);
258         final List<PatchEntity> entities = new ArrayList<>();
259
260         entities.add(entityMerge);
261
262         final InstanceIdentifierContext<? extends SchemaNode> iidContext =
263                 new InstanceIdentifierContext<>(this.instanceIdCreateAndDelete, null, null, this.refSchemaCtx);
264         final PatchContext patchContext = new PatchContext(iidContext, entities, "patchM");
265         final TransactionVarsWrapper wrapper = new TransactionVarsWrapper(iidContext, null, transactionChainHandler);
266         final PatchStatusContext patchStatusContext =
267                 PatchDataTransactionUtil.patchData(patchContext, wrapper, this.refSchemaCtx);
268
269         for (final PatchStatusEntity entity : patchStatusContext.getEditCollection()) {
270             assertTrue(entity.isOk());
271         }
272         assertTrue(patchStatusContext.isOk());
273     }
274 }