7bf7d500866feca453330b922c54f8958b5f6cfb
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / test / java / org / opendaylight / controller / cluster / datastore / utils / PruningDataTreeModificationTest.java
1 /*
2  * Copyright (c) 2014, 2015 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.controller.cluster.datastore.utils;
10
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertTrue;
13 import static org.mockito.Mockito.doThrow;
14 import static org.mockito.Mockito.mock;
15 import static org.mockito.Mockito.times;
16 import static org.mockito.Mockito.verify;
17 import static org.opendaylight.controller.md.cluster.datastore.model.CompositeModel.AUG_CONTAINER;
18 import static org.opendaylight.controller.md.cluster.datastore.model.CompositeModel.AUG_INNER_CONTAINER;
19 import static org.opendaylight.controller.md.cluster.datastore.model.CompositeModel.AUG_QNAME;
20 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.NAME_QNAME;
21 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.TEST_QNAME;
22 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.innerNode;
23 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.outerNode;
24 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.outerNodeEntry;
25 import com.google.common.base.Optional;
26 import com.google.common.reflect.Reflection;
27 import java.lang.reflect.InvocationHandler;
28 import java.lang.reflect.InvocationTargetException;
29 import java.lang.reflect.Method;
30 import org.junit.Before;
31 import org.junit.Test;
32 import org.mockito.Mock;
33 import org.mockito.MockitoAnnotations;
34 import org.opendaylight.controller.cluster.datastore.ShardDataTree;
35 import org.opendaylight.controller.md.cluster.datastore.model.CarsModel;
36 import org.opendaylight.controller.md.cluster.datastore.model.PeopleModel;
37 import org.opendaylight.controller.md.cluster.datastore.model.SchemaContextHelper;
38 import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
39 import org.opendaylight.yangtools.yang.common.QName;
40 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
41 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
42 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
43 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
44 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
45 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateTip;
46 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
47 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModificationCursor;
48 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
49 import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
50 import org.opendaylight.yangtools.yang.data.api.schema.tree.TipProducingDataTree;
51 import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType;
52 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
53 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
54 import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
55 import org.opendaylight.yangtools.yang.data.impl.schema.tree.SchemaValidationFailedException;
56 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
57
58 public class PruningDataTreeModificationTest {
59     static final SchemaContext SCHEMA_CONTEXT = SchemaContextHelper.select(SchemaContextHelper.CARS_YANG,
60             SchemaContextHelper.ODL_DATASTORE_TEST_YANG);
61
62     static final QName INVALID_TEST_QNAME = QName.create(TestModel.TEST_QNAME, "invalid");
63     static final YangInstanceIdentifier INVALID_TEST_PATH = YangInstanceIdentifier.of(INVALID_TEST_QNAME);
64
65     @Mock
66     private DataTreeModification mockModification;
67
68     private TipProducingDataTree dataTree;
69     private DataTreeModification realModification;
70     private DataTreeModification proxyModification;
71     private PruningDataTreeModification pruningDataTreeModification;
72
73     @Before
74     public void setUp(){
75         MockitoAnnotations.initMocks(this);
76
77         dataTree = InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION);
78         dataTree.setSchemaContext(SCHEMA_CONTEXT);
79
80         realModification = dataTree.takeSnapshot().newModification();
81         proxyModification = Reflection.newProxy(DataTreeModification.class, new InvocationHandler() {
82             @Override
83             public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
84                 try {
85                     method.invoke(mockModification, args);
86                     return method.invoke(realModification, args);
87                 } catch (InvocationTargetException e) {
88                     throw e.getCause();
89                 }
90             }
91         });
92
93         pruningDataTreeModification = new PruningDataTreeModification(proxyModification, dataTree, SCHEMA_CONTEXT);
94     }
95
96     @Test
97     public void testDelete(){
98         pruningDataTreeModification.delete(CarsModel.BASE_PATH);
99
100         verify(mockModification, times(1)).delete(CarsModel.BASE_PATH);
101     }
102
103     @Test
104     public void testDeleteOnException(){
105         YangInstanceIdentifier path = CarsModel.BASE_PATH;
106         doThrow(SchemaValidationFailedException.class).when(mockModification).delete(path);
107
108         pruningDataTreeModification.delete(path);
109
110         verify(mockModification, times(1)).delete(path);
111     }
112
113
114     @Test
115     public void testMerge(){
116         NormalizedNode<?, ?> normalizedNode = CarsModel.create();
117         YangInstanceIdentifier path = CarsModel.BASE_PATH;
118         pruningDataTreeModification.merge(path, normalizedNode);
119
120         verify(mockModification, times(1)).merge(path, normalizedNode);
121     }
122
123     @Test
124     public void testMergeWithInvalidNamespace() throws DataValidationFailedException{
125         NormalizedNode<?, ?> normalizedNode = PeopleModel.emptyContainer();
126         YangInstanceIdentifier path = PeopleModel.BASE_PATH;
127
128         pruningDataTreeModification.merge(path, normalizedNode);
129
130         verify(mockModification, times(1)).merge(path, normalizedNode);
131
132         DataTreeCandidateTip candidate = getCandidate();
133         assertEquals("getModificationType", ModificationType.UNMODIFIED, candidate.getRootNode().getModificationType());
134     }
135
136     @Test
137     public void testMergeWithInvalidChildNodeNames() throws DataValidationFailedException{
138         ContainerNode augContainer = ImmutableContainerNodeBuilder.create().withNodeIdentifier(
139                 new YangInstanceIdentifier.NodeIdentifier(AUG_CONTAINER)).withChild(
140                         ImmutableNodes.containerNode(AUG_INNER_CONTAINER)).build();
141
142         DataContainerChild<?, ?> outerNode = outerNode(outerNodeEntry(1, innerNode("one", "two")));
143         ContainerNode normalizedNode = ImmutableContainerNodeBuilder.create().withNodeIdentifier(
144                 new YangInstanceIdentifier.NodeIdentifier(TEST_QNAME)).withChild(outerNode).withChild(augContainer).
145                             withChild(ImmutableNodes.leafNode(AUG_QNAME, "aug")).build();
146
147         YangInstanceIdentifier path = TestModel.TEST_PATH;
148
149         pruningDataTreeModification.merge(path, normalizedNode);
150
151         dataTree.commit(getCandidate());
152
153         ContainerNode prunedNode = ImmutableContainerNodeBuilder.create().withNodeIdentifier(
154                 new YangInstanceIdentifier.NodeIdentifier(TEST_QNAME)).withChild(outerNode).build();
155
156         Optional<NormalizedNode<?, ?>> actual = dataTree.takeSnapshot().readNode(path);
157         assertEquals("After pruning present", true, actual.isPresent());
158         assertEquals("After pruning", prunedNode, actual.get());
159     }
160
161     @Test
162     public void testMergeWithValidNamespaceAndInvalidNodeName() throws DataValidationFailedException{
163         NormalizedNode<?, ?> normalizedNode = ImmutableNodes.containerNode(INVALID_TEST_QNAME);
164         YangInstanceIdentifier path = INVALID_TEST_PATH;
165
166         pruningDataTreeModification.merge(path, normalizedNode);
167
168         verify(mockModification, times(1)).merge(path, normalizedNode);
169
170         DataTreeCandidateTip candidate = getCandidate();
171         assertEquals("getModificationType", ModificationType.UNMODIFIED, candidate.getRootNode().getModificationType());
172     }
173
174     @Test
175     public void testWrite(){
176         NormalizedNode<?, ?> normalizedNode = CarsModel.create();
177         YangInstanceIdentifier path = CarsModel.BASE_PATH;
178         pruningDataTreeModification.write(path, normalizedNode);
179
180         verify(mockModification, times(1)).write(path, normalizedNode);
181     }
182
183     @Test
184     public void testWriteRootNode() throws Exception {
185         final DataTree localDataTree = InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION);
186         localDataTree.setSchemaContext(SCHEMA_CONTEXT);
187
188         DataTreeModification mod = localDataTree.takeSnapshot().newModification();
189         mod.write(CarsModel.BASE_PATH, CarsModel.create());
190         mod.ready();
191         localDataTree.validate(mod);
192         localDataTree.commit(localDataTree.prepare(mod));
193
194         NormalizedNode<?, ?> normalizedNode = dataTree.takeSnapshot().readNode(YangInstanceIdentifier.EMPTY).get();
195         pruningDataTreeModification.write(YangInstanceIdentifier.EMPTY, normalizedNode);
196         dataTree.commit(getCandidate());
197
198         Optional<NormalizedNode<?, ?>> actual = dataTree.takeSnapshot().readNode(YangInstanceIdentifier.EMPTY);
199         assertEquals("Root present", true, actual.isPresent());
200         assertEquals("Root node", normalizedNode, actual.get());
201     }
202
203     @Test
204     public void testWriteRootNodeWithInvalidChild() throws Exception{
205         ShardDataTree shardDataTree = new ShardDataTree(SCHEMA_CONTEXT, TreeType.CONFIGURATION);
206         NormalizedNode<?, ?> root = shardDataTree.readNode(YangInstanceIdentifier.EMPTY).get();
207
208         NormalizedNode<?, ?> normalizedNode = ImmutableContainerNodeBuilder.create().withNodeIdentifier(
209                 new YangInstanceIdentifier.NodeIdentifier(root.getNodeType())).withChild(
210                         ImmutableNodes.containerNode(AUG_CONTAINER)).build();
211         pruningDataTreeModification.write(YangInstanceIdentifier.EMPTY, normalizedNode);
212         dataTree.commit(getCandidate());
213
214         Optional<NormalizedNode<?, ?>> actual = dataTree.takeSnapshot().readNode(YangInstanceIdentifier.EMPTY);
215         assertEquals("Root present", true, actual.isPresent());
216         assertEquals("Root node", root, actual.get());
217
218     }
219
220     @Test
221     public void testWriteWithInvalidNamespace() throws DataValidationFailedException{
222         NormalizedNode<?, ?> normalizedNode = PeopleModel.emptyContainer();
223         YangInstanceIdentifier path = PeopleModel.BASE_PATH;
224
225         pruningDataTreeModification.write(path, normalizedNode);
226
227         verify(mockModification, times(1)).write(path, normalizedNode);
228
229         DataTreeCandidateTip candidate = getCandidate();
230         assertEquals("getModificationType", ModificationType.UNMODIFIED, candidate.getRootNode().getModificationType());
231     }
232
233     @Test
234     public void testWriteWithInvalidChildNodeNames() throws DataValidationFailedException{
235         ContainerNode augContainer = ImmutableContainerNodeBuilder.create().withNodeIdentifier(
236                 new YangInstanceIdentifier.NodeIdentifier(AUG_CONTAINER)).withChild(
237                         ImmutableNodes.containerNode(AUG_INNER_CONTAINER)).build();
238
239         DataContainerChild<?, ?> outerNode = outerNode(outerNodeEntry(1, innerNode("one", "two")));
240         ContainerNode normalizedNode = ImmutableContainerNodeBuilder.create().withNodeIdentifier(
241                 new YangInstanceIdentifier.NodeIdentifier(TEST_QNAME)).withChild(outerNode).withChild(augContainer).
242                             withChild(ImmutableNodes.leafNode(AUG_QNAME, "aug")).
243                                 withChild(ImmutableNodes.leafNode(NAME_QNAME, "name")).build();
244
245         YangInstanceIdentifier path = TestModel.TEST_PATH;
246
247         pruningDataTreeModification.write(path, normalizedNode);
248
249         dataTree.commit(getCandidate());
250
251         ContainerNode prunedNode = ImmutableContainerNodeBuilder.create().withNodeIdentifier(
252                 new YangInstanceIdentifier.NodeIdentifier(TEST_QNAME)).withChild(outerNode).
253                         withChild(ImmutableNodes.leafNode(NAME_QNAME, "name")).build();
254
255         Optional<NormalizedNode<?, ?>> actual = dataTree.takeSnapshot().readNode(path);
256         assertEquals("After pruning present", true, actual.isPresent());
257         assertEquals("After pruning", prunedNode, actual.get());
258     }
259
260     @Test
261     public void testReady(){
262         pruningDataTreeModification.ready();
263
264         verify(mockModification).ready();
265     }
266
267     @Test
268     public void testApplyToCursor(){
269         DataTreeModificationCursor dataTreeModificationCursor = mock(DataTreeModificationCursor.class);
270         pruningDataTreeModification.applyToCursor(dataTreeModificationCursor);
271
272         verify(mockModification).applyToCursor(dataTreeModificationCursor);
273     }
274
275     @Test
276     public void testReadNode(){
277         pruningDataTreeModification.readNode(CarsModel.BASE_PATH);
278
279         verify(mockModification).readNode(CarsModel.BASE_PATH);
280     }
281
282     @Test
283     public void testNewModification(){
284         realModification.ready();
285         DataTreeModification dataTreeModification = pruningDataTreeModification.newModification();
286
287         assertTrue("new modification not of type PruningDataTreeModification", dataTreeModification instanceof PruningDataTreeModification);
288     }
289
290     private DataTreeCandidateTip getCandidate() throws DataValidationFailedException {
291         pruningDataTreeModification.ready();
292         DataTreeModification mod = pruningDataTreeModification.getResultingModification();
293         mod = mod == proxyModification ? realModification : mod;
294         dataTree.validate(mod);
295         DataTreeCandidateTip candidate = dataTree.prepare(mod);
296         return candidate;
297     }
298 }