diff options
author | 2017-11-03 13:33:53 +0100 | |
---|---|---|
committer | 2017-11-03 12:58:01 +0000 | |
commit | 9779f4b3ffe24bb2338630c66169da92c880ffbb (patch) | |
tree | fac37c53b70b7bbfcea00f180554b3a0dfddd59c /infra/translate-impl/src | |
parent | 054eb07de938df56000a8fc5cb41cb77f84bf2b5 (diff) |
HONEYCOMB-359 - Wildcarded writers
Adds option to specify subtree writer that can handle whole subtree
of nodes without having whole subtree specified. Its checking
if node is children at runtime, rather than having pre-computed tree
Change-Id: Ic46f2bd6de84f0dd14865825399f5a90a1f80859
Signed-off-by: Jan Srnicek <jsrnicek@cisco.com>
Diffstat (limited to 'infra/translate-impl/src')
6 files changed, 267 insertions, 54 deletions
diff --git a/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/read/registry/CompositeReaderRegistryBuilder.java b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/read/registry/CompositeReaderRegistryBuilder.java index f8290f166..4f7e1e140 100644 --- a/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/read/registry/CompositeReaderRegistryBuilder.java +++ b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/read/registry/CompositeReaderRegistryBuilder.java @@ -16,8 +16,6 @@ package io.fd.honeycomb.translate.impl.read.registry; -import static com.google.common.base.Preconditions.checkArgument; - import com.google.common.collect.ImmutableMap; import io.fd.honeycomb.translate.impl.read.GenericListReader; import io.fd.honeycomb.translate.impl.read.GenericReader; @@ -29,12 +27,6 @@ import io.fd.honeycomb.translate.read.registry.ReaderRegistry; import io.fd.honeycomb.translate.read.registry.ReaderRegistryBuilder; import io.fd.honeycomb.translate.util.AbstractSubtreeManagerRegistryBuilderBuilder; import io.fd.honeycomb.translate.util.YangDAG; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import javax.annotation.concurrent.NotThreadSafe; import org.opendaylight.yangtools.concepts.Builder; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.Identifiable; @@ -43,6 +35,15 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.Nonnull; +import javax.annotation.concurrent.NotThreadSafe; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkArgument; + @NotThreadSafe public final class CompositeReaderRegistryBuilder extends AbstractSubtreeManagerRegistryBuilderBuilder<Reader<? extends DataObject, ? extends Builder<?>>, ReaderRegistry> @@ -63,6 +64,11 @@ public final class CompositeReaderRegistryBuilder } @Override + protected Reader<? extends DataObject, ? extends Builder<?>> getWildcardedSubtreeHandler(@Nonnull Reader<? extends DataObject, ? extends Builder<?>> handler) { + throw new UnsupportedOperationException("Wildcarded readers are not supported"); + } + + @Override public <D extends DataObject> void addStructuralReader(@Nonnull InstanceIdentifier<D> id, @Nonnull Class<? extends Builder<D>> builderType) { // prevent case to submit structural reader for list, which would cause fail because target setter consumes diff --git a/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistry.java b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistry.java index 146ddb9c5..c3bc1ee0e 100644 --- a/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistry.java +++ b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistry.java @@ -21,7 +21,6 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.base.Optional; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; @@ -32,12 +31,15 @@ import io.fd.honeycomb.translate.write.WriteContext; import io.fd.honeycomb.translate.write.Writer; import io.fd.honeycomb.translate.write.registry.UpdateFailedException; import io.fd.honeycomb.translate.write.registry.WriterRegistry; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.concurrent.ThreadSafe; @@ -54,39 +56,23 @@ final class FlatWriterRegistry implements WriterRegistry { private static final Logger LOG = LoggerFactory.getLogger(FlatWriterRegistry.class); - // All types handled by writers directly or as children - private final ImmutableSet<InstanceIdentifier<?>> handledTypes; - private final Set<InstanceIdentifier<?>> writersOrderReversed; private final Set<InstanceIdentifier<?>> writersOrder; - private final Map<InstanceIdentifier<?>, Writer<?>> writers; + private final Map<InstanceIdentifier<?>, Writer<?>> writersById; + private final Set<? extends Writer<?>> writers; /** * Create flat registry instance. * - * @param writers immutable, ordered map of writers to use to process updates. Order of the writers has to be one in + * @param writersById immutable, ordered map of writers to use to process updates. Order of the writers has to be one in * which create and update operations should be handled. Deletes will be handled in reversed order. * All deletes are handled before handling all the updates. */ - FlatWriterRegistry(@Nonnull final ImmutableMap<InstanceIdentifier<?>, Writer<?>> writers) { - this.writers = writers; - this.writersOrderReversed = Sets.newLinkedHashSet(Lists.reverse(Lists.newArrayList(writers.keySet()))); - this.writersOrder = writers.keySet(); - this.handledTypes = getAllHandledTypes(writers); - } - - private static ImmutableSet<InstanceIdentifier<?>> getAllHandledTypes( - @Nonnull final ImmutableMap<InstanceIdentifier<?>, Writer<?>> writers) { - final ImmutableSet.Builder<InstanceIdentifier<?>> handledTypesBuilder = ImmutableSet.builder(); - for (Map.Entry<InstanceIdentifier<?>, Writer<?>> writerEntry : writers.entrySet()) { - final InstanceIdentifier<?> writerType = writerEntry.getKey(); - final Writer<?> writer = writerEntry.getValue(); - handledTypesBuilder.add(writerType); - if (writer instanceof SubtreeWriter) { - handledTypesBuilder.addAll(((SubtreeWriter<?>) writer).getHandledChildTypes()); - } - } - return handledTypesBuilder.build(); + FlatWriterRegistry(@Nonnull final ImmutableMap<InstanceIdentifier<?>, Writer<?>> writersById) { + this.writersById = writersById; + this.writersOrderReversed = Sets.newLinkedHashSet(Lists.reverse(Lists.newArrayList(writersById.keySet()))); + this.writersOrder = writersById.keySet(); + this.writers = writersById.entrySet().stream().map(Map.Entry::getValue).collect(Collectors.toSet()); } @Override @@ -145,9 +131,9 @@ final class FlatWriterRegistry implements WriterRegistry { if (writer == null) { // This node must be handled by a subtree writer, find it and call it or else fail - checkArgument(handledTypes.contains(singleType), "Unable to process update. Missing writers for: %s", - singleType); writer = getSubtreeWriterResponsible(singleType); + checkArgument(writer != null, "Unable to process update. Missing writers for: %s", + singleType); singleTypeUpdates = getParentDataObjectUpdate(ctx, updates, writer); } @@ -168,9 +154,9 @@ final class FlatWriterRegistry implements WriterRegistry { @Nullable private Writer<?> getSubtreeWriterResponsible(final InstanceIdentifier<?> singleType) { - return writers.values().stream() + return writersById.values().stream() .filter(w -> w instanceof SubtreeWriter) - .filter(w -> ((SubtreeWriter<?>) w).getHandledChildTypes().contains(singleType)) + .filter(w -> w.canProcess(singleType)) .findFirst() .orElse(null); } @@ -249,10 +235,23 @@ final class FlatWriterRegistry implements WriterRegistry { private void checkAllTypesCanBeHandled( @Nonnull final Multimap<InstanceIdentifier<?>, ? extends DataObjectUpdate> updates) { - if (!handledTypes.containsAll(updates.keySet())) { - final Sets.SetView<InstanceIdentifier<?>> missingWriters = Sets.difference(updates.keySet(), handledTypes); - LOG.warn("Unable to process update. Missing writers for: {}", missingWriters); - throw new IllegalArgumentException("Unable to process update. Missing writers for: " + missingWriters); + + List<InstanceIdentifier<?>> noWriterNodes = new ArrayList<>(); + for (InstanceIdentifier<?> id : updates.keySet()) { + // either there is direct writer for the iid + if (writersById.containsKey(id)) { + continue; + } else { + // or subtree one + if (writers.stream().anyMatch(o -> o.canProcess(id))) { + continue; + } + } + noWriterNodes.add(id); + } + + if (!noWriterNodes.isEmpty()) { + throw new IllegalArgumentException("Unable to process update. Missing writers for: " + noWriterNodes); } } @@ -269,7 +268,7 @@ final class FlatWriterRegistry implements WriterRegistry { @Nullable private Writer<?> getWriter(@Nonnull final InstanceIdentifier<?> singleType) { - return writers.get(singleType); + return writersById.get(singleType); } } diff --git a/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistryBuilder.java b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistryBuilder.java index 0c6d0a1b4..43606064e 100644 --- a/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistryBuilder.java +++ b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistryBuilder.java @@ -24,15 +24,16 @@ import io.fd.honeycomb.translate.write.Writer; import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder; import io.fd.honeycomb.translate.write.registry.WriterRegistry; import io.fd.honeycomb.translate.write.registry.WriterRegistryBuilder; -import java.util.Set; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import javax.annotation.concurrent.NotThreadSafe; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.Nonnull; +import javax.annotation.concurrent.NotThreadSafe; +import java.util.Set; +import java.util.stream.Collectors; + /** * Builder for {@link FlatWriterRegistry} allowing users to specify inter-writer relationships. */ @@ -53,6 +54,11 @@ public final class FlatWriterRegistryBuilder return SubtreeWriter.createForWriter(handledChildren, writer); } + @Override + protected Writer<? extends DataObject> getWildcardedSubtreeHandler(@Nonnull Writer<? extends DataObject> handler) { + return SubtreeWriter.createWildcardedForWriter(handler); + } + /** * Create FlatWriterRegistry with writers ordered according to submitted relationships. */ diff --git a/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/SubtreeWriter.java b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/SubtreeWriter.java index b2a571b40..a1a5f3fd0 100644 --- a/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/SubtreeWriter.java +++ b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/SubtreeWriter.java @@ -37,15 +37,16 @@ final class SubtreeWriter<D extends DataObject> implements Writer<D> { private final Writer<D> delegate; private final Set<InstanceIdentifier<?>> handledChildTypes = new HashSet<>(); + private boolean isWildcarded = false; - private SubtreeWriter(final Writer<D> delegate, Set<InstanceIdentifier<?>> handledTypes) { + private SubtreeWriter(final Writer<D> delegate, final Set<InstanceIdentifier<?>> handledTypes) { this.delegate = delegate; for (InstanceIdentifier<?> handledType : handledTypes) { // Iid has to start with writer's handled root type checkArgument(delegate.getManagedDataObjectType().getTargetType().equals( handledType.getPathArguments().iterator().next().getType()), "Handled node from subtree has to be identified by an instance identifier starting from: %s." - + "Instance identifier was: %s", getManagedDataObjectType().getTargetType(), handledType); + + "Instance identifier was: %s", getManagedDataObjectType().getTargetType(), handledType); checkArgument(Iterables.size(handledType.getPathArguments()) > 1, "Handled node from subtree identifier too short: %s", handledType); handledChildTypes.add(InstanceIdentifier.create(Iterables.concat( @@ -53,6 +54,11 @@ final class SubtreeWriter<D extends DataObject> implements Writer<D> { } } + private SubtreeWriter(final Writer<D> delegate) { + this.delegate = delegate; + this.isWildcarded = true; + } + /** * Return set of types also handled by this writer. All of the types are children of the type managed by this * writer excluding the type of this writer. @@ -75,6 +81,20 @@ final class SubtreeWriter<D extends DataObject> implements Writer<D> { } @Override + public boolean canProcess(@Nonnull InstanceIdentifier<?> instanceIdentifier) { + if (isWildcarded) { + final Class<D> parent = delegate.getManagedDataObjectType().getTargetType(); + for (InstanceIdentifier.PathArgument pathArgument : instanceIdentifier.getPathArguments()) { + if (pathArgument.getType().equals(parent)) { + return true; + } + } + return false; + } + return handledChildTypes.contains(instanceIdentifier); + } + + @Override @Nonnull public InstanceIdentifier<D> getManagedDataObjectType() { return delegate.getManagedDataObjectType(); @@ -87,4 +107,11 @@ final class SubtreeWriter<D extends DataObject> implements Writer<D> { @Nonnull final Writer<? extends DataObject> writer) { return new SubtreeWriter<>(writer, handledChildren); } + + /** + * Wrap a writer as a subtree writer. + */ + static Writer<?> createWildcardedForWriter(@Nonnull final Writer<? extends DataObject> writer) { + return new SubtreeWriter<>(writer); + } } diff --git a/infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistryTest.java b/infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistryTest.java index 151436975..01852d13f 100644 --- a/infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistryTest.java +++ b/infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistryTest.java @@ -25,6 +25,7 @@ import static org.mockito.Matchers.any; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; @@ -39,15 +40,19 @@ import io.fd.honeycomb.translate.util.DataObjects.DataObject1; import io.fd.honeycomb.translate.util.DataObjects.DataObject2; import io.fd.honeycomb.translate.write.DataObjectUpdate; import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; import io.fd.honeycomb.translate.write.Writer; import io.fd.honeycomb.translate.write.registry.UpdateFailedException; import io.fd.honeycomb.translate.write.registry.WriterRegistry; import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import org.junit.Before; import org.junit.Test; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.stubbing.Answer; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; @@ -72,6 +77,18 @@ public class FlatWriterRegistryTest { when(writer1.getManagedDataObjectType()).thenReturn(DataObject1.IID); when(writer2.getManagedDataObjectType()).thenReturn(DataObject2.IID); when(writer3.getManagedDataObjectType()).thenReturn(DataObjects.DataObject3.IID); + when(writer4.getManagedDataObjectType()).thenReturn(DataObjects.DataObject1ChildK.IID); + // TODO - HONEYCOMB-412 - thenCallRealMethod doest work with default methods + // https://stackoverflow.com/questions/27663252/can-you-make-mockito-1-10-17-work-with-default-methods-in-interfaces + when(writer1.canProcess(any())).thenAnswer(answerWithImpl()); + when(writer2.canProcess(any())).thenAnswer(answerWithImpl()); + when(writer3.canProcess(any())).thenAnswer(answerWithImpl()); + when(writer4.canProcess(any())).thenAnswer(answerWithImpl()); + } + + private static Answer<Object> answerWithImpl() { + return invocationOnMock -> new CheckedMockWriter(Writer.class.cast(invocationOnMock.getMock())).canProcess( + InstanceIdentifier.class.cast(invocationOnMock.getArguments()[0])); } @Test @@ -112,8 +129,12 @@ public class FlatWriterRegistryTest { inOrder.verify(writer1).processModification(iid, dataObject, dataObject, ctx); inOrder.verify(writer2).processModification(iid2, dataObject2, dataObject2, ctx); - verifyNoMoreInteractions(writer1); - verifyNoMoreInteractions(writer2); + // TODO - HONEYCOMB-412 -reintroduce verifyNoMoreInteractions and remove manual verify + // we are really interested just in invocations of processModification(),so adding specific verify to check that + verify(writer1,times(1)).processModification(any(),any(),any(),any()); + verify(writer2,times(1)).processModification(any(),any(),any(),any()); + //verifyNoMoreInteractions(writer1); + //verifyNoMoreInteractions(writer2); } @Test @@ -136,8 +157,12 @@ public class FlatWriterRegistryTest { inOrder.verify(writer2).processModification(iid2, dataObject2, null, ctx); inOrder.verify(writer1).processModification(iid, dataObject, null, ctx); - verifyNoMoreInteractions(writer1); - verifyNoMoreInteractions(writer2); + // TODO - HONEYCOMB-412 -reintroduce verifyNoMoreInteractions and remove manual verify + // we are really interested just in invocations of processModification(),so adding specific verify to check that + verify(writer1,times(1)).processModification(any(),any(),any(),any()); + verify(writer2,times(1)).processModification(any(),any(),any(),any()); + //verifyNoMoreInteractions(writer1); + //verifyNoMoreInteractions(writer2); } @Test @@ -170,8 +195,12 @@ public class FlatWriterRegistryTest { inOrder.verify(writer1).processModification(iid, dataObject, dataObject, ctx); inOrder.verify(writer2).processModification(iid2, dataObject2, dataObject2, ctx); - verifyNoMoreInteractions(writer1); - verifyNoMoreInteractions(writer2); + // TODO - HONEYCOMB-412 -reintroduce verifyNoMoreInteractions and remove manual verify + // we are really interested just in invocations of processModification(),so adding specific verify to check that + verify(writer1,times(2)).processModification(any(),any(),any(),any()); + verify(writer2,times(2)).processModification(any(),any(),any(),any()); + //verifyNoMoreInteractions(writer1); + //verifyNoMoreInteractions(writer2); } @Test(expected = IllegalArgumentException.class) @@ -298,4 +327,35 @@ public class FlatWriterRegistryTest { final InstanceIdentifier<D> iid) { return DataObjectUpdate.create(iid, mock(type), mock(type)); } + + //TODO - HONEYCOMB-412 - remove after + /** + * Used to utilize default implementation of canProcess() + * */ + static class CheckedMockWriter implements Writer{ + + private final Writer mockedWriter; + + CheckedMockWriter(final Writer mockedWriter) { + this.mockedWriter = mockedWriter; + } + + @Override + public void processModification(@Nonnull final InstanceIdentifier id, @Nullable final DataObject dataBefore, + @Nullable final DataObject dataAfter, @Nonnull final WriteContext ctx) + throws WriteFailedException { + mockedWriter.processModification(id,dataBefore,dataAfter,ctx); + } + + @Override + public boolean supportsDirectUpdate() { + return mockedWriter.supportsDirectUpdate(); + } + + @Nonnull + @Override + public InstanceIdentifier getManagedDataObjectType() { + return mockedWriter.getManagedDataObjectType(); + } + } }
\ No newline at end of file diff --git a/infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/write/registry/WildcardedSubtreeWriterTest.java b/infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/write/registry/WildcardedSubtreeWriterTest.java new file mode 100644 index 000000000..7006eeaf4 --- /dev/null +++ b/infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/write/registry/WildcardedSubtreeWriterTest.java @@ -0,0 +1,115 @@ +/* + * 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.translate.impl.write.registry; + +import io.fd.honeycomb.translate.write.Writer; +import org.junit.Before; +import org.junit.Test; +import org.mockito.MockitoAnnotations; +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.FromAugmentAugment; +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.SimpleNestedAugment; +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.from.augment.FromAugmentEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithChoice; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.choice.choice.c3.C3; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedList; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class WildcardedSubtreeWriterTest { + + private static final InstanceIdentifier<ContainerWithList> C_WITH_LIST = InstanceIdentifier.create(ContainerWithList.class); + private static final InstanceIdentifier<ContainerWithChoice> C_WITH_CHOICE = InstanceIdentifier.create(ContainerWithChoice.class); + private static final InstanceIdentifier<AugTarget> C_AUG = InstanceIdentifier.create(AugTarget.class); + + private static final InstanceIdentifier<ListInContainer> L_IN_CONTAINER = C_WITH_LIST.child(ListInContainer.class); + private static final InstanceIdentifier<ContainerInList> C_IN_LIST = L_IN_CONTAINER.child(ContainerInList.class); + + private static final InstanceIdentifier<NestedList> N_LIST = C_IN_LIST.child(NestedList.class); + + private Writer subtreeContainerWithList; + private Writer subtreeContainerWithChoice; + private Writer subtreeAugTarget; + + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + Writer<ContainerWithList> writerContainerWithList = mock(Writer.class); + Writer<ContainerWithChoice> writerContainerWithChoice = mock(Writer.class); + Writer<AugTarget> writerAugTarget = mock(Writer.class); + when(writerContainerWithList.getManagedDataObjectType()).thenReturn(C_WITH_LIST); + when(writerContainerWithChoice.getManagedDataObjectType()).thenReturn(C_WITH_CHOICE); + when(writerAugTarget.getManagedDataObjectType()).thenReturn(C_AUG); + subtreeContainerWithList = SubtreeWriter.createWildcardedForWriter(writerContainerWithList); + subtreeContainerWithChoice = SubtreeWriter.createWildcardedForWriter(writerContainerWithChoice); + subtreeAugTarget = SubtreeWriter.createWildcardedForWriter(writerAugTarget); + } + + @Test + public void testParent() { + assertTrue(subtreeContainerWithList.canProcess(C_WITH_LIST)); + assertFalse(subtreeContainerWithList.canProcess(C_WITH_CHOICE)); + + assertTrue(subtreeContainerWithChoice.canProcess(C_WITH_CHOICE)); + assertFalse(subtreeContainerWithChoice.canProcess(C_WITH_LIST)); + + assertTrue(subtreeAugTarget.canProcess(C_AUG)); + assertFalse(subtreeAugTarget.canProcess(C_WITH_LIST)); + } + + @Test + public void testDirectChild() { + assertTrue(subtreeContainerWithList.canProcess(L_IN_CONTAINER)); + assertFalse(subtreeContainerWithList.canProcess(C_WITH_CHOICE.child(C3.class))); + + assertTrue(subtreeContainerWithChoice.canProcess(C_WITH_CHOICE.child(C3.class))); + assertFalse(subtreeContainerWithChoice.canProcess(L_IN_CONTAINER)); + } + + @Test + public void testIndirectChild() { + assertTrue(subtreeContainerWithList.canProcess(C_IN_LIST)); + assertTrue(subtreeContainerWithList.canProcess(N_LIST)); + } + + @Test + public void testAugDirectChild() { + assertTrue(subtreeAugTarget.canProcess(C_AUG.augmentation(FromAugmentAugment.class).child(FromAugment.class))); + assertFalse(subtreeContainerWithList.canProcess(C_AUG.augmentation(FromAugmentAugment.class).child(FromAugment.class))); + } + + @Test + public void testAugIndirectChild() { + assertTrue(subtreeAugTarget.canProcess(C_AUG.augmentation(FromAugmentAugment.class) + .child(FromAugment.class) + .augmentation(SimpleNestedAugment.class))); + assertFalse(subtreeContainerWithList.canProcess(C_AUG.augmentation(FromAugmentAugment.class) + .child(FromAugment.class) + .augmentation(FromAugmentListAugment.class) + .child(FromAugmentEntry.class))); + } +} |