Split out yang-data-tree-{api,spi}
[yangtools.git] / data / yang-data-tree-ri / src / test / java / org / opendaylight / yangtools / yang / data / tree / leafref / DataTreeCandidateValidatorTest.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.leafref;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertThrows;
12
13 import java.util.HashMap;
14 import java.util.Map;
15 import org.eclipse.jdt.annotation.NonNull;
16 import org.junit.AfterClass;
17 import org.junit.BeforeClass;
18 import org.junit.Test;
19 import org.opendaylight.yangtools.yang.common.QName;
20 import org.opendaylight.yangtools.yang.common.QNameModule;
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.YangInstanceIdentifier.NodeWithValue;
25 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
26 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
27 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.SystemMapNode;
32 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
33 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
34 import org.opendaylight.yangtools.yang.data.tree.api.DataTree;
35 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidate;
36 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeConfiguration;
37 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeModification;
38 import org.opendaylight.yangtools.yang.data.tree.api.DataValidationFailedException;
39 import org.opendaylight.yangtools.yang.data.tree.impl.di.InMemoryDataTreeFactory;
40 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
41 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
42 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
43 import org.opendaylight.yangtools.yang.model.api.Module;
44 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48 public class DataTreeCandidateValidatorTest {
49
50     private static EffectiveModelContext context;
51     private static Module valModule;
52     private static QNameModule valModuleQname;
53     private static LeafRefContext rootLeafRefContext;
54     public static DataTree inMemoryDataTree;
55
56     private static QName odl;
57     private static QName project;
58     private static QName name;
59     private static QName desc;
60     private static QName lead;
61     private static QName owner;
62     private static QName odlContributor;
63     private static QName contributor;
64     private static QName odlProjectName;
65     private static QName odlProjectDesc;
66     private static QName login;
67     private static QName contributorName;
68     private static QName l1;
69     private static QName l2;
70     private static QName con1;
71     private static QName ch1;
72     private static QName ch2;
73     private static QName leafrefInChoice;
74     private static QName listInChoice;
75
76     private static QName leafrefInChoiceToChoice;
77     private static QName con3;
78     private static QName list3InChoice;
79     private static QName l3;
80     private static QName choiceInCon3;
81
82     private static QName listInChoiceKey;
83     private static QName k;
84
85     private static QName leafrefLeafList;
86
87     private static final Logger LOG = LoggerFactory.getLogger(DataTreeCandidateValidatorTest.class);
88     private static final String NEW_LINE = System.getProperty("line.separator");
89
90     @BeforeClass
91     public static void init() throws DataValidationFailedException {
92         context = YangParserTestUtils.parseYangResourceDirectory("/leafref-validation");
93
94         for (final Module module : context.getModules()) {
95             if (module.getName().equals("leafref-validation")) {
96                 valModule = module;
97             }
98         }
99
100         valModuleQname = valModule.getQNameModule();
101         rootLeafRefContext = LeafRefContext.create(context);
102
103         odl = QName.create(valModuleQname, "odl-project");
104         project = QName.create(valModuleQname, "project");
105         name = QName.create(valModuleQname, "name");
106         desc = QName.create(valModuleQname, "desc");
107         lead = QName.create(valModuleQname, "project-lead");
108         owner = QName.create(valModuleQname, "project-owner");
109
110         odlContributor = QName.create(valModuleQname, "odl-contributor");
111         contributor = QName.create(valModuleQname, "contributor");
112         odlProjectName = QName.create(valModuleQname, "odl-project-name");
113         login = QName.create(valModuleQname, "login");
114         contributorName = QName.create(valModuleQname, "contributor-name");
115
116         con1 = QName.create(valModuleQname, "con1");
117         l1 = QName.create(valModuleQname, "l1");
118         l2 = QName.create(valModuleQname, "l2");
119         odlProjectDesc = QName.create(valModuleQname, "odl-project-desc");
120
121         ch1 = QName.create(valModuleQname, "ch1");
122         ch2 = QName.create(valModuleQname, "ch2");
123         leafrefInChoice = QName.create(valModuleQname, "leafref-in-choice");
124         listInChoice = QName.create(valModuleQname, "list-in-choice");
125
126         leafrefInChoiceToChoice = QName.create(valModuleQname, "leafref-in-choice-to-choice");
127         con3 = QName.create(valModuleQname, "con3");
128         list3InChoice = QName.create(valModuleQname, "list3-in-choice");
129         l3 = QName.create(valModuleQname, "l3");
130         choiceInCon3 = QName.create(valModuleQname, "choice-in-con3");
131
132         listInChoiceKey = QName.create(valModuleQname, "list-in-choice-key");
133         k = QName.create(valModuleQname, "k");
134
135         leafrefLeafList = QName.create(valModuleQname, "leafref-leaf-list");
136
137         inMemoryDataTree = new InMemoryDataTreeFactory().create(DataTreeConfiguration.DEFAULT_OPERATIONAL, context);
138
139         final DataTreeModification initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
140
141         final ContainerNode odlProjectContainer = createOdlContainer();
142
143         final YangInstanceIdentifier path = YangInstanceIdentifier.of(odl);
144         initialDataTreeModification.write(path, odlProjectContainer);
145         initialDataTreeModification.ready();
146
147         final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree
148                 .prepare(initialDataTreeModification);
149         inMemoryDataTree.commit(writeContributorsCandidate);
150     }
151
152     @AfterClass
153     public static void cleanup() {
154         inMemoryDataTree = null;
155         rootLeafRefContext = null;
156         valModule = null;
157         context = null;
158     }
159
160     @Test
161     public void dataTreeCanditateValidationTest() throws DataValidationFailedException {
162         write();
163
164         write2();
165
166         delete();
167
168         writeContributors();
169
170         writeMapEntry();
171
172         writeIntoMapEntry();
173     }
174
175     private static void writeContributors() throws DataValidationFailedException {
176
177         final ContainerNode contributorContainer = createBasicContributorContainer();
178
179         final YangInstanceIdentifier contributorPath = YangInstanceIdentifier.of(odlContributor);
180         final DataTreeModification writeModification = inMemoryDataTree.takeSnapshot().newModification();
181         writeModification.write(contributorPath, contributorContainer);
182         writeModification.ready();
183
184         final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree
185                 .prepare(writeModification);
186
187         LOG.debug("*************************");
188         LOG.debug("Before write of contributors: ");
189         LOG.debug("*************************");
190         LOG.debug(inMemoryDataTree.toString());
191
192         final LeafRefDataValidationFailedException ex = assertThrows(LeafRefDataValidationFailedException.class,
193             () -> LeafRefValidation.validate(writeContributorsCandidate, rootLeafRefContext));
194         assertEquals(3, ex.getValidationsErrorsCount());
195
196         inMemoryDataTree.commit(writeContributorsCandidate);
197
198         LOG.debug("*************************");
199         LOG.debug("After write of contributors: ");
200         LOG.debug("*************************");
201         LOG.debug(inMemoryDataTree.toString());
202     }
203
204     private static void writeIntoMapEntry() throws DataValidationFailedException {
205         final Map<QName, Object> keys = new HashMap<>();
206         keys.put(name, "New Project");
207         final NodeIdentifierWithPredicates mapEntryPath = NodeIdentifierWithPredicates.of(project, keys);
208
209         final YangInstanceIdentifier leaderPath = YangInstanceIdentifier.of(odl).node(project).node(mapEntryPath)
210             .node(lead);
211
212         final LeafNode<String> leader = ImmutableNodes.leafNode(lead, "Updated leader");
213
214         final DataTreeModification writeModification = inMemoryDataTree.takeSnapshot().newModification();
215         writeModification.write(leaderPath, leader);
216         writeModification.ready();
217
218         final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree.prepare(writeModification);
219
220         LOG.debug("*************************");
221         LOG.debug("Before write into map entry (update of leader name): ");
222         LOG.debug("*************************");
223         LOG.debug(inMemoryDataTree.toString());
224
225         final LeafRefDataValidationFailedException ex = assertThrows(LeafRefDataValidationFailedException.class,
226             () -> LeafRefValidation.validate(writeContributorsCandidate, rootLeafRefContext));
227         assertEquals(1, ex.getValidationsErrorsCount());
228
229         inMemoryDataTree.commit(writeContributorsCandidate);
230
231         LOG.debug("*************************");
232         LOG.debug("After write into map entry (update of leader name): ");
233         LOG.debug("*************************");
234         LOG.debug(inMemoryDataTree.toString());
235     }
236
237     private static void writeMapEntry() throws DataValidationFailedException {
238         final NodeIdentifierWithPredicates mapEntryPath = NodeIdentifierWithPredicates.of(project, name, "New Project");
239
240         final MapEntryNode newProjectMapEntry = createProjectListEntry(
241                 "New Project", "New Project description ...",
242                 "Leader of New Project", "Owner of New Project");
243
244         final DataTreeModification writeModification = inMemoryDataTree.takeSnapshot().newModification();
245         writeModification.write(YangInstanceIdentifier.of(odl).node(project).node(mapEntryPath), newProjectMapEntry);
246         writeModification.ready();
247
248         final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree.prepare(writeModification);
249
250         LOG.debug("*************************");
251         LOG.debug("Before map entry write: ");
252         LOG.debug("*************************");
253         LOG.debug(inMemoryDataTree.toString());
254
255         final LeafRefDataValidationFailedException ex = assertThrows(LeafRefDataValidationFailedException.class,
256             () -> LeafRefValidation.validate(writeContributorsCandidate, rootLeafRefContext));
257         assertEquals(2, ex.getValidationsErrorsCount());
258
259         inMemoryDataTree.commit(writeContributorsCandidate);
260
261         LOG.debug("*************************");
262         LOG.debug("After map entry write: ");
263         LOG.debug("*************************");
264         LOG.debug(inMemoryDataTree.toString());
265     }
266
267     private static void write() throws DataValidationFailedException {
268         final ContainerNode contributorContainer = createContributorContainer(
269             (ContainerSchemaNode) valModule.getDataChildByName(odlContributor));
270
271         final YangInstanceIdentifier contributorPath = YangInstanceIdentifier.of(odlContributor);
272         final DataTreeModification writeModification = inMemoryDataTree.takeSnapshot().newModification();
273         writeModification.write(contributorPath, contributorContainer);
274
275         writeModification.write(YangInstanceIdentifier.of(l1),
276             ImmutableNodes.leafNode(l1, "Leafref l1 under the root"));
277         writeModification.write(YangInstanceIdentifier.of(l2),
278             ImmutableNodes.leafNode(l2, "Leafref target l2 under the root"));
279
280         writeModification.ready();
281         final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree.prepare(writeModification);
282
283         LOG.debug("*************************");
284         LOG.debug("Before write: ");
285         LOG.debug("*************************");
286         LOG.debug(inMemoryDataTree.toString());
287
288         final LeafRefDataValidationFailedException ex = assertThrows(LeafRefDataValidationFailedException.class,
289             () -> LeafRefValidation.validate(writeContributorsCandidate, rootLeafRefContext));
290         assertEquals(12, ex.getValidationsErrorsCount());
291
292         inMemoryDataTree.commit(writeContributorsCandidate);
293
294         LOG.debug("*************************");
295         LOG.debug("After write: ");
296         LOG.debug("*************************");
297         LOG.debug(inMemoryDataTree.toString());
298     }
299
300     private static void write2() throws DataValidationFailedException {
301         final DataTreeModification writeModification = inMemoryDataTree.takeSnapshot().newModification();
302         writeModification.write(YangInstanceIdentifier.of(odl).node(con1), Builders.containerBuilder()
303             .withNodeIdentifier(new NodeIdentifier(con1))
304             .addChild(ImmutableNodes.leafNode(l1, "l1 value"))
305             .build());
306         writeModification.write(YangInstanceIdentifier.of(odl).node(ch1), createChoiceNode());
307         writeModification.write(YangInstanceIdentifier.of(odl).node(con3), createCon3Node());
308         writeModification.write(YangInstanceIdentifier.of(odl).node(leafrefLeafList), createLeafRefLeafListNode());
309         writeModification.ready();
310
311         final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree.prepare(writeModification);
312
313         LOG.debug("*************************");
314         LOG.debug("Before write2: ");
315         LOG.debug("*************************");
316         LOG.debug(inMemoryDataTree.toString());
317
318         final LeafRefDataValidationFailedException ex = assertThrows(LeafRefDataValidationFailedException.class,
319             () -> LeafRefValidation.validate(writeContributorsCandidate, rootLeafRefContext));
320         assertEquals(6, ex.getValidationsErrorsCount());
321
322         inMemoryDataTree.commit(writeContributorsCandidate);
323
324         LOG.debug("*************************");
325         LOG.debug("After write2: ");
326         LOG.debug("*************************");
327         LOG.debug(inMemoryDataTree.toString());
328     }
329
330     private static @NonNull LeafSetNode<Object> createLeafRefLeafListNode() {
331         return Builders.leafSetBuilder()
332             .withNodeIdentifier(new NodeIdentifier(leafrefLeafList))
333             .addChild(createLeafSetEntry(leafrefLeafList, "k1"))
334             .addChild(createLeafSetEntry(leafrefLeafList, "k2"))
335             .addChild(createLeafSetEntry(leafrefLeafList, "k3"))
336             .build();
337     }
338
339     private static ContainerNode createCon3Node() {
340         return Builders.containerBuilder()
341             .withNodeIdentifier(new NodeIdentifier(con3))
342             .addChild(Builders.choiceBuilder()
343                 .withNodeIdentifier(new NodeIdentifier(choiceInCon3))
344                 .addChild(Builders.mapBuilder()
345                     .withNodeIdentifier(new NodeIdentifier(list3InChoice))
346                     .addChild(createList3Entry("k1", "val1", "valA", "valX"))
347                     .addChild(createList3Entry("k2", "val2", "valB", "valY"))
348                     .build())
349                 .build())
350             .build();
351     }
352
353     private static MapEntryNode createList3Entry(final String keyVal,final String l3Val1, final String l3Val2,
354             final String l3Val3) {
355         return Builders.mapEntryBuilder()
356             .withNodeIdentifier(NodeIdentifierWithPredicates.of(list3InChoice, k, keyVal))
357             .addChild(ImmutableNodes.leafNode(k, keyVal))
358             .addChild(Builders.leafSetBuilder()
359                 .withNodeIdentifier(new NodeIdentifier(l3))
360                 .addChild(createLeafSetEntry(l3, l3Val1))
361                 .addChild(createLeafSetEntry(l3, l3Val2))
362                 .addChild(createLeafSetEntry(l3, l3Val3))
363                 .build())
364             .build();
365     }
366
367     private static LeafSetEntryNode<Object> createLeafSetEntry(final QName qname, final String val) {
368         return Builders.leafSetEntryBuilder()
369             .withNodeIdentifier(new NodeWithValue<>(qname, val))
370             .withValue(val)
371             .build();
372     }
373
374     private static ChoiceNode createChoiceNode() {
375         return Builders.choiceBuilder()
376             .withNodeIdentifier(new NodeIdentifier(ch1))
377             .addChild(Builders.choiceBuilder()
378                 .withNodeIdentifier(new NodeIdentifier(ch2))
379                 .addChild(Builders.mapBuilder()
380                     .withNodeIdentifier(new NodeIdentifier(listInChoice))
381                     .addChild(createListInChoiceEntry("key1", "leafref-in-choice value", "val1"))
382                     .addChild(createListInChoiceEntry("key2", "l1 value", "val2"))
383                     .addChild(createListInChoiceEntry("key3", "l1 value", "val3"))
384                     .build())
385                 .build())
386             .build();
387     }
388
389     private static MapEntryNode createListInChoiceEntry(final String keyVal, final String leafrefInChoiceVal,
390             final String leafrefInChoiceToChoiceVal) {
391         return Builders.mapEntryBuilder()
392             .withNodeIdentifier(NodeIdentifierWithPredicates.of(listInChoice, listInChoiceKey, keyVal))
393             .addChild(ImmutableNodes.leafNode(listInChoiceKey, keyVal))
394             .addChild(ImmutableNodes.leafNode(leafrefInChoice, leafrefInChoiceVal))
395             .addChild(ImmutableNodes.leafNode(leafrefInChoiceToChoice, leafrefInChoiceToChoiceVal))
396             .build();
397     }
398
399     private static void delete() throws DataValidationFailedException {
400         final DataTreeModification delete = inMemoryDataTree.takeSnapshot().newModification();
401         delete.delete(YangInstanceIdentifier.of(odlContributor));
402         delete.ready();
403
404         final DataTreeCandidate deleteContributorsCanditate = inMemoryDataTree.prepare(delete);
405
406         LOG.debug("*************************");
407         LOG.debug("Before delete: ");
408         LOG.debug("*************************");
409         LOG.debug(inMemoryDataTree.toString());
410
411
412         final LeafRefDataValidationFailedException ex = assertThrows(LeafRefDataValidationFailedException.class,
413             () -> LeafRefValidation.validate(deleteContributorsCanditate, rootLeafRefContext));
414         assertEquals(6, ex.getValidationsErrorsCount());
415
416         inMemoryDataTree.commit(deleteContributorsCanditate);
417
418         LOG.debug("*************************");
419         LOG.debug("After delete: ");
420         LOG.debug("*************************");
421         LOG.debug(inMemoryDataTree.toString());
422     }
423
424     private static ContainerNode createContributorContainer(final ContainerSchemaNode contributorCont) {
425         return Builders.containerBuilder()
426             .withNodeIdentifier(new NodeIdentifier(odlContributor))
427             .addChild(createContributorList((ListSchemaNode) contributorCont.findDataChildByName(contributor).get()))
428             .build();
429
430     }
431
432     private static SystemMapNode createContributorList(final ListSchemaNode contributorListSchemaNode) {
433         return Builders.mapBuilder()
434             .withNodeIdentifier(new NodeIdentifier(contributor))
435             .addChild(createContributorListEntry("Leader of Yangtools", "Yangtools Leader name", "Yangtools",
436                 "Yangtools description ..."))
437             .addChild(createContributorListEntry("Leader of MD-SAL", "MD-SAL Leader name", "MD-SAL",
438                 "MD-SAL description ..."))
439             .addChild(createContributorListEntry("Leader of Controller", "Controller Leader name", "Controller",
440                 "Controller description ..."))
441             .addChild(createContributorListEntry("jdoe", "John Doe", "MD-SAL", "Yangtools description ..."))
442             .addChild(createContributorListEntry("foo", "foo name", "Controller", "MD-SAL description ..."))
443             .addChild(createContributorListEntry("bar", "bar name", "Yangtools", "Controller description ..."))
444             .addChild(createContributorListEntry("baz", "baz name", "Unknown Project",
445                 "Unknown Project description ..."))
446             .addChild(createContributorListEntry("pk", "pk name", "Unknown Project 2", "Controller description ..."))
447             .build();
448     }
449
450     private static MapEntryNode createContributorListEntry(final String loginVal, final String contributorNameVal,
451             final String odlProjectNameVal, final String odlProjectDescVal) {
452         return Builders.mapEntryBuilder()
453             .withNodeIdentifier(NodeIdentifierWithPredicates.of(contributor, login, loginVal))
454             .addChild(ImmutableNodes.leafNode(login, loginVal))
455             .addChild(ImmutableNodes.leafNode(contributorName, contributorNameVal))
456             .addChild(ImmutableNodes.leafNode(odlProjectName, odlProjectNameVal))
457             .addChild(ImmutableNodes.leafNode(odlProjectDesc, odlProjectDescVal))
458             .build();
459     }
460
461     private static ContainerNode createOdlContainer() {
462         return Builders.containerBuilder()
463             .withNodeIdentifier(new NodeIdentifier(odl))
464             .addChild(createProjectList())
465             .build();
466     }
467
468     private static SystemMapNode createProjectList() {
469         return Builders.mapBuilder()
470             .withNodeIdentifier(new NodeIdentifier(project))
471             .addChild(createProjectListEntry("Yangtools", "Yangtools description ...", "Leader of Yangtools",
472                 "Owner of Yangtools"))
473             .addChild(createProjectListEntry("MD-SAL", "MD-SAL description ...", "Leader of MD-SAL", "Owner of MD-SAL"))
474             .addChild(createProjectListEntry("Controller", "Controller description ...", "Leader of Controller",
475             "Owner of Controller")).build();
476     }
477
478     private static MapEntryNode createProjectListEntry(final String nameVal, final String descVal, final String leadVal,
479             final String ownerVal) {
480         return Builders.mapEntryBuilder()
481             .withNodeIdentifier(NodeIdentifierWithPredicates.of(project, name, nameVal))
482             .addChild(ImmutableNodes.leafNode(name, nameVal))
483             .addChild(ImmutableNodes.leafNode(desc, descVal))
484             .addChild(ImmutableNodes.leafNode(lead, leadVal))
485             .addChild(ImmutableNodes.leafNode(owner, ownerVal))
486             .build();
487     }
488
489     private static ContainerNode createBasicContributorContainer() {
490         return Builders.containerBuilder()
491             .withNodeIdentifier(new NodeIdentifier(odlContributor))
492             .addChild(createBasicContributorList())
493             .build();
494     }
495
496     private static SystemMapNode createBasicContributorList() {
497         return Builders.mapBuilder()
498             .withNodeIdentifier(new NodeIdentifier(contributor))
499             .addChild(createContributorListEntry("Leader of Yangtools", "Yangtools Leader name", "Yangtools",
500                 "Yangtools description ..."))
501             .addChild(createContributorListEntry("Leader of MD-SAL", "MD-SAL Leader name", "MD-SAL",
502                 "MD-SAL description ..."))
503             .addChild(createContributorListEntry("Leader of Controller", "Controller Leader name", "Controller",
504                 "Controller description ...")).build();
505     }
506 }