diff options
author | Marek Gradzki <mgradzki@cisco.com> | 2017-01-17 13:30:50 +0100 |
---|---|---|
committer | Marek Gradzki <mgradzki@cisco.com> | 2017-01-17 14:11:13 +0100 |
commit | 78886acd688284585c2e219e18d7289f49cc8a45 (patch) | |
tree | 0d7b032f865312dbd35b475e800a887def4bdfc7 | |
parent | 487f6c742ba4b23d3b738b89dd2f7efb45b2693a (diff) |
HONEYCOMB-302: add support for nested augmentations
Change-Id: I60f1b3f79ddb578d6fca157fe5736de40b30623e
Signed-off-by: Marek Gradzki <mgradzki@cisco.com>
4 files changed, 440 insertions, 26 deletions
diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModificationDiff.java b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModificationDiff.java index 86666ba70..9903d99fc 100644 --- a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModificationDiff.java +++ b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModificationDiff.java @@ -24,6 +24,7 @@ import static org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationT import static org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType.WRITE; import com.google.common.collect.ImmutableMap; +import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; @@ -296,19 +297,23 @@ final class ModificationDiff { private final DataTreeCandidateNode dataCandidate; // Using Object as type for schema node since it's the only type that's a parent to all schema node types from // yangtools. The hierarchy does not use e.g. SchemaNode class for all types + private final Object parentNode; private final Object schemaNode; Modification(final YangInstanceIdentifier id, final DataTreeCandidateNode dataCandidate, + final Object parentNode, final Object schemaNode) { this.id = id; this.dataCandidate = dataCandidate; + this.parentNode = parentNode; this.schemaNode = schemaNode; } - Stream<Modification> streamChildren() { - return dataCandidate.getChildNodes().stream() - .map(child -> new Modification(id.node(child.getIdentifier()), child, schemaChild(schemaNode, child.getIdentifier()))); + Modification(final YangInstanceIdentifier id, + final DataTreeCandidateNode dataCandidate, + final Object schemaNode) { + this(id, dataCandidate, schemaNode, schemaNode); } List<Modification> getChildNodes() { @@ -355,35 +360,98 @@ final class ModificationDiff { return dataCandidate.getDataAfter().isPresent(); } + private AugmentationSchema findAugmentation(Object currentNode, + final YangInstanceIdentifier.AugmentationIdentifier identifier) { + if (currentNode != null) { + // check if identifier points to some augmentation of currentNode + if (currentNode instanceof AugmentationTarget) { + Optional<AugmentationSchema> augmentationSchema = + ((AugmentationTarget) currentNode).getAvailableAugmentations().stream() + .filter(aug -> identifier.equals(new YangInstanceIdentifier.AugmentationIdentifier( + aug.getChildNodes().stream() + .map(SchemaNode::getQName) + .collect(Collectors.toSet())))) + .findFirst(); + if (augmentationSchema.isPresent()) { + return augmentationSchema.get(); + } + } + + // continue search: + Collection<DataSchemaNode> childNodes = Collections.emptyList(); + if (currentNode instanceof DataNodeContainer) { + childNodes = ((DataNodeContainer) currentNode).getChildNodes(); + } else if (currentNode instanceof ChoiceSchemaNode) { + childNodes = ((ChoiceSchemaNode) currentNode).getCases().stream() + .flatMap(cas -> cas.getChildNodes().stream()).collect(Collectors.toList()); + } + return childNodes.stream().map(n -> findAugmentation(n, identifier)).filter(n -> n != null).findFirst() + .orElse(null); + } else { + return null; + } + } + + Stream<Modification> streamChildren() { + return dataCandidate.getChildNodes().stream() + .map(child -> { + final YangInstanceIdentifier childId = id.node(child.getIdentifier()); + final Object schemaChild = schemaChild(schemaNode, child.getIdentifier()); + // An augment cannot change other augment, so we do not update parent node if we are streaming + // children of AugmentationSchema (otherwise we would fail to find schema for nested augmentations): + final Object newParent = (schemaNode instanceof AugmentationSchema) + ? parentNode + : schemaNode; + return new Modification(childId, child, newParent, schemaChild); + }); + } + /** * Find next schema node in hierarchy. */ - private Object schemaChild(final Object schema, final YangInstanceIdentifier.PathArgument identifier) { + private Object schemaChild(final Object schemaNode, final YangInstanceIdentifier.PathArgument identifier) { Object found = null; if (identifier instanceof YangInstanceIdentifier.AugmentationIdentifier) { - if (schema instanceof AugmentationTarget) { + if (schemaNode instanceof AugmentationTarget) { // Find matching augmentation - found = ((AugmentationTarget) schema).getAvailableAugmentations().stream() - .filter(aug -> identifier.equals(new YangInstanceIdentifier.AugmentationIdentifier( - aug.getChildNodes().stream() - .map(SchemaNode::getQName) - .collect(Collectors.toSet())))) - .findFirst() - .orElse(null); + found = ((AugmentationTarget) schemaNode).getAvailableAugmentations().stream() + .filter(aug -> identifier.equals(new YangInstanceIdentifier.AugmentationIdentifier( + aug.getChildNodes().stream() + .map(SchemaNode::getQName) + .collect(Collectors.toSet())))) + .findFirst() + .orElse(null); + + if (found == null) { + // An augment cannot change other augment, but all augments only change their targets (data nodes). + // + // As a consequence, if nested augmentations are present, + // AugmentationSchema might reference child schema node instances that do not include changes + // from nested augments. + // + // But schemaNode, as mentioned earlier, contains all the changes introduced by augments. + // + // On the other hand, in case of augments which introduce leaves, + // we need to address AugmentationSchema node directly so we can't simply do + // found = schemaNode; + // + found = + findAugmentation(parentNode, (YangInstanceIdentifier.AugmentationIdentifier) identifier); + } } - } else if (schema instanceof DataNodeContainer) { + } else if (schemaNode instanceof DataNodeContainer) { // Special handling for list aggregator nodes. If we are at list aggregator node e.g. MapNode and // we are searching for schema for a list entry e.g. MapEntryNode just return the same schema - if (schema instanceof ListSchemaNode && - ((SchemaNode) schema).getQName().equals(identifier.getNodeType())) { - found = schema; + if (schemaNode instanceof ListSchemaNode && + ((SchemaNode) schemaNode).getQName().equals(identifier.getNodeType())) { + found = schemaNode; } else { - found = ((DataNodeContainer) schema).getDataChildByName(identifier.getNodeType()); + found = ((DataNodeContainer) schemaNode).getDataChildByName(identifier.getNodeType()); } - } else if (schema instanceof ChoiceSchemaNode) { + } else if (schemaNode instanceof ChoiceSchemaNode) { // For choices, iterate through all the cases - final Optional<DataSchemaNode> maybeChild = ((ChoiceSchemaNode) schema).getCases().stream() + final Optional<DataSchemaNode> maybeChild = ((ChoiceSchemaNode) schemaNode).getCases().stream() .flatMap(cas -> cas.getChildNodes().stream()) .filter(child -> child.getQName().equals(identifier.getNodeType())) .findFirst(); @@ -391,12 +459,12 @@ final class ModificationDiff { found = maybeChild.get(); } // Special handling for leaf-list nodes. Basically the same as is for list mixin nodes - } else if (schema instanceof LeafListSchemaNode && - ((SchemaNode) schema).getQName().equals(identifier.getNodeType())) { - found = schema; + } else if (schemaNode instanceof LeafListSchemaNode && + ((SchemaNode) schemaNode).getQName().equals(identifier.getNodeType())) { + found = schemaNode; } - return checkNotNull(found, "Unable to find child node in: %s identifiable by: %s", schema, identifier); + return checkNotNull(found, "Unable to find child node in: %s identifiable by: %s", schemaNode, identifier); } @Override diff --git a/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/AbstractInfraTest.java b/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/AbstractInfraTest.java index 3c996f6a6..e2a74ab69 100644 --- a/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/AbstractInfraTest.java +++ b/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/AbstractInfraTest.java @@ -21,14 +21,13 @@ import static org.mockito.Mockito.when; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import com.google.common.util.concurrent.Futures; -import java.util.Collections; +import java.util.Arrays; import java.util.Map; import javassist.ClassPool; import org.junit.Before; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.$YangModuleInfoImpl; import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer; import org.opendaylight.yangtools.binding.data.codec.gen.impl.DataObjectSerializerGenerator; import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator; @@ -70,7 +69,11 @@ abstract class AbstractInfraTest { static ModuleInfoBackedContext getSchemaContext() { final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create(); - moduleInfoBackedContext.addModuleInfos(Collections.singleton($YangModuleInfoImpl.getInstance())); + moduleInfoBackedContext.addModuleInfos(Arrays.asList( + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.$YangModuleInfoImpl.getInstance(), + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.$YangModuleInfoImpl.getInstance() + + )); return moduleInfoBackedContext; } diff --git a/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/NestedAugmentationWriteTest.java b/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/NestedAugmentationWriteTest.java new file mode 100644 index 000000000..ef7430dd3 --- /dev/null +++ b/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/NestedAugmentationWriteTest.java @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.data.impl; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import io.fd.honeycomb.data.DataModification; +import io.fd.honeycomb.translate.impl.write.registry.FlatWriterRegistryBuilder; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.Writer; +import io.fd.honeycomb.translate.write.registry.WriterRegistry; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.AugTarget; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.AugTargetBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.FromAugment2Augment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.FromAugment2AugmentBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.FromAugmentAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.FromAugmentAugmentBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.FromAugmentListAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.FromAugmentListAugmentBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.SimpleAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.SimpleAugmentBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.SimpleNestedAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.SimpleNestedAugmentBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.aug.target.FromAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.aug.target.FromAugmentBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.aug.target.from.augment.FromAugment2; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.aug.target.from.augment.FromAugment2Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.aug.target.from.augment.FromAugmentEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.aug.target.from.augment.FromAugmentEntryBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.aug.target.from.augment.FromAugmentEntryKey; +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; +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.tree.TipProducingDataTree; +import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType; +import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory; + +/** + * Testing write for model with nested augmentation. + * See <a href="https://jira.fd.io/browse/HONEYCOMB-302">HONEYCOMB-302</a>} for more details. + */ +public class NestedAugmentationWriteTest extends AbstractInfraTest { + + private static final InstanceIdentifier<AugTarget> AUG_TARGET_ID = InstanceIdentifier.create(AugTarget.class); + private static final InstanceIdentifier<FromAugmentAugment> FROM_AUGMENT_AUGMENT_ID = + AUG_TARGET_ID.augmentation(FromAugmentAugment.class); + private static final InstanceIdentifier<FromAugment> FROM_AUGMENT_ID = + FROM_AUGMENT_AUGMENT_ID.child(FromAugment.class); + private static final InstanceIdentifier<SimpleAugment> SIMPLE_AUGMENT_ID = + AUG_TARGET_ID.augmentation(SimpleAugment.class); + private static final InstanceIdentifier<FromAugment2Augment> FROM_AUGMENT2_AUGMENT_ID = + FROM_AUGMENT_ID.augmentation(FromAugment2Augment.class); + private static final InstanceIdentifier<FromAugment2> FROM_AUGMENT2_ID = + FROM_AUGMENT2_AUGMENT_ID.child(FromAugment2.class); + private static final InstanceIdentifier<SimpleNestedAugment> SIMPLE_NESTED_AUGMENT_ID = + FROM_AUGMENT_ID.augmentation(SimpleNestedAugment.class); + private static final InstanceIdentifier<FromAugmentListAugment> FROM_AUGMENT_LIST_AUGMENT_ID = + FROM_AUGMENT_ID.augmentation(FromAugmentListAugment.class); + private static final InstanceIdentifier<FromAugmentEntry> FROM_AUGMENT_ENTRY_ID = + FROM_AUGMENT_LIST_AUGMENT_ID.child(FromAugmentEntry.class); + + private TipProducingDataTree dataTree; + private WriterRegistry writerRegistry; + + private final Writer<AugTarget> augTargetWriter = mockWriter(AUG_TARGET_ID); + private final Writer<FromAugment> fromAugmentWriter = mockWriter(FROM_AUGMENT_ID); + private final Writer<FromAugment2> fromAugment2Writer = mockWriter(FROM_AUGMENT2_ID); + private final Writer<FromAugmentEntry> fromAugmentListWriter = mockWriter(FROM_AUGMENT_ENTRY_ID); + + private final Writer<SimpleAugment> simpleAugmentWriter = mockWriter(SIMPLE_AUGMENT_ID); + private final Writer<SimpleNestedAugment> simpleNestedAugmentWriter = mockWriter(SIMPLE_NESTED_AUGMENT_ID); + + private static <D extends DataObject> Writer<D> mockWriter(final InstanceIdentifier<D> id) { + final Writer<D> mock = (Writer<D>) mock(Writer.class); + when(mock.getManagedDataObjectType()).thenReturn(id); + return mock; + } + + @Override + void postSetup() { + initDataTree(); + initWriterRegistry(); + } + + private void initDataTree() { + dataTree = InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION); + dataTree.setSchemaContext(schemaContext); + } + + private void initWriterRegistry() { + writerRegistry = new FlatWriterRegistryBuilder() + .add(augTargetWriter) + .add(fromAugmentWriter) + .add(simpleAugmentWriter) + .add(fromAugment2Writer) + .add(simpleNestedAugmentWriter) + .add(fromAugmentListWriter) + .build(); + } + + @Test + public void testSimpleAugmentationWrite() throws Exception { + final ModifiableDataTreeDelegator modifiableDataTreeDelegator = + new ModifiableDataTreeDelegator(serializer, dataTree, schemaContext, writerRegistry, contextBroker); + + final DataModification dataModification = modifiableDataTreeDelegator.newModification(); + final AugTarget data = new AugTargetBuilder() + .setSomeLeaf("aug-target-leaf-val") + .addAugmentation(SimpleAugment.class, simpleAugment()) + .build(); + + final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalizedNode = + serializer.toNormalizedNode(AUG_TARGET_ID, data); + dataModification.write(normalizedNode.getKey(), normalizedNode.getValue()); + + dataModification.commit(); + + verify(simpleAugmentWriter).update(eq(SIMPLE_AUGMENT_ID), eq(null), eq(simpleAugment()), any(WriteContext.class)); + } + + @Test + public void testSimpleNestedAugmentationWrite() throws Exception { + final ModifiableDataTreeDelegator modifiableDataTreeDelegator = + new ModifiableDataTreeDelegator(serializer, dataTree, schemaContext, writerRegistry, contextBroker); + + final DataModification dataModification = modifiableDataTreeDelegator.newModification(); + + final SimpleNestedAugment augData = simpleNestedAugment(); + final AugTarget data = augTarget(fromAugmentSimple(augData)); + + final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalizedNode = + serializer.toNormalizedNode(AUG_TARGET_ID, data); + dataModification.write(normalizedNode.getKey(), normalizedNode.getValue()); + + dataModification.commit(); + + verify(augTargetWriter).update(eq(AUG_TARGET_ID), eq(null), eq(data), any(WriteContext.class)); + verify(fromAugmentWriter).update(eq(FROM_AUGMENT_ID), eq(null), eq(fromAugmentSimple(augData)), any(WriteContext.class)); + verify(simpleNestedAugmentWriter).update(eq(SIMPLE_NESTED_AUGMENT_ID), eq(null), eq(augData), any(WriteContext.class)); + } + + private SimpleAugment simpleAugment() { + return new SimpleAugmentBuilder().setSimpleAugmentLeaf("val").build(); + } + + @Test + public void testNestedAugmentationWrite() throws Exception { + final ModifiableDataTreeDelegator modifiableDataTreeDelegator = + new ModifiableDataTreeDelegator(serializer, dataTree, schemaContext, writerRegistry, contextBroker); + + final DataModification dataModification = modifiableDataTreeDelegator.newModification(); + final AugTarget data = augTarget(fromAugment(FromAugment2Augment.class, fromAugment2Augment(fromAugment2()))); + + final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalizedNode = + serializer.toNormalizedNode(AUG_TARGET_ID, data); + dataModification.write(normalizedNode.getKey(), normalizedNode.getValue()); + + dataModification.commit(); + + verify(augTargetWriter).update(eq(AUG_TARGET_ID), eq(null), eq(data), any(WriteContext.class)); + verify(fromAugmentWriter).update(eq(FROM_AUGMENT_ID), eq(null), eq(fromAugment()), any(WriteContext.class)); + verify(fromAugment2Writer).update(eq(FROM_AUGMENT2_ID), eq(null), eq(fromAugment2()), any(WriteContext.class)); + } + + @Test + public void testNestedAugmentationListWrite() throws Exception { + final ModifiableDataTreeDelegator modifiableDataTreeDelegator = + new ModifiableDataTreeDelegator(serializer, dataTree, schemaContext, writerRegistry, contextBroker); + + final DataModification dataModification = modifiableDataTreeDelegator.newModification(); + final List<FromAugmentEntry> entries = Arrays.asList( + new FromAugmentEntryBuilder().setSomeLeaf("1").build(), + new FromAugmentEntryBuilder().setSomeLeaf("2").build() + ); + final FromAugment fromAugment = fromAugment(FromAugmentListAugment.class, fromAugmentList(entries)); + final AugTarget data = augTarget(fromAugment); + + final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalizedNode = + serializer.toNormalizedNode(AUG_TARGET_ID, data); + dataModification.write(normalizedNode.getKey(), normalizedNode.getValue()); + dataModification.commit(); + + final ArgumentCaptor<DataObject> doCaptor = ArgumentCaptor.forClass(DataObject.class); + verify(augTargetWriter).update(eq(AUG_TARGET_ID), eq(null), doCaptor.capture(), any(WriteContext.class)); + assertEquals(data.getSomeLeaf(), ((AugTarget)doCaptor.getValue()).getSomeLeaf()); + + verify(fromAugmentWriter).update(eq(FROM_AUGMENT_ID), eq(null), doCaptor.capture(), any(WriteContext.class)); + assertEquals(fromAugment.getSomeLeaf(), ((FromAugment)doCaptor.getValue()).getSomeLeaf()); + + + final KeyedInstanceIdentifier<FromAugmentEntry, FromAugmentEntryKey> keyedNestedList1 = + FROM_AUGMENT_LIST_AUGMENT_ID.child(FromAugmentEntry.class, new FromAugmentEntryKey("1")); + final KeyedInstanceIdentifier<FromAugmentEntry, FromAugmentEntryKey> keyedNestedList2 = + FROM_AUGMENT_LIST_AUGMENT_ID.child(FromAugmentEntry.class, new FromAugmentEntryKey("2")); + + verify(fromAugmentListWriter) + .update(eq(keyedNestedList1), eq(null), eq(entries.get(0)), any(WriteContext.class)); + verify(fromAugmentListWriter) + .update(eq(keyedNestedList2), eq(null), eq(entries.get(1)), any(WriteContext.class)); + } + + private AugTarget augTarget(FromAugment fromAugment) { + return new AugTargetBuilder() + .setSomeLeaf("aug-target-leaf-val") + .addAugmentation(FromAugmentAugment.class, + new FromAugmentAugmentBuilder().setFromAugment(fromAugment).build()) + .build(); + } + + private FromAugment fromAugment() { + return new FromAugmentBuilder() + .setSomeLeaf("from-augment-leaf-val") + .addAugmentation(FromAugment2Augment.class, new FromAugment2AugmentBuilder() + .setFromAugment2(fromAugment2()).build()) + .build(); + } + + private FromAugment fromAugmentSimple(SimpleNestedAugment simpleNestedAugment) { + return new FromAugmentBuilder() + .setSomeLeaf("from-augment-leaf-val") + .addAugmentation(SimpleNestedAugment.class, simpleNestedAugment) + .build(); + } + + private SimpleNestedAugment simpleNestedAugment() { + return new SimpleNestedAugmentBuilder() + .setSimpleNestedAugmentLeaf("simple-nested-augment-leaf-val").build(); + } + + private FromAugment fromAugment(final Class<? extends Augmentation<FromAugment>> augmentationClass, + final Augmentation<FromAugment> augmentation) { + return new FromAugmentBuilder() + .setSomeLeaf("from-augment-leaf-val") + .addAugmentation(augmentationClass, augmentation) + .build(); + } + + private FromAugment2Augment fromAugment2Augment(FromAugment2 fromAugment2) { + return new FromAugment2AugmentBuilder().setFromAugment2(fromAugment2).build(); + } + + private FromAugment2 fromAugment2() { + return new FromAugment2Builder() + .setNewLeaf("new-leaf-val") + .build(); + } + + private FromAugmentListAugment fromAugmentList(final List<FromAugmentEntry> entries) { + return new FromAugmentListAugmentBuilder() + .setFromAugmentEntry(entries) + .build(); + } +} diff --git a/infra/it/test-model/src/main/yang/hc-aug-test.yang b/infra/it/test-model/src/main/yang/hc-aug-test.yang new file mode 100644 index 000000000..8a83ab56f --- /dev/null +++ b/infra/it/test-model/src/main/yang/hc-aug-test.yang @@ -0,0 +1,63 @@ +module hc-aug-test { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:hc:aug:test"; + prefix "hcat"; + + revision "2017-01--9" { + description "Test model for aumentations of augmentations (https://jira.fd.io/browse/HONEYCOMB-302)"; + } + + import yang-ext { + prefix "ext"; + } + + container aug-target { + leaf some-leaf { + type string; + } + } + + augment "/aug-target" { + ext:augment-identifier "from-augment-augment"; + container from-augment { + leaf some-leaf { + type string; + } + } + } + + augment "/aug-target" { + ext:augment-identifier "simple-augment"; + leaf simple-augment-leaf { + type string; + } + } + + augment "/aug-target/from-augment" { + ext:augment-identifier "simple-nested-augment"; + leaf simple-nested-augment-leaf { + type string; + } + } + + augment "/aug-target/from-augment" { + ext:augment-identifier "from-augment2-augment"; + container from-augment-2 { + leaf new-leaf { + type string; + } + } + } + + augment "/aug-target/from-augment" { + ext:augment-identifier "from-augment-list-augment"; + list from-augment-entry { + key some-leaf; + + leaf some-leaf { + type string; + } + } + } + +} |