Migrate yang-data-tree-ri to JUnit5
[yangtools.git] / data / yang-data-tree-ri / src / test / java / org / opendaylight / yangtools / yang / data / tree / impl / YT776Test.java
1 /*
2  * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.jupiter.api.Assertions.assertEquals;
11 import static org.junit.jupiter.api.Assertions.assertThrows;
12 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.choiceBuilder;
13 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.containerBuilder;
14 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.leafBuilder;
15 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.leafSetBuilder;
16 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.mapBuilder;
17 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.mapEntryBuilder;
18 import static org.opendaylight.yangtools.yang.data.tree.impl.ListConstraintsValidation.assertTooFewElements;
19 import static org.opendaylight.yangtools.yang.data.tree.impl.ListConstraintsValidation.assertTooManyElements;
20
21 import com.google.common.collect.ImmutableMap;
22 import org.junit.jupiter.api.AfterAll;
23 import org.junit.jupiter.api.BeforeAll;
24 import org.junit.jupiter.api.BeforeEach;
25 import org.junit.jupiter.api.Test;
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.NodeIdentifierWithPredicates;
30 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
32 import org.opendaylight.yangtools.yang.data.tree.api.DataTree;
33 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeConfiguration;
34 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeModification;
35 import org.opendaylight.yangtools.yang.data.tree.api.DataValidationFailedException;
36 import org.opendaylight.yangtools.yang.data.tree.impl.di.InMemoryDataTreeFactory;
37 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
38 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
39
40 class YT776Test {
41     private static final QName MODULE = QName.create("yt776", "yt776");
42     private static final NodeIdentifier BOX = new NodeIdentifier(QName.create(MODULE, "box"));
43     private static final QName OBJECT = QName.create(MODULE, "object");
44     private static final QName OBJECT_ID = QName.create(MODULE, "object-id");
45     private static final NodeIdentifier OBJECT_LIST = new NodeIdentifier(OBJECT);
46     private static final NodeIdentifierWithPredicates OBJECT_ITEM = NodeIdentifierWithPredicates.of(OBJECT,
47         ImmutableMap.of(OBJECT_ID, "1"));
48     private static final LeafNode<?> OBJECT_ID_LEAF = leafBuilder().withNodeIdentifier(new NodeIdentifier(OBJECT_ID))
49             .withValue("1").build();
50     private static final NodeIdentifier ATTRIBUTES = new NodeIdentifier(QName.create(MODULE, "attributes"));
51
52     private static final QName NESTED = QName.create(MODULE, "nested");
53     private static final QName NESTED_ATTRIBUTE = QName.create(MODULE, "nested-attribute");
54     private static final NodeIdentifier NESTED_LIST = new NodeIdentifier(NESTED);
55     private static final NodeIdentifierWithPredicates NESTED_ITEM = NodeIdentifierWithPredicates.of(NESTED,
56         ImmutableMap.of(NESTED_ATTRIBUTE, "foo"));
57
58     private static final NodeIdentifier ANY_OF = new NodeIdentifier(QName.create(MODULE, "any-of"));
59     private static final QName SOME_LEAF = QName.create(MODULE, "some-leaf");
60     private static final NodeIdentifier SOME_LEAF_ID = new NodeIdentifier(SOME_LEAF);
61     private static final QName SOME_LIST = QName.create(MODULE, "some-list");
62     private static final NodeIdentifier SOME_LIST_ID = new NodeIdentifier(SOME_LIST);
63     private static final NodeIdentifierWithPredicates SOME_LIST_ITEM = NodeIdentifierWithPredicates.of(SOME_LIST,
64                 ImmutableMap.of(SOME_LEAF, "foo"));
65     private static EffectiveModelContext SCHEMA_CONTEXT;
66
67     private DataTree dataTree;
68
69     @BeforeAll
70     static void beforeClass() {
71         SCHEMA_CONTEXT = YangParserTestUtils.parseYang("""
72             module yt776 {
73               namespace yt776;
74               prefix yt776;
75
76               container box {
77                 list object {
78                   key object-id;
79
80                   leaf object-id {
81                     type string;
82                   }
83
84                   leaf-list attributes {
85                     type string;
86                     min-elements 1;
87                     max-elements 2;
88                   }
89
90                   list nested {
91                     key nested-attribute;
92                     max-elements 1;
93                     leaf nested-attribute {
94                       type string;
95                     }
96                   }
97                 }
98
99                 choice any-of {
100                   leaf some-leaf {
101                     type string;
102                   }
103                   list some-list {
104                     key some-leaf;
105                     min-elements 1;
106
107                     leaf some-leaf {
108                       type string;
109                     }
110                   }
111                 }
112               }
113             }""");
114     }
115
116     @AfterAll
117     static void afterClass() {
118         SCHEMA_CONTEXT = null;
119     }
120
121     @BeforeEach
122     void init() {
123         dataTree = new InMemoryDataTreeFactory().create(DataTreeConfiguration.DEFAULT_CONFIGURATION, SCHEMA_CONTEXT);
124     }
125
126     @Test
127     void testNoAttributes() {
128         final var mod = dataTree.takeSnapshot().newModification();
129         mod.write(YangInstanceIdentifier.of(BOX), containerBuilder().withNodeIdentifier(BOX)
130             .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
131                 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
132                     .withChild(OBJECT_ID_LEAF)
133                     .build())
134                 .build())
135             .build());
136
137         final IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, mod::ready);
138         // FIXME: This is actually mandatory leaf enforcer kicking in: attributes have to be present. This is
139         //        most probably not what we want.
140         assertEquals("Node (yt776)object[{(yt776)object-id=1}] is missing mandatory descendant /(yt776)attributes",
141                 ex.getMessage());
142     }
143
144     @Test
145     void testEmptyAttributes() throws DataValidationFailedException {
146         final var mod = write(containerBuilder().withNodeIdentifier(BOX)
147             .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
148                 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
149                     .withChild(OBJECT_ID_LEAF)
150                     .withChild(leafSetBuilder().withNodeIdentifier(ATTRIBUTES).build())
151                     .build())
152                 .build())
153             .build());
154
155         final var ex = assertThrows(MinMaxElementsValidationFailedException.class, mod::ready);
156         assertEquals("(yt776)attributes does not have enough elements (0), needs at least 1", ex.getMessage());
157         assertTooFewElements(ex);
158     }
159
160     @Test
161     void testOneAttribute() throws DataValidationFailedException {
162         writeAndCommit(containerBuilder().withNodeIdentifier(BOX)
163             .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
164                 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
165                     .withChild(OBJECT_ID_LEAF)
166                     .withChild(leafSetBuilder().withNodeIdentifier(ATTRIBUTES)
167                         .withChildValue("object1")
168                         .build())
169                     .build())
170                 .build())
171             .build());
172     }
173
174     @Test
175     void testTwoAttributes() throws DataValidationFailedException {
176         writeAndCommit(containerBuilder().withNodeIdentifier(BOX)
177             .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
178                 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
179                     .withChild(OBJECT_ID_LEAF)
180                     .withChild(leafSetBuilder().withNodeIdentifier(ATTRIBUTES)
181                         .withChildValue("object1")
182                         .withChildValue("object2")
183                         .build())
184                     .build())
185                 .build())
186             .build());
187     }
188
189     @Test
190     void testThreeAttributes() throws DataValidationFailedException {
191         final var mod = write(containerBuilder().withNodeIdentifier(BOX)
192             .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
193                 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
194                     .withChild(OBJECT_ID_LEAF)
195                     .withChild(leafSetBuilder().withNodeIdentifier(ATTRIBUTES)
196                         .withChildValue("object1")
197                         .withChildValue("object2")
198                         .withChildValue("object3")
199                         .build())
200                     .build())
201                 .build())
202             .build());
203
204         final var ex = assertThrows(MinMaxElementsValidationFailedException.class, mod::ready);
205         assertEquals("(yt776)attributes has too many elements (3), can have at most 2", ex.getMessage());
206         assertTooManyElements(ex);
207     }
208
209     @Test
210     void testEmptyAndMergeOne() throws DataValidationFailedException {
211         final var mod = dataTree.takeSnapshot().newModification();
212         mod.write(YangInstanceIdentifier.of(BOX), containerBuilder().withNodeIdentifier(BOX)
213             .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
214                 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
215                     .withChild(OBJECT_ID_LEAF)
216                     .build())
217                 .build())
218             .build());
219         mod.merge(YangInstanceIdentifier.of(BOX), containerBuilder().withNodeIdentifier(BOX)
220             .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
221                 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
222                     .withChild(OBJECT_ID_LEAF)
223                     .withChild(leafSetBuilder().withNodeIdentifier(ATTRIBUTES)
224                         .withChildValue("object1")
225                         .build())
226                     .build())
227                 .build())
228             .build());
229
230         commit(mod);
231     }
232
233     @Test
234     void testEmptyAndMergeOneWithListTouched() throws DataValidationFailedException {
235         final var mod = dataTree.takeSnapshot().newModification();
236         mod.write(YangInstanceIdentifier.of(BOX), containerBuilder().withNodeIdentifier(BOX)
237             .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
238                 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
239                     .withChild(OBJECT_ID_LEAF)
240                     .build())
241                 .build())
242             .build());
243         mod.merge(YangInstanceIdentifier.of(BOX), containerBuilder().withNodeIdentifier(BOX)
244             .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
245                 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
246                     .withChild(OBJECT_ID_LEAF)
247                     .withChild(leafSetBuilder().withNodeIdentifier(ATTRIBUTES)
248                         .withChildValue("object1")
249                         .build())
250                     .build())
251                 .build())
252             .build());
253
254         mod.delete(YangInstanceIdentifier.of(BOX, OBJECT_LIST, OBJECT_ITEM, NESTED_LIST, NESTED_ITEM));
255
256         commit(mod);
257     }
258
259     @Test
260     void testDisappearInChoice() throws DataValidationFailedException {
261         var mod = dataTree.takeSnapshot().newModification();
262         // Initialize choice with list
263         mod.write(YangInstanceIdentifier.of(BOX), containerBuilder()
264             .withNodeIdentifier(BOX)
265             .withChild(choiceBuilder().withNodeIdentifier(ANY_OF)
266                 .withChild(mapBuilder().withNodeIdentifier(SOME_LIST_ID)
267                     .withChild(mapEntryBuilder()
268                         .withNodeIdentifier(SOME_LIST_ITEM)
269                         .withChild(leafBuilder().withNodeIdentifier(SOME_LEAF_ID).withValue("foo").build())
270                         .build())
271                     .build())
272                 .build())
273             .build());
274         commit(mod);
275
276         // Now delete the single item, causing the list to fizzle, while creating the alterinative case
277         mod = dataTree.takeSnapshot().newModification();
278         mod.delete(YangInstanceIdentifier.of(BOX, ANY_OF, SOME_LIST_ID, SOME_LIST_ITEM));
279         mod.write(YangInstanceIdentifier.of(BOX, ANY_OF, SOME_LEAF_ID),
280             leafBuilder().withNodeIdentifier(SOME_LEAF_ID).withValue("foo").build());
281
282         commit(mod);
283     }
284
285     private DataTreeModification write(final ContainerNode data) throws DataValidationFailedException {
286         final var mod = dataTree.takeSnapshot().newModification();
287         mod.write(YangInstanceIdentifier.of(BOX), data);
288         return mod;
289     }
290
291     private void writeAndCommit(final ContainerNode data) throws DataValidationFailedException {
292         final var mod = dataTree.takeSnapshot().newModification();
293         mod.write(YangInstanceIdentifier.of(BOX), data);
294         commit(mod);
295     }
296
297     private void commit(final DataTreeModification mod) throws DataValidationFailedException {
298         mod.ready();
299         dataTree.validate(mod);
300         dataTree.commit(dataTree.prepare(mod));
301     }
302 }