Use SchemaContextHandler non-statically
[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
9 package org.opendaylight.restconf.nb.rfc8040.rests.utils;
10
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;
21
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;
52
53 public class PatchDataTransactionUtilTest {
54
55     private static final String PATH_FOR_NEW_SCHEMA_CONTEXT = "/jukebox";
56
57     @Mock
58     private DOMTransactionChain transactionChain;
59
60     @Mock
61     private DOMDataReadWriteTransaction rwTransaction;
62
63     @Mock
64     private DOMDataBroker mockDataBroker;
65
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;
75
76     @Before
77     public void setUp() throws Exception {
78         initMocks(this);
79
80         Mockito.doReturn(transactionChain).when(mockDataBroker).createTransactionChain(Mockito.any());
81         transactionChainHandler = new TransactionChainHandler(mockDataBroker);
82
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");
93
94         /* instance identifier for accessing container node "player" */
95         this.instanceIdContainer = YangInstanceIdentifier.builder()
96                 .node(baseQName)
97                 .node(containerPlayerQName)
98                 .build();
99
100         /* instance identifier for accessing leaf node "gap" */
101         this.instanceIdCreateAndDelete = instanceIdContainer.node(leafGapQName);
102
103         /* values that are used for creating leaf for testPatchDataCreateAndDelete test */
104         final LeafNode<?> buildGapLeaf = Builders.leafBuilder()
105                 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(leafGapQName))
106                 .withValue(0.2)
107                 .build();
108
109         final ContainerNode buildPlayerContainer = Builders.containerBuilder()
110                 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(containerPlayerQName))
111                 .withChild(buildGapLeaf)
112                 .build();
113
114         this.buildBaseContainerForTests = Builders.containerBuilder()
115                 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(baseQName))
116                 .withChild(buildPlayerContainer)
117                 .build();
118
119         this.targetNodeForCreateAndDelete = YangInstanceIdentifier.builder(this.instanceIdCreateAndDelete)
120                 .node(containerPlayerQName)
121                 .node(leafGapQName)
122                 .build();
123
124         /* instance identifier for accessing leaf node "name" in list "artist" */
125         this.instanceIdMerge = YangInstanceIdentifier.builder()
126                 .node(baseQName)
127                 .node(containerLibraryQName)
128                 .node(listArtistQName)
129                 .nodeWithKey(listArtistQName, QName.create(listArtistQName, "name"), "name of artist")
130                 .node(leafNameQName)
131                 .build();
132
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")
137                 .build();
138
139         final LeafNode<Object> contentDescription = Builders.leafBuilder()
140                 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(baseQName, "description")))
141                 .withValue("description of artist")
142                 .build();
143
144         final MapEntryNode mapEntryNode = Builders.mapEntryBuilder()
145                 .withNodeIdentifier(nodeWithKey)
146                 .withChild(contentName)
147                 .withChild(contentDescription)
148                 .build();
149
150         this.buildArtistList = Builders.mapBuilder()
151                 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(listArtistQName))
152                 .withChild(mapEntryNode)
153                 .build();
154
155         this.targetNodeMerge = YangInstanceIdentifier.builder()
156                 .node(baseQName)
157                 .node(containerLibraryQName)
158                 .node(listArtistQName)
159                 .nodeWithKey(listArtistQName, leafNameQName, "name of artist")
160                 .build();
161
162         /* Mocks */
163         doReturn(this.rwTransaction).when(this.transactionChain).newReadWriteTransaction();
164         doReturn(Futures.immediateCheckedFuture(null)).when(this.rwTransaction).submit();
165     }
166
167     @Test
168     public void testPatchDataReplaceMergeAndRemove() {
169         doReturn(Futures.immediateCheckedFuture(false)).doReturn(Futures.immediateCheckedFuture(true))
170                 .when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, this.targetNodeMerge);
171
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<>();
177
178         entities.add(entityReplace);
179         entities.add(entityMerge);
180         entities.add(entityRemove);
181
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);
188
189         for (final PatchStatusEntity entity : patchStatusContext.getEditCollection()) {
190             assertTrue(entity.isOk());
191         }
192         assertTrue(patchStatusContext.isOk());
193     }
194
195     @Test
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);
201
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<>();
207
208         entities.add(entityCreate);
209         entities.add(entityDelete);
210
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);
217
218         for (final PatchStatusEntity entity : patchStatusContext.getEditCollection()) {
219             assertTrue("Edit " + entity.getEditId() + " failed", entity.isOk());
220         }
221         assertTrue(patchStatusContext.isOk());
222     }
223
224     @Test
225     public void deleteNonexistentDataTest() {
226         doReturn(Futures.immediateCheckedFuture(false))
227                 .when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, this.targetNodeForCreateAndDelete);
228
229         final PatchEntity entityDelete =
230                 new PatchEntity("edit", DELETE, this.targetNodeForCreateAndDelete);
231         final List<PatchEntity> entities = new ArrayList<>();
232
233         entities.add(entityDelete);
234
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);
241
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());
247     }
248
249     @Test
250     public void testPatchMergePutContainer() throws Exception {
251         doReturn(Futures.immediateCheckedFuture(false)).doReturn(Futures.immediateCheckedFuture(true))
252                 .when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, this.targetNodeForCreateAndDelete);
253
254         final PatchEntity entityMerge =
255                 new PatchEntity("edit1", MERGE, this.instanceIdContainer, this.buildBaseContainerForTests);
256         final List<PatchEntity> entities = new ArrayList<>();
257
258         entities.add(entityMerge);
259
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);
266
267         for (final PatchStatusEntity entity : patchStatusContext.getEditCollection()) {
268             assertTrue(entity.isOk());
269         }
270         assertTrue(patchStatusContext.isOk());
271     }
272 }