From: Robert Varga Date: Thu, 22 Oct 2015 20:41:47 +0000 (+0200) Subject: Enforce case uniqueness X-Git-Tag: release/beryllium~37 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=yangtools.git;a=commitdiff_plain;h=401382e6bb243710d0a93bd7210161ea5994c101 Enforce case uniqueness Validate case leaf exclusion. RFC6020 requires that at most once case inside a choice is present at any time. This means we must not allow leaves which belong to different case statements exist at the same point in time. Change-Id: If8235ffc4aff87fd96d5071158b7e794ef8c3c5e Signed-off-by: Robert Varga --- diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AbstractNodeContainerModificationStrategy.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AbstractNodeContainerModificationStrategy.java index 3b0b586b12..b7f2f6003c 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AbstractNodeContainerModificationStrategy.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AbstractNodeContainerModificationStrategy.java @@ -8,6 +8,7 @@ package org.opendaylight.yangtools.yang.data.impl.schema.tree; import static com.google.common.base.Preconditions.checkArgument; + import com.google.common.base.Optional; import com.google.common.base.Preconditions; import java.util.Collection; @@ -213,6 +214,10 @@ abstract class AbstractNodeContainerModificationStrategy extends SchemaAwareAppl } } + protected boolean verifyChildrenStructure() { + return verifyChildrenStructure; + } + @SuppressWarnings("rawtypes") protected abstract NormalizedNodeContainerBuilder createBuilder(NormalizedNode original); } diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/CaseEnforcer.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/CaseEnforcer.java new file mode 100644 index 0000000000..62a5f837dd --- /dev/null +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/CaseEnforcer.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.yangtools.yang.data.impl.schema.tree; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMap.Builder; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import org.opendaylight.yangtools.concepts.Immutable; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType; +import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; + +final class CaseEnforcer implements Immutable { + private final Map children; + + private CaseEnforcer(final Map children) { + this.children = Preconditions.checkNotNull(children); + } + + static CaseEnforcer forTree(final ChoiceCaseNode schema, final TreeType treeType) { + final Builder builder = ImmutableMap.builder(); + if (SchemaAwareApplyOperation.belongsToTree(treeType, schema)) { + for (DataSchemaNode child : schema.getChildNodes()) { + if (SchemaAwareApplyOperation.belongsToTree(treeType, child)) { + builder.put(NodeIdentifier.create(child.getQName()), child); + } + } + } + + final Map children = builder.build(); + return children.isEmpty() ? null : new CaseEnforcer(children); + } + + Set> getChildEntries() { + return children.entrySet(); + } + + Set getChildIdentifiers() { + return children.keySet(); + } +} diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ChoiceModificationStrategy.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ChoiceModificationStrategy.java index 47f1e66b4e..3a0d14a72d 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ChoiceModificationStrategy.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ChoiceModificationStrategy.java @@ -8,14 +8,27 @@ package org.opendaylight.yangtools.yang.data.impl.schema.tree; import static com.google.common.base.Preconditions.checkArgument; + import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.base.Predicates; +import com.google.common.base.Verify; +import com.google.common.collect.Collections2; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMap.Builder; +import java.util.Collection; import java.util.Map; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import java.util.Map.Entry; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes; import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType; +import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNode; +import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.Version; import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder; import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableChoiceNodeBuilder; import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; @@ -23,27 +36,38 @@ import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; final class ChoiceModificationStrategy extends AbstractNodeContainerModificationStrategy { - private final Map childNodes; + private final Map childNodes; + // FIXME: enforce leaves not coming from two case statements at the same time + private final Map> exclusions; + private final Map caseEnforcers; ChoiceModificationStrategy(final ChoiceSchemaNode schemaNode, final TreeType treeType) { super(ChoiceNode.class, treeType); - final ImmutableMap.Builder child = ImmutableMap.builder(); + final Builder childBuilder = ImmutableMap.builder(); + final Builder enforcerBuilder = ImmutableMap.builder(); for (final ChoiceCaseNode caze : schemaNode.getCases()) { - if (SchemaAwareApplyOperation.belongsToTree(treeType,caze)) { - for (final DataSchemaNode cazeChild : caze.getChildNodes()) { - if (SchemaAwareApplyOperation.belongsToTree(treeType,cazeChild)) { - final ModificationApplyOperation childNode = SchemaAwareApplyOperation.from(cazeChild, treeType); - child.put(NodeIdentifier.create(cazeChild.getQName()), childNode); - } + final CaseEnforcer enforcer = CaseEnforcer.forTree(caze, treeType); + if (enforcer != null) { + for (final Entry e : enforcer.getChildEntries()) { + childBuilder.put(e.getKey(), SchemaAwareApplyOperation.from(e.getValue(), treeType)); + enforcerBuilder.put(e.getKey(), enforcer); } } } - childNodes = child.build(); + childNodes = childBuilder.build(); + caseEnforcers = enforcerBuilder.build(); + + final Builder> exclusionsBuilder = ImmutableMap.builder(); + for (CaseEnforcer e : caseEnforcers.values()) { + exclusionsBuilder.put(e, ImmutableList.copyOf( + Collections2.filter(caseEnforcers.values(), Predicates.not(Predicates.equalTo(e))))); + } + exclusions = exclusionsBuilder.build(); } @Override - public Optional getChild(final YangInstanceIdentifier.PathArgument child) { + public Optional getChild(final PathArgument child) { return Optional.fromNullable(childNodes.get(child)); } @@ -53,4 +77,58 @@ final class ChoiceModificationStrategy extends AbstractNodeContainerModification checkArgument(original instanceof ChoiceNode); return ImmutableChoiceNodeBuilder.create((ChoiceNode) original); } + + @Override + void verifyStructure(final NormalizedNode writtenValue, final boolean verifyChildren) { + if(verifyChildrenStructure() && verifyChildren) { + enforceCases(writtenValue); + } + super.verifyStructure(writtenValue, verifyChildren); + } + + private void enforceCases(final TreeNode tree) { + enforceCases(tree.getData()); + } + + private void enforceCases(final NormalizedNode normalizedNode) { + Verify.verify(normalizedNode instanceof ChoiceNode); + final Collection> children = ((ChoiceNode) normalizedNode).getValue(); + if (!children.isEmpty()) { + final DataContainerChild firstChild = children.iterator().next(); + final CaseEnforcer enforcer = caseEnforcers.get(firstChild.getIdentifier()); + Verify.verifyNotNull(enforcer, "Case enforcer cannot be null. Most probably, child node %s of choice node %s does not belong in current tree type.", firstChild.getIdentifier(), normalizedNode.getIdentifier()); + + // Make sure no leaves from other cases are present + for (CaseEnforcer other : exclusions.get(enforcer)) { + for (NodeIdentifier id : other.getChildIdentifiers()) { + final Optional> maybeChild = NormalizedNodes.getDirectChild(normalizedNode, id); + Preconditions.checkArgument(!maybeChild.isPresent(), + "Child %s (from case %s) implies non-presence of child %s (from case %s), which is %s", + firstChild.getIdentifier(), enforcer, id, other, maybeChild.orNull()); + } + } + } + } + + @Override + protected TreeNode applyMerge(final ModifiedNode modification, final TreeNode currentMeta, final Version version) { + final TreeNode ret = super.applyMerge(modification, currentMeta, version); + enforceCases(ret); + return ret; + } + + @Override + protected TreeNode applyWrite(final ModifiedNode modification, final Optional currentMeta, + final Version version) { + final TreeNode ret = super.applyWrite(modification, currentMeta, version); + enforceCases(ret); + return ret; + } + + @Override + protected TreeNode applyTouch(final ModifiedNode modification, final TreeNode currentMeta, final Version version) { + final TreeNode ret = super.applyTouch(modification, currentMeta, version); + enforceCases(ret); + return ret; + } } diff --git a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/CaseExclusionTest.java b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/CaseExclusionTest.java new file mode 100644 index 0000000000..cec5bbbc43 --- /dev/null +++ b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/CaseExclusionTest.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.yangtools.yang.data.impl.schema.tree; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.leafNode; + +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; +import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException; + +public class CaseExclusionTest { + + private SchemaContext schemaContext; + + @Before + public void prepare() throws ReactorException { + schemaContext = RetestModel.createTestContext("/case-exclusion-test.yang"); + assertNotNull("Schema context must not be null.", schemaContext); + } + + private InMemoryDataTree initDataTree() { + InMemoryDataTree inMemoryDataTree = (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create( + TreeType.CONFIGURATION); + inMemoryDataTree.setSchemaContext(schemaContext); + return inMemoryDataTree; + } + + @Test + public void testCorrectCaseWrite() throws DataValidationFailedException { + final InMemoryDataTree inMemoryDataTree = initDataTree(); + final NodeIdentifier choice1Id = new NodeIdentifier(QName.create(TestModel.TEST_QNAME, "choice1")); + + final ContainerNode container = Builders + .containerBuilder() + .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME)) + .withChild( + Builders.choiceBuilder().withNodeIdentifier(choice1Id) + .withChild(leafNode(QName.create(TestModel.TEST_QNAME, "case1-leaf1"), "leaf-value")) + .build()).build(); + final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification(); + modificationTree.write(TestModel.TEST_PATH, container); + modificationTree.ready(); + + inMemoryDataTree.validate(modificationTree); + final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree); + inMemoryDataTree.commit(prepare); + } + + @Test(expected = IllegalArgumentException.class) + public void testCaseExclusion() throws DataValidationFailedException { + final InMemoryDataTree inMemoryDataTree = initDataTree(); + final NodeIdentifier choice1Id = new NodeIdentifier(QName.create(TestModel.TEST_QNAME, "choice1")); + + final ContainerNode container = Builders + .containerBuilder() + .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME)) + .withChild( + Builders.choiceBuilder() + .withNodeIdentifier(choice1Id) + .withChild(leafNode(QName.create(TestModel.TEST_QNAME, "case1-leaf1"), "leaf-value")) + .withChild( + ImmutableNodes.containerNode(QName.create(TestModel.TEST_QNAME, "case2-cont"))) + .build()).build(); + try { + final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification(); + modificationTree.write(TestModel.TEST_PATH, container); + modificationTree.ready(); + + inMemoryDataTree.validate(modificationTree); + final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree); + inMemoryDataTree.commit(prepare); + } catch (IllegalArgumentException e) { + assertTrue(e.getMessage().contains("implies non-presence of child")); + throw e; + } + } + + @Test(expected = IllegalArgumentException.class) + public void testCaseExclusionOnChoiceWrite() throws DataValidationFailedException { + final InMemoryDataTree inMemoryDataTree = initDataTree(); + // Container write + final ContainerNode container = Builders.containerBuilder() + .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME)).build(); + + final InMemoryDataTreeModification modificationTree1 = inMemoryDataTree.takeSnapshot().newModification(); + modificationTree1.write(TestModel.TEST_PATH, container); + modificationTree1.ready(); + + inMemoryDataTree.validate(modificationTree1); + final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree1); + inMemoryDataTree.commit(prepare1); + + // Choice write + final NodeIdentifier choice1Id = new NodeIdentifier(QName.create(TestModel.TEST_QNAME, "choice1")); + final ChoiceNode choice = Builders.choiceBuilder().withNodeIdentifier(choice1Id) + .withChild(leafNode(QName.create(TestModel.TEST_QNAME, "case1-leaf1"), "leaf-value")) + .withChild(ImmutableNodes.containerNode(QName.create(TestModel.TEST_QNAME, "case2-cont"))).build(); + + try { + final InMemoryDataTreeModification modificationTree2 = inMemoryDataTree.takeSnapshot().newModification(); + modificationTree2.write(TestModel.TEST_PATH.node(choice1Id), choice); + modificationTree2.ready(); + + inMemoryDataTree.validate(modificationTree2); + + final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(modificationTree2); + inMemoryDataTree.commit(prepare2); + } catch (IllegalArgumentException e) { + assertTrue(e.getMessage().contains("implies non-presence of child")); + throw e; + } + } +} diff --git a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ConfigStatementValidationTest.java b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ConfigStatementValidationTest.java index 072f45ea62..f35ad36e1a 100644 --- a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ConfigStatementValidationTest.java +++ b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ConfigStatementValidationTest.java @@ -11,6 +11,8 @@ import static org.junit.Assert.assertNotNull; import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.leafNode; import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntryBuilder; import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapNodeBuilder; + +import com.google.common.base.VerifyException; import org.junit.Before; import org.junit.Test; import org.opendaylight.yangtools.yang.common.QName; @@ -148,7 +150,7 @@ public class ConfigStatementValidationTest { inMemoryDataTree.commit(prepare); } - @Test(expected=SchemaValidationFailedException.class) + @Test(expected=VerifyException.class) public void testOnDataCaseLeafFail() throws DataValidationFailedException { final InMemoryDataTree inMemoryDataTree = (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION); diff --git a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/RetestModel.java b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/RetestModel.java index 756abb0785..9f31295f6d 100644 --- a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/RetestModel.java +++ b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/RetestModel.java @@ -40,4 +40,9 @@ public class RetestModel { public static SchemaContext createTestContext() throws ReactorException { return RetestUtils.parseYangStreams(Arrays.asList(getDatastoreTestInputStream())); } + + public static SchemaContext createTestContext(String resourcePath) throws ReactorException { + InputStream yangStream = RetestModel.class.getResourceAsStream(resourcePath); + return RetestUtils.parseYangStreams(Arrays.asList(yangStream)); + } } diff --git a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/Retest_ConfigStatementValidationTest.java b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/Retest_ConfigStatementValidationTest.java index 6bb03a55fa..383857ceb7 100644 --- a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/Retest_ConfigStatementValidationTest.java +++ b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/Retest_ConfigStatementValidationTest.java @@ -13,6 +13,7 @@ import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.le import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntryBuilder; import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapNodeBuilder; +import com.google.common.base.VerifyException; import org.junit.Before; import org.junit.Test; import org.opendaylight.yangtools.yang.common.QName; @@ -38,20 +39,20 @@ public class Retest_ConfigStatementValidationTest { private static final Short ONE_ID = 1; private static final Short TWO_ID = 2; - private static final YangInstanceIdentifier OUTER_LIST_1_PATH = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH) - .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, ONE_ID) // + private static final YangInstanceIdentifier OUTER_LIST_1_PATH = YangInstanceIdentifier + .builder(TestModel.OUTER_LIST_PATH).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, ONE_ID) // .build(); - private static final YangInstanceIdentifier OUTER_LIST_2_PATH = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH) - .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, TWO_ID) // + private static final YangInstanceIdentifier OUTER_LIST_2_PATH = YangInstanceIdentifier + .builder(TestModel.OUTER_LIST_PATH).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, TWO_ID) // .build(); - private static final MapEntryNode INNER_FOO_ENTRY_NODE = - ImmutableNodes.mapEntry(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "foo"); + private static final MapEntryNode INNER_FOO_ENTRY_NODE = ImmutableNodes.mapEntry(TestModel.INNER_LIST_QNAME, + TestModel.NAME_QNAME, "foo"); - private static final MapEntryNode INNER_BAR_ENTRY_NODE = - ImmutableNodes.mapEntryBuilder(QName.create(TestModel.TEST_QNAME, "inner-list2"), TestModel.NAME_QNAME, "foo") - .withChild(ImmutableNodes.leafNode(TestModel.VALUE_QNAME, "value")).build(); + private static final MapEntryNode INNER_BAR_ENTRY_NODE = ImmutableNodes + .mapEntryBuilder(QName.create(TestModel.TEST_QNAME, "inner-list2"), TestModel.NAME_QNAME, "foo") + .withChild(ImmutableNodes.leafNode(TestModel.VALUE_QNAME, "value")).build(); private static final MapEntryNode FOO_NODE = mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, ONE_ID) // .withChild(mapNodeBuilder(TestModel.INNER_LIST_QNAME).withChild(INNER_FOO_ENTRY_NODE) // @@ -66,21 +67,15 @@ public class Retest_ConfigStatementValidationTest { private SchemaContext schemaContext; private static ContainerNode createFooTestContainerNode() { - return ImmutableContainerNodeBuilder - .create() + return ImmutableContainerNodeBuilder.create() .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TestModel.TEST_QNAME)) - .withChild( - mapNodeBuilder(TestModel.OUTER_LIST_QNAME) - .withChild(FOO_NODE).build()).build(); + .withChild(mapNodeBuilder(TestModel.OUTER_LIST_QNAME).withChild(FOO_NODE).build()).build(); } private static ContainerNode createBarTestContainerNode() { - return ImmutableContainerNodeBuilder - .create() + return ImmutableContainerNodeBuilder.create() .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TestModel.TEST_QNAME)) - .withChild( - mapNodeBuilder(TestModel.OUTER_LIST_QNAME) - .withChild(BAR_NODE).build()).build(); + .withChild(mapNodeBuilder(TestModel.OUTER_LIST_QNAME).withChild(BAR_NODE).build()).build(); } @Before @@ -89,14 +84,15 @@ public class Retest_ConfigStatementValidationTest { assertNotNull("Schema context must not be null.", schemaContext); } - @Test(expected=SchemaValidationFailedException.class) + @Test(expected = SchemaValidationFailedException.class) public void testOnPathFail() throws DataValidationFailedException { - final InMemoryDataTree inMemoryDataTree = - (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION); + final InMemoryDataTree inMemoryDataTree = (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create( + TreeType.CONFIGURATION); inMemoryDataTree.setSchemaContext(schemaContext); final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification(); - final YangInstanceIdentifier ii = OUTER_LIST_1_PATH.node(new YangInstanceIdentifier.NodeIdentifier(TestModel.INNER_LIST_QNAME)) - .node(INNER_FOO_ENTRY_NODE.getIdentifier()); + final YangInstanceIdentifier ii = OUTER_LIST_1_PATH.node( + new YangInstanceIdentifier.NodeIdentifier(TestModel.INNER_LIST_QNAME)).node( + INNER_FOO_ENTRY_NODE.getIdentifier()); modificationTree.write(ii, INNER_FOO_ENTRY_NODE); inMemoryDataTree.validate(modificationTree); @@ -104,10 +100,10 @@ public class Retest_ConfigStatementValidationTest { inMemoryDataTree.commit(prepare); } - @Test(expected=SchemaValidationFailedException.class) + @Test(expected = SchemaValidationFailedException.class) public void testOnDataFail() throws DataValidationFailedException { - final InMemoryDataTree inMemoryDataTree = - (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION); + final InMemoryDataTree inMemoryDataTree = (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create( + TreeType.CONFIGURATION); inMemoryDataTree.setSchemaContext(schemaContext); final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification(); modificationTree.write(TestModel.TEST_PATH, createFooTestContainerNode()); @@ -117,10 +113,10 @@ public class Retest_ConfigStatementValidationTest { inMemoryDataTree.commit(prepare); } - @Test(expected=SchemaValidationFailedException.class) + @Test(expected = SchemaValidationFailedException.class) public void testOnDataLeafFail() throws DataValidationFailedException { - final InMemoryDataTree inMemoryDataTree = - (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION); + final InMemoryDataTree inMemoryDataTree = (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create( + TreeType.CONFIGURATION); inMemoryDataTree.setSchemaContext(schemaContext); final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification(); modificationTree.write(TestModel.TEST_PATH, createBarTestContainerNode()); @@ -130,13 +126,13 @@ public class Retest_ConfigStatementValidationTest { inMemoryDataTree.commit(prepare); } - @Test(expected=SchemaValidationFailedException.class) + @Test(expected = SchemaValidationFailedException.class) public void testOnPathCaseLeafFail() throws DataValidationFailedException { - final InMemoryDataTree inMemoryDataTree = - (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION); + final InMemoryDataTree inMemoryDataTree = (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create( + TreeType.CONFIGURATION); inMemoryDataTree.setSchemaContext(schemaContext); - final YangInstanceIdentifier.NodeIdentifier choice1Id = new YangInstanceIdentifier.NodeIdentifier( - QName.create(TestModel.TEST_QNAME, "choice1")); + final YangInstanceIdentifier.NodeIdentifier choice1Id = new YangInstanceIdentifier.NodeIdentifier(QName.create( + TestModel.TEST_QNAME, "choice1")); final YangInstanceIdentifier.NodeIdentifier case2ContId = new YangInstanceIdentifier.NodeIdentifier( QName.create(TestModel.TEST_QNAME, "case2-cont")); final YangInstanceIdentifier ii = TestModel.TEST_PATH.node(choice1Id).node(case2ContId); @@ -151,13 +147,13 @@ public class Retest_ConfigStatementValidationTest { inMemoryDataTree.commit(prepare); } - @Test(expected=SchemaValidationFailedException.class) + @Test(expected = VerifyException.class) public void testOnDataCaseLeafFail() throws DataValidationFailedException { - final InMemoryDataTree inMemoryDataTree = - (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION); + final InMemoryDataTree inMemoryDataTree = (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create( + TreeType.CONFIGURATION); inMemoryDataTree.setSchemaContext(schemaContext); - final YangInstanceIdentifier.NodeIdentifier choice1Id = new YangInstanceIdentifier.NodeIdentifier( - QName.create(TestModel.TEST_QNAME, "choice1")); + final YangInstanceIdentifier.NodeIdentifier choice1Id = new YangInstanceIdentifier.NodeIdentifier(QName.create( + TestModel.TEST_QNAME, "choice1")); final YangInstanceIdentifier ii = TestModel.TEST_PATH.node(choice1Id); final ChoiceNode choice1 = Builders.choiceBuilder().withNodeIdentifier(choice1Id) .withChild(leafNode(QName.create(TestModel.TEST_QNAME, "case1-leaf1"), "leaf-value")).build(); diff --git a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/TestModel.java b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/TestModel.java index b21dfc03f3..9dd298b14c 100644 --- a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/TestModel.java +++ b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/TestModel.java @@ -43,9 +43,14 @@ public final class TestModel { } public static SchemaContext createTestContext() { + return createTestContext(DATASTORE_TEST_YANG); + } + + public static SchemaContext createTestContext(String resourcePath) { YangParserImpl parser = new YangParserImpl(); try { - return parser.parseSources(Collections.singleton(Resources.asByteSource(TestModel.class.getResource(DATASTORE_TEST_YANG)))); + return parser.parseSources(Collections.singleton(Resources.asByteSource(TestModel.class + .getResource(resourcePath)))); } catch (IOException | YangSyntaxErrorException e) { throw new IllegalStateException("Failed to create context", e); } diff --git a/yang/yang-data-impl/src/test/resources/case-exclusion-test.yang b/yang/yang-data-impl/src/test/resources/case-exclusion-test.yang new file mode 100644 index 0000000000..e006ad2558 --- /dev/null +++ b/yang/yang-data-impl/src/test/resources/case-exclusion-test.yang @@ -0,0 +1,70 @@ +module case-exclusion-test { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test"; + prefix "store-test"; + + revision "2014-03-13" { + description "Initial revision."; + } + + container test { + presence true; + config true; + choice choice1 { + case case1 { + leaf case1-leaf1 { + type string; + } + } + case case2 { + container case2-cont { + leaf case2-leaf1 { + type string; + } + } + } + } + + list outer-list { + + key id; + leaf id { + type uint16; + } + choice outer-choice { + case one { + leaf one { + type string; + } + } + case two-three { + leaf two { + type string; + } + leaf three { + type string; + } + } + } + list inner-list { + key name; + leaf name { + type string; + } + leaf value { + type string; + } + } + + list inner-list2 { + key name; + leaf name { + type string; + } + leaf value { + type string; + } + } + } + } +}