Use Builders in yang-data-tree-ri tests
[yangtools.git] / data / yang-data-tree-ri / src / test / java / org / opendaylight / yangtools / yang / data / tree / impl / ListConstraintsValidation.java
1 /*
2  * Copyright (c) 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 package org.opendaylight.yangtools.yang.data.tree.impl;
9
10 import static org.hamcrest.CoreMatchers.instanceOf;
11 import static org.hamcrest.MatcherAssert.assertThat;
12 import static org.junit.Assert.assertEquals;
13 import static org.junit.Assert.assertNotNull;
14 import static org.junit.Assert.assertThrows;
15 import static org.junit.Assert.assertTrue;
16
17 import java.util.List;
18 import java.util.Optional;
19 import org.junit.AfterClass;
20 import org.junit.Before;
21 import org.junit.BeforeClass;
22 import org.junit.Test;
23 import org.opendaylight.yangtools.yang.common.ErrorSeverity;
24 import org.opendaylight.yangtools.yang.common.ErrorTag;
25 import org.opendaylight.yangtools.yang.common.ErrorType;
26 import org.opendaylight.yangtools.yang.common.QName;
27 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
30 import org.opendaylight.yangtools.yang.data.api.YangNetconfError;
31 import org.opendaylight.yangtools.yang.data.api.YangNetconfErrorAware;
32 import org.opendaylight.yangtools.yang.data.api.schema.DistinctNodeContainer;
33 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
34 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
35 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
36 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
37 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
38 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
39 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
40 import org.opendaylight.yangtools.yang.data.tree.api.DataTree;
41 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidate;
42 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeConfiguration;
43 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeModification;
44 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeSnapshot;
45 import org.opendaylight.yangtools.yang.data.tree.api.DataValidationFailedException;
46 import org.opendaylight.yangtools.yang.data.tree.impl.di.InMemoryDataTreeFactory;
47 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
48 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
49
50 public class ListConstraintsValidation {
51     private static final QName MASTER_CONTAINER_QNAME = QName.create(
52             "urn:opendaylight:params:xml:ns:yang:list-constraints-validation-test-model", "2015-02-02",
53             "master-container");
54     private static final QName MIN_MAX_LIST_QNAME = QName.create(MASTER_CONTAINER_QNAME, "min-max-list");
55     private static final QName MIN_MAX_KEY_LEAF_QNAME = QName.create(MASTER_CONTAINER_QNAME, "min-max-key-leaf");
56     private static final QName UNBOUNDED_LIST_QNAME = QName.create(MASTER_CONTAINER_QNAME, "unbounded-list");
57     private static final QName UNBOUNDED_KEY_LEAF_QNAME = QName.create(MASTER_CONTAINER_QNAME, "unbounded-key-leaf");
58     private static final QName MIN_MAX_LEAF_LIST_QNAME = QName.create(MASTER_CONTAINER_QNAME, "min-max-leaf-list");
59     private static final QName UNBOUNDED_LEAF_LIST_QNAME = QName.create(MASTER_CONTAINER_QNAME, "unbounded-leaf-list");
60     private static final QName UNKEYED_LIST_QNAME = QName.create(MASTER_CONTAINER_QNAME, "unkeyed-list");
61     private static final QName UNKEYED_LEAF_QNAME = QName.create(MASTER_CONTAINER_QNAME, "unkeyed-leaf");
62
63     private static final YangInstanceIdentifier MASTER_CONTAINER_PATH = YangInstanceIdentifier
64             .of(MASTER_CONTAINER_QNAME);
65     private static final YangInstanceIdentifier MIN_MAX_LIST_PATH = YangInstanceIdentifier
66             .builder(MASTER_CONTAINER_PATH).node(MIN_MAX_LIST_QNAME).build();
67     private static final YangInstanceIdentifier UNBOUNDED_LIST_PATH = YangInstanceIdentifier
68             .builder(MASTER_CONTAINER_PATH).node(UNBOUNDED_LIST_QNAME).build();
69     private static final YangInstanceIdentifier MIN_MAX_LEAF_LIST_PATH = YangInstanceIdentifier
70             .builder(MASTER_CONTAINER_PATH).node(MIN_MAX_LEAF_LIST_QNAME).build();
71     private static final YangInstanceIdentifier UNBOUNDED_LEAF_LIST_PATH = YangInstanceIdentifier
72             .builder(MASTER_CONTAINER_PATH).node(UNBOUNDED_LEAF_LIST_QNAME).build();
73     private static final YangInstanceIdentifier UNKEYED_LIST_PATH = YangInstanceIdentifier
74             .builder(MASTER_CONTAINER_PATH).node(UNKEYED_LIST_QNAME).build();
75
76     private static EffectiveModelContext schemaContext;
77
78     private DataTree inMemoryDataTree;
79
80     @BeforeClass
81     public static void beforeClass() {
82         schemaContext = YangParserTestUtils.parseYangResource("/list-constraints-validation-test-model.yang");
83     }
84
85     @AfterClass
86     public static void afterClass() {
87         schemaContext = null;
88     }
89
90     @Before
91     public void prepare() throws DataValidationFailedException {
92         inMemoryDataTree = new InMemoryDataTreeFactory().create(DataTreeConfiguration.DEFAULT_OPERATIONAL,
93             schemaContext);
94         final DataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
95         final DataTreeModification modificationTree = initialDataTreeSnapshot.newModification();
96
97         modificationTree.write(MASTER_CONTAINER_PATH, ImmutableNodes.containerNode(MASTER_CONTAINER_QNAME));
98         modificationTree.ready();
99         inMemoryDataTree.commit(inMemoryDataTree.prepare(modificationTree));
100     }
101
102     @Test
103     public void minMaxListTestPass() throws DataValidationFailedException {
104
105         final MapEntryNode fooEntryNode = ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME, MIN_MAX_KEY_LEAF_QNAME, "foo");
106         final MapEntryNode barEntryNode = ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME, MIN_MAX_KEY_LEAF_QNAME, "bar");
107         final MapNode mapNode1 = ImmutableNodes.mapNodeBuilder()
108                 .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LIST_QNAME))
109                 .withChild(fooEntryNode).build();
110         final MapNode mapNode2 = ImmutableNodes.mapNodeBuilder()
111                 .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LIST_QNAME))
112                 .withChild(barEntryNode).build();
113
114         final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
115         modificationTree.write(MIN_MAX_LIST_PATH, mapNode1);
116         modificationTree.merge(MIN_MAX_LIST_PATH, mapNode2);
117         modificationTree.ready();
118
119         inMemoryDataTree.validate(modificationTree);
120         final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
121         inMemoryDataTree.commit(prepare);
122
123         final DataTreeSnapshot snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
124         final Optional<NormalizedNode> minMaxListRead = snapshotAfterCommit.readNode(MIN_MAX_LIST_PATH);
125         assertTrue(minMaxListRead.isPresent());
126         assertEquals(2, ((NormalizedNodeContainer<?>) minMaxListRead.get()).size());
127     }
128
129     @Test(expected = DataValidationFailedException.class)
130     public void minMaxListFail() throws DataValidationFailedException {
131         DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
132
133         final MapEntryNode fooEntryNode = ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME, MIN_MAX_KEY_LEAF_QNAME, "foo");
134         final MapEntryNode barEntryNode = ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME, MIN_MAX_KEY_LEAF_QNAME, "bar");
135         final MapEntryNode gooEntryNode = ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME, MIN_MAX_KEY_LEAF_QNAME, "goo");
136         final MapNode mapNode = ImmutableNodes.mapNodeBuilder()
137                 .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LIST_QNAME))
138                 .withChild(fooEntryNode).build();
139
140         final YangInstanceIdentifier fooPath = MIN_MAX_LIST_PATH.node(fooEntryNode.getIdentifier());
141         final YangInstanceIdentifier barPath = MIN_MAX_LIST_PATH.node(barEntryNode.getIdentifier());
142         final YangInstanceIdentifier gooPath = MIN_MAX_LIST_PATH.node(gooEntryNode.getIdentifier());
143
144         modificationTree.write(MIN_MAX_LIST_PATH, mapNode);
145         modificationTree.merge(barPath, barEntryNode);
146         modificationTree.write(gooPath, gooEntryNode);
147         modificationTree.delete(gooPath);
148         modificationTree.ready();
149
150         inMemoryDataTree.validate(modificationTree);
151         DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree);
152         inMemoryDataTree.commit(prepare1);
153
154         DataTreeSnapshot snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
155         Optional<NormalizedNode> minMaxListRead = snapshotAfterCommit.readNode(MIN_MAX_LIST_PATH);
156         assertTrue(minMaxListRead.isPresent());
157         assertEquals(2, ((NormalizedNodeContainer<?>) minMaxListRead.get()).size());
158
159         modificationTree = inMemoryDataTree.takeSnapshot().newModification();
160         modificationTree.write(gooPath, gooEntryNode);
161         modificationTree.ready();
162
163         inMemoryDataTree.validate(modificationTree);
164         prepare1 = inMemoryDataTree.prepare(modificationTree);
165         inMemoryDataTree.commit(prepare1);
166
167         snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
168         minMaxListRead = snapshotAfterCommit.readNode(MIN_MAX_LIST_PATH);
169         assertTrue(minMaxListRead.isPresent());
170         assertEquals(3, ((NormalizedNodeContainer<?>) minMaxListRead.get()).size());
171
172         modificationTree = inMemoryDataTree.takeSnapshot().newModification();
173
174         modificationTree.delete(gooPath);
175         modificationTree.delete(fooPath);
176         modificationTree.ready();
177
178         inMemoryDataTree.validate(modificationTree);
179     }
180
181     @Test
182     public void minMaxLeafListPass() throws DataValidationFailedException {
183         final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
184
185         final NodeWithValue<Object> barPath = new NodeWithValue<>(MIN_MAX_LIST_QNAME, "bar");
186         final NodeWithValue<Object> gooPath = new NodeWithValue<>(MIN_MAX_LIST_QNAME, "goo");
187
188         modificationTree.write(MIN_MAX_LEAF_LIST_PATH, Builders.leafSetBuilder()
189             .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LEAF_LIST_QNAME))
190             .withChildValue("foo")
191             .build());
192         modificationTree.write(MIN_MAX_LEAF_LIST_PATH.node(barPath), Builders.leafSetEntryBuilder()
193             .withNodeIdentifier(barPath)
194             .withValue("bar")
195             .build());
196         modificationTree.merge(MIN_MAX_LEAF_LIST_PATH.node(gooPath), Builders.leafSetEntryBuilder()
197             .withNodeIdentifier(gooPath)
198             .withValue("goo")
199             .build());
200         modificationTree.delete(MIN_MAX_LEAF_LIST_PATH.node(gooPath));
201         modificationTree.ready();
202
203         inMemoryDataTree.validate(modificationTree);
204         final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree);
205         inMemoryDataTree.commit(prepare1);
206
207         final DataTreeSnapshot snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
208         final Optional<NormalizedNode> masterContainer = snapshotAfterCommit.readNode(MASTER_CONTAINER_PATH);
209         assertTrue(masterContainer.isPresent());
210         final NormalizedNodeContainer<?> leafList =
211             (NormalizedNodeContainer<?>) ((DistinctNodeContainer) masterContainer.get())
212                 .childByArg(new NodeIdentifier(MIN_MAX_LEAF_LIST_QNAME));
213         assertNotNull(leafList);
214         assertEquals(2, leafList.size());
215     }
216
217     @Test
218     public void minMaxLeafListFail() {
219         final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
220
221         final NodeWithValue<Object> barPath = new NodeWithValue<>(MIN_MAX_LIST_QNAME, "bar");
222         final NodeWithValue<Object> gooPath = new NodeWithValue<>(MIN_MAX_LIST_QNAME, "goo");
223         final NodeWithValue<Object> fuuPath = new NodeWithValue<>(MIN_MAX_LIST_QNAME, "fuu");
224
225         modificationTree.write(MIN_MAX_LEAF_LIST_PATH, Builders.leafSetBuilder()
226             .withNodeIdentifier(new NodeIdentifier(MIN_MAX_LEAF_LIST_QNAME))
227             .withChildValue("foo")
228             .build());
229         modificationTree.write(MIN_MAX_LEAF_LIST_PATH.node(barPath), Builders.leafSetEntryBuilder()
230             .withNodeIdentifier(barPath)
231             .withValue("bar")
232             .build());
233         modificationTree.merge(MIN_MAX_LEAF_LIST_PATH.node(gooPath), Builders.leafSetEntryBuilder()
234             .withNodeIdentifier(gooPath)
235             .withValue("goo")
236             .build());
237         modificationTree.write(MIN_MAX_LEAF_LIST_PATH.node(fuuPath), Builders.leafSetEntryBuilder()
238             .withNodeIdentifier(fuuPath)
239             .withValue("fuu")
240             .build());
241
242         final MinMaxElementsValidationFailedException ex = assertThrows(MinMaxElementsValidationFailedException.class,
243             () -> modificationTree.ready());
244         assertEquals("(urn:opendaylight:params:xml:ns:yang:list-constraints-validation-test-model?"
245             + "revision=2015-02-02)min-max-leaf-list has too many elements (4), can have at most 3",
246             ex.getMessage());
247         assertTooManyElements(ex);
248     }
249
250     @Test
251     public void unkeyedListTestPass() throws DataValidationFailedException {
252         final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
253
254         final UnkeyedListNode unkeyedListNode = Builders.unkeyedListBuilder()
255             .withNodeIdentifier(new NodeIdentifier(UNKEYED_LIST_QNAME))
256             .withValue(List.of(Builders.unkeyedListEntryBuilder()
257                 .withNodeIdentifier(new NodeIdentifier(UNKEYED_LEAF_QNAME))
258                 .withChild(ImmutableNodes.leafNode(UNKEYED_LEAF_QNAME, "foo"))
259                 .build()))
260             .build();
261
262         modificationTree.write(MASTER_CONTAINER_PATH, ImmutableNodes.containerNode(MASTER_CONTAINER_QNAME));
263         modificationTree.merge(UNKEYED_LIST_PATH, unkeyedListNode);
264         modificationTree.ready();
265
266         inMemoryDataTree.validate(modificationTree);
267         final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree);
268         inMemoryDataTree.commit(prepare1);
269
270         final DataTreeSnapshot snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
271         final Optional<NormalizedNode> unkeyedListRead = snapshotAfterCommit.readNode(UNKEYED_LIST_PATH);
272         assertTrue(unkeyedListRead.isPresent());
273         assertEquals(1, ((UnkeyedListNode) unkeyedListRead.get()).size());
274     }
275
276     @Test
277     public void unkeyedListTestFail() {
278         final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
279
280         modificationTree.write(UNKEYED_LIST_PATH, Builders.unkeyedListBuilder()
281             .withNodeIdentifier(new NodeIdentifier(UNKEYED_LIST_QNAME))
282             .withValue(List.of(
283                 Builders.unkeyedListEntryBuilder()
284                     .withNodeIdentifier(new NodeIdentifier(UNKEYED_LEAF_QNAME))
285                     .withChild(ImmutableNodes.leafNode(UNKEYED_LEAF_QNAME, "foo"))
286                     .build(),
287                 Builders.unkeyedListEntryBuilder()
288                     .withNodeIdentifier(new NodeIdentifier(UNKEYED_LEAF_QNAME))
289                     .withChild(ImmutableNodes.leafNode(UNKEYED_LEAF_QNAME, "bar"))
290                     .build()))
291             .build());
292         final MinMaxElementsValidationFailedException ex = assertThrows(MinMaxElementsValidationFailedException.class,
293             () -> modificationTree.ready());
294         assertEquals("(urn:opendaylight:params:xml:ns:yang:list-constraints-validation-test-model?"
295             + "revision=2015-02-02)unkeyed-list has too many elements (2), can have at most 1", ex.getMessage());
296         assertTooManyElements(ex);
297     }
298
299     static void assertTooFewElements(final Exception ex) {
300         assertOperationFailed(ex, "too-few-elements");
301     }
302
303     static void assertTooManyElements(final Exception ex) {
304         assertOperationFailed(ex, "too-many-elements");
305     }
306
307     private static void assertOperationFailed(final Exception ex, final String expectedAppTag) {
308         assertThat(ex, instanceOf(YangNetconfErrorAware.class));
309         final List<YangNetconfError> errors = ((YangNetconfErrorAware) ex).getNetconfErrors();
310         assertEquals(1, errors.size());
311         final YangNetconfError error = errors.get(0);
312         assertEquals(ErrorSeverity.ERROR, error.severity());
313         assertEquals(ErrorType.APPLICATION, error.type());
314         assertEquals(ErrorTag.OPERATION_FAILED, error.tag());
315         assertEquals(expectedAppTag, error.appTag());
316     }
317 }