From 677a81daf4349220de65880fcac26537bcd9cb0c Mon Sep 17 00:00:00 2001 From: Marek Gradzki Date: Tue, 16 Jan 2018 13:59:41 +0100 Subject: Improve integration tests for SubtreeWriter Change-Id: I20209b800eaa892e0fb742066003e956d00bbb22 Signed-off-by: Marek Gradzki --- .../fd/honeycomb/data/impl/AbstractInfraTest.java | 3 +- .../data/impl/HoneycombWriteInfraTest.java | 51 ------- .../fd/honeycomb/data/impl/SubtreeWriteTest.java | 162 +++++++++++++++++++++ .../io/fd/honeycomb/subtree/test/model/Ids.java | 33 +++++ .../test-model/src/main/yang/hc-subtree-test.yang | 30 ++++ 5 files changed, 227 insertions(+), 52 deletions(-) create mode 100644 infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/SubtreeWriteTest.java create mode 100644 infra/it/test-model/src/main/java/io/fd/honeycomb/subtree/test/model/Ids.java create mode 100644 infra/it/test-model/src/main/yang/hc-subtree-test.yang 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 3e25733df..ebe9862d9 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 @@ -71,7 +71,8 @@ abstract class AbstractInfraTest { final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create(); 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() + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.$YangModuleInfoImpl.getInstance(), + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.subtree.test.rev180116.$YangModuleInfoImpl.getInstance() )); return moduleInfoBackedContext; diff --git a/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/HoneycombWriteInfraTest.java b/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/HoneycombWriteInfraTest.java index 54b93c768..6d8099c6e 100644 --- a/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/HoneycombWriteInfraTest.java +++ b/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/HoneycombWriteInfraTest.java @@ -16,10 +16,8 @@ package io.fd.honeycomb.data.impl; -import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -522,53 +520,4 @@ public class HoneycombWriteInfraTest extends AbstractInfraTest { // No modification verifyNoMoreInteractions(simpleContainerWriter); } - - @Test - public void testSubtreeWriter() throws Exception { - writerRegistry = new FlatWriterRegistryBuilder(new YangDAG()) - // Handles also container from grouping - .subtreeAdd(Sets.newHashSet(Ids.CONTAINER_FROM_GROUPING_ID), containerWithChoiceWriter) - .build(); - - final ModifiableDataTreeDelegator modifiableDataTreeDelegator = - new ModifiableDataTreeDelegator(serializer, dataTree, schemaContext, writerRegistry, contextBroker); - - final ContainerWithChoice containerWithChoice = - new ContainerWithChoiceBuilder().setContainerFromGrouping(getContainerFromGrouping()).build(); - - // Test write subtree node - DataModification dataModification = modifiableDataTreeDelegator.newModification(); - writeContainerFromGrouping(dataModification); - dataModification.commit(); - - verify(containerWithChoiceWriter, atLeastOnce()).getManagedDataObjectType(); - verify(containerWithChoiceWriter) - .processModification(eq(Ids.CONTAINER_WITH_CHOICE_ID), eq(null), eq(containerWithChoice), any(WriteContext.class)); - verifyNoMoreInteractions(containerWithChoiceWriter); - - // Test delete sub-node - dataModification = modifiableDataTreeDelegator.newModification(); - final ContainerWithChoice containerWithChoiceEmpty = new ContainerWithChoiceBuilder().build(); - deleteContainerFromGrouping(dataModification); - dataModification.commit(); - - verify(containerWithChoiceWriter, atLeastOnce()).getManagedDataObjectType(); - verify(containerWithChoiceWriter) - .processModification(eq(Ids.CONTAINER_WITH_CHOICE_ID), eq(containerWithChoice), eq(containerWithChoiceEmpty), any(WriteContext.class)); - verifyNoMoreInteractions(containerWithChoiceWriter); - - // Test write with subtree node that's not handled by subtree writer - dataModification = modifiableDataTreeDelegator.newModification(); - writeContainerWithChoice(dataModification); - try { - dataModification.commit(); - fail("Missing writer for C3 should occur"); - } catch (IllegalArgumentException e) { - return; - } - } - - private void deleteContainerFromGrouping(final DataModification dataModification) { - dataModification.delete(serializer.toYangInstanceIdentifier(Ids.CONTAINER_FROM_GROUPING_ID)); - } } \ No newline at end of file diff --git a/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/SubtreeWriteTest.java b/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/SubtreeWriteTest.java new file mode 100644 index 000000000..f46174754 --- /dev/null +++ b/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/SubtreeWriteTest.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2018 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.mockito.ArgumentMatchers.eq; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.google.common.collect.Sets; +import io.fd.honeycomb.data.DataModification; +import io.fd.honeycomb.subtree.test.model.Ids; +import io.fd.honeycomb.translate.impl.write.registry.FlatWriterRegistryBuilder; +import io.fd.honeycomb.translate.util.YangDAG; +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.Map; +import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.subtree.test.rev180116.C1; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.subtree.test.rev180116.C1Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.subtree.test.rev180116.c1.C2; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.subtree.test.rev180116.c1.C2Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.subtree.test.rev180116.c1.C3; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.subtree.test.rev180116.c1.C3Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.subtree.test.rev180116.c1.C4; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.subtree.test.rev180116.c1.C4Builder; +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 honeycomb writes from data tree up to mocked writers. + */ +public final class SubtreeWriteTest extends AbstractInfraTest { + + private TipProducingDataTree dataTree; + + @Mock + private Writer c1Writer; + + @Override + void postSetup() { + dataTree = InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION); + dataTree.setSchemaContext(schemaContext); + } + + @Test(expected = IllegalArgumentException.class) + public void testMissingWriter() throws Exception { + when(c1Writer.getManagedDataObjectType()).thenReturn(Ids.C1_ID); + + final WriterRegistry writerRegistry = new FlatWriterRegistryBuilder(new YangDAG()) + .subtreeAdd(Sets.newHashSet(Ids.C2_ID, Ids.C3_ID), c1Writer) + .build(); + + // Prepare modification for C4 + final ModifiableDataTreeDelegator modifiableDataTreeDelegator = + new ModifiableDataTreeDelegator(serializer, dataTree, schemaContext, writerRegistry, contextBroker); + final C4 c4 = new C4Builder().setLeaf4(4).build(); + final Map.Entry> c4NormalizedNode = + serializer.toNormalizedNode(Ids.C4_ID, c4); + final DataModification dataModification = modifiableDataTreeDelegator.newModification(); + dataModification.write(c4NormalizedNode.getKey(), c4NormalizedNode.getValue()); + + // Commit modification and fail with missing writer for C4 + dataModification.commit(); + } + + @Test + public void testWrite() throws Exception { + when(c1Writer.getManagedDataObjectType()).thenReturn(Ids.C1_ID); + + final WriterRegistry writerRegistry = new FlatWriterRegistryBuilder(new YangDAG()) + .subtreeAdd(Sets.newHashSet(Ids.C2_ID, Ids.C3_ID), c1Writer) + .build(); + + // Prepare modification for C1 and C2 containers + final ModifiableDataTreeDelegator modifiableDataTreeDelegator = + new ModifiableDataTreeDelegator(serializer, dataTree, schemaContext, writerRegistry, contextBroker); + final C2 c2 = new C2Builder().setLeaf2(2).build(); + final C3 c3 = new C3Builder().setLeaf3(3).build(); + final Map.Entry> c2NormalizedNode = + serializer.toNormalizedNode(Ids.C2_ID, c2); + final Map.Entry> c3NormalizedNode = + serializer.toNormalizedNode(Ids.C3_ID, c3); + + // Create data + final DataModification dataModification = modifiableDataTreeDelegator.newModification(); + dataModification.write(c2NormalizedNode.getKey(), c2NormalizedNode.getValue()); + dataModification.write(c3NormalizedNode.getKey(), c3NormalizedNode.getValue()); + dataModification.commit(); + + // Check if updates for two child containers are wrapped into single update + verify(c1Writer).processModification(any(), any(), any(), any()); + + // Verify that writer received create modification for C1 with C2 and C3 included + final C1 expectedC1 = new C1Builder().setC2(c2).setC3(c3).build(); + verify(c1Writer).processModification(eq(Ids.C1_ID), eq(null), eq(expectedC1), any(WriteContext.class)); + } + + @Test + public void testDelete() throws Exception { + when(c1Writer.getManagedDataObjectType()).thenReturn(Ids.C1_ID); + + final WriterRegistry writerRegistry = new FlatWriterRegistryBuilder(new YangDAG()) + .subtreeAdd(Sets.newHashSet(Ids.C2_ID, Ids.C3_ID), c1Writer) + .build(); + + // Prepare C1 with leaf1 and C1, C2 containers + final ModifiableDataTreeDelegator modifiableDataTreeDelegator = + new ModifiableDataTreeDelegator(serializer, dataTree, schemaContext, writerRegistry, contextBroker); + final C2 c2 = new C2Builder().setLeaf2(2).build(); + final C3 c3 = new C3Builder().setLeaf3(3).build(); + final C1 c1 = new C1Builder().setC2(c2).setC3(c3).setLeaf1("some-value").build(); + final Map.Entry> c1NormalizedNode = + serializer.toNormalizedNode(Ids.C1_ID, c1); + + // Create data + DataModification dataModification = modifiableDataTreeDelegator.newModification(); + dataModification.write(c1NormalizedNode.getKey(), c1NormalizedNode.getValue()); + dataModification.commit(); + verify(c1Writer).processModification(eq(Ids.C1_ID), eq(null), eq(c1), any(WriteContext.class)); + + // Now delete C1 and C2 + dataModification = modifiableDataTreeDelegator.newModification(); + dataModification.delete(serializer.toYangInstanceIdentifier(Ids.C2_ID)); + dataModification.delete(serializer.toYangInstanceIdentifier(Ids.C3_ID)); + dataModification.commit(); + + // Check that in total, there were 2 invocations of processModification + verify(c1Writer, times(2)).processModification(any(), any(), any(), any()); + + // First create for C1 + final InOrder inOrder = Mockito.inOrder(c1Writer); + inOrder.verify(c1Writer).processModification(eq(Ids.C1_ID), eq(null), eq(c1), any(WriteContext.class)); + + // Then delete for C1 and C2, but wrapped in C1 update + final C1 c1WithoutC2AndC3 = new C1Builder().setLeaf1("some-value").build(); + inOrder.verify(c1Writer) + .processModification(eq(Ids.C1_ID), eq(c1), eq(c1WithoutC2AndC3), any(WriteContext.class)); + } +} \ No newline at end of file diff --git a/infra/it/test-model/src/main/java/io/fd/honeycomb/subtree/test/model/Ids.java b/infra/it/test-model/src/main/java/io/fd/honeycomb/subtree/test/model/Ids.java new file mode 100644 index 000000000..52e838418 --- /dev/null +++ b/infra/it/test-model/src/main/java/io/fd/honeycomb/subtree/test/model/Ids.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018 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.subtree.test.model; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.subtree.test.rev180116.C1; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.subtree.test.rev180116.c1.C2; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.subtree.test.rev180116.c1.C3; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.subtree.test.rev180116.c1.C4; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Instance identifiers referencing all complex nodes within honeycomb's subtree test model. + */ +public interface Ids { + InstanceIdentifier C1_ID = InstanceIdentifier.create(C1.class); + InstanceIdentifier C2_ID = C1_ID.child(C2.class); + InstanceIdentifier C3_ID = C1_ID.child(C3.class); + InstanceIdentifier C4_ID = C1_ID.child(C4.class); +} diff --git a/infra/it/test-model/src/main/yang/hc-subtree-test.yang b/infra/it/test-model/src/main/yang/hc-subtree-test.yang new file mode 100644 index 000000000..09b3fc737 --- /dev/null +++ b/infra/it/test-model/src/main/yang/hc-subtree-test.yang @@ -0,0 +1,30 @@ +module hc-subtree-test { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:hc:subtree:test"; + prefix "hc-subtree-test"; + + revision "2018-01-16" { + description "HC model for testing subtree writers."; + } + + container c1 { + leaf leaf1 { + type string; + } + container c2 { + leaf leaf2 { + type int32; + } + } + container c3 { + leaf leaf3 { + type int32; + } + } + container c4 { + leaf leaf4 { + type int32; + } + } + } +} -- cgit 1.2.3-korg