From 63345b3a904073754de966a3b56037ba08af7622 Mon Sep 17 00:00:00 2001 From: Marek Gradzki Date: Tue, 14 Aug 2018 10:05:37 +0200 Subject: [PATCH] Consider AugmentationNodes when direct descendant is not found With previous refactors it is quite easy to arrive at a simple solution to take augmentations into account. This also This includes a unit test from upstream based on afi-safi-name with bgp-openconfig-extensions. JIRA: YANGTOOLS-892 Change-Id: I237ed2c6cbed458a2109a48b468a30650f103a48 Signed-off-by: Marek Gradzki Signed-off-by: Robert Varga (cherry picked from commit e4777b6feff804cdcf633c28d4b654b0e885dbd1) --- .../yang/data/codec/xml/Yangtools892Test.java | 89 ++++++++++++++ .../yangtools892/bgp-test-extensions.yang | 27 +++++ .../test/resources/yangtools892/neighbour.xml | 38 ++++++ .../resources/yangtools892/peer-groups.xml | 7 ++ .../yangtools892/test-bgp-multiprotocol.yang | 33 ++++++ .../yangtools892/test-bgp-types.yang | 23 ++++ .../test/resources/yangtools892/test-bgp.yang | 111 ++++++++++++++++++ .../yangtools892/test-network-instance.yang | 70 +++++++++++ .../yangtools892/test-policy-types.yang | 14 +++ .../data/impl/leafref/LeafRefValidation.java | 10 +- 10 files changed, 419 insertions(+), 3 deletions(-) create mode 100644 yang/yang-data-codec-xml/src/test/java/org/opendaylight/yangtools/yang/data/codec/xml/Yangtools892Test.java create mode 100644 yang/yang-data-codec-xml/src/test/resources/yangtools892/bgp-test-extensions.yang create mode 100644 yang/yang-data-codec-xml/src/test/resources/yangtools892/neighbour.xml create mode 100644 yang/yang-data-codec-xml/src/test/resources/yangtools892/peer-groups.xml create mode 100644 yang/yang-data-codec-xml/src/test/resources/yangtools892/test-bgp-multiprotocol.yang create mode 100644 yang/yang-data-codec-xml/src/test/resources/yangtools892/test-bgp-types.yang create mode 100644 yang/yang-data-codec-xml/src/test/resources/yangtools892/test-bgp.yang create mode 100644 yang/yang-data-codec-xml/src/test/resources/yangtools892/test-network-instance.yang create mode 100644 yang/yang-data-codec-xml/src/test/resources/yangtools892/test-policy-types.yang diff --git a/yang/yang-data-codec-xml/src/test/java/org/opendaylight/yangtools/yang/data/codec/xml/Yangtools892Test.java b/yang/yang-data-codec-xml/src/test/java/org/opendaylight/yangtools/yang/data/codec/xml/Yangtools892Test.java new file mode 100644 index 0000000000..e564b41a09 --- /dev/null +++ b/yang/yang-data-codec-xml/src/test/java/org/opendaylight/yangtools/yang/data/codec/xml/Yangtools892Test.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2018 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.codec.xml; + +import java.io.InputStream; +import javax.xml.stream.XMLStreamReader; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.yangtools.util.xml.UntrustedXML; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.Revision; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeConfiguration; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; +import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefContext; +import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefValidation; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter; +import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult; +import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory; +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils; + +public class Yangtools892Test { + private static final String TEST_BGP_NAME = "test-bgp"; + private static final String TEST_BGP_NS = "urn:opendaylight:params:xml:ns:yang:test:bgp"; + private static final String TEST_BGP_REV = "2018-08-14"; + private static final QName BGP = QName.create(TEST_BGP_NS, TEST_BGP_REV, "bgp"); + private static final YangInstanceIdentifier BGP_ID = YangInstanceIdentifier.of(BGP); + + private static final String NETWORK_INSTANCE_NAME = "test-network-instance"; + private static final String NETWORK_INSTANCE_NS = "urn:opendaylight:params:xml:ns:yang:test:network:instance"; + private static final String NETWORK_INSTANCE_REV = "2018-08-14"; + private static final QName NETWORK_INSTANCES = + QName.create(NETWORK_INSTANCE_NS, NETWORK_INSTANCE_REV, "network-instances"); + private static final YangInstanceIdentifier NETWORK_INSTANCES_ID = YangInstanceIdentifier.of(NETWORK_INSTANCES); + + private SchemaContext schemaContext; + private LeafRefContext leafRefContext; + private DataTree dataTree; + private ContainerSchemaNode bgpNode; + private ContainerSchemaNode networkInstancesNode; + + @Before + public void setup() { + schemaContext = YangParserTestUtils.parseYangResourceDirectory("/yangtools892"); + leafRefContext = LeafRefContext.create(schemaContext); + dataTree = new InMemoryDataTreeFactory().create(DataTreeConfiguration.DEFAULT_CONFIGURATION, schemaContext); + final Module testBgpModule = schemaContext.findModule(TEST_BGP_NAME, Revision.of(TEST_BGP_REV)).get(); + bgpNode = (ContainerSchemaNode) testBgpModule.findDataChildByName(BGP).get(); + final Module networkInstanceModule = + schemaContext.findModule(NETWORK_INSTANCE_NAME, Revision.of(NETWORK_INSTANCE_REV)).get(); + networkInstancesNode = (ContainerSchemaNode) networkInstanceModule.findDataChildByName(NETWORK_INSTANCES).get(); + } + + @Test + public void testWriteBgpNeighbour() throws Exception { + final DataTreeModification writeModification = dataTree.takeSnapshot().newModification(); + final NormalizedNode bgp = readNode("/yangtools892/peer-groups.xml", bgpNode); + writeModification.write(BGP_ID, bgp); + final NormalizedNode networkInstances = readNode("/yangtools892/neighbour.xml", networkInstancesNode); + writeModification.write(NETWORK_INSTANCES_ID, networkInstances); + + writeModification.ready(); + final DataTreeCandidate writeContributorsCandidate = dataTree.prepare(writeModification); + LeafRefValidation.validate(writeContributorsCandidate, leafRefContext); + dataTree.commit(writeContributorsCandidate); + } + + private NormalizedNode readNode(final String filename, final ContainerSchemaNode node) throws Exception { + final InputStream resourceAsStream = Yangtools891Test.class.getResourceAsStream(filename); + final XMLStreamReader reader = UntrustedXML.createXMLStreamReader(resourceAsStream); + final NormalizedNodeResult result = new NormalizedNodeResult(); + final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result); + final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, node); + xmlParser.parse(reader); + return result.getResult(); + } +} \ No newline at end of file diff --git a/yang/yang-data-codec-xml/src/test/resources/yangtools892/bgp-test-extensions.yang b/yang/yang-data-codec-xml/src/test/resources/yangtools892/bgp-test-extensions.yang new file mode 100644 index 0000000000..42415d90f8 --- /dev/null +++ b/yang/yang-data-codec-xml/src/test/resources/yangtools892/bgp-test-extensions.yang @@ -0,0 +1,27 @@ +module bgp-test-extensions { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:bgp:test:extensions"; + prefix "odl-oc-ext"; + + import test-bgp-types { prefix bgp-types; } + import test-network-instance { prefix netinst; } + import test-bgp { prefix test-bgp; } + + revision 2018-08-14; + + augment /netinst:network-instances/netinst:network-instance/netinst:protocols/netinst:protocol { + uses test-bgp:bgp-top { + augment bgp/neighbors/neighbor/afi-safis/afi-safi { + uses test-bgp:bgp-neighbor-add-paths_config; + } + + augment bgp/neighbors/neighbor/config { + description + "Augmentation to allow association of a neighbor with a + peer-group"; + uses test-bgp:bgp-neighbor-peer-group_config; + } + } + } + +} diff --git a/yang/yang-data-codec-xml/src/test/resources/yangtools892/neighbour.xml b/yang/yang-data-codec-xml/src/test/resources/yangtools892/neighbour.xml new file mode 100644 index 0000000000..690c41d6fc --- /dev/null +++ b/yang/yang-data-codec-xml/src/test/resources/yangtools892/neighbour.xml @@ -0,0 +1,38 @@ + + + global-bgp + + global-bgp + + + + x:BGP + test-bgp-instance + + test-bgp-instance + x:BGP + + + + + 10.25.1.9 + + application-peers + + + + x:IPV4-UNICAST + + x:IPV4-UNICAST + + true + 0 + + + + + + + + + \ No newline at end of file diff --git a/yang/yang-data-codec-xml/src/test/resources/yangtools892/peer-groups.xml b/yang/yang-data-codec-xml/src/test/resources/yangtools892/peer-groups.xml new file mode 100644 index 0000000000..07c4e55ec6 --- /dev/null +++ b/yang/yang-data-codec-xml/src/test/resources/yangtools892/peer-groups.xml @@ -0,0 +1,7 @@ + + + + application-peers + + + \ No newline at end of file diff --git a/yang/yang-data-codec-xml/src/test/resources/yangtools892/test-bgp-multiprotocol.yang b/yang/yang-data-codec-xml/src/test/resources/yangtools892/test-bgp-multiprotocol.yang new file mode 100644 index 0000000000..41a2749287 --- /dev/null +++ b/yang/yang-data-codec-xml/src/test/resources/yangtools892/test-bgp-multiprotocol.yang @@ -0,0 +1,33 @@ +module test-bgp-multiprotocol { + yang-version "1"; + namespace "urn:opendaylight:params:xml:ns:yang:test:bgp:multiprotocol"; + prefix "bgp-mp"; + + import test-bgp-types { prefix bgp-types; } + + revision "2018-08-14"; + + grouping bgp-afi-safi_config { + leaf afi-safi-name { + type identityref { + base bgp-types:afi-safi-type; + } + } + } + + grouping bgp-common-afi-safi-list { + list afi-safi { + key "afi-safi-name"; + + leaf afi-safi-name { + type leafref { + path "../config/afi-safi-name"; + } + } + + container config { + uses bgp-afi-safi_config; + } + } + } +} diff --git a/yang/yang-data-codec-xml/src/test/resources/yangtools892/test-bgp-types.yang b/yang/yang-data-codec-xml/src/test/resources/yangtools892/test-bgp-types.yang new file mode 100644 index 0000000000..ae06008334 --- /dev/null +++ b/yang/yang-data-codec-xml/src/test/resources/yangtools892/test-bgp-types.yang @@ -0,0 +1,23 @@ +module test-bgp-types { + yang-version "1"; + namespace "urn:opendaylight:params:xml:ns:yang:test:bgp:types"; + prefix "bgp-types"; + + revision "2018-08-14"; + + typedef peer-type { + type enumeration { + enum INTERNAL { + } + enum EXTERNAL { + } + } + } + + identity afi-safi-type { + } + + identity IPV4-UNICAST { + base afi-safi-type; + } +} diff --git a/yang/yang-data-codec-xml/src/test/resources/yangtools892/test-bgp.yang b/yang/yang-data-codec-xml/src/test/resources/yangtools892/test-bgp.yang new file mode 100644 index 0000000000..af9f5d15cf --- /dev/null +++ b/yang/yang-data-codec-xml/src/test/resources/yangtools892/test-bgp.yang @@ -0,0 +1,111 @@ +module test-bgp { + yang-version "1"; + namespace "urn:opendaylight:params:xml:ns:yang:test:bgp"; + prefix "bgp"; + + import test-bgp-multiprotocol { prefix bgp-mp; } + import test-bgp-types { prefix bgp-types; } + + revision "2018-08-14"; + + grouping bgp-neighbor_config { + leaf peer-type { + type bgp-types:peer-type; + } + } + + grouping bgp-neighbor-add-paths_config { + leaf receive { + type boolean; + default false; + } + + leaf send-max { + type uint8; + } + } + + grouping bgp-neighbor-peer-group_config { + leaf peer-group { + type leafref { + path "/bgp/peer-groups/peer-group/peer-group-name"; + } + } + } + + grouping bgp-neighbors { + list neighbor { + key "neighbor-address"; + + leaf neighbor-address { + type string; + } + + uses bgp-neighbor-group; + } + } + + grouping bgp-peer-group { + list peer-group { + key "peer-group-name"; + + leaf peer-group-name { + type string; + } + + uses bgp-neighbor-group; + + } + } + + grouping bgp-neighbor-group { + container config { + uses bgp-neighbor_config; + } + + container afi-safis { + uses bgp-mp:bgp-common-afi-safi-list; + } + } + + grouping bgp-neighbor-neighbor-address_config { + leaf neighbor-address { + type string; + } + } + + grouping bgp-peer-group-peer-group-name_config { + leaf peer-group-name { + type string; + } + } + + augment /bgp/neighbors/neighbor/config { + uses bgp-neighbor-peer-group_config; + } + + augment /bgp/neighbors/neighbor/config { + uses bgp-neighbor-neighbor-address_config; + } + + augment /bgp/peer-groups/peer-group/config { + uses bgp-peer-group-peer-group-name_config; + } + + grouping bgp-top { + container bgp { + presence "Container for BGP protocol hierarchy"; + + container neighbors { + uses bgp-neighbors; + } + + container peer-groups { + uses bgp-peer-group; + } + } + } + + uses bgp-top; +} + diff --git a/yang/yang-data-codec-xml/src/test/resources/yangtools892/test-network-instance.yang b/yang/yang-data-codec-xml/src/test/resources/yangtools892/test-network-instance.yang new file mode 100644 index 0000000000..70947c432b --- /dev/null +++ b/yang/yang-data-codec-xml/src/test/resources/yangtools892/test-network-instance.yang @@ -0,0 +1,70 @@ +module test-network-instance { + yang-version "1"; + namespace "urn:opendaylight:params:xml:ns:yang:test:network:instance"; + prefix netinst; + + import test-policy-types { prefix "pt"; } + + revision 2018-08-14; + + grouping network-instance-top { + container network-instances { + list network-instance { + key "name"; + + leaf name { + type leafref { + path "../config/name"; + } + } + + container config { + uses network-instance-config; + } + + container protocols { + list protocol { + key "identifier name"; + + leaf identifier { + type leafref { + path "../config/identifier"; + } + } + + leaf name { + type leafref { + path "../config/name"; + } + } + + container config { + uses protocols-config; + } + } + } + } + } + } + + grouping network-instance-config { + leaf name { + type string; + } + } + + grouping protocols-config { + leaf identifier { + type identityref { + base "pt:install-protocol-type"; + } + } + + leaf name { + type string; + } + } + + uses network-instance-top; +} + diff --git a/yang/yang-data-codec-xml/src/test/resources/yangtools892/test-policy-types.yang b/yang/yang-data-codec-xml/src/test/resources/yangtools892/test-policy-types.yang new file mode 100644 index 0000000000..6aff5b2b9e --- /dev/null +++ b/yang/yang-data-codec-xml/src/test/resources/yangtools892/test-policy-types.yang @@ -0,0 +1,14 @@ +module test-policy-types { + yang-version "1"; + namespace "urn:opendaylight:params:xml:ns:yang:test:policy:types"; + prefix "ptypes"; + + revision "2018-08-14"; + + identity install-protocol-type { + } + + identity BGP { + base install-protocol-type; + } +} diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefValidation.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefValidation.java index 5de4f032ba..bf1433203f 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefValidation.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefValidation.java @@ -390,9 +390,13 @@ public final class LeafRefValidation { final YangInstanceIdentifier current) { final Optional> child = parent.getChild(arg); if (!child.isPresent()) { - for (final DataContainerChild choice : parent.getValue()) { - if (choice instanceof ChoiceNode) { - addValues(values, choice, nodePredicates, path, current); + // FIXME: YANGTOOLS-901. We have SchemaContext nearby, hence we should be able to cache how to get + // to the leaf with with specified QName, without having to iterate through Choices/Augmentations. + // That perhaps means we should not have QNameWithPredicates, but NodeIdentifierWithPredicates as + // the path specification. + for (final DataContainerChild mixin : parent.getValue()) { + if (mixin instanceof AugmentationNode || mixin instanceof ChoiceNode) { + addValues(values, mixin, nodePredicates, path, current); } } } else { -- 2.36.6