2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.restconf.nb.rfc8040.rests.utils;
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertFalse;
13 import static org.junit.Assert.assertTrue;
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;
22 import com.google.common.util.concurrent.Futures;
23 import java.util.ArrayList;
24 import java.util.List;
25 import org.junit.Before;
26 import org.junit.Test;
27 import org.mockito.Mock;
28 import org.mockito.Mockito;
29 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
30 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
31 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
32 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
33 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
34 import org.opendaylight.restconf.common.errors.RestconfError;
35 import org.opendaylight.restconf.common.patch.PatchContext;
36 import org.opendaylight.restconf.common.patch.PatchEntity;
37 import org.opendaylight.restconf.common.patch.PatchStatusContext;
38 import org.opendaylight.restconf.common.patch.PatchStatusEntity;
39 import org.opendaylight.restconf.nb.rfc8040.TestRestconfUtils;
40 import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
41 import org.opendaylight.restconf.nb.rfc8040.references.SchemaContextRef;
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.schema.ContainerNode;
46 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
47 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
48 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
49 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
50 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
51 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
53 public class PatchDataTransactionUtilTest {
55 private static final String PATH_FOR_NEW_SCHEMA_CONTEXT = "/jukebox";
58 private DOMTransactionChain transactionChain;
61 private DOMDataReadWriteTransaction rwTransaction;
64 private DOMDataBroker mockDataBroker;
66 private TransactionChainHandler transactionChainHandler;
67 private SchemaContextRef refSchemaCtx;
68 private YangInstanceIdentifier instanceIdContainer;
69 private YangInstanceIdentifier instanceIdCreateAndDelete;
70 private YangInstanceIdentifier instanceIdMerge;
71 private ContainerNode buildBaseContainerForTests;
72 private YangInstanceIdentifier targetNodeForCreateAndDelete;
73 private YangInstanceIdentifier targetNodeMerge;
74 private MapNode buildArtistList;
77 public void setUp() throws Exception {
80 Mockito.doReturn(transactionChain).when(mockDataBroker).createTransactionChain(Mockito.any());
81 transactionChainHandler = new TransactionChainHandler(mockDataBroker);
83 this.refSchemaCtx = new SchemaContextRef(
84 YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles(PATH_FOR_NEW_SCHEMA_CONTEXT)));
85 final QName baseQName = QName.create("http://example.com/ns/example-jukebox", "2015-04-04", "jukebox");
86 final QName containerPlayerQName = QName.create(baseQName, "player");
87 final QName leafGapQName = QName.create(baseQName, "gap");
88 final QName containerLibraryQName = QName.create(baseQName, "library");
89 final QName listArtistQName = QName.create(baseQName, "artist");
90 final QName leafNameQName = QName.create(baseQName, "name");
91 final YangInstanceIdentifier.NodeIdentifierWithPredicates nodeWithKey =
92 new YangInstanceIdentifier.NodeIdentifierWithPredicates(listArtistQName, leafNameQName, "name of artist");
94 /* instance identifier for accessing container node "player" */
95 this.instanceIdContainer = YangInstanceIdentifier.builder()
97 .node(containerPlayerQName)
100 /* instance identifier for accessing leaf node "gap" */
101 this.instanceIdCreateAndDelete = instanceIdContainer.node(leafGapQName);
103 /* values that are used for creating leaf for testPatchDataCreateAndDelete test */
104 final LeafNode<?> buildGapLeaf = Builders.leafBuilder()
105 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(leafGapQName))
109 final ContainerNode buildPlayerContainer = Builders.containerBuilder()
110 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(containerPlayerQName))
111 .withChild(buildGapLeaf)
114 this.buildBaseContainerForTests = Builders.containerBuilder()
115 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(baseQName))
116 .withChild(buildPlayerContainer)
119 this.targetNodeForCreateAndDelete = YangInstanceIdentifier.builder(this.instanceIdCreateAndDelete)
120 .node(containerPlayerQName)
124 /* instance identifier for accessing leaf node "name" in list "artist" */
125 this.instanceIdMerge = YangInstanceIdentifier.builder()
127 .node(containerLibraryQName)
128 .node(listArtistQName)
129 .nodeWithKey(listArtistQName, QName.create(listArtistQName, "name"), "name of artist")
133 /* values that are used for creating leaf for testPatchDataReplaceMergeAndRemove test */
134 final LeafNode<Object> contentName = Builders.leafBuilder()
135 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(baseQName, "name")))
136 .withValue("name of artist")
139 final LeafNode<Object> contentDescription = Builders.leafBuilder()
140 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(baseQName, "description")))
141 .withValue("description of artist")
144 final MapEntryNode mapEntryNode = Builders.mapEntryBuilder()
145 .withNodeIdentifier(nodeWithKey)
146 .withChild(contentName)
147 .withChild(contentDescription)
150 this.buildArtistList = Builders.mapBuilder()
151 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(listArtistQName))
152 .withChild(mapEntryNode)
155 this.targetNodeMerge = YangInstanceIdentifier.builder()
157 .node(containerLibraryQName)
158 .node(listArtistQName)
159 .nodeWithKey(listArtistQName, leafNameQName, "name of artist")
163 doReturn(this.rwTransaction).when(this.transactionChain).newReadWriteTransaction();
164 doReturn(Futures.immediateCheckedFuture(null)).when(this.rwTransaction).submit();
168 public void testPatchDataReplaceMergeAndRemove() {
169 doReturn(Futures.immediateCheckedFuture(false)).doReturn(Futures.immediateCheckedFuture(true))
170 .when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, this.targetNodeMerge);
172 final PatchEntity entityReplace =
173 new PatchEntity("edit1", REPLACE, this.targetNodeMerge, this.buildArtistList);
174 final PatchEntity entityMerge = new PatchEntity("edit2", MERGE, this.targetNodeMerge, this.buildArtistList);
175 final PatchEntity entityRemove = new PatchEntity("edit3", REMOVE, this.targetNodeMerge);
176 final List<PatchEntity> entities = new ArrayList<>();
178 entities.add(entityReplace);
179 entities.add(entityMerge);
180 entities.add(entityRemove);
182 final InstanceIdentifierContext<? extends SchemaNode> iidContext =
183 new InstanceIdentifierContext<>(this.instanceIdMerge, null, null, this.refSchemaCtx.get());
184 final PatchContext patchContext = new PatchContext(iidContext, entities, "patchRMRm");
185 final TransactionVarsWrapper wrapper = new TransactionVarsWrapper(iidContext, null, transactionChainHandler);
186 final PatchStatusContext patchStatusContext =
187 PatchDataTransactionUtil.patchData(patchContext, wrapper, this.refSchemaCtx);
189 for (final PatchStatusEntity entity : patchStatusContext.getEditCollection()) {
190 assertTrue(entity.isOk());
192 assertTrue(patchStatusContext.isOk());
196 public void testPatchDataCreateAndDelete() throws Exception {
197 doReturn(Futures.immediateCheckedFuture(false))
198 .when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, this.instanceIdContainer);
199 doReturn(Futures.immediateCheckedFuture(true))
200 .when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, this.targetNodeForCreateAndDelete);
202 final PatchEntity entityCreate =
203 new PatchEntity("edit1", CREATE, this.instanceIdContainer, this.buildBaseContainerForTests);
204 final PatchEntity entityDelete =
205 new PatchEntity("edit2", DELETE, this.targetNodeForCreateAndDelete);
206 final List<PatchEntity> entities = new ArrayList<>();
208 entities.add(entityCreate);
209 entities.add(entityDelete);
211 final InstanceIdentifierContext<? extends SchemaNode> iidContext =
212 new InstanceIdentifierContext<>(this.instanceIdCreateAndDelete, null, null, this.refSchemaCtx.get());
213 final PatchContext patchContext = new PatchContext(iidContext, entities, "patchCD");
214 final TransactionVarsWrapper wrapper = new TransactionVarsWrapper(iidContext, null, transactionChainHandler);
215 final PatchStatusContext patchStatusContext =
216 PatchDataTransactionUtil.patchData(patchContext, wrapper, this.refSchemaCtx);
218 for (final PatchStatusEntity entity : patchStatusContext.getEditCollection()) {
219 assertTrue("Edit " + entity.getEditId() + " failed", entity.isOk());
221 assertTrue(patchStatusContext.isOk());
225 public void deleteNonexistentDataTest() {
226 doReturn(Futures.immediateCheckedFuture(false))
227 .when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, this.targetNodeForCreateAndDelete);
229 final PatchEntity entityDelete =
230 new PatchEntity("edit", DELETE, this.targetNodeForCreateAndDelete);
231 final List<PatchEntity> entities = new ArrayList<>();
233 entities.add(entityDelete);
235 final InstanceIdentifierContext<? extends SchemaNode> iidContext =
236 new InstanceIdentifierContext<>(this.instanceIdCreateAndDelete, null, null, this.refSchemaCtx.get());
237 final PatchContext patchContext = new PatchContext(iidContext, entities, "patchD");
238 final TransactionVarsWrapper wrapper = new TransactionVarsWrapper(iidContext, null, transactionChainHandler);
239 final PatchStatusContext patchStatusContext =
240 PatchDataTransactionUtil.patchData(patchContext, wrapper, this.refSchemaCtx);
242 assertFalse(patchStatusContext.isOk());
243 assertEquals(RestconfError.ErrorType.PROTOCOL,
244 patchStatusContext.getEditCollection().get(0).getEditErrors().get(0).getErrorType());
245 assertEquals(RestconfError.ErrorTag.DATA_MISSING,
246 patchStatusContext.getEditCollection().get(0).getEditErrors().get(0).getErrorTag());
250 public void testPatchMergePutContainer() throws Exception {
251 doReturn(Futures.immediateCheckedFuture(false)).doReturn(Futures.immediateCheckedFuture(true))
252 .when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, this.targetNodeForCreateAndDelete);
254 final PatchEntity entityMerge =
255 new PatchEntity("edit1", MERGE, this.instanceIdContainer, this.buildBaseContainerForTests);
256 final List<PatchEntity> entities = new ArrayList<>();
258 entities.add(entityMerge);
260 final InstanceIdentifierContext<? extends SchemaNode> iidContext =
261 new InstanceIdentifierContext<>(this.instanceIdCreateAndDelete, null, null, this.refSchemaCtx.get());
262 final PatchContext patchContext = new PatchContext(iidContext, entities, "patchM");
263 final TransactionVarsWrapper wrapper = new TransactionVarsWrapper(iidContext, null, transactionChainHandler);
264 final PatchStatusContext patchStatusContext =
265 PatchDataTransactionUtil.patchData(patchContext, wrapper, this.refSchemaCtx);
267 for (final PatchStatusEntity entity : patchStatusContext.getEditCollection()) {
268 assertTrue(entity.isOk());
270 assertTrue(patchStatusContext.isOk());