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.tree.impl;
10 import static org.hamcrest.CoreMatchers.containsString;
11 import static org.hamcrest.CoreMatchers.instanceOf;
12 import static org.hamcrest.CoreMatchers.startsWith;
13 import static org.hamcrest.MatcherAssert.assertThat;
14 import static org.junit.Assert.assertEquals;
15 import static org.junit.Assert.assertThrows;
17 import java.util.List;
18 import org.junit.BeforeClass;
19 import org.junit.Test;
20 import org.opendaylight.yangtools.yang.common.ErrorSeverity;
21 import org.opendaylight.yangtools.yang.common.ErrorTag;
22 import org.opendaylight.yangtools.yang.common.ErrorType;
23 import org.opendaylight.yangtools.yang.common.QName;
24 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
25 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
27 import org.opendaylight.yangtools.yang.data.api.YangNetconfError;
28 import org.opendaylight.yangtools.yang.data.api.YangNetconfErrorAware;
29 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
31 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
32 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
33 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidate;
34 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeConfiguration;
35 import org.opendaylight.yangtools.yang.data.tree.api.DataValidationFailedException;
36 import org.opendaylight.yangtools.yang.data.tree.api.TreeType;
37 import org.opendaylight.yangtools.yang.data.tree.api.UniqueConstraintException;
38 import org.opendaylight.yangtools.yang.data.tree.impl.di.InMemoryDataTreeFactory;
39 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
41 public class UniqueConstraintTest {
42 private static final String NS = "foo";
43 private static final String REV = "2016-05-17";
44 private static final QName TASK_CONTAINER = QName.create(NS, REV, "task-container");
45 private static final QName TASK = QName.create(NS, REV, "task");
46 private static final QName TASK_ID = QName.create(NS, REV, "task-id");
47 private static final QName MY_LEAF_1 = QName.create(NS, REV, "my-leaf-1");
48 private static final QName MY_LEAF_2 = QName.create(NS, REV, "my-leaf-2");
49 private static final QName MY_LEAF_3 = QName.create(NS, REV, "my-leaf-3");
50 private static final QName MY_CONTAINER = QName.create(NS, REV, "my-container");
52 private static EffectiveModelContext TEST_MODEL;
55 public static void beforeClass() {
56 TEST_MODEL = TestModel.createTestContext("/yt570.yang");
60 public void switchEntriesTest() throws DataValidationFailedException {
61 final InMemoryDataTree inMemoryDataTree = initDataTree(TEST_MODEL, true);
62 writeMapEntry(inMemoryDataTree, "1", "l1", "l2", "l3");
63 writeMapEntry(inMemoryDataTree, "2", "l2", "l3", "l4");
65 final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
67 final MapEntryNode mapEntry1 = createMapEntry("1", "l2", "l3", "l4");
68 final MapEntryNode mapEntry2 = createMapEntry("2", "l1", "l2", "l3");
70 //switch values of map entries
71 modificationTree.write(
72 YangInstanceIdentifier.of(TASK_CONTAINER).node(TASK)
73 .node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "1")), mapEntry1);
74 modificationTree.write(
75 YangInstanceIdentifier.of(TASK_CONTAINER).node(TASK)
76 .node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, "2")), mapEntry2);
78 modificationTree.ready();
79 inMemoryDataTree.validate(modificationTree);
80 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
81 inMemoryDataTree.commit(prepare);
85 public void mapTest() throws DataValidationFailedException {
86 final InMemoryDataTree inMemoryDataTree = emptyDataTree(TEST_MODEL, true);
89 verifyException(assertThrows(UniqueValidationFailedException.class,
90 () -> writeMap(inMemoryDataTree, true)),
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]");
96 writeMap(inMemoryDataTree, false);
97 verifyException(assertThrows(UniqueConstraintException.class,
98 () -> writeMapEntry(inMemoryDataTree, "4", "l1", "l2", "l30")),
99 "(foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=",
100 "}] violates unique constraint on [l2, l1] of ",
101 "(foo?revision=2016-05-17)my-leaf-1",
102 "(foo?revision=2016-05-17)my-leaf-2");
106 public void mapEntryTest() throws DataValidationFailedException {
107 final InMemoryDataTree inMemoryDataTree = initDataTree(TEST_MODEL, true);
108 writeAndRemoveMapEntries(inMemoryDataTree, true);
109 writeAndRemoveMapEntries(inMemoryDataTree, false);
112 private static void writeAndRemoveMapEntries(final InMemoryDataTree inMemoryDataTree, final boolean clear)
113 throws DataValidationFailedException {
114 writeMapEntry(inMemoryDataTree, "1", "l1", "l2", "l3");
115 writeMapEntry(inMemoryDataTree, "2", "l2", "l3", "l4");
116 writeMapEntry(inMemoryDataTree, "3", "l3", "l4", "l5");
117 writeMapEntry(inMemoryDataTree, "2", "l2", "l3", "l6");
118 writeMapEntry(inMemoryDataTree, "10", "l2", "l10", "l4");
119 verifyException(assertThrows(UniqueConstraintException.class,
120 () -> writeMapEntry(inMemoryDataTree, "4", "l1", "l5", "l3")),
121 "(foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=",
122 "}] violates unique constraint on [l1, l3] of ",
123 "(foo?revision=2016-05-17)my-container, my-leaf-3",
124 "(foo?revision=2016-05-17)my-leaf-1");
125 writeMapEntry(inMemoryDataTree, "4", "l4", "l5", "l6");
126 verifyException(assertThrows(UniqueConstraintException.class,
127 () -> writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7")),
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");
132 removeMapEntry(inMemoryDataTree, taskEntryKey("3"));
133 writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7");
134 writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7");
135 verifyException(assertThrows(UniqueConstraintException.class,
136 () -> writeMapEntry(inMemoryDataTree, "6", "l3", "l4", "l11")),
137 "(foo?revision=2016-05-17)task[{(foo?revision=2016-05-17)task-id=",
138 "}] violates unique constraint on [l4, l3] of ",
139 "(foo?revision=2016-05-17)my-leaf-1",
140 "(foo?revision=2016-05-17)my-leaf-2");
143 removeMapEntry(inMemoryDataTree, taskEntryKey("1"));
144 removeMapEntry(inMemoryDataTree, taskEntryKey("2"));
145 removeMapEntry(inMemoryDataTree, taskEntryKey("4"));
146 removeMapEntry(inMemoryDataTree, taskEntryKey("5"));
147 removeMapEntry(inMemoryDataTree, taskEntryKey("10"));
151 private static void verifyException(final Exception ex, final String expectedStart,
152 final String... expectedLeaves) {
153 verifyExceptionMessage(expectedStart, ex.getMessage(), expectedLeaves);
154 assertThat(ex, instanceOf(YangNetconfErrorAware.class));
155 final List<YangNetconfError> errors = ((YangNetconfErrorAware) ex).getNetconfErrors();
156 assertEquals(1, errors.size());
157 final YangNetconfError error = errors.get(0);
158 assertEquals(ErrorSeverity.ERROR, error.severity());
159 assertEquals(ErrorType.APPLICATION, error.type());
160 assertEquals(ErrorTag.OPERATION_FAILED, error.tag());
161 assertEquals("data-not-unique", error.appTag());
164 private static void verifyExceptionMessage(final String expectedStart, final String message,
165 final String... leafs) {
166 assertThat(message, startsWith(expectedStart));
167 for (final String leaf : leafs) {
168 assertThat(message, containsString(leaf));
172 private static void writeMap(final InMemoryDataTree inMemoryDataTree, final boolean withUniqueViolation)
173 throws DataValidationFailedException {
174 final MapNode taskNode = Builders
176 .withNodeIdentifier(new NodeIdentifier(TASK))
177 .withChild(createMapEntry("1", "l1", "l2", "l3"))
178 .withChild(createMapEntry("2", "l2", "l3", "l4"))
180 withUniqueViolation ? createMapEntry("3", "l1", "l2", "l10") : createMapEntry("3", "l3", "l4",
183 final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
184 modificationTree.write(YangInstanceIdentifier.of(TASK_CONTAINER).node(TASK), taskNode);
185 modificationTree.ready();
186 inMemoryDataTree.validate(modificationTree);
187 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
188 inMemoryDataTree.commit(prepare);
191 private static void writeMapEntry(final InMemoryDataTree inMemoryDataTree, final Object taskIdValue,
192 final Object myLeaf1Value, final Object myLeaf2Value, final Object myLeaf3Value)
193 throws DataValidationFailedException {
194 final MapEntryNode taskEntryNode = Builders
196 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, taskIdValue))
197 .withChild(ImmutableNodes.leafNode(TASK_ID, taskIdValue))
198 .withChild(ImmutableNodes.leafNode(MY_LEAF_1, myLeaf1Value))
199 .withChild(ImmutableNodes.leafNode(MY_LEAF_2, myLeaf2Value))
201 Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(MY_CONTAINER))
202 .withChild(ImmutableNodes.leafNode(MY_LEAF_3, myLeaf3Value)).build()).build();
204 final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
205 modificationTree.write(
206 YangInstanceIdentifier.of(TASK_CONTAINER).node(TASK)
207 .node(NodeIdentifierWithPredicates.of(TASK, TASK_ID, taskIdValue)),
209 modificationTree.ready();
210 inMemoryDataTree.validate(modificationTree);
211 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
212 inMemoryDataTree.commit(prepare);
215 private static void removeMapEntry(final InMemoryDataTree inMemoryDataTree,
216 final NodeIdentifierWithPredicates mapEntryKey) throws DataValidationFailedException {
217 final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
218 modificationTree.delete(YangInstanceIdentifier.of(TASK_CONTAINER).node(TASK).node(mapEntryKey));
219 modificationTree.ready();
220 inMemoryDataTree.validate(modificationTree);
221 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
222 inMemoryDataTree.commit(prepare);
225 private static MapEntryNode createMapEntry(final Object taskIdValue, final Object myLeaf1Value,
226 final Object myLeaf2Value, final Object myLeaf3Value) throws DataValidationFailedException {
229 .withNodeIdentifier(NodeIdentifierWithPredicates.of(TASK, TASK_ID, taskIdValue))
230 .withChild(ImmutableNodes.leafNode(TASK_ID, taskIdValue))
231 .withChild(ImmutableNodes.leafNode(MY_LEAF_1, myLeaf1Value))
232 .withChild(ImmutableNodes.leafNode(MY_LEAF_2, myLeaf2Value))
234 Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(MY_CONTAINER))
235 .withChild(ImmutableNodes.leafNode(MY_LEAF_3, myLeaf3Value)).build()).build();
238 private static NodeIdentifierWithPredicates taskEntryKey(final String taskId) {
239 return NodeIdentifierWithPredicates.of(TASK, TASK_ID, taskId);
243 public void disabledUniqueIndexTest() throws DataValidationFailedException {
244 final InMemoryDataTree inMemoryDataTree = initDataTree(TEST_MODEL, false);
246 writeMapEntry(inMemoryDataTree, "1", "l1", "l2", "l3");
247 writeMapEntry(inMemoryDataTree, "2", "l2", "l3", "l4");
248 writeMapEntry(inMemoryDataTree, "3", "l3", "l4", "l5");
249 writeMapEntry(inMemoryDataTree, "2", "l2", "l3", "l6");
250 writeMapEntry(inMemoryDataTree, "10", "l2", "l10", "l4");
251 writeMapEntry(inMemoryDataTree, "4", "l1", "l5", "l3");
252 writeMapEntry(inMemoryDataTree, "4", "l4", "l5", "l6");
253 writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7");
254 removeMapEntry(inMemoryDataTree, taskEntryKey("3"));
255 writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7");
256 writeMapEntry(inMemoryDataTree, "5", "l3", "l4", "l7");
257 writeMapEntry(inMemoryDataTree, "6", "l3", "l4", "l7");
260 private static InMemoryDataTree initDataTree(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 final MapNode taskNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(TASK)).build();
267 final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
268 modificationTree.write(YangInstanceIdentifier.of(TASK_CONTAINER).node(TASK), taskNode);
269 modificationTree.ready();
271 inMemoryDataTree.validate(modificationTree);
272 final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
273 inMemoryDataTree.commit(prepare);
274 return inMemoryDataTree;
277 private static InMemoryDataTree emptyDataTree(final EffectiveModelContext schemaContext,
278 final boolean uniqueIndex) {
279 final InMemoryDataTree inMemoryDataTree = (InMemoryDataTree) new InMemoryDataTreeFactory().create(
280 new DataTreeConfiguration.Builder(TreeType.CONFIGURATION).setUniqueIndexes(uniqueIndex).build());
281 inMemoryDataTree.setEffectiveModelContext(schemaContext);
283 return inMemoryDataTree;