Migrate yang-data-tree-ri to JUnit5
[yangtools.git] / data / yang-data-tree-ri / src / test / java / org / opendaylight / yangtools / yang / data / tree / impl / Bug5830Test.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.jupiter.api.Assertions.assertEquals;
11 import static org.junit.jupiter.api.Assertions.assertNotNull;
12 import static org.junit.jupiter.api.Assertions.assertThrows;
13 import static org.junit.jupiter.api.Assertions.assertTrue;
14 import static org.junit.jupiter.api.Assertions.fail;
15
16 import org.junit.jupiter.api.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.YangInstanceIdentifier.NodeIdentifierWithPredicates;
21 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
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.DataTreeConfiguration;
26 import org.opendaylight.yangtools.yang.data.tree.api.DataValidationFailedException;
27 import org.opendaylight.yangtools.yang.data.tree.impl.di.InMemoryDataTreeFactory;
28 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
29 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
30
31 class Bug5830Test {
32     private static final String NS = "foo";
33     private static final String REV = "2016-05-17";
34     private static final QName TASK_CONTAINER = QName.create(NS, REV, "task-container");
35     private static final QName TASK = QName.create(NS, REV, "task");
36     private static final QName TASK_ID = QName.create(NS, REV, "task-id");
37     private static final QName TASK_DATA = QName.create(NS, REV, "task-data");
38     private static final QName OTHER_DATA = QName.create(NS, REV, "other-data");
39     private static final QName MANDATORY_DATA = QName.create(NS, REV, "mandatory-data");
40     private static final QName TASK_MANDATORY_LEAF = QName.create(NS, REV, "task-mandatory-leaf");
41     private static final QName NON_PRESENCE_CONTAINER = QName.create(NS, REV, "non-presence-container");
42     private static final QName NON_PRESENCE_CONTAINER_2 = QName.create(NS, REV, "non-presence-container-2");
43     private static final QName PRESENCE_CONTAINER_2 = QName.create(NS, REV, "presence-container-2");
44     private static final QName MANDATORY_LEAF_2 = QName.create(NS, REV, "mandatory-leaf-2");
45
46     private static DataTree initDataTree(final EffectiveModelContext schemaContext)
47             throws DataValidationFailedException {
48         final var inMemoryDataTree = new InMemoryDataTreeFactory().create(
49                 DataTreeConfiguration.DEFAULT_CONFIGURATION, schemaContext);
50
51         final var taskNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(TASK)).build();
52         final var modificationTree = inMemoryDataTree.takeSnapshot().newModification();
53         modificationTree.write(YangInstanceIdentifier.of(TASK_CONTAINER, TASK), taskNode);
54         modificationTree.ready();
55
56         inMemoryDataTree.validate(modificationTree);
57         final var prepare = inMemoryDataTree.prepare(modificationTree);
58         inMemoryDataTree.commit(prepare);
59         return inMemoryDataTree;
60     }
61
62     @Test
63     void testMandatoryNodes() throws DataValidationFailedException {
64         testPresenceContainer();
65         testNonPresenceContainer();
66         testMultipleContainers();
67     }
68
69     private static void testPresenceContainer() throws DataValidationFailedException {
70         final var schemaContext = YangParserTestUtils.parseYang("""
71             module foo-presence {
72               yang-version 1;
73               namespace "foo";
74               prefix foo;
75
76               revision 2016-05-17 {
77                 description "test";
78               }
79
80               container task-container {
81                 list task {
82                   key "task-id";
83                   leaf task-id {
84                     type string;
85                   }
86                   leaf task-mandatory-leaf {
87                     type string;
88                     mandatory true;
89                   }
90
91                   container task-data {
92                     presence "Task data";
93                     leaf mandatory-data {
94                       type string;
95                       mandatory true;
96                     }
97                     leaf other-data {
98                       type string;
99                     }
100                   }
101                 }
102               }
103             }""");
104         assertNotNull(schemaContext, "Schema context must not be null.");
105
106         testContainerIsNotPresent(schemaContext);
107         final var ex = assertThrows(IllegalArgumentException.class, () -> testContainerIsPresent(schemaContext));
108         assertEquals(
109             "Node (foo?revision=2016-05-17)task-data is missing mandatory descendant /(foo?revision=2016-05-17)"
110                 + "mandatory-data", ex.getMessage());
111         testMandatoryDataLeafIsPresent(schemaContext);
112     }
113
114     private static void testNonPresenceContainer() throws DataValidationFailedException {
115         final var schemaContext = YangParserTestUtils.parseYang("""
116             module foo-non-presence {
117               yang-version 1;
118               namespace "foo";
119               prefix foo;
120
121               revision 2016-05-17 {
122                 description "test";
123               }
124
125               container task-container {
126                 list task {
127                   key "task-id";
128
129                   leaf task-id {
130                     type string;
131                   }
132                   leaf task-mandatory-leaf {
133                     type string;
134                     mandatory true;
135                   }
136
137                   container task-data {
138                     leaf mandatory-data {
139                       type string;
140                       mandatory true;
141                     }
142                     leaf other-data {
143                       type string;
144                     }
145                   }
146                 }
147               }
148             }""");
149         assertNotNull(schemaContext, "Schema context must not be null.");
150
151         try {
152             testContainerIsNotPresent(schemaContext);
153             fail("Should fail due to missing mandatory node.");
154         } catch (IllegalArgumentException e) {
155             assertEquals(
156                     "Node (foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=123}] is missing mandatory "
157                             + "descendant /(foo?revision=2016-05-17)task-data/mandatory-data", e.getMessage());
158         }
159
160         try {
161             testContainerIsPresent(schemaContext);
162             fail("Should fail due to missing mandatory node.");
163         } catch (IllegalArgumentException e) {
164             assertEquals(
165                     "Node (foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=123}] is missing mandatory "
166                             + "descendant /(foo?revision=2016-05-17)task-data/mandatory-data", e.getMessage());
167         }
168         testMandatoryDataLeafIsPresent(schemaContext);
169     }
170
171     private static void testMultipleContainers() throws DataValidationFailedException {
172         final var schemaContext = YangParserTestUtils.parseYang("""
173             module foo-multiple {
174               yang-version 1;
175               namespace "foo";
176               prefix foo;
177
178               revision 2016-05-17 {
179                 description "test";
180               }
181
182               container task-container {
183                 list task {
184                   key "task-id";
185
186                   leaf task-id {
187                     type string;
188                   }
189                   leaf task-mandatory-leaf {
190                     type string;
191                     mandatory true;
192                   }
193
194                   container task-data {
195                     presence "Task data";
196
197                     leaf mandatory-data {
198                       type string;
199                       mandatory true;
200                     }
201                     leaf other-data {
202                       type string;
203                     }
204
205                     container non-presence-container {
206
207                       container presence-container {
208                         presence "presence container";
209
210                         leaf mandatory-leaf {
211                           mandatory true;
212                           type string;
213                         }
214                       }
215
216                       container non-presence-container-2 {
217                         leaf mandatory-leaf-2 {
218                           mandatory true;
219                           type string;
220                         }
221                       }
222
223                       container presence-container-2 {
224                         presence "presence container";
225
226                         leaf mandatory-leaf-3 {
227                           mandatory true;
228                           type string;
229                         }
230                       }
231                     }
232                   }
233                 }
234               }
235             }""");
236         assertNotNull(schemaContext, "Schema context must not be null.");
237
238         testContainerIsNotPresent(schemaContext);
239
240         try {
241             testContainerIsPresent(schemaContext);
242             fail("Should fail due to missing mandatory node under present presence container.");
243         } catch (IllegalArgumentException e) {
244             assertTrue(e.getMessage().startsWith(
245                     "Node (foo?revision=2016-05-17)task-data is missing mandatory descendant"));
246         }
247
248         try {
249             testMandatoryDataLeafIsPresent(schemaContext);
250             fail("Should fail due to missing mandatory node under present presence container.");
251         } catch (IllegalArgumentException e) {
252             assertEquals("""
253                 Node (foo?revision=2016-05-17)task-data is missing mandatory descendant \
254                 /(foo?revision=2016-05-17)non-presence-container/\
255                 non-presence-container-2/mandatory-leaf-2""", e.getMessage());
256         }
257
258         testMandatoryLeaf2IsPresent(schemaContext, false);
259
260         try {
261             testMandatoryLeaf2IsPresent(schemaContext, true);
262             fail("Should fail due to missing mandatory node under present presence container.");
263         } catch (IllegalArgumentException e) {
264             assertEquals(
265                     "Node (foo?revision=2016-05-17)presence-container-2 is missing mandatory "
266                             + "descendant /(foo?revision=2016-05-17)mandatory-leaf-3", e.getMessage());
267         }
268     }
269
270     private static void testContainerIsNotPresent(final EffectiveModelContext schemaContext)
271             throws DataValidationFailedException {
272         final var inMemoryDataTree = initDataTree(schemaContext);
273         final var taskEntryNode = Builders.mapEntryBuilder()
274                 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123"))
275                 .withChild(ImmutableNodes.leafNode(TASK_ID, "123"))
276                 .withChild(ImmutableNodes.leafNode(TASK_MANDATORY_LEAF, "mandatory data"))
277                 .build();
278
279         final var modificationTree = inMemoryDataTree.takeSnapshot().newModification();
280         modificationTree.write(
281             YangInstanceIdentifier.of(TASK_CONTAINER, TASK).node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123")),
282             taskEntryNode);
283         modificationTree.ready();
284
285         inMemoryDataTree.validate(modificationTree);
286         final var prepare = inMemoryDataTree.prepare(modificationTree);
287         inMemoryDataTree.commit(prepare);
288     }
289
290     private static void testContainerIsPresent(final EffectiveModelContext schemaContext)
291             throws DataValidationFailedException {
292         final var inMemoryDataTree = initDataTree(schemaContext);
293
294         final var taskEntryNode = Builders.mapEntryBuilder()
295                 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123"))
296                 .withChild(ImmutableNodes.leafNode(TASK_ID, "123"))
297                 .withChild(ImmutableNodes.leafNode(TASK_MANDATORY_LEAF, "mandatory data"))
298                 .withChild(createTaskDataContainer(false)).build();
299
300         final var modificationTree = inMemoryDataTree.takeSnapshot().newModification();
301         modificationTree.write(
302             YangInstanceIdentifier.of(TASK_CONTAINER, TASK).node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123")),
303             taskEntryNode);
304         modificationTree.ready();
305
306         inMemoryDataTree.validate(modificationTree);
307         final var prepare = inMemoryDataTree.prepare(modificationTree);
308         inMemoryDataTree.commit(prepare);
309     }
310
311     private static void testMandatoryDataLeafIsPresent(final EffectiveModelContext schemaContext)
312             throws DataValidationFailedException {
313         final var inMemoryDataTree = initDataTree(schemaContext);
314
315         final var taskEntryNode = Builders.mapEntryBuilder()
316                 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123"))
317                 .withChild(ImmutableNodes.leafNode(TASK_ID, "123"))
318                 .withChild(ImmutableNodes.leafNode(TASK_MANDATORY_LEAF, "mandatory data"))
319                 .withChild(createTaskDataContainer(true)).build();
320
321         final var modificationTree = inMemoryDataTree.takeSnapshot().newModification();
322         modificationTree.write(
323             YangInstanceIdentifier.of(TASK_CONTAINER, TASK).node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123")),
324             taskEntryNode);
325         modificationTree.ready();
326
327         inMemoryDataTree.validate(modificationTree);
328         final var prepare = inMemoryDataTree.prepare(modificationTree);
329         inMemoryDataTree.commit(prepare);
330     }
331
332     private static void testMandatoryLeaf2IsPresent(final EffectiveModelContext schemaContext,
333             final boolean withPresenceContianer) throws DataValidationFailedException {
334         final var inMemoryDataTree = initDataTree(schemaContext);
335
336         final var taskEntryNode = Builders.mapEntryBuilder()
337                 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123"))
338                 .withChild(ImmutableNodes.leafNode(TASK_ID, "123"))
339                 .withChild(ImmutableNodes.leafNode(TASK_MANDATORY_LEAF, "mandatory data"))
340                 .withChild(createTaskDataMultipleContainer(withPresenceContianer))
341                 .build();
342
343         final var modificationTree = inMemoryDataTree.takeSnapshot().newModification();
344         modificationTree.write(
345             YangInstanceIdentifier.of(TASK_CONTAINER, TASK).node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "123")),
346             taskEntryNode);
347         modificationTree.ready();
348
349         inMemoryDataTree.validate(modificationTree);
350         final var prepare = inMemoryDataTree.prepare(modificationTree);
351         inMemoryDataTree.commit(prepare);
352     }
353
354     private static DataContainerChild createTaskDataContainer(final boolean withMandatoryNode) {
355         final var taskDataBuilder = Builders.containerBuilder()
356                 .withNodeIdentifier(new NodeIdentifier(TASK_DATA))
357                 .withChild(ImmutableNodes.leafNode(OTHER_DATA, "foo"));
358         if (withMandatoryNode) {
359             taskDataBuilder.withChild(ImmutableNodes.leafNode(MANDATORY_DATA, "mandatory-data-value"));
360         }
361         return taskDataBuilder.build();
362     }
363
364     private static DataContainerChild createTaskDataMultipleContainer(final boolean withPresenceContianer) {
365         final var nonPresenceContainerBuilder = Builders.containerBuilder()
366             .withNodeIdentifier(new NodeIdentifier(NON_PRESENCE_CONTAINER))
367             .withChild(Builders.containerBuilder()
368                 .withNodeIdentifier(new NodeIdentifier(NON_PRESENCE_CONTAINER_2))
369                 .withChild(ImmutableNodes.leafNode(MANDATORY_LEAF_2, "mandatory leaf data 2")).build());
370
371         if (withPresenceContianer) {
372             nonPresenceContainerBuilder.withChild(Builders.containerBuilder()
373                     .withNodeIdentifier(new NodeIdentifier(PRESENCE_CONTAINER_2)).build());
374         }
375
376         return Builders.containerBuilder()
377             .withNodeIdentifier(new NodeIdentifier(TASK_DATA))
378             .withChild(ImmutableNodes.leafNode(OTHER_DATA, "foo"))
379             .withChild(ImmutableNodes.leafNode(MANDATORY_DATA, "mandatory-data-value"))
380             .withChild(nonPresenceContainerBuilder.build())
381             .build();
382     }
383 }