From 68ec91ba3edcf95953a00d41dca525b1e83dbba5 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Sun, 28 May 2023 20:18:51 +0200 Subject: [PATCH] Refactor AbstractDataTreeChangeListenerTest Rather than exposing the underlying DTCL implementation, expose only the collector aspect, requiring the collector to be closed -- which also tears down the listener. This is a stepping stone to allowing step-by-step assertions, but the notable change is that we await the initial synchronization before giving out the collector. Change-Id: I9337bc5b80eb9976ad9dec143b59ef75d742cbfd Signed-off-by: Robert Varga --- .../dom/adapter/Bug1125RegressionTest.java | 25 +-- .../Bug1333DataChangeListenerTest.java | 54 +++--- .../dom/adapter/Bug1418AugmentationTest.java | 108 ++++++------ .../Bug2562DeserializedUnkeyedListTest.java | 27 ++- .../dom/adapter/Bug3090MultiKeyList.java | 25 ++- .../ListInsertionDataChangeListenerTest.java | 166 +++++++++--------- .../AbstractDataTreeChangeListenerTest.java | 139 +++++++++------ 7 files changed, 280 insertions(+), 264 deletions(-) diff --git a/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/Bug1125RegressionTest.java b/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/Bug1125RegressionTest.java index 490299f36b..cbe44d5c53 100644 --- a/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/Bug1125RegressionTest.java +++ b/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/Bug1125RegressionTest.java @@ -11,10 +11,8 @@ import static org.opendaylight.mdsal.binding.test.model.util.ListsBindingUtils.T import static org.opendaylight.mdsal.binding.test.model.util.ListsBindingUtils.path; import static org.opendaylight.mdsal.binding.test.model.util.ListsBindingUtils.topLevelList; -import com.google.common.collect.ImmutableSet; import java.util.Set; import org.junit.Test; -import org.opendaylight.mdsal.binding.api.WriteTransaction; import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractDataTreeChangeListenerTest; import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections; import org.opendaylight.mdsal.common.api.LogicalDatastoreType; @@ -45,7 +43,7 @@ public class Bug1125RegressionTest extends AbstractDataTreeChangeListenerTest { @Override protected Set getModuleInfos() throws Exception { - return ImmutableSet.of(BindingReflections.getModuleInfo(Top.class), + return Set.of(BindingReflections.getModuleInfo(Top.class), BindingReflections.getModuleInfo(TreeComplexUsesAugment.class)); } @@ -59,19 +57,22 @@ public class Bug1125RegressionTest extends AbstractDataTreeChangeListenerTest { } private void deleteAndListenAugment(final InstanceIdentifier path) { - TreeComplexUsesAugment augment = writeInitialState(); - TestListener listener = createListener(LogicalDatastoreType.OPERATIONAL, - WILDCARDED_AUGMENT_PATH, added(FOO_AUGMENT_PATH, augment), deleted(FOO_AUGMENT_PATH, augment)); - WriteTransaction tx = getDataBroker().newWriteOnlyTransaction(); - tx.delete(LogicalDatastoreType.OPERATIONAL, path); - assertCommit(tx.commit()); - listener.verify(); + final var augment = writeInitialState(); + try (var collector = createCollector(LogicalDatastoreType.OPERATIONAL, WILDCARDED_AUGMENT_PATH)) { + final var tx = getDataBroker().newWriteOnlyTransaction(); + tx.delete(LogicalDatastoreType.OPERATIONAL, path); + assertCommit(tx.commit()); + + collector.assertModifications( + added(FOO_AUGMENT_PATH, augment), + deleted(FOO_AUGMENT_PATH, augment)); + } } private TreeComplexUsesAugment writeInitialState() { - WriteTransaction initialTx = getDataBroker().newWriteOnlyTransaction(); + var initialTx = getDataBroker().newWriteOnlyTransaction(); initialTx.put(LogicalDatastoreType.OPERATIONAL, TOP_PATH, new TopBuilder().build()); - TreeComplexUsesAugment fooAugment = new TreeComplexUsesAugmentBuilder() + var fooAugment = new TreeComplexUsesAugmentBuilder() .setContainerWithUses(new ContainerWithUsesBuilder().setLeafFromGrouping("foo").build()) .build(); initialTx.put(LogicalDatastoreType.OPERATIONAL, path(TOP_FOO_KEY), topLevelList(TOP_FOO_KEY, fooAugment)); diff --git a/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/Bug1333DataChangeListenerTest.java b/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/Bug1333DataChangeListenerTest.java index 10db76fed3..9328e8cb5b 100644 --- a/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/Bug1333DataChangeListenerTest.java +++ b/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/Bug1333DataChangeListenerTest.java @@ -14,17 +14,14 @@ import static org.opendaylight.mdsal.binding.test.model.util.ListsBindingUtils.c import static org.opendaylight.mdsal.binding.test.model.util.ListsBindingUtils.path; import static org.opendaylight.mdsal.binding.test.model.util.ListsBindingUtils.top; import static org.opendaylight.mdsal.binding.test.model.util.ListsBindingUtils.topLevelList; -import static org.opendaylight.mdsal.common.api.LogicalDatastoreType.CONFIGURATION; import com.google.common.collect.ImmutableSet; import java.util.Set; import org.junit.Test; -import org.opendaylight.mdsal.binding.api.ReadWriteTransaction; import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractDataTreeChangeListenerTest; import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections; import org.opendaylight.mdsal.common.api.LogicalDatastoreType; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.TreeComplexUsesAugment; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.complex.from.grouping.ListViaUses; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.Top; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.two.level.list.TopLevelList; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; @@ -53,63 +50,62 @@ public class Bug1333DataChangeListenerTest extends AbstractDataTreeChangeListene } public Top writeTopWithListItem(final LogicalDatastoreType store) { - ReadWriteTransaction tx = getDataBroker().newReadWriteTransaction(); - Top topItem = topWithListItem(); + var tx = getDataBroker().newWriteOnlyTransaction(); + var topItem = topWithListItem(); tx.put(store, TOP_PATH, topItem); assertCommit(tx.commit()); return topItem; } public void deleteItem(final LogicalDatastoreType store, final InstanceIdentifier path) { - ReadWriteTransaction tx = getDataBroker().newReadWriteTransaction(); + var tx = getDataBroker().newWriteOnlyTransaction(); tx.delete(store, path); assertCommit(tx.commit()); } @Test public void writeTopWithListItemAugmentedListenTopSubtree() { - TestListener listener = createListener(CONFIGURATION, TOP_PATH, added(TOP_PATH, topWithListItem())); + try (var collector = createCollector(LogicalDatastoreType.CONFIGURATION, TOP_PATH)) { + writeTopWithListItem(LogicalDatastoreType.CONFIGURATION); - writeTopWithListItem(CONFIGURATION); - - listener.verify(); + collector.assertModifications(added(TOP_PATH, topWithListItem())); + } } @Test public void writeTopWithListItemAugmentedListenAugmentSubtreeWildcarded() { - TestListener listener = createListener(CONFIGURATION, AUGMENT_WILDCARD, - added(path(TOP_FOO_KEY, TreeComplexUsesAugment.class), complexUsesAugment(USES_ONE_KEY, USES_TWO_KEY))); - - writeTopWithListItem(CONFIGURATION); + try (var collector = createCollector(LogicalDatastoreType.CONFIGURATION, AUGMENT_WILDCARD)) { + writeTopWithListItem(LogicalDatastoreType.CONFIGURATION); - listener.verify(); + collector.assertModifications( + added(path(TOP_FOO_KEY, TreeComplexUsesAugment.class), complexUsesAugment(USES_ONE_KEY, USES_TWO_KEY))); + } } @Test public void deleteAugmentChildListenTopSubtree() { - Top top = writeTopWithListItem(CONFIGURATION); - - TestListener listener = createListener(CONFIGURATION, TOP_PATH, added(TOP_PATH, top), - subtreeModified(TOP_PATH, top, top(topLevelList(TOP_FOO_KEY, complexUsesAugment(USES_TWO_KEY))))); + final var top = writeTopWithListItem(LogicalDatastoreType.CONFIGURATION); - InstanceIdentifier deletePath = path(TOP_FOO_KEY, USES_ONE_KEY); - deleteItem(CONFIGURATION, deletePath); + try (var collector = createCollector(LogicalDatastoreType.CONFIGURATION, TOP_PATH)) { + deleteItem(LogicalDatastoreType.CONFIGURATION, path(TOP_FOO_KEY, USES_ONE_KEY)); - listener.verify(); + collector.assertModifications( + added(TOP_PATH, top), + subtreeModified(TOP_PATH, top, top(topLevelList(TOP_FOO_KEY, complexUsesAugment(USES_TWO_KEY))))); + } } @Test public void deleteAugmentChildListenAugmentSubtreeWildcarded() { - writeTopWithListItem(CONFIGURATION); + writeTopWithListItem(LogicalDatastoreType.CONFIGURATION); + + try (var collector = createCollector(LogicalDatastoreType.CONFIGURATION, AUGMENT_WILDCARD)) { + deleteItem(LogicalDatastoreType.CONFIGURATION, path(TOP_FOO_KEY, USES_ONE_KEY)); - TestListener listener = createListener(CONFIGURATION, AUGMENT_WILDCARD, + collector.assertModifications( added(path(TOP_FOO_KEY, TreeComplexUsesAugment.class), complexUsesAugment(USES_ONE_KEY, USES_TWO_KEY)), subtreeModified(path(TOP_FOO_KEY, TreeComplexUsesAugment.class), complexUsesAugment(USES_ONE_KEY, USES_TWO_KEY), complexUsesAugment(USES_TWO_KEY))); - - InstanceIdentifier deletePath = path(TOP_FOO_KEY, USES_ONE_KEY); - deleteItem(CONFIGURATION, deletePath); - - listener.verify(); + } } } diff --git a/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/Bug1418AugmentationTest.java b/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/Bug1418AugmentationTest.java index 076ed09b58..b413993a7d 100644 --- a/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/Bug1418AugmentationTest.java +++ b/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/Bug1418AugmentationTest.java @@ -15,10 +15,8 @@ import static org.opendaylight.mdsal.binding.test.model.util.ListsBindingUtils.t import static org.opendaylight.mdsal.binding.test.model.util.ListsBindingUtils.topLevelList; import static org.opendaylight.mdsal.common.api.LogicalDatastoreType.CONFIGURATION; -import com.google.common.collect.ImmutableSet; import java.util.Set; import org.junit.Test; -import org.opendaylight.mdsal.binding.api.WriteTransaction; import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractDataTreeChangeListenerTest; import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.TreeComplexUsesAugment; @@ -43,106 +41,102 @@ public class Bug1418AugmentationTest extends AbstractDataTreeChangeListenerTest new ListViaUsesKey("list key modified"); @Override - protected Set getModuleInfos() throws Exception { - return ImmutableSet.of(BindingReflections.getModuleInfo(Top.class), - BindingReflections.getModuleInfo(TreeComplexUsesAugment.class), - BindingReflections.getModuleInfo(TreeLeafOnlyUsesAugment.class)); + protected Set getModuleInfos() { + return Set.of(BindingReflections.getModuleInfo(Top.class), + BindingReflections.getModuleInfo(TreeComplexUsesAugment.class)); } @Test public void leafOnlyAugmentationCreatedTest() { - TreeLeafOnlyUsesAugment leafOnlyUsesAugment = leafOnlyUsesAugment("test leaf"); - final TestListener listener = createListener(CONFIGURATION, SIMPLE_AUGMENT, - added(path(TOP_FOO_KEY, TreeLeafOnlyUsesAugment.class), leafOnlyUsesAugment)); - - WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); - writeTx.put(CONFIGURATION, TOP, top()); - writeTx.put(CONFIGURATION, TOP_FOO, topLevelList(new TopLevelListKey(TOP_FOO_KEY))); - writeTx.put(CONFIGURATION, SIMPLE_AUGMENT, leafOnlyUsesAugment); - assertCommit(writeTx.commit()); - - listener.verify(); + final var leafOnlyUsesAugment = leafOnlyUsesAugment("test leaf"); + try (var collector = createCollector(CONFIGURATION, SIMPLE_AUGMENT)) { + final var writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(CONFIGURATION, TOP, top()); + writeTx.put(CONFIGURATION, TOP_FOO, topLevelList(new TopLevelListKey(TOP_FOO_KEY))); + writeTx.put(CONFIGURATION, SIMPLE_AUGMENT, leafOnlyUsesAugment); + assertCommit(writeTx.commit()); + + collector.assertModifications(added(path(TOP_FOO_KEY, TreeLeafOnlyUsesAugment.class), leafOnlyUsesAugment)); + } } @Test public void leafOnlyAugmentationUpdatedTest() { - WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); + var writeTx = getDataBroker().newWriteOnlyTransaction(); writeTx.put(CONFIGURATION, TOP, top()); writeTx.put(CONFIGURATION, TOP_FOO, topLevelList(new TopLevelListKey(TOP_FOO_KEY))); - TreeLeafOnlyUsesAugment leafOnlyUsesAugmentBefore = leafOnlyUsesAugment("test leaf"); + final var leafOnlyUsesAugmentBefore = leafOnlyUsesAugment("test leaf"); writeTx.put(CONFIGURATION, SIMPLE_AUGMENT, leafOnlyUsesAugmentBefore); assertCommit(writeTx.commit()); - TreeLeafOnlyUsesAugment leafOnlyUsesAugmentAfter = leafOnlyUsesAugment("test leaf changed"); - final TestListener listener = createListener(CONFIGURATION, SIMPLE_AUGMENT, + final var leafOnlyUsesAugmentAfter = leafOnlyUsesAugment("test leaf changed"); + try (var collector = createCollector(CONFIGURATION, SIMPLE_AUGMENT)) { + writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(CONFIGURATION, SIMPLE_AUGMENT, leafOnlyUsesAugmentAfter); + assertCommit(writeTx.commit()); + + collector.assertModifications( added(path(TOP_FOO_KEY, TreeLeafOnlyUsesAugment.class), leafOnlyUsesAugmentBefore), replaced(path(TOP_FOO_KEY, TreeLeafOnlyUsesAugment.class), leafOnlyUsesAugmentBefore, leafOnlyUsesAugmentAfter)); - - writeTx = getDataBroker().newWriteOnlyTransaction(); - writeTx.put(CONFIGURATION, SIMPLE_AUGMENT, leafOnlyUsesAugmentAfter); - assertCommit(writeTx.commit()); - - listener.verify(); + } } @Test public void leafOnlyAugmentationDeletedTest() { - WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); + var writeTx = getDataBroker().newWriteOnlyTransaction(); writeTx.put(CONFIGURATION, TOP, top()); writeTx.put(CONFIGURATION, TOP_FOO, topLevelList(new TopLevelListKey(TOP_FOO_KEY))); - TreeLeafOnlyUsesAugment leafOnlyUsesAugment = leafOnlyUsesAugment("test leaf"); + final var leafOnlyUsesAugment = leafOnlyUsesAugment("test leaf"); writeTx.put(CONFIGURATION, SIMPLE_AUGMENT, leafOnlyUsesAugment); assertCommit(writeTx.commit()); - final TestListener listener = createListener(CONFIGURATION, SIMPLE_AUGMENT, + try (var collector = createCollector(CONFIGURATION, SIMPLE_AUGMENT)) { + writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.delete(CONFIGURATION, SIMPLE_AUGMENT); + assertCommit(writeTx.commit()); + + collector.assertModifications( added(path(TOP_FOO_KEY, TreeLeafOnlyUsesAugment.class), leafOnlyUsesAugment), deleted(path(TOP_FOO_KEY, TreeLeafOnlyUsesAugment.class), leafOnlyUsesAugment)); - - writeTx = getDataBroker().newWriteOnlyTransaction(); - writeTx.delete(CONFIGURATION, SIMPLE_AUGMENT); - assertCommit(writeTx.commit()); - - listener.verify(); + } } @Test public void complexAugmentationCreatedTest() { - TreeComplexUsesAugment complexUsesAugment = complexUsesAugment(LIST_VIA_USES_KEY); - final TestListener listener = createListener(CONFIGURATION, COMPLEX_AUGMENT, - added(path(TOP_FOO_KEY, TreeComplexUsesAugment.class), complexUsesAugment)); - - WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); - writeTx.put(CONFIGURATION, TOP, top()); - writeTx.put(CONFIGURATION, TOP_FOO, topLevelList(new TopLevelListKey(TOP_FOO_KEY))); - writeTx.put(CONFIGURATION, COMPLEX_AUGMENT, complexUsesAugment); - assertCommit(writeTx.commit()); - - listener.verify(); + try (var collector = createCollector(CONFIGURATION, COMPLEX_AUGMENT)) { + final var complexUsesAugment = complexUsesAugment(LIST_VIA_USES_KEY); + final var writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(CONFIGURATION, TOP, top()); + writeTx.put(CONFIGURATION, TOP_FOO, topLevelList(new TopLevelListKey(TOP_FOO_KEY))); + writeTx.put(CONFIGURATION, COMPLEX_AUGMENT, complexUsesAugment); + assertCommit(writeTx.commit()); + + collector.assertModifications(added(path(TOP_FOO_KEY, TreeComplexUsesAugment.class), complexUsesAugment)); + } } @Test public void complexAugmentationUpdatedTest() { - WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); + var writeTx = getDataBroker().newWriteOnlyTransaction(); writeTx.put(CONFIGURATION, TOP, top()); writeTx.put(CONFIGURATION, TOP_FOO, topLevelList(new TopLevelListKey(TOP_FOO_KEY))); - TreeComplexUsesAugment complexUsesAugmentBefore = complexUsesAugment(LIST_VIA_USES_KEY); + final var complexUsesAugmentBefore = complexUsesAugment(LIST_VIA_USES_KEY); writeTx.put(CONFIGURATION, COMPLEX_AUGMENT, complexUsesAugmentBefore); assertCommit(writeTx.commit()); - TreeComplexUsesAugment complexUsesAugmentAfter = complexUsesAugment(LIST_VIA_USES_KEY_MOD); + try (var collector = createCollector(CONFIGURATION, COMPLEX_AUGMENT)) { + final var complexUsesAugmentAfter = complexUsesAugment(LIST_VIA_USES_KEY_MOD); + writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(CONFIGURATION, COMPLEX_AUGMENT, complexUsesAugmentAfter); + assertCommit(writeTx.commit()); - final TestListener listener = createListener(CONFIGURATION, COMPLEX_AUGMENT, + collector.assertModifications( added(path(TOP_FOO_KEY, TreeComplexUsesAugment.class), complexUsesAugmentBefore), // While we are overwriting the augment, at the transaction ends up replacing one child with another, // so the Augmentation ends up not being overwritten, but modified subtreeModified(path(TOP_FOO_KEY, TreeComplexUsesAugment.class), complexUsesAugmentBefore, complexUsesAugmentAfter)); - - writeTx = getDataBroker().newWriteOnlyTransaction(); - writeTx.put(CONFIGURATION, COMPLEX_AUGMENT, complexUsesAugmentAfter); - assertCommit(writeTx.commit()); - - listener.verify(); + } } } diff --git a/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/Bug2562DeserializedUnkeyedListTest.java b/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/Bug2562DeserializedUnkeyedListTest.java index d3a07ad6ef..5ab6c8466e 100644 --- a/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/Bug2562DeserializedUnkeyedListTest.java +++ b/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/Bug2562DeserializedUnkeyedListTest.java @@ -7,20 +7,16 @@ */ package org.opendaylight.mdsal.binding.dom.adapter; -import com.google.common.collect.ImmutableSet; -import java.util.Arrays; +import java.util.List; import java.util.Map; import java.util.Set; import org.junit.Test; -import org.opendaylight.mdsal.binding.api.ReadWriteTransaction; import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractDataTreeChangeListenerTest; import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections; import org.opendaylight.mdsal.common.api.LogicalDatastoreType; import org.opendaylight.yang.gen.v1.opendaylight.test.bug._2562.namespace.rev160101.Root; import org.opendaylight.yang.gen.v1.opendaylight.test.bug._2562.namespace.rev160101.RootBuilder; -import org.opendaylight.yang.gen.v1.opendaylight.test.bug._2562.namespace.rev160101.root.Fooroot; import org.opendaylight.yang.gen.v1.opendaylight.test.bug._2562.namespace.rev160101.root.FoorootBuilder; -import org.opendaylight.yang.gen.v1.opendaylight.test.bug._2562.namespace.rev160101.root.fooroot.Barroot; import org.opendaylight.yang.gen.v1.opendaylight.test.bug._2562.namespace.rev160101.root.fooroot.BarrootBuilder; import org.opendaylight.yang.gen.v1.opendaylight.test.bug._2562.namespace.rev160101.root.fooroot.BarrootKey; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; @@ -31,22 +27,21 @@ public class Bug2562DeserializedUnkeyedListTest extends AbstractDataTreeChangeLi @Override protected Set getModuleInfos() throws Exception { - return ImmutableSet.of(BindingReflections.getModuleInfo(Root.class)); + return Set.of(BindingReflections.getModuleInfo(Root.class)); } @Test public void writeListToList2562Root() { - final Barroot barRoot = new BarrootBuilder().setType(2).setValue(2).withKey(new BarrootKey(2)).build(); - final Fooroot fooRoot = new FoorootBuilder().setBarroot(Map.of(barRoot.key(), barRoot)).build(); - final Root root = new RootBuilder().setFooroot(Arrays.asList(fooRoot)).build(); + final var barRoot = new BarrootBuilder().setType(2).setValue(2).withKey(new BarrootKey(2)).build(); + final var fooRoot = new FoorootBuilder().setBarroot(Map.of(barRoot.key(), barRoot)).build(); + final var root = new RootBuilder().setFooroot(List.of(fooRoot)).build(); - final TestListener listenerRoot = createListener(LogicalDatastoreType.CONFIGURATION, ROOT_PATH, - added(ROOT_PATH, root)); + try (var collector = createCollector(LogicalDatastoreType.CONFIGURATION, ROOT_PATH)) { + final var readWriteTransaction = getDataBroker().newReadWriteTransaction(); + readWriteTransaction.put(LogicalDatastoreType.CONFIGURATION, ROOT_PATH, root); + assertCommit(readWriteTransaction.commit()); - final ReadWriteTransaction readWriteTransaction = getDataBroker().newReadWriteTransaction(); - readWriteTransaction.put(LogicalDatastoreType.CONFIGURATION, ROOT_PATH, root); - assertCommit(readWriteTransaction.commit()); - - listenerRoot.verify(); + collector.assertModifications(added(ROOT_PATH, root)); + } } } diff --git a/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/Bug3090MultiKeyList.java b/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/Bug3090MultiKeyList.java index ad2fec0df8..c4b533ebef 100644 --- a/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/Bug3090MultiKeyList.java +++ b/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/Bug3090MultiKeyList.java @@ -7,7 +7,6 @@ */ package org.opendaylight.mdsal.binding.dom.adapter; -import com.google.common.collect.ImmutableSet; import java.util.ArrayList; import java.util.HashSet; import java.util.Objects; @@ -15,7 +14,6 @@ import java.util.Set; import java.util.stream.Collectors; import org.junit.Test; import org.opendaylight.mdsal.binding.api.DataObjectModification.ModificationType; -import org.opendaylight.mdsal.binding.api.ReadWriteTransaction; import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractDataTreeChangeListenerTest; import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections; import org.opendaylight.mdsal.common.api.LogicalDatastoreType; @@ -32,7 +30,7 @@ public class Bug3090MultiKeyList extends AbstractDataTreeChangeListenerTest { @Override protected Set getModuleInfos() throws Exception { - return ImmutableSet.of(BindingReflections.getModuleInfo(Root.class)); + return Set.of(BindingReflections.getModuleInfo(Root.class)); } @Test @@ -47,17 +45,16 @@ public class Bug3090MultiKeyList extends AbstractDataTreeChangeListenerTest { ); } - final Root root = new RootBuilder().setListInRoot(BindingMap.of(listInRoots)).build(); + final var root = new RootBuilder().setListInRoot(BindingMap.of(listInRoots)).build(); - final TestListener listener = createListener(LogicalDatastoreType.CONFIGURATION, ROOT_PATH, - match(ModificationType.WRITE, ROOT_PATH, Objects::isNull, - (DataMatcher) dataAfter -> checkData(root, dataAfter))); + try (var collector = createCollector(LogicalDatastoreType.CONFIGURATION, ROOT_PATH)) { + final var readWriteTransaction = getDataBroker().newReadWriteTransaction(); + readWriteTransaction.put(LogicalDatastoreType.CONFIGURATION, ROOT_PATH, root); + assertCommit(readWriteTransaction.commit()); - final ReadWriteTransaction readWriteTransaction = getDataBroker().newReadWriteTransaction(); - readWriteTransaction.put(LogicalDatastoreType.CONFIGURATION, ROOT_PATH, root); - assertCommit(readWriteTransaction.commit()); - - listener.verify(); + collector.assertModifications(match(ModificationType.WRITE, ROOT_PATH, Objects::isNull, + (DataMatcher) dataAfter -> checkData(root, dataAfter))); + } } private static boolean checkData(final Root expected, final Root actual) { @@ -65,8 +62,8 @@ public class Bug3090MultiKeyList extends AbstractDataTreeChangeListenerTest { return false; } - Set expListInRoot = new HashSet<>(expected.getListInRoot().values()); - Set actualListInRoot = actual.getListInRoot().values().stream() + var expListInRoot = new HashSet<>(expected.nonnullListInRoot().values()); + var actualListInRoot = actual.nonnullListInRoot().values().stream() .map(list -> new ListInRootBuilder(list).build()).collect(Collectors.toSet()); return expListInRoot.equals(actualListInRoot); } diff --git a/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/ListInsertionDataChangeListenerTest.java b/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/ListInsertionDataChangeListenerTest.java index e761ba6f3c..fb61d7a4cd 100644 --- a/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/ListInsertionDataChangeListenerTest.java +++ b/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/ListInsertionDataChangeListenerTest.java @@ -21,7 +21,6 @@ import java.util.stream.Collectors; import org.junit.Before; import org.junit.Test; import org.opendaylight.mdsal.binding.api.DataObjectModification.ModificationType; -import org.opendaylight.mdsal.binding.api.ReadWriteTransaction; import org.opendaylight.mdsal.binding.api.WriteTransaction; import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractDataTreeChangeListenerTest; import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections; @@ -60,109 +59,110 @@ public class ListInsertionDataChangeListenerTest extends AbstractDataTreeChangeL final TopLevelList topFoo = topLevelList(TOP_FOO_KEY); // Listener for TOP element - final TestListener topListener = createListener(CONFIGURATION, TOP, - added(TOP, top(topLevelList(TOP_FOO_KEY))), replaced(TOP, top(topFoo), top)); - - // Listener for all list items. This one should see Foo item deleted and Bar item added. - final TestListener allListener = createListener(CONFIGURATION, WILDCARDED, - added(TOP_FOO, topFoo), added(TOP_BAR, topBar), deleted(TOP_FOO, topFoo)); - - // Listener for all Foo item. This one should see only Foo item deleted. - final TestListener fooListener = createListener(CONFIGURATION, TOP_FOO, - added(TOP_FOO, topFoo), deleted(TOP_FOO, topFoo)); - - // Listener for bar list items. - final TestListener barListener = createListener(CONFIGURATION, TOP_BAR, - added(TOP_BAR, topBar)); - - ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction(); - writeTx.put(CONFIGURATION, TOP, top); - assertCommit(writeTx.commit()); - - topListener.verify(); - allListener.verify(); - fooListener.verify(); - barListener.verify(); + try (var topListener = createCollector(CONFIGURATION, TOP)) { + // Listener for all list items. This one should see Foo item deleted and Bar item added. + try (var allListener = createCollector(CONFIGURATION, WILDCARDED)) { + // Listener for all Foo item. This one should see only Foo item deleted. + try (var fooListener = createCollector(CONFIGURATION, TOP_FOO)) { + // Listener for bar list items. + try (var barListener = createCollector(CONFIGURATION, TOP_BAR)) { + final var writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(CONFIGURATION, TOP, top); + assertCommit(writeTx.commit()); + + barListener.assertModifications(added(TOP_BAR, topBar)); + } + fooListener.assertModifications(added(TOP_FOO, topFoo), deleted(TOP_FOO, topFoo)); + } + allListener.assertModifications( + added(TOP_FOO, topFoo), + added(TOP_BAR, topBar), + deleted(TOP_FOO, topFoo)); + } + topListener.assertModifications( + added(TOP, top(topLevelList(TOP_FOO_KEY))), + replaced(TOP, top(topFoo), top)); + } } @Test public void mergeTopNodeSubtreeListeners() { - final TopLevelList topBar = topLevelList(TOP_BAR_KEY); - final TopLevelList topFoo = topLevelList(TOP_FOO_KEY); - - final TestListener topListener = createListener(CONFIGURATION, TOP, + final var topBar = topLevelList(TOP_BAR_KEY); + final var topFoo = topLevelList(TOP_FOO_KEY); + + try (var topListener = createCollector(CONFIGURATION, TOP)) { + try (var allListener = createCollector(CONFIGURATION, WILDCARDED)) { + try (var fooListener = createCollector(CONFIGURATION, TOP_FOO)) { + try (var barListener = createCollector(CONFIGURATION, TOP_BAR)) { + final var writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.merge(CONFIGURATION, TOP, top(topLevelList(TOP_BAR_KEY))); + assertCommit(writeTx.commit()); + + barListener.assertModifications(added(TOP_BAR, topBar)); + } + fooListener.assertModifications(added(TOP_FOO, topFoo)); + } + allListener.assertModifications(added(TOP_FOO, topFoo), added(TOP_BAR, topBar)); + } + topListener.assertModifications( added(TOP, top(topLevelList(TOP_FOO_KEY))), topSubtreeModified(topFoo, topBar)); - final TestListener allListener = createListener(CONFIGURATION, WILDCARDED, - added(TOP_FOO, topFoo), added(TOP_BAR, topBar)); - final TestListener fooListener = createListener(CONFIGURATION, TOP_FOO, - added(TOP_FOO, topFoo)); - final TestListener barListener = createListener(CONFIGURATION, TOP_BAR, - added(TOP_BAR, topBar)); - - ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction(); - writeTx.merge(CONFIGURATION, TOP, top(topLevelList(TOP_BAR_KEY))); - assertCommit(writeTx.commit()); - - topListener.verify(); - allListener.verify(); - fooListener.verify(); - barListener.verify(); + } } @Test public void putTopBarNodeSubtreeListeners() { - final TopLevelList topBar = topLevelList(TOP_BAR_KEY); - final TopLevelList topFoo = topLevelList(TOP_FOO_KEY); - - final TestListener topListener = createListener(CONFIGURATION, TOP, + final var topBar = topLevelList(TOP_BAR_KEY); + final var topFoo = topLevelList(TOP_FOO_KEY); + + try (var topListener = createCollector(CONFIGURATION, TOP)) { + try (var allListener = createCollector(CONFIGURATION, WILDCARDED)) { + try (var fooListener = createCollector(CONFIGURATION, TOP_FOO)) { + try (var barListener = createCollector(CONFIGURATION, TOP_BAR)) { + var writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(CONFIGURATION, TOP_BAR, topLevelList(TOP_BAR_KEY)); + assertCommit(writeTx.commit()); + + barListener.assertModifications(added(TOP_BAR, topBar)); + } + fooListener.assertModifications(added(TOP_FOO, topFoo)); + } + allListener.assertModifications(added(TOP_FOO, topFoo), added(TOP_BAR, topBar)); + } + topListener.assertModifications( added(TOP, top(topLevelList(TOP_FOO_KEY))), topSubtreeModified(topFoo, topBar)); - final TestListener allListener = createListener(CONFIGURATION, WILDCARDED, - added(TOP_FOO, topFoo), added(TOP_BAR, topBar)); - final TestListener fooListener = createListener(CONFIGURATION, TOP_FOO, - added(TOP_FOO, topFoo)); - final TestListener barListener = createListener(CONFIGURATION, TOP_BAR, - added(TOP_BAR, topBar)); - - ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction(); - writeTx.put(CONFIGURATION, TOP_BAR, topLevelList(TOP_BAR_KEY)); - assertCommit(writeTx.commit()); - - topListener.verify(); - allListener.verify(); - fooListener.verify(); - barListener.verify(); + } } @Test public void mergeTopBarNodeSubtreeListeners() { - final TopLevelList topBar = topLevelList(TOP_BAR_KEY); - final TopLevelList topFoo = topLevelList(TOP_FOO_KEY); - - final TestListener topListener = createListener(CONFIGURATION, TOP, + final var topBar = topLevelList(TOP_BAR_KEY); + final var topFoo = topLevelList(TOP_FOO_KEY); + + try (var topListener = createCollector(CONFIGURATION, TOP)) { + try (var allListener = createCollector(CONFIGURATION, WILDCARDED)) { + try (var fooListener = createCollector(CONFIGURATION, TOP_FOO)) { + try (var barListener = createCollector(CONFIGURATION, TOP_BAR)) { + final var writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.merge(CONFIGURATION, TOP_BAR, topLevelList(TOP_BAR_KEY)); + assertCommit(writeTx.commit()); + + barListener.assertModifications(added(TOP_BAR, topBar)); + } + fooListener.assertModifications(added(TOP_FOO, topFoo)); + } + allListener.assertModifications(added(TOP_FOO, topFoo), added(TOP_BAR, topBar)); + } + topListener.assertModifications( added(TOP, top(topLevelList(TOP_FOO_KEY))), topSubtreeModified(topFoo, topBar)); - final TestListener allListener = createListener(CONFIGURATION, WILDCARDED, - added(TOP_FOO, topFoo), added(TOP_BAR, topBar)); - final TestListener fooListener = createListener(CONFIGURATION, TOP_FOO, - added(TOP_FOO, topFoo)); - final TestListener barListener = createListener(CONFIGURATION, TOP_BAR, - added(TOP_BAR, topBar)); - - ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction(); - writeTx.merge(CONFIGURATION, TOP_BAR, topLevelList(TOP_BAR_KEY)); - assertCommit(writeTx.commit()); - - topListener.verify(); - allListener.verify(); - fooListener.verify(); - barListener.verify(); + } } private static Matcher topSubtreeModified(final TopLevelList topFoo, final TopLevelList topBar) { return match(ModificationType.SUBTREE_MODIFIED, TOP, (DataMatcher) dataBefore -> Objects.equals(top(topFoo), dataBefore), dataAfter -> { - Set expList = new HashSet<>(top(topBar, topFoo).getTopLevelList().values()); - Set actualList = dataAfter.getTopLevelList().values().stream() + var expList = new HashSet<>(top(topBar, topFoo).nonnullTopLevelList().values()); + var actualList = dataAfter.nonnullTopLevelList().values().stream() .map(list -> new TopLevelListBuilder(list).build()).collect(Collectors.toSet()); return expList.equals(actualList); }); diff --git a/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/test/AbstractDataTreeChangeListenerTest.java b/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/test/AbstractDataTreeChangeListenerTest.java index b11d595450..249b765838 100644 --- a/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/test/AbstractDataTreeChangeListenerTest.java +++ b/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/test/AbstractDataTreeChangeListenerTest.java @@ -7,25 +7,25 @@ */ package org.opendaylight.mdsal.binding.dom.adapter.test; +import static java.util.Objects.requireNonNull; import static org.junit.Assert.fail; -import com.google.common.util.concurrent.SettableFuture; +import com.google.common.base.Stopwatch; import com.google.common.util.concurrent.Uninterruptibles; import java.util.ArrayDeque; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Deque; import java.util.List; import java.util.Objects; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; +import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.mdsal.binding.api.DataObjectModification.ModificationType; import org.opendaylight.mdsal.binding.api.DataTreeChangeListener; import org.opendaylight.mdsal.binding.api.DataTreeIdentifier; import org.opendaylight.mdsal.binding.api.DataTreeModification; import org.opendaylight.mdsal.common.api.LogicalDatastoreType; +import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; @@ -47,41 +47,20 @@ public class AbstractDataTreeChangeListenerTest extends AbstractConcurrentDataBr boolean apply(T data); } - protected static final class TestListener implements DataTreeChangeListener { - private final SettableFuture>> future = SettableFuture.create(); - private final List> accumulatedChanges = new ArrayList<>(); - private final Deque> matchers; - private final int expChangeCount; + protected static final class ModificationCollector implements AutoCloseable { + private final TestListener listener; + private final Registration reg; - private TestListener(final List> matchers) { - this.matchers = new ArrayDeque<>(matchers); - expChangeCount = this.matchers.size(); + private ModificationCollector(final TestListener listener, final Registration reg) { + this.listener = requireNonNull(listener); + this.reg = requireNonNull(reg); } - @Override - public void onDataTreeChanged(final Collection> changes) { - synchronized (accumulatedChanges) { - accumulatedChanges.addAll(changes); - if (expChangeCount == accumulatedChanges.size()) { - future.set(List.copyOf(accumulatedChanges)); - } - } - } + @SafeVarargs + public final void assertModifications(final Matcher... inOrder) { + final var matchers = new ArrayDeque<>(Arrays.asList(inOrder)); + final var changes = new ArrayDeque<>(listener.awaitChanges(matchers.size())); - public List> changes() { - try { - final var changes = future.get(5, TimeUnit.SECONDS); - Uninterruptibles.sleepUninterruptibly(500, TimeUnit.MILLISECONDS); - return changes; - } catch (InterruptedException | TimeoutException | ExecutionException e) { - throw new AssertionError(String.format( - "Data tree change notifications not received. Expected: %s. Actual: %s - %s", - expChangeCount, accumulatedChanges.size(), accumulatedChanges), e); - } - } - - public void verify() { - final var changes = new ArrayDeque<>(changes()); while (!changes.isEmpty()) { final var mod = changes.pop(); final var matcher = matchers.peek(); @@ -101,9 +80,60 @@ public class AbstractDataTreeChangeListenerTest extends AbstractConcurrentDataBr } } - public boolean hasChanges() { - synchronized (accumulatedChanges) { - return !accumulatedChanges.isEmpty(); + @Override + public void close() { + reg.close(); + } + } + + private static final class TestListener implements DataTreeChangeListener { + private final Deque> accumulatedChanges = new ArrayDeque<>(); + + private boolean synced; + + @Override + public synchronized void onDataTreeChanged(final Collection> changes) { + accumulatedChanges.addAll(changes); + synced = true; + } + + @Override + public synchronized void onInitialData() { + synced = true; + } + + private void awaitSync() { + final var sw = Stopwatch.createStarted(); + + do { + synchronized (this) { + if (synced) { + return; + } + } + + Uninterruptibles.sleepUninterruptibly(100, TimeUnit.MILLISECONDS); + } while (sw.elapsed(TimeUnit.SECONDS) < 5); + + throw new AssertionError("Failed to achieve initial sync"); + } + + private List> awaitChanges(final int expectedCount) { + final var sw = Stopwatch.createStarted(); + + do { + synchronized (this) { + if (accumulatedChanges.size() >= expectedCount) { + return List.copyOf(accumulatedChanges); + } + } + + Uninterruptibles.sleepUninterruptibly(100, TimeUnit.MILLISECONDS); + } while (sw.elapsed(TimeUnit.SECONDS) < 5); + + synchronized (this) { + throw new AssertionError("Expected %s changes, received only %s".formatted(expectedCount, + accumulatedChanges.size())); } } } @@ -112,42 +142,45 @@ public class AbstractDataTreeChangeListenerTest extends AbstractConcurrentDataBr super(true); } - @SafeVarargs - protected final TestListener createListener(final LogicalDatastoreType store, - final InstanceIdentifier path, final Matcher... matchers) { - final var listener = new TestListener<>(Arrays.asList(matchers)); - getDataBroker().registerDataTreeChangeListener(DataTreeIdentifier.create(store, path), listener); - return listener; + protected final @NonNull ModificationCollector createCollector( + final LogicalDatastoreType store, final InstanceIdentifier path) { + final var listener = new TestListener(); + final var reg = getDataBroker().registerDataTreeChangeListener(DataTreeIdentifier.create(store, path), + listener); + listener.awaitSync(); + return new ModificationCollector<>(listener, reg); } - public static Matcher match(final ModificationType type, final InstanceIdentifier path, - final DataMatcher checkDataBefore, final DataMatcher checkDataAfter) { + public static @NonNull Matcher match(final ModificationType type, + final InstanceIdentifier path, final DataMatcher checkDataBefore, + final DataMatcher checkDataAfter) { return modification -> type == modification.getRootNode().getModificationType() && path.equals(modification.getRootPath().getRootIdentifier()) && checkDataBefore.apply(modification.getRootNode().getDataBefore()) && checkDataAfter.apply(modification.getRootNode().getDataAfter()); } - public static Matcher match(final ModificationType type, final InstanceIdentifier path, - final T expDataBefore, final T expDataAfter) { + public static @NonNull Matcher match(final ModificationType type, + final InstanceIdentifier path, final T expDataBefore, final T expDataAfter) { return match(type, path, dataBefore -> Objects.equals(expDataBefore, dataBefore), (DataMatcher) dataAfter -> Objects.equals(expDataAfter, dataAfter)); } - public static Matcher added(final InstanceIdentifier path, final T data) { + public static @NonNull Matcher added(final InstanceIdentifier path, final T data) { return match(ModificationType.WRITE, path, null, data); } - public static Matcher replaced(final InstanceIdentifier path, final T dataBefore, - final T dataAfter) { + public static @NonNull Matcher replaced(final InstanceIdentifier path, + final T dataBefore, final T dataAfter) { return match(ModificationType.WRITE, path, dataBefore, dataAfter); } - public static Matcher deleted(final InstanceIdentifier path, final T dataBefore) { + public static @NonNull Matcher deleted(final InstanceIdentifier path, + final T dataBefore) { return match(ModificationType.DELETE, path, dataBefore, null); } - public static Matcher subtreeModified(final InstanceIdentifier path, + public static @NonNull Matcher subtreeModified(final InstanceIdentifier path, final T dataBefore, final T dataAfter) { return match(ModificationType.SUBTREE_MODIFIED, path, dataBefore, dataAfter); } -- 2.36.6