Migrate yang-data-tree-ri to JUnit5
[yangtools.git] / data / yang-data-tree-ri / src / test / java / org / opendaylight / yangtools / yang / data / tree / impl / UniqueConstraintTest.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.assertInstanceOf;
12 import static org.junit.jupiter.api.Assertions.assertThrows;
13 import static org.junit.jupiter.api.Assertions.assertTrue;
14
15 import org.junit.jupiter.api.BeforeAll;
16 import org.junit.jupiter.api.Test;
17 import org.opendaylight.yangtools.yang.common.ErrorSeverity;
18 import org.opendaylight.yangtools.yang.common.ErrorTag;
19 import org.opendaylight.yangtools.yang.common.ErrorType;
20 import org.opendaylight.yangtools.yang.common.QName;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
24 import org.opendaylight.yangtools.yang.data.api.YangNetconfErrorAware;
25 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
26 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
27 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
28 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeConfiguration;
29 import org.opendaylight.yangtools.yang.data.tree.api.DataValidationFailedException;
30 import org.opendaylight.yangtools.yang.data.tree.api.TreeType;
31 import org.opendaylight.yangtools.yang.data.tree.api.UniqueConstraintException;
32 import org.opendaylight.yangtools.yang.data.tree.impl.di.InMemoryDataTreeFactory;
33 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
34
35 class UniqueConstraintTest {
36     private static final String NS = "foo";
37     private static final String REV = "2016-05-17";
38     private static final QName TASK_CONTAINER = QName.create(NS, REV, "task-container");
39     private static final QName TASK = QName.create(NS, REV, "task");
40     private static final QName TASK_ID = QName.create(NS, REV, "task-id");
41     private static final QName MY_LEAF_1 = QName.create(NS, REV, "my-leaf-1");
42     private static final QName MY_LEAF_2 = QName.create(NS, REV, "my-leaf-2");
43     private static final QName MY_LEAF_3 = QName.create(NS, REV, "my-leaf-3");
44     private static final QName MY_CONTAINER = QName.create(NS, REV, "my-container");
45
46     private static EffectiveModelContext TEST_MODEL;
47
48     @BeforeAll
49     static void beforeClass() {
50         TEST_MODEL = TestModel.createTestContext("/yt570.yang");
51     }
52
53     @Test
54     void switchEntriesTest() throws DataValidationFailedException {
55         final var inMemoryDataTree = initDataTree(TEST_MODEL, true);
56         writeMapEntry(inMemoryDataTree, "1", "l1", "l2", "l3");
57         writeMapEntry(inMemoryDataTree, "2", "l2", "l3", "l4");
58
59         final var modificationTree = inMemoryDataTree.takeSnapshot().newModification();
60
61         final var mapEntry1 = createMapEntry("1", "l2", "l3", "l4");
62         final var mapEntry2 = createMapEntry("2", "l1", "l2", "l3");
63
64         //switch values of map entries
65         modificationTree.write(
66                 YangInstanceIdentifier.of(TASK_CONTAINER).node(TASK)
67                         .node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "1")), mapEntry1);
68         modificationTree.write(
69                 YangInstanceIdentifier.of(TASK_CONTAINER).node(TASK)
70                         .node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "2")), mapEntry2);
71
72         modificationTree.ready();
73         inMemoryDataTree.validate(modificationTree);
74         final var prepare = inMemoryDataTree.prepare(modificationTree);
75         inMemoryDataTree.commit(prepare);
76     }
77
78     @Test
79     void mapTest() throws DataValidationFailedException {
80         final var inMemoryDataTree = emptyDataTree(TEST_MODEL, true);
81
82
83         verifyException(assertThrows(UniqueValidationFailedException.class,
84             () -> writeMap(inMemoryDataTree, true)),
85             "(foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=",
86             "}] violates unique constraint on [l1, l2] of ",
87             "(foo?revision=2016-05-17)my-leaf-1",
88             "(foo?revision=2016-05-17)my-leaf-2]");
89
90         writeMap(inMemoryDataTree, false);
91         verifyException(assertThrows(UniqueConstraintException.class,
92             () -> writeMapEntry(inMemoryDataTree, "4", "l1", "l2", "l30")),
93             "(foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=",
94             "}] violates unique constraint on [l1, l2] of ",
95             "(foo?revision=2016-05-17)my-leaf-1",
96             "(foo?revision=2016-05-17)my-leaf-2");
97     }
98
99     @Test
100     void mapEntryTest() throws DataValidationFailedException {
101         final var inMemoryDataTree = initDataTree(TEST_MODEL, true);
102         writeAndRemoveMapEntries(inMemoryDataTree, true);
103         writeAndRemoveMapEntries(inMemoryDataTree, false);
104     }
105
106     private static void writeAndRemoveMapEntries(final InMemoryDataTree inMemoryDataTree, final boolean clear)
107             throws DataValidationFailedException {
108         writeMapEntry(inMemoryDataTree, "1", "l1", "l2", "l3");
109         writeMapEntry(inMemoryDataTree, "2", "l2", "l3", "l4");
110         writeMapEntry(inMemoryDataTree, "3", "l3", "l4", "l5");
111         writeMapEntry(inMemoryDataTree, "2", "l2", "l3", "l6");
112         writeMapEntry(inMemoryDataTree, "10", "l2", "l10", "l4");
113         verifyException(assertThrows(UniqueConstraintException.class,
114             () -> writeMapEntry(inMemoryDataTree, "4", "l1", "l5", "l3")),
115             "(foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=",
116                     "}] violates unique constraint on [l1, l3] of ",
117                     "(foo?revision=2016-05-17)my-container, my-leaf-3",
118                     "(foo?revision=2016-05-17)my-leaf-1");
119         writeMapEntry(inMemoryDataTree, "4", "l4", "l5", "l6");
120         verifyException(assertThrows(UniqueConstraintException.class,
121             () -> writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7")),
122             "(foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=",
123             "}] violates unique constraint on [l3, l4] of ",
124             "(foo?revision=2016-05-17)my-leaf-1",
125             "(foo?revision=2016-05-17)my-leaf-2");
126         removeMapEntry(inMemoryDataTree, taskEntryKey("3"));
127         writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7");
128         writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7");
129         verifyException(assertThrows(UniqueConstraintException.class,
130             () -> writeMapEntry(inMemoryDataTree, "6", "l3", "l4", "l11")),
131             "(foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=",
132             "}] violates unique constraint on [l3, l4] of ",
133             "(foo?revision=2016-05-17)my-leaf-1",
134             "(foo?revision=2016-05-17)my-leaf-2");
135
136         if (clear) {
137             removeMapEntry(inMemoryDataTree, taskEntryKey("1"));
138             removeMapEntry(inMemoryDataTree, taskEntryKey("2"));
139             removeMapEntry(inMemoryDataTree, taskEntryKey("4"));
140             removeMapEntry(inMemoryDataTree, taskEntryKey("5"));
141             removeMapEntry(inMemoryDataTree, taskEntryKey("10"));
142         }
143     }
144
145     private static void verifyException(final Exception ex, final String expectedStart,
146             final String... expectedLeaves) {
147         verifyExceptionMessage(expectedStart, ex.getMessage(), expectedLeaves);
148         assertInstanceOf(YangNetconfErrorAware.class, ex);
149         final var errors = ((YangNetconfErrorAware) ex).getNetconfErrors();
150         assertEquals(1, errors.size());
151         final var error = errors.get(0);
152         assertEquals(ErrorSeverity.ERROR, error.severity());
153         assertEquals(ErrorType.APPLICATION, error.type());
154         assertEquals(ErrorTag.OPERATION_FAILED, error.tag());
155         assertEquals("data-not-unique", error.appTag());
156     }
157
158     private static void verifyExceptionMessage(final String expectedStart, final String message,
159             final String... leafs) {
160         assertTrue(message.startsWith(expectedStart));
161         for (final var leaf : leafs) {
162             assertTrue(message.contains(leaf));
163         }
164     }
165
166     private static void writeMap(final InMemoryDataTree inMemoryDataTree, final boolean withUniqueViolation)
167             throws DataValidationFailedException {
168         final var taskNode = Builders
169                 .mapBuilder()
170                 .withNodeIdentifier(new NodeIdentifier(TASK))
171                 .withChild(createMapEntry("1", "l1", "l2", "l3"))
172                 .withChild(createMapEntry("2", "l2", "l3", "l4"))
173                 .withChild(
174                         withUniqueViolation ? createMapEntry("3", "l1", "l2", "l10") : createMapEntry("3", "l3", "l4",
175                                 "l5")).build();
176
177         final var modificationTree = inMemoryDataTree.takeSnapshot().newModification();
178         modificationTree.write(YangInstanceIdentifier.of(TASK_CONTAINER).node(TASK), taskNode);
179         modificationTree.ready();
180         inMemoryDataTree.validate(modificationTree);
181         final var prepare = inMemoryDataTree.prepare(modificationTree);
182         inMemoryDataTree.commit(prepare);
183     }
184
185     private static void writeMapEntry(final InMemoryDataTree inMemoryDataTree, final Object taskIdValue,
186             final Object myLeaf1Value, final Object myLeaf2Value, final Object myLeaf3Value)
187             throws DataValidationFailedException {
188         final var taskEntryNode = Builders
189                 .mapEntryBuilder()
190                 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, taskIdValue))
191                 .withChild(ImmutableNodes.leafNode(TASK_ID, taskIdValue))
192                 .withChild(ImmutableNodes.leafNode(MY_LEAF_1, myLeaf1Value))
193                 .withChild(ImmutableNodes.leafNode(MY_LEAF_2, myLeaf2Value))
194                 .withChild(
195                         Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(MY_CONTAINER))
196                                 .withChild(ImmutableNodes.leafNode(MY_LEAF_3, myLeaf3Value)).build()).build();
197
198         final var modificationTree = inMemoryDataTree.takeSnapshot().newModification();
199         modificationTree.write(
200                 YangInstanceIdentifier.of(TASK_CONTAINER).node(TASK)
201                         .node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, taskIdValue)),
202                 taskEntryNode);
203         modificationTree.ready();
204         inMemoryDataTree.validate(modificationTree);
205         final var prepare = inMemoryDataTree.prepare(modificationTree);
206         inMemoryDataTree.commit(prepare);
207     }
208
209     private static void removeMapEntry(final InMemoryDataTree inMemoryDataTree,
210             final NodeIdentifierWithPredicates mapEntryKey) throws DataValidationFailedException {
211         final var modificationTree = inMemoryDataTree.takeSnapshot().newModification();
212         modificationTree.delete(YangInstanceIdentifier.of(TASK_CONTAINER).node(TASK).node(mapEntryKey));
213         modificationTree.ready();
214         inMemoryDataTree.validate(modificationTree);
215         final var prepare = inMemoryDataTree.prepare(modificationTree);
216         inMemoryDataTree.commit(prepare);
217     }
218
219     private static MapEntryNode createMapEntry(final Object taskIdValue, final Object myLeaf1Value,
220             final Object myLeaf2Value, final Object myLeaf3Value) {
221         return Builders
222                 .mapEntryBuilder()
223                 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, taskIdValue))
224                 .withChild(ImmutableNodes.leafNode(TASK_ID, taskIdValue))
225                 .withChild(ImmutableNodes.leafNode(MY_LEAF_1, myLeaf1Value))
226                 .withChild(ImmutableNodes.leafNode(MY_LEAF_2, myLeaf2Value))
227                 .withChild(
228                         Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(MY_CONTAINER))
229                                 .withChild(ImmutableNodes.leafNode(MY_LEAF_3, myLeaf3Value)).build()).build();
230     }
231
232     private static NodeIdentifierWithPredicates taskEntryKey(final String taskId) {
233         return NodeIdentifierWithPredicates.of(TASK, TASK_ID, taskId);
234     }
235
236     @Test
237     void disabledUniqueIndexTest() throws DataValidationFailedException {
238         final var inMemoryDataTree = initDataTree(TEST_MODEL, false);
239
240         writeMapEntry(inMemoryDataTree, "1", "l1", "l2", "l3");
241         writeMapEntry(inMemoryDataTree, "2", "l2", "l3", "l4");
242         writeMapEntry(inMemoryDataTree, "3", "l3", "l4", "l5");
243         writeMapEntry(inMemoryDataTree, "2", "l2", "l3", "l6");
244         writeMapEntry(inMemoryDataTree, "10", "l2", "l10", "l4");
245         writeMapEntry(inMemoryDataTree, "4", "l1", "l5", "l3");
246         writeMapEntry(inMemoryDataTree, "4", "l4", "l5", "l6");
247         writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7");
248         removeMapEntry(inMemoryDataTree, taskEntryKey("3"));
249         writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7");
250         writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7");
251         writeMapEntry(inMemoryDataTree, "6", "l3", "l4", "l7");
252     }
253
254     private static InMemoryDataTree initDataTree(final EffectiveModelContext schemaContext, final boolean uniqueIndex)
255             throws DataValidationFailedException {
256         final var inMemoryDataTree = (InMemoryDataTree) new InMemoryDataTreeFactory().create(
257             new DataTreeConfiguration.Builder(TreeType.CONFIGURATION).setUniqueIndexes(uniqueIndex).build());
258         inMemoryDataTree.setEffectiveModelContext(schemaContext);
259
260         final var taskNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(TASK)).build();
261         final var modificationTree = inMemoryDataTree.takeSnapshot().newModification();
262         modificationTree.write(YangInstanceIdentifier.of(TASK_CONTAINER).node(TASK), taskNode);
263         modificationTree.ready();
264
265         inMemoryDataTree.validate(modificationTree);
266         final var prepare = inMemoryDataTree.prepare(modificationTree);
267         inMemoryDataTree.commit(prepare);
268         return inMemoryDataTree;
269     }
270
271     private static InMemoryDataTree emptyDataTree(final EffectiveModelContext schemaContext,
272             final boolean uniqueIndex) {
273         final var inMemoryDataTree = (InMemoryDataTree) new InMemoryDataTreeFactory().create(
274             new DataTreeConfiguration.Builder(TreeType.CONFIGURATION).setUniqueIndexes(uniqueIndex).build());
275         inMemoryDataTree.setEffectiveModelContext(schemaContext);
276
277         return inMemoryDataTree;
278     }
279 }