2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.data.impl.schema.tree;
10 import static org.hamcrest.CoreMatchers.containsString;
11 import static org.hamcrest.CoreMatchers.startsWith;
12 import static org.hamcrest.MatcherAssert.assertThat;
13 import static org.junit.Assert.assertThrows;
15 import org.junit.BeforeClass;
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.YangInstanceIdentifier.NodeIdentifierWithPredicates;
21 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
22 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
24 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeConfiguration;
25 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
26 import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType;
27 import org.opendaylight.yangtools.yang.data.api.schema.tree.UniqueConstraintException;
28 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
29 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
30 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
31 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
33 public class UniqueConstraintTest {
34 private static final String NS = "foo";
35 private static final String REV = "2016-05-17";
36 private static final QName TASK_CONTAINER = QName.create(NS, REV, "task-container");
37 private static final QName TASK = QName.create(NS, REV, "task");
38 private static final QName TASK_ID = QName.create(NS, REV, "task-id");
39 private static final QName MY_LEAF_1 = QName.create(NS, REV, "my-leaf-1");
40 private static final QName MY_LEAF_2 = QName.create(NS, REV, "my-leaf-2");
41 private static final QName MY_LEAF_3 = QName.create(NS, REV, "my-leaf-3");
42 private static final QName MY_CONTAINER = QName.create(NS, REV, "my-container");
44 private static EffectiveModelContext TEST_MODEL;
47 public static void beforeClass() {
48 TEST_MODEL = TestModel.createTestContext("/yt570.yang");
52 public void switchEntriesTest() throws ReactorException, DataValidationFailedException {
53 final InMemoryDataTree inMemoryDataTree = initDataTree(TEST_MODEL, true);
54 writeMapEntry(inMemoryDataTree, "1", "l1", "l2", "l3");
55 writeMapEntry(inMemoryDataTree, "2", "l2", "l3", "l4");
57 final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
59 final MapEntryNode mapEntry1 = createMapEntry("1", "l2", "l3", "l4");
60 final MapEntryNode mapEntry2 = createMapEntry("2", "l1", "l2", "l3");
62 //switch values of map entries
63 modificationTree.write(
64 YangInstanceIdentifier.of(TASK_CONTAINER).node(TASK)
65 .node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "1")), mapEntry1);
66 modificationTree.write(
67 YangInstanceIdentifier.of(TASK_CONTAINER).node(TASK)
68 .node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "2")), mapEntry2);
70 modificationTree.ready();
71 inMemoryDataTree.validate(modificationTree);
72 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
73 inMemoryDataTree.commit(prepare);
77 public void mapTest() throws ReactorException, DataValidationFailedException {
78 final InMemoryDataTree inMemoryDataTree = emptyDataTree(TEST_MODEL, true);
81 verifyExceptionMessage(assertThrows(IllegalArgumentException.class, () -> writeMap(inMemoryDataTree, true)),
82 "(foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=",
83 "}] violates unique constraint on [l2, l1] of ",
84 "(foo?revision=2016-05-17)my-leaf-1",
85 "(foo?revision=2016-05-17)my-leaf-2]");
87 writeMap(inMemoryDataTree, false);
88 verifyExceptionMessage(assertThrows(UniqueConstraintException.class,
89 () -> writeMapEntry(inMemoryDataTree, "4", "l1", "l2", "l30")),
90 "(foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=",
91 "}] violates unique constraint on [l2, l1] of ",
92 "(foo?revision=2016-05-17)my-leaf-1",
93 "(foo?revision=2016-05-17)my-leaf-2");
97 public void mapEntryTest() throws ReactorException, DataValidationFailedException {
98 final InMemoryDataTree inMemoryDataTree = initDataTree(TEST_MODEL, true);
99 writeAndRemoveMapEntries(inMemoryDataTree, true);
100 writeAndRemoveMapEntries(inMemoryDataTree, false);
103 private static void writeAndRemoveMapEntries(final InMemoryDataTree inMemoryDataTree, final boolean clear)
104 throws DataValidationFailedException {
105 writeMapEntry(inMemoryDataTree, "1", "l1", "l2", "l3");
106 writeMapEntry(inMemoryDataTree, "2", "l2", "l3", "l4");
107 writeMapEntry(inMemoryDataTree, "3", "l3", "l4", "l5");
108 writeMapEntry(inMemoryDataTree, "2", "l2", "l3", "l6");
109 writeMapEntry(inMemoryDataTree, "10", "l2", "l10", "l4");
110 verifyExceptionMessage(assertThrows(UniqueConstraintException.class,
111 () -> writeMapEntry(inMemoryDataTree, "4", "l1", "l5", "l3")),
112 "(foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=",
113 "}] violates unique constraint on [l1, l3] of ",
114 "(foo?revision=2016-05-17)my-container, my-leaf-3",
115 "(foo?revision=2016-05-17)my-leaf-1");
116 writeMapEntry(inMemoryDataTree, "4", "l4", "l5", "l6");
117 verifyExceptionMessage(assertThrows(UniqueConstraintException.class,
118 () -> writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7")),
119 "(foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=",
120 "}] violates unique constraint on [l4, l3] of ",
121 "(foo?revision=2016-05-17)my-leaf-1",
122 "(foo?revision=2016-05-17)my-leaf-2");
123 removeMapEntry(inMemoryDataTree, taskEntryKey("3"));
124 writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7");
125 writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7");
126 verifyExceptionMessage(assertThrows(UniqueConstraintException.class,
127 () -> writeMapEntry(inMemoryDataTree, "6", "l3", "l4", "l11")),
128 "(foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=",
129 "}] violates unique constraint on [l4, l3] of ",
130 "(foo?revision=2016-05-17)my-leaf-1",
131 "(foo?revision=2016-05-17)my-leaf-2");
134 removeMapEntry(inMemoryDataTree, taskEntryKey("1"));
135 removeMapEntry(inMemoryDataTree, taskEntryKey("2"));
136 removeMapEntry(inMemoryDataTree, taskEntryKey("4"));
137 removeMapEntry(inMemoryDataTree, taskEntryKey("5"));
138 removeMapEntry(inMemoryDataTree, taskEntryKey("10"));
142 private static void verifyExceptionMessage(final Exception ex, final String expectedStart,
143 final String... expectedLeaves) {
144 verifyExceptionMessage(expectedStart, ex.getMessage(), expectedLeaves);
147 private static void verifyExceptionMessage(final String expectedStart, final String message,
148 final String... leafs) {
149 assertThat(message, startsWith(expectedStart));
150 for (final String leaf : leafs) {
151 assertThat(message, containsString(leaf));
155 private static void writeMap(final InMemoryDataTree inMemoryDataTree, final boolean withUniqueViolation)
156 throws DataValidationFailedException {
157 final MapNode taskNode = Builders
159 .withNodeIdentifier(new NodeIdentifier(TASK))
160 .withChild(createMapEntry("1", "l1", "l2", "l3"))
161 .withChild(createMapEntry("2", "l2", "l3", "l4"))
163 withUniqueViolation ? createMapEntry("3", "l1", "l2", "l10") : createMapEntry("3", "l3", "l4",
166 final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
167 modificationTree.write(YangInstanceIdentifier.of(TASK_CONTAINER).node(TASK), taskNode);
168 modificationTree.ready();
169 inMemoryDataTree.validate(modificationTree);
170 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
171 inMemoryDataTree.commit(prepare);
174 private static void writeMapEntry(final InMemoryDataTree inMemoryDataTree, final Object taskIdValue,
175 final Object myLeaf1Value, final Object myLeaf2Value, final Object myLeaf3Value)
176 throws DataValidationFailedException {
177 final MapEntryNode taskEntryNode = Builders
179 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, taskIdValue))
180 .withChild(ImmutableNodes.leafNode(TASK_ID, taskIdValue))
181 .withChild(ImmutableNodes.leafNode(MY_LEAF_1, myLeaf1Value))
182 .withChild(ImmutableNodes.leafNode(MY_LEAF_2, myLeaf2Value))
184 Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(MY_CONTAINER))
185 .withChild(ImmutableNodes.leafNode(MY_LEAF_3, myLeaf3Value)).build()).build();
187 final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
188 modificationTree.write(
189 YangInstanceIdentifier.of(TASK_CONTAINER).node(TASK)
190 .node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, taskIdValue)),
192 modificationTree.ready();
193 inMemoryDataTree.validate(modificationTree);
194 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
195 inMemoryDataTree.commit(prepare);
198 private static void removeMapEntry(final InMemoryDataTree inMemoryDataTree,
199 final NodeIdentifierWithPredicates mapEntryKey) throws DataValidationFailedException {
200 final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
201 modificationTree.delete(YangInstanceIdentifier.of(TASK_CONTAINER).node(TASK).node(mapEntryKey));
202 modificationTree.ready();
203 inMemoryDataTree.validate(modificationTree);
204 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
205 inMemoryDataTree.commit(prepare);
208 private static MapEntryNode createMapEntry(final Object taskIdValue, final Object myLeaf1Value,
209 final Object myLeaf2Value, final Object myLeaf3Value) throws DataValidationFailedException {
212 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, taskIdValue))
213 .withChild(ImmutableNodes.leafNode(TASK_ID, taskIdValue))
214 .withChild(ImmutableNodes.leafNode(MY_LEAF_1, myLeaf1Value))
215 .withChild(ImmutableNodes.leafNode(MY_LEAF_2, myLeaf2Value))
217 Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(MY_CONTAINER))
218 .withChild(ImmutableNodes.leafNode(MY_LEAF_3, myLeaf3Value)).build()).build();
221 private static NodeIdentifierWithPredicates taskEntryKey(final String taskId) {
222 return NodeIdentifierWithPredicates.of(TASK, TASK_ID, taskId);
226 public void disabledUniqueIndexTest() throws ReactorException, DataValidationFailedException {
227 final InMemoryDataTree inMemoryDataTree = initDataTree(TEST_MODEL, false);
229 writeMapEntry(inMemoryDataTree, "1", "l1", "l2", "l3");
230 writeMapEntry(inMemoryDataTree, "2", "l2", "l3", "l4");
231 writeMapEntry(inMemoryDataTree, "3", "l3", "l4", "l5");
232 writeMapEntry(inMemoryDataTree, "2", "l2", "l3", "l6");
233 writeMapEntry(inMemoryDataTree, "10", "l2", "l10", "l4");
234 writeMapEntry(inMemoryDataTree, "4", "l1", "l5", "l3");
235 writeMapEntry(inMemoryDataTree, "4", "l4", "l5", "l6");
236 writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7");
237 removeMapEntry(inMemoryDataTree, taskEntryKey("3"));
238 writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7");
239 writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7");
240 writeMapEntry(inMemoryDataTree, "6", "l3", "l4", "l7");
243 private static InMemoryDataTree initDataTree(final EffectiveModelContext schemaContext, final boolean uniqueIndex)
244 throws DataValidationFailedException {
245 final InMemoryDataTree inMemoryDataTree = (InMemoryDataTree) new InMemoryDataTreeFactory().create(
246 new DataTreeConfiguration.Builder(TreeType.CONFIGURATION).setUniqueIndexes(uniqueIndex).build());
247 inMemoryDataTree.setEffectiveModelContext(schemaContext);
249 final MapNode taskNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(TASK)).build();
250 final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
251 modificationTree.write(YangInstanceIdentifier.of(TASK_CONTAINER).node(TASK), taskNode);
252 modificationTree.ready();
254 inMemoryDataTree.validate(modificationTree);
255 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
256 inMemoryDataTree.commit(prepare);
257 return inMemoryDataTree;
260 private static InMemoryDataTree emptyDataTree(final EffectiveModelContext schemaContext, final boolean uniqueIndex)
261 throws DataValidationFailedException {
262 final InMemoryDataTree inMemoryDataTree = (InMemoryDataTree) new InMemoryDataTreeFactory().create(
263 new DataTreeConfiguration.Builder(TreeType.CONFIGURATION).setUniqueIndexes(uniqueIndex).build());
264 inMemoryDataTree.setEffectiveModelContext(schemaContext);
266 return inMemoryDataTree;