635455056b8212d2939a893b1092de8fa1a34ba7
[yangtools.git] / data / yang-data-tree-ri / src / test / java / org / opendaylight / yangtools / yang / data / tree / impl / DataTreeCandidatesTest.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.yangtools.yang.data.tree.impl;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertThrows;
12
13 import java.util.Collection;
14 import java.util.List;
15 import org.junit.Before;
16 import org.junit.Test;
17 import org.opendaylight.yangtools.yang.common.QName;
18 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
20 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
21 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
22 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
23 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
24 import org.opendaylight.yangtools.yang.data.tree.api.DataTree;
25 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidate;
26 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidateNode;
27 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeConfiguration;
28 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeModification;
29 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeModificationCursor;
30 import org.opendaylight.yangtools.yang.data.tree.api.DataValidationFailedException;
31 import org.opendaylight.yangtools.yang.data.tree.api.ModificationType;
32 import org.opendaylight.yangtools.yang.data.tree.api.TreeType;
33 import org.opendaylight.yangtools.yang.data.tree.impl.di.InMemoryDataTreeFactory;
34 import org.opendaylight.yangtools.yang.data.tree.spi.DataTreeCandidates;
35 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
36
37 public class DataTreeCandidatesTest extends AbstractTestModelTest {
38     private DataTree dataTree;
39
40     @Before
41     public void setUp() throws Exception {
42         dataTree = new InMemoryDataTreeFactory().create(DataTreeConfiguration.DEFAULT_OPERATIONAL, SCHEMA_CONTEXT);
43
44         final ContainerNode testContainer = Builders.containerBuilder()
45             .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
46             .withChild(Builders.containerBuilder()
47                 .withNodeIdentifier(new NodeIdentifier(SchemaContext.NAME))
48                 .build())
49             .build();
50
51         final InMemoryDataTreeModification modification = (InMemoryDataTreeModification) dataTree.takeSnapshot()
52                 .newModification();
53         final DataTreeModificationCursor cursor = modification.openCursor();
54         cursor.write(TestModel.TEST_PATH.getLastPathArgument(), testContainer);
55         modification.ready();
56
57         dataTree.validate(modification);
58         final DataTreeCandidate candidate = dataTree.prepare(modification);
59         dataTree.commit(candidate);
60     }
61
62     @Test
63     public void testRootedCandidate() throws DataValidationFailedException {
64         final DataTree innerDataTree = new InMemoryDataTreeFactory().create(
65             new DataTreeConfiguration.Builder(TreeType.OPERATIONAL)
66             .setMandatoryNodesValidation(true)
67             .setRootPath(TestModel.INNER_CONTAINER_PATH)
68             .setUniqueIndexes(true).build(), SCHEMA_CONTEXT);
69
70         final LeafNode<String> leaf = ImmutableNodes.leafNode(TestModel.VALUE_QNAME, "testing-value");
71
72         final DataTreeModification modification = innerDataTree.takeSnapshot().newModification();
73         modification.write(TestModel.VALUE_PATH, leaf);
74
75         modification.ready();
76         dataTree.validate(modification);
77         final DataTreeCandidate candidate = dataTree.prepare(modification);
78         dataTree.commit(candidate);
79
80         final DataTreeModification newModification = dataTree.takeSnapshot().newModification();
81         final DataTreeCandidate newCandidate = DataTreeCandidates.newDataTreeCandidate(TestModel.INNER_CONTAINER_PATH,
82             candidate.getRootNode());
83
84         // lets see if getting the identifier of the root node throws an exception
85         assertThrows(IllegalStateException.class, () ->  newCandidate.getRootNode().name());
86
87         // lets see if we can apply this rooted candidate to a new dataTree
88         DataTreeCandidates.applyToModification(newModification,
89                 newCandidate);
90
91         final LeafNode<?> readLeaf = (LeafNode<?>) newModification.readNode(TestModel.INNER_VALUE_PATH).orElseThrow();
92         assertEquals(readLeaf, leaf);
93     }
94
95     @Test
96     public void testEmptyMergeOnContainer() throws DataValidationFailedException {
97         DataTreeModification modification = dataTree.takeSnapshot().newModification();
98         modification.merge(TestModel.NON_PRESENCE_PATH, ImmutableNodes.containerNode(TestModel.NON_PRESENCE_QNAME));
99         modification.ready();
100         dataTree.validate(modification);
101
102         // The entire transaction needs to fizzle to a no-op
103         DataTreeCandidate candidate = dataTree.prepare(modification);
104         DataTreeCandidateNode node = candidate.getRootNode();
105         assertEquals(ModificationType.UNMODIFIED, node.modificationType());
106
107         // 'test'
108         assertUnmodified(1, node.childNodes());
109     }
110
111     @Test
112     public void testEmptyWriteOnContainer() throws DataValidationFailedException {
113         DataTreeModification modification = dataTree.takeSnapshot().newModification();
114         modification.write(TestModel.NON_PRESENCE_PATH, ImmutableNodes.containerNode(TestModel.NON_PRESENCE_QNAME));
115         modification.ready();
116         dataTree.validate(modification);
117
118         // The entire transaction needs to fizzle to a no-op
119         DataTreeCandidate candidate = dataTree.prepare(modification);
120         DataTreeCandidateNode node = candidate.getRootNode();
121         assertEquals(ModificationType.UNMODIFIED, node.modificationType());
122
123         // 'test'
124         assertUnmodified(1, node.childNodes());
125     }
126
127     @Test
128     public void testEmptyMergesOnDeleted() throws DataValidationFailedException {
129         DataTreeModification modification = dataTree.takeSnapshot().newModification();
130         modification.delete(TestModel.NON_PRESENCE_PATH);
131         modification.merge(TestModel.DEEP_CHOICE_PATH, ImmutableNodes.choiceNode(TestModel.DEEP_CHOICE_QNAME));
132         modification.ready();
133         dataTree.validate(modification);
134
135         final DataTreeCandidate candidate = dataTree.prepare(modification);
136         assertEquals(YangInstanceIdentifier.of(), candidate.getRootPath());
137         final DataTreeCandidateNode node = candidate.getRootNode();
138         assertEquals(ModificationType.UNMODIFIED, node.modificationType());
139
140         // 'test'
141         assertUnmodified(1, node.childNodes());
142     }
143
144     @Test
145     public void testEmptyMergesOnExisting() throws DataValidationFailedException {
146         // Make sure 'non-presence' is present
147         DataTreeModification modification = dataTree.takeSnapshot().newModification();
148         modification.write(TestModel.NAME_PATH, ImmutableNodes.leafNode(TestModel.NAME_QNAME, "foo"));
149         modification.ready();
150         dataTree.validate(modification);
151         dataTree.commit(dataTree.prepare(modification));
152
153         // Issue an empty merge on it and a child choice
154         modification = dataTree.takeSnapshot().newModification();
155         modification.merge(TestModel.NON_PRESENCE_PATH, ImmutableNodes.containerNode(TestModel.NON_PRESENCE_QNAME));
156         modification.merge(TestModel.DEEP_CHOICE_PATH, ImmutableNodes.choiceNode(TestModel.DEEP_CHOICE_QNAME));
157         modification.ready();
158         dataTree.validate(modification);
159
160         // The entire transaction needs to fizzle to a no-op
161         final DataTreeCandidate candidate = dataTree.prepare(modification);
162         assertEquals(YangInstanceIdentifier.of(), candidate.getRootPath());
163         final DataTreeCandidateNode node = candidate.getRootNode();
164         assertEquals(ModificationType.UNMODIFIED, node.modificationType());
165
166         // 'non-presence' and 'test'
167         assertUnmodified(2, node.childNodes());
168     }
169
170     @Test
171     public void testAggregateWithoutChanges() throws DataValidationFailedException {
172         DataTreeModification modification1 = dataTree.takeSnapshot().newModification();
173         modification1.write(
174                 TestModel.INNER_CONTAINER_PATH.node(QName.create(TestModel.INNER_CONTAINER_QNAME,"value")),
175                 ImmutableNodes.leafNode(QName.create(TestModel.INNER_CONTAINER_QNAME,"value"),"value1"));
176         modification1.ready();
177         dataTree.validate(modification1);
178         DataTreeCandidate candidate1 = dataTree.prepare(modification1);
179         dataTree.commit(candidate1);
180
181         DataTreeModification modification2 = dataTree.takeSnapshot().newModification();
182         modification2.delete(TestModel.INNER_CONTAINER_PATH);
183         modification2.ready();
184         dataTree.validate(modification2);
185         DataTreeCandidate candidate2 = dataTree.prepare(modification2);
186         dataTree.commit(candidate2);
187
188         DataTreeCandidate aggregateCandidate = DataTreeCandidates.aggregate(List.of(candidate1, candidate2));
189
190         assertEquals(ModificationType.UNMODIFIED, aggregateCandidate.getRootNode().modificationType());
191     }
192
193     @Test
194     public void testAggregate() throws DataValidationFailedException {
195         DataTreeModification modification = dataTree.takeSnapshot().newModification();
196         modification.write(
197                 TestModel.INNER_CONTAINER_PATH.node(QName.create(TestModel.INNER_CONTAINER_QNAME,"value")),
198                 ImmutableNodes.leafNode(QName.create(TestModel.INNER_CONTAINER_QNAME,"value"),"value1"));
199         modification.ready();
200         dataTree.validate(modification);
201         DataTreeCandidate candidate = dataTree.prepare(modification);
202         dataTree.commit(candidate);
203
204         DataTreeModification modification1 = dataTree.takeSnapshot().newModification();
205         modification1.delete(TestModel.INNER_CONTAINER_PATH);
206         modification1.ready();
207         dataTree.validate(modification1);
208         DataTreeCandidate candidate1 = dataTree.prepare(modification1);
209         dataTree.commit(candidate1);
210
211         DataTreeModification modification2 = dataTree.takeSnapshot().newModification();
212         modification2.write(
213                 TestModel.INNER_CONTAINER_PATH.node(QName.create(TestModel.INNER_CONTAINER_QNAME,"value")),
214                 ImmutableNodes.leafNode(QName.create(TestModel.INNER_CONTAINER_QNAME,"value"),"value2"));
215         modification2.ready();
216         dataTree.validate(modification2);
217         DataTreeCandidate candidate2 = dataTree.prepare(modification2);
218         dataTree.commit(candidate2);
219
220         DataTreeCandidate aggregateCandidate = DataTreeCandidates.aggregate(List.of(candidate1, candidate2));
221
222         assertEquals(ModificationType.SUBTREE_MODIFIED,aggregateCandidate.getRootNode().modificationType());
223     }
224
225     private static void assertUnmodified(final int expSize, final Collection<DataTreeCandidateNode> nodes) {
226         assertEquals(expSize, nodes.size());
227         nodes.forEach(node -> assertEquals(ModificationType.UNMODIFIED, node.modificationType()));
228     }
229 }