Bug 5968: Mandatory leaf enforcement does not work in some cases
[yangtools.git] / yang / yang-data-impl / src / test / java / org / opendaylight / yangtools / yang / data / impl / schema / tree / Bug5968Test.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.impl.schema.tree;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotNull;
12 import static org.junit.Assert.fail;
13
14 import com.google.common.collect.ImmutableMap;
15 import org.junit.Before;
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.ContainerNode;
22 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
24 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
25 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeConfiguration;
26 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
27 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
28 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
29 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
30 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
31 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
32
33 public class Bug5968Test {
34     private static final String NS = "foo";
35     private static final String REV = "2016-07-28";
36     private static final QName ROOT = QName.create(NS, REV, "root");
37     private static final QName MY_LIST = QName.create(NS, REV, "my-list");
38     private static final QName LIST_ID = QName.create(NS, REV, "list-id");
39     private static final QName MANDATORY_LEAF = QName.create(NS, REV, "mandatory-leaf");
40     private static final QName COMMON_LEAF = QName.create(NS, REV, "common-leaf");
41     private SchemaContext schemaContext;
42
43     @Before
44     public void init() throws ReactorException {
45         this.schemaContext = TestModel.createTestContext("/bug5968/foo.yang");
46         assertNotNull("Schema context must not be null.", this.schemaContext);
47     }
48
49     private static InMemoryDataTree initDataTree(final SchemaContext schemaContext, final boolean withMapNode)
50             throws DataValidationFailedException {
51         final InMemoryDataTree inMemoryDataTree = (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create(
52                 DataTreeConfiguration.DEFAULT_CONFIGURATION);
53         inMemoryDataTree.setSchemaContext(schemaContext);
54
55         final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> root = Builders.containerBuilder()
56                 .withNodeIdentifier(new NodeIdentifier(ROOT));
57         final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
58         modificationTree.write(
59                 YangInstanceIdentifier.of(ROOT),
60                 withMapNode ? root.withChild(
61                         Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(MY_LIST)).build()).build() : root
62                         .build());
63         modificationTree.ready();
64
65         inMemoryDataTree.validate(modificationTree);
66         final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
67         inMemoryDataTree.commit(prepare);
68
69         return inMemoryDataTree;
70     }
71
72     private static InMemoryDataTree emptyDataTree(final SchemaContext schemaContext)
73             throws DataValidationFailedException {
74         final InMemoryDataTree inMemoryDataTree = (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create(
75                 DataTreeConfiguration.DEFAULT_CONFIGURATION);
76         inMemoryDataTree.setSchemaContext(schemaContext);
77
78         return inMemoryDataTree;
79     }
80
81     @Test
82     public void writeInvalidContainerTest() throws ReactorException, DataValidationFailedException {
83         final InMemoryDataTree inMemoryDataTree = emptyDataTree(schemaContext);
84
85         final MapNode myList = createMap(true);
86         final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> root = Builders.containerBuilder()
87                 .withNodeIdentifier(new NodeIdentifier(ROOT)).withChild(myList);
88
89         final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
90         modificationTree.write(YangInstanceIdentifier.of(ROOT), root.build());
91
92         try {
93             modificationTree.ready();
94             inMemoryDataTree.validate(modificationTree);
95             final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
96             inMemoryDataTree.commit(prepare);
97             fail("Should fail due to missing mandatory leaf.");
98         } catch (final IllegalArgumentException e) {
99             assertEquals(
100                     "Node (foo?revision=2016-07-28)my-list[{(foo?revision=2016-07-28)list-id=1}] is missing mandatory "
101                             + "descendant /(foo?revision=2016-07-28)mandatory-leaf", e.getMessage());
102         }
103     }
104
105     @Test
106     public void writeInvalidMapTest() throws ReactorException, DataValidationFailedException {
107         final InMemoryDataTree inMemoryDataTree = emptyDataTree(schemaContext);
108         final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
109         writeMap(modificationTree, true);
110
111         try {
112             modificationTree.ready();
113             inMemoryDataTree.validate(modificationTree);
114             final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
115             inMemoryDataTree.commit(prepare);
116             fail("Should fail due to missing mandatory leaf.");
117         } catch (final IllegalArgumentException e) {
118             assertEquals(
119                     "Node (foo?revision=2016-07-28)my-list[{(foo?revision=2016-07-28)list-id=1}] is missing mandatory "
120                             + "descendant /(foo?revision=2016-07-28)mandatory-leaf", e.getMessage());
121         }
122     }
123
124     @Test
125     public void writeInvalidMapEntryTest() throws ReactorException, DataValidationFailedException {
126         final InMemoryDataTree inMemoryDataTree = initDataTree(schemaContext, true);
127         final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
128
129         writeMapEntry(modificationTree, "1", null, "common-value");
130
131         try {
132             modificationTree.ready();
133             inMemoryDataTree.validate(modificationTree);
134             final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
135             inMemoryDataTree.commit(prepare);
136             fail("Should fail due to missing mandatory leaf.");
137         } catch (final IllegalArgumentException e) {
138             assertEquals(
139                     "Node (foo?revision=2016-07-28)my-list[{(foo?revision=2016-07-28)list-id=1}] is missing mandatory "
140                             + "descendant /(foo?revision=2016-07-28)mandatory-leaf", e.getMessage());
141         }
142     }
143
144     private static void writeMap(final InMemoryDataTreeModification modificationTree, final boolean mandatoryDataMissing)
145             throws DataValidationFailedException {
146         final MapNode myList = createMap(mandatoryDataMissing);
147         modificationTree.write(YangInstanceIdentifier.of(ROOT).node(MY_LIST), myList);
148     }
149
150     private static MapNode createMap(final boolean mandatoryDataMissing) throws DataValidationFailedException {
151         return Builders
152                 .mapBuilder()
153                 .withNodeIdentifier(new NodeIdentifier(MY_LIST))
154                 .withChild(
155                         mandatoryDataMissing ? createMapEntry("1", "common-value") : createMapEntry("1",
156                                 "mandatory-value", "common-value")).build();
157     }
158
159     private static void writeMapEntry(final InMemoryDataTreeModification modificationTree, final Object listIdValue,
160             final Object mandatoryLeafValue, final Object commonLeafValue) throws DataValidationFailedException {
161         final MapEntryNode taskEntryNode = mandatoryLeafValue == null ? createMapEntry(listIdValue, commonLeafValue)
162                 : createMapEntry(listIdValue, mandatoryLeafValue, commonLeafValue);
163
164         modificationTree.write(
165                 YangInstanceIdentifier.of(ROOT).node(MY_LIST)
166                         .node(new NodeIdentifierWithPredicates(MY_LIST, ImmutableMap.of(LIST_ID, listIdValue))),
167                 taskEntryNode);
168     }
169
170     private static MapEntryNode createMapEntry(final Object listIdValue, final Object mandatoryLeafValue,
171             final Object commonLeafValue) throws DataValidationFailedException {
172         return Builders.mapEntryBuilder()
173                 .withNodeIdentifier(new NodeIdentifierWithPredicates(MY_LIST, ImmutableMap.of(LIST_ID, listIdValue)))
174                 .withChild(ImmutableNodes.leafNode(LIST_ID, listIdValue))
175                 .withChild(ImmutableNodes.leafNode(MANDATORY_LEAF, mandatoryLeafValue))
176                 .withChild(ImmutableNodes.leafNode(COMMON_LEAF, commonLeafValue)).build();
177     }
178
179     private static MapEntryNode createMapEntry(final Object listIdValue, final Object commonLeafValue)
180             throws DataValidationFailedException {
181         return Builders.mapEntryBuilder()
182                 .withNodeIdentifier(new NodeIdentifierWithPredicates(MY_LIST, ImmutableMap.of(LIST_ID, listIdValue)))
183                 .withChild(ImmutableNodes.leafNode(LIST_ID, listIdValue))
184                 .withChild(ImmutableNodes.leafNode(COMMON_LEAF, commonLeafValue)).build();
185     }
186
187     @Test
188     public void writeValidContainerTest() throws ReactorException, DataValidationFailedException {
189         final InMemoryDataTree inMemoryDataTree = emptyDataTree(schemaContext);
190
191         final MapNode myList = createMap(false);
192         final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> root = Builders.containerBuilder()
193                 .withNodeIdentifier(new NodeIdentifier(ROOT)).withChild(myList);
194
195         final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
196         modificationTree.write(YangInstanceIdentifier.of(ROOT), root.build());
197         modificationTree.ready();
198         inMemoryDataTree.validate(modificationTree);
199         final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
200         inMemoryDataTree.commit(prepare);
201     }
202
203     @Test
204     public void writeValidMapTest() throws ReactorException, DataValidationFailedException {
205         final InMemoryDataTree inMemoryDataTree = emptyDataTree(schemaContext);
206         final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
207         writeMap(modificationTree, false);
208
209         modificationTree.ready();
210         inMemoryDataTree.validate(modificationTree);
211         final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
212         inMemoryDataTree.commit(prepare);
213     }
214
215     @Test
216     public void writeValidMapEntryTest() throws ReactorException, DataValidationFailedException {
217         final InMemoryDataTree inMemoryDataTree = initDataTree(schemaContext, true);
218         final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
219
220         writeMapEntry(modificationTree, "1", "mandatory-value", "common-value");
221
222         modificationTree.ready();
223         inMemoryDataTree.validate(modificationTree);
224         final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
225         inMemoryDataTree.commit(prepare);
226     }
227 }