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(UniqueValidationFailedException.class,
82 () -> writeMap(inMemoryDataTree, true)),
83 "(foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=",
84 "}] violates unique constraint on [l2, l1] of ",
85 "(foo?revision=2016-05-17)my-leaf-1",
86 "(foo?revision=2016-05-17)my-leaf-2]");
88 writeMap(inMemoryDataTree, false);
89 verifyExceptionMessage(assertThrows(UniqueConstraintException.class,
90 () -> writeMapEntry(inMemoryDataTree, "4", "l1", "l2", "l30")),
91 "(foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=",
92 "}] violates unique constraint on [l2, l1] of ",
93 "(foo?revision=2016-05-17)my-leaf-1",
94 "(foo?revision=2016-05-17)my-leaf-2");
98 public void mapEntryTest() throws ReactorException, DataValidationFailedException {
99 final InMemoryDataTree inMemoryDataTree = initDataTree(TEST_MODEL, true);
100 writeAndRemoveMapEntries(inMemoryDataTree, true);
101 writeAndRemoveMapEntries(inMemoryDataTree, false);
104 private static void writeAndRemoveMapEntries(final InMemoryDataTree inMemoryDataTree, final boolean clear)
105 throws DataValidationFailedException {
106 writeMapEntry(inMemoryDataTree, "1", "l1", "l2", "l3");
107 writeMapEntry(inMemoryDataTree, "2", "l2", "l3", "l4");
108 writeMapEntry(inMemoryDataTree, "3", "l3", "l4", "l5");
109 writeMapEntry(inMemoryDataTree, "2", "l2", "l3", "l6");
110 writeMapEntry(inMemoryDataTree, "10", "l2", "l10", "l4");
111 verifyExceptionMessage(assertThrows(UniqueConstraintException.class,
112 () -> writeMapEntry(inMemoryDataTree, "4", "l1", "l5", "l3")),
113 "(foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=",
114 "}] violates unique constraint on [l1, l3] of ",
115 "(foo?revision=2016-05-17)my-container, my-leaf-3",
116 "(foo?revision=2016-05-17)my-leaf-1");
117 writeMapEntry(inMemoryDataTree, "4", "l4", "l5", "l6");
118 verifyExceptionMessage(assertThrows(UniqueConstraintException.class,
119 () -> writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7")),
120 "(foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=",
121 "}] violates unique constraint on [l4, l3] of ",
122 "(foo?revision=2016-05-17)my-leaf-1",
123 "(foo?revision=2016-05-17)my-leaf-2");
124 removeMapEntry(inMemoryDataTree, taskEntryKey("3"));
125 writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7");
126 writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7");
127 verifyExceptionMessage(assertThrows(UniqueConstraintException.class,
128 () -> writeMapEntry(inMemoryDataTree, "6", "l3", "l4", "l11")),
129 "(foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=",
130 "}] violates unique constraint on [l4, l3] of ",
131 "(foo?revision=2016-05-17)my-leaf-1",
132 "(foo?revision=2016-05-17)my-leaf-2");
135 removeMapEntry(inMemoryDataTree, taskEntryKey("1"));
136 removeMapEntry(inMemoryDataTree, taskEntryKey("2"));
137 removeMapEntry(inMemoryDataTree, taskEntryKey("4"));
138 removeMapEntry(inMemoryDataTree, taskEntryKey("5"));
139 removeMapEntry(inMemoryDataTree, taskEntryKey("10"));
143 private static void verifyExceptionMessage(final Exception ex, final String expectedStart,
144 final String... expectedLeaves) {
145 verifyExceptionMessage(expectedStart, ex.getMessage(), expectedLeaves);
148 private static void verifyExceptionMessage(final String expectedStart, final String message,
149 final String... leafs) {
150 assertThat(message, startsWith(expectedStart));
151 for (final String leaf : leafs) {
152 assertThat(message, containsString(leaf));
156 private static void writeMap(final InMemoryDataTree inMemoryDataTree, final boolean withUniqueViolation)
157 throws DataValidationFailedException {
158 final MapNode taskNode = Builders
160 .withNodeIdentifier(new NodeIdentifier(TASK))
161 .withChild(createMapEntry("1", "l1", "l2", "l3"))
162 .withChild(createMapEntry("2", "l2", "l3", "l4"))
164 withUniqueViolation ? createMapEntry("3", "l1", "l2", "l10") : createMapEntry("3", "l3", "l4",
167 final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
168 modificationTree.write(YangInstanceIdentifier.of(TASK_CONTAINER).node(TASK), taskNode);
169 modificationTree.ready();
170 inMemoryDataTree.validate(modificationTree);
171 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
172 inMemoryDataTree.commit(prepare);
175 private static void writeMapEntry(final InMemoryDataTree inMemoryDataTree, final Object taskIdValue,
176 final Object myLeaf1Value, final Object myLeaf2Value, final Object myLeaf3Value)
177 throws DataValidationFailedException {
178 final MapEntryNode taskEntryNode = Builders
180 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, taskIdValue))
181 .withChild(ImmutableNodes.leafNode(TASK_ID, taskIdValue))
182 .withChild(ImmutableNodes.leafNode(MY_LEAF_1, myLeaf1Value))
183 .withChild(ImmutableNodes.leafNode(MY_LEAF_2, myLeaf2Value))
185 Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(MY_CONTAINER))
186 .withChild(ImmutableNodes.leafNode(MY_LEAF_3, myLeaf3Value)).build()).build();
188 final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
189 modificationTree.write(
190 YangInstanceIdentifier.of(TASK_CONTAINER).node(TASK)
191 .node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, taskIdValue)),
193 modificationTree.ready();
194 inMemoryDataTree.validate(modificationTree);
195 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
196 inMemoryDataTree.commit(prepare);
199 private static void removeMapEntry(final InMemoryDataTree inMemoryDataTree,
200 final NodeIdentifierWithPredicates mapEntryKey) throws DataValidationFailedException {
201 final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
202 modificationTree.delete(YangInstanceIdentifier.of(TASK_CONTAINER).node(TASK).node(mapEntryKey));
203 modificationTree.ready();
204 inMemoryDataTree.validate(modificationTree);
205 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
206 inMemoryDataTree.commit(prepare);
209 private static MapEntryNode createMapEntry(final Object taskIdValue, final Object myLeaf1Value,
210 final Object myLeaf2Value, final Object myLeaf3Value) throws DataValidationFailedException {
213 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, taskIdValue))
214 .withChild(ImmutableNodes.leafNode(TASK_ID, taskIdValue))
215 .withChild(ImmutableNodes.leafNode(MY_LEAF_1, myLeaf1Value))
216 .withChild(ImmutableNodes.leafNode(MY_LEAF_2, myLeaf2Value))
218 Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(MY_CONTAINER))
219 .withChild(ImmutableNodes.leafNode(MY_LEAF_3, myLeaf3Value)).build()).build();
222 private static NodeIdentifierWithPredicates taskEntryKey(final String taskId) {
223 return NodeIdentifierWithPredicates.of(TASK, TASK_ID, taskId);
227 public void disabledUniqueIndexTest() throws ReactorException, DataValidationFailedException {
228 final InMemoryDataTree inMemoryDataTree = initDataTree(TEST_MODEL, false);
230 writeMapEntry(inMemoryDataTree, "1", "l1", "l2", "l3");
231 writeMapEntry(inMemoryDataTree, "2", "l2", "l3", "l4");
232 writeMapEntry(inMemoryDataTree, "3", "l3", "l4", "l5");
233 writeMapEntry(inMemoryDataTree, "2", "l2", "l3", "l6");
234 writeMapEntry(inMemoryDataTree, "10", "l2", "l10", "l4");
235 writeMapEntry(inMemoryDataTree, "4", "l1", "l5", "l3");
236 writeMapEntry(inMemoryDataTree, "4", "l4", "l5", "l6");
237 writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7");
238 removeMapEntry(inMemoryDataTree, taskEntryKey("3"));
239 writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7");
240 writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7");
241 writeMapEntry(inMemoryDataTree, "6", "l3", "l4", "l7");
244 private static InMemoryDataTree initDataTree(final EffectiveModelContext schemaContext, final boolean uniqueIndex)
245 throws DataValidationFailedException {
246 final InMemoryDataTree inMemoryDataTree = (InMemoryDataTree) new InMemoryDataTreeFactory().create(
247 new DataTreeConfiguration.Builder(TreeType.CONFIGURATION).setUniqueIndexes(uniqueIndex).build());
248 inMemoryDataTree.setEffectiveModelContext(schemaContext);
250 final MapNode taskNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(TASK)).build();
251 final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
252 modificationTree.write(YangInstanceIdentifier.of(TASK_CONTAINER).node(TASK), taskNode);
253 modificationTree.ready();
255 inMemoryDataTree.validate(modificationTree);
256 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
257 inMemoryDataTree.commit(prepare);
258 return inMemoryDataTree;
261 private static InMemoryDataTree emptyDataTree(final EffectiveModelContext schemaContext, final boolean uniqueIndex)
262 throws DataValidationFailedException {
263 final InMemoryDataTree inMemoryDataTree = (InMemoryDataTree) new InMemoryDataTreeFactory().create(
264 new DataTreeConfiguration.Builder(TreeType.CONFIGURATION).setUniqueIndexes(uniqueIndex).build());
265 inMemoryDataTree.setEffectiveModelContext(schemaContext);
267 return inMemoryDataTree;