Split out yang-data-tree-impl
[yangtools.git] / data / yang-data-tree-ri / src / test / java / org / opendaylight / yangtools / yang / data / tree / impl / YT776Test.java
1 /*
2  * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.Assert.assertEquals;
11 import static org.junit.Assert.assertThrows;
12 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.choiceBuilder;
13 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.containerBuilder;
14 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.leafBuilder;
15 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.leafSetBuilder;
16 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.mapBuilder;
17 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.mapEntryBuilder;
18 import static org.opendaylight.yangtools.yang.data.tree.impl.ListConstraintsValidation.assertTooFewElements;
19 import static org.opendaylight.yangtools.yang.data.tree.impl.ListConstraintsValidation.assertTooManyElements;
20
21 import com.google.common.collect.ImmutableMap;
22 import org.junit.AfterClass;
23 import org.junit.Before;
24 import org.junit.BeforeClass;
25 import org.junit.Test;
26 import org.opendaylight.yangtools.yang.common.QName;
27 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
30 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
32 import org.opendaylight.yangtools.yang.data.tree.api.DataTree;
33 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeConfiguration;
34 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeModification;
35 import org.opendaylight.yangtools.yang.data.tree.api.DataValidationFailedException;
36 import org.opendaylight.yangtools.yang.data.tree.impl.di.InMemoryDataTreeFactory;
37 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
38
39 public class YT776Test {
40     private static final QName MODULE = QName.create("yt776", "yt776");
41     private static final NodeIdentifier BOX = new NodeIdentifier(QName.create(MODULE, "box"));
42     private static final QName OBJECT = QName.create(MODULE, "object");
43     private static final QName OBJECT_ID = QName.create(MODULE, "object-id");
44     private static final NodeIdentifier OBJECT_LIST = new NodeIdentifier(OBJECT);
45     private static final NodeIdentifierWithPredicates OBJECT_ITEM = NodeIdentifierWithPredicates.of(OBJECT,
46         ImmutableMap.of(OBJECT_ID, "1"));
47     private static final LeafNode<?> OBJECT_ID_LEAF = leafBuilder().withNodeIdentifier(new NodeIdentifier(OBJECT_ID))
48             .withValue("1").build();
49     private static final NodeIdentifier ATTRIBUTES = new NodeIdentifier(QName.create(MODULE, "attributes"));
50
51     private static final QName NESTED = QName.create(MODULE, "nested");
52     private static final QName NESTED_ATTRIBUTE = QName.create(MODULE, "nested-attribute");
53     private static final NodeIdentifier NESTED_LIST = new NodeIdentifier(NESTED);
54     private static final NodeIdentifierWithPredicates NESTED_ITEM = NodeIdentifierWithPredicates.of(NESTED,
55         ImmutableMap.of(NESTED_ATTRIBUTE, "foo"));
56
57     private static final NodeIdentifier ANY_OF = new NodeIdentifier(QName.create(MODULE, "any-of"));
58     private static final QName SOME_LEAF = QName.create(MODULE, "some-leaf");
59     private static final NodeIdentifier SOME_LEAF_ID = new NodeIdentifier(SOME_LEAF);
60     private static final QName SOME_LIST = QName.create(MODULE, "some-list");
61     private static final NodeIdentifier SOME_LIST_ID = new NodeIdentifier(SOME_LIST);
62     private static final NodeIdentifierWithPredicates SOME_LIST_ITEM = NodeIdentifierWithPredicates.of(SOME_LIST,
63                 ImmutableMap.of(SOME_LEAF, "foo"));
64     private static EffectiveModelContext SCHEMA_CONTEXT;
65
66     private DataTree dataTree;
67
68     @BeforeClass
69     public static void beforeClass() {
70         SCHEMA_CONTEXT = TestModel.createTestContext("/yt776.yang");
71     }
72
73     @AfterClass
74     public static void afterClass() {
75         SCHEMA_CONTEXT = null;
76     }
77
78     @Before
79     public void init() {
80         dataTree = new InMemoryDataTreeFactory().create(DataTreeConfiguration.DEFAULT_CONFIGURATION, SCHEMA_CONTEXT);
81     }
82
83     @Test
84     public void testNoAttributes() {
85         final DataTreeModification mod = dataTree.takeSnapshot().newModification();
86         mod.write(YangInstanceIdentifier.create(BOX), containerBuilder().withNodeIdentifier(BOX)
87             .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
88                 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
89                     .withChild(OBJECT_ID_LEAF)
90                     .build())
91                 .build())
92             .build());
93
94         final IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, mod::ready);
95         // FIXME: This is actually mandatory leaf enforcer kicking in: attributes have to be present. This is
96         //        most probably not what we want.
97         assertEquals("Node (yt776)object[{(yt776)object-id=1}] is missing mandatory descendant /(yt776)attributes",
98                 ex.getMessage());
99     }
100
101     @Test
102     public void testEmptyAttributes() throws DataValidationFailedException {
103         final DataTreeModification mod = write(containerBuilder().withNodeIdentifier(BOX)
104             .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
105                 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
106                     .withChild(OBJECT_ID_LEAF)
107                     .withChild(leafSetBuilder().withNodeIdentifier(ATTRIBUTES).build())
108                     .build())
109                 .build())
110             .build());
111
112         final IllegalArgumentException ex = assertThrows(MinMaxElementsValidationFailedException.class, mod::ready);
113         assertEquals("(yt776)attributes does not have enough elements (0), needs at least 1", ex.getMessage());
114         assertTooFewElements(ex);
115     }
116
117     @Test
118     public void testOneAttribute() throws DataValidationFailedException {
119         writeAndCommit(containerBuilder().withNodeIdentifier(BOX)
120             .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
121                 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
122                     .withChild(OBJECT_ID_LEAF)
123                     .withChild(leafSetBuilder().withNodeIdentifier(ATTRIBUTES)
124                         .withChildValue("object1")
125                         .build())
126                     .build())
127                 .build())
128             .build());
129     }
130
131     @Test
132     public void testTwoAttributes() throws DataValidationFailedException {
133         writeAndCommit(containerBuilder().withNodeIdentifier(BOX)
134             .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
135                 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
136                     .withChild(OBJECT_ID_LEAF)
137                     .withChild(leafSetBuilder().withNodeIdentifier(ATTRIBUTES)
138                         .withChildValue("object1")
139                         .withChildValue("object2")
140                         .build())
141                     .build())
142                 .build())
143             .build());
144     }
145
146     @Test
147     public void testThreeAttributes() throws DataValidationFailedException {
148         final DataTreeModification mod = write(containerBuilder().withNodeIdentifier(BOX)
149             .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
150                 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
151                     .withChild(OBJECT_ID_LEAF)
152                     .withChild(leafSetBuilder().withNodeIdentifier(ATTRIBUTES)
153                         .withChildValue("object1")
154                         .withChildValue("object2")
155                         .withChildValue("object3")
156                         .build())
157                     .build())
158                 .build())
159             .build());
160
161         final IllegalArgumentException ex = assertThrows(MinMaxElementsValidationFailedException.class, mod::ready);
162         assertEquals("(yt776)attributes has too many elements (3), can have at most 2", ex.getMessage());
163         assertTooManyElements(ex);
164     }
165
166     @Test
167     public void testEmptyAndMergeOne() throws DataValidationFailedException {
168         final DataTreeModification mod = dataTree.takeSnapshot().newModification();
169         mod.write(YangInstanceIdentifier.create(BOX), containerBuilder().withNodeIdentifier(BOX)
170             .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
171                 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
172                     .withChild(OBJECT_ID_LEAF)
173                     .build())
174                 .build())
175             .build());
176         mod.merge(YangInstanceIdentifier.create(BOX), containerBuilder().withNodeIdentifier(BOX)
177             .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
178                 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
179                     .withChild(OBJECT_ID_LEAF)
180                     .withChild(leafSetBuilder().withNodeIdentifier(ATTRIBUTES)
181                         .withChildValue("object1")
182                         .build())
183                     .build())
184                 .build())
185             .build());
186
187         commit(mod);
188     }
189
190     @Test
191     public void testEmptyAndMergeOneWithListTouched() throws DataValidationFailedException {
192         final DataTreeModification mod = dataTree.takeSnapshot().newModification();
193         mod.write(YangInstanceIdentifier.create(BOX), containerBuilder().withNodeIdentifier(BOX)
194             .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
195                 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
196                     .withChild(OBJECT_ID_LEAF)
197                     .build())
198                 .build())
199             .build());
200         mod.merge(YangInstanceIdentifier.create(BOX), containerBuilder().withNodeIdentifier(BOX)
201             .withChild(mapBuilder().withNodeIdentifier(OBJECT_LIST)
202                 .addChild(mapEntryBuilder().withNodeIdentifier(OBJECT_ITEM)
203                     .withChild(OBJECT_ID_LEAF)
204                     .withChild(leafSetBuilder().withNodeIdentifier(ATTRIBUTES)
205                         .withChildValue("object1")
206                         .build())
207                     .build())
208                 .build())
209             .build());
210
211         mod.delete(YangInstanceIdentifier.create(BOX, OBJECT_LIST, OBJECT_ITEM, NESTED_LIST, NESTED_ITEM));
212
213         commit(mod);
214     }
215
216     @Test
217     public void testDisappearInChoice() throws DataValidationFailedException {
218         DataTreeModification mod = dataTree.takeSnapshot().newModification();
219         // Initialize choice with list
220         mod.write(YangInstanceIdentifier.create(BOX), containerBuilder().withNodeIdentifier(BOX)
221             .withChild(choiceBuilder().withNodeIdentifier(ANY_OF)
222                 .withChild(mapBuilder().withNodeIdentifier(SOME_LIST_ID)
223                     .withChild(mapEntryBuilder()
224                         .withNodeIdentifier(SOME_LIST_ITEM)
225                         .withChild(leafBuilder().withNodeIdentifier(SOME_LEAF_ID).withValue("foo").build())
226                         .build())
227                     .build())
228                 .build())
229             .build());
230         commit(mod);
231
232         // Now delete the single item, causing the list to fizzle, while creating the alterinative case
233         mod = dataTree.takeSnapshot().newModification();
234         mod.delete(YangInstanceIdentifier.create(BOX, ANY_OF, SOME_LIST_ID, SOME_LIST_ITEM));
235         mod.write(YangInstanceIdentifier.create(BOX, ANY_OF, SOME_LEAF_ID),
236             leafBuilder().withNodeIdentifier(SOME_LEAF_ID).withValue("foo").build());
237
238         commit(mod);
239     }
240
241     private DataTreeModification write(final ContainerNode data) throws DataValidationFailedException {
242         final DataTreeModification mod = dataTree.takeSnapshot().newModification();
243         mod.write(YangInstanceIdentifier.create(BOX), data);
244         return mod;
245     }
246
247     private void writeAndCommit(final ContainerNode data) throws DataValidationFailedException {
248         final DataTreeModification mod = dataTree.takeSnapshot().newModification();
249         mod.write(YangInstanceIdentifier.create(BOX), data);
250         commit(mod);
251     }
252
253     private void commit(final DataTreeModification mod) throws DataValidationFailedException {
254         mod.ready();
255         dataTree.validate(mod);
256         dataTree.commit(dataTree.prepare(mod));
257     }
258 }