X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-inmemory-datastore%2Fsrc%2Ftest%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fmd%2Fsal%2Fdom%2Fstore%2Fimpl%2FDatastoreTestTask.java;h=a62c0ba88f1fd5226e947160030ee651ac2c418d;hp=8384dd8d1bd154972fa6e41cd369d1abf56e45cc;hb=refs%2Fchanges%2F00%2F71800%2F2;hpb=6f07382ef045eb71a3875e23ef71701e8af67814 diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/DatastoreTestTask.java b/opendaylight/md-sal/sal-inmemory-datastore/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/DatastoreTestTask.java index 8384dd8d1b..a62c0ba88f 100644 --- a/opendaylight/md-sal/sal-inmemory-datastore/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/DatastoreTestTask.java +++ b/opendaylight/md-sal/sal-inmemory-datastore/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/DatastoreTestTask.java @@ -10,91 +10,111 @@ package org.opendaylight.controller.md.sal.dom.store.impl; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.SettableFuture; +import com.google.common.util.concurrent.Uninterruptibles; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; - -import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; -import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; -import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener; +import java.util.function.Function; +import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener; import org.opendaylight.controller.sal.core.spi.data.DOMStore; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreTreeChangePublisher; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; - -import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.SettableFuture; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; +import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType; public class DatastoreTestTask { private final DOMStore store; - private AsyncDataChangeListener> changeListener; private WriteTransactionCustomizer setup; private WriteTransactionCustomizer write; private ReadTransactionVerifier read; private WriteTransactionCustomizer cleanup; private YangInstanceIdentifier changePath; - private DataChangeScope changeScope; - private volatile boolean postSetup = false; - private final ChangeEventListener internalListener; + private DOMStoreTreeChangePublisher storeTreeChangePublisher; + private ChangeEventListener internalListener; private final TestDCLExecutorService dclExecutorService; public DatastoreTestTask(final DOMStore datastore, final TestDCLExecutorService dclExecutorService) { this.store = datastore; this.dclExecutorService = dclExecutorService; - internalListener = new ChangeEventListener(); } - public DatastoreTestTask changeListener(final YangInstanceIdentifier path, final DataChangeScope scope, - final AsyncDataChangeListener> changeListener) { - this.changeListener = changeListener; + @SafeVarargs + public final DatastoreTestTask changeListener(final YangInstanceIdentifier path, + Function... matchers) { + assertTrue(store instanceof DOMStoreTreeChangePublisher); + this.storeTreeChangePublisher = (DOMStoreTreeChangePublisher)store; this.changePath = path; - this.changeScope = scope; + this.internalListener = new ChangeEventListener(matchers); return this; } - public DatastoreTestTask changeListener(final YangInstanceIdentifier path, final DataChangeScope scope) { - this.changePath = path; - this.changeScope = scope; - return this; + public static Function added(YangInstanceIdentifier path) { + return candidate -> candidate.getRootNode().getModificationType() == ModificationType.WRITE + && path.equals(candidate.getRootPath()) && !candidate.getRootNode().getDataBefore().isPresent() + && candidate.getRootNode().getDataAfter().isPresent(); + } + + public static Function replaced(YangInstanceIdentifier path) { + return candidate -> candidate.getRootNode().getModificationType() == ModificationType.WRITE + && path.equals(candidate.getRootPath()) && candidate.getRootNode().getDataBefore().isPresent() + && candidate.getRootNode().getDataAfter().isPresent(); + } + + public static Function deleted(YangInstanceIdentifier path) { + return candidate -> candidate.getRootNode().getModificationType() == ModificationType.DELETE + && path.equals(candidate.getRootPath()) && candidate.getRootNode().getDataBefore().isPresent() + && !candidate.getRootNode().getDataAfter().isPresent(); + } + + public static Function subtreeModified(YangInstanceIdentifier path) { + return candidate -> candidate.getRootNode().getModificationType() == ModificationType.SUBTREE_MODIFIED + && path.equals(candidate.getRootPath()) && candidate.getRootNode().getDataBefore().isPresent() + && candidate.getRootNode().getDataAfter().isPresent(); } - public DatastoreTestTask setup(final WriteTransactionCustomizer setup) { - this.setup = setup; + public DatastoreTestTask setup(final WriteTransactionCustomizer customizer) { + this.setup = customizer; return this; } - public DatastoreTestTask test(final WriteTransactionCustomizer write) { - this.write = write; + public DatastoreTestTask test(final WriteTransactionCustomizer customizer) { + this.write = customizer; return this; } - public DatastoreTestTask read(final ReadTransactionVerifier read) { - this.read = read; + public DatastoreTestTask read(final ReadTransactionVerifier customizer) { + this.read = customizer; return this; } - public DatastoreTestTask cleanup(final WriteTransactionCustomizer cleanup) { - this.cleanup = cleanup; + public DatastoreTestTask cleanup(final WriteTransactionCustomizer customizer) { + this.cleanup = customizer; return this; } - public void run() throws InterruptedException, ExecutionException, TimeoutException { + public void run() throws Exception { if (setup != null) { execute(setup); } ListenerRegistration registration = null; if (changePath != null) { - registration = store.registerChangeListener(changePath, internalListener, changeScope); + registration = storeTreeChangePublisher.registerTreeChangeListener(changePath, internalListener); } Preconditions.checkState(write != null, "Write Transaction must be set."); - postSetup = true; dclExecutorService.afterTestSetup(); execute(write); @@ -102,9 +122,6 @@ public class DatastoreTestTask { registration.close(); } - if (changeListener != null) { - changeListener.onDataChanged(getChangeEvent()); - } if (read != null) { read.verify(store.newReadOnlyTransaction()); } @@ -113,26 +130,12 @@ public class DatastoreTestTask { } } - public AsyncDataChangeEvent> getChangeEvent() { - try { - return internalListener.receivedChange.get(10, TimeUnit.SECONDS); - } catch( Exception e ) { - fail( "Error getting the AsyncDataChangeEvent from the Future: " + e ); - } - - // won't get here - return null; + public void verifyChangeEvents() { + internalListener.verifyChangeEvents(); } public void verifyNoChangeEvent() { - try { - Object unexpected = internalListener.receivedChange.get(500, TimeUnit.MILLISECONDS); - fail( "Got unexpected AsyncDataChangeEvent from the Future: " + unexpected ); - } catch( TimeoutException e ) { - // Expected - } catch( Exception e ) { - fail( "Error getting the AsyncDataChangeEvent from the Future: " + e ); - } + internalListener.verifyNoChangeEvent(); } private void execute(final WriteTransactionCustomizer writeCustomizer) throws InterruptedException, @@ -153,48 +156,86 @@ public class DatastoreTestTask { void verify(DOMStoreReadTransaction tx); } - private final class ChangeEventListener implements - AsyncDataChangeListener> { + private final class ChangeEventListener implements DOMDataTreeChangeListener { - protected final SettableFuture>> receivedChange = SettableFuture - .create(); + final SettableFuture> future = SettableFuture.create(); + final Collection accumulatedChanges = new ArrayList<>(); + final Function[] matchers; + final int expChangeCount; + + ChangeEventListener(Function[] matchers) { + this.expChangeCount = matchers.length; + this.matchers = matchers; + } + + Collection changes() { + try { + Collection changes = internalListener.future.get(10, TimeUnit.SECONDS); + Uninterruptibles.sleepUninterruptibly(500, TimeUnit.MILLISECONDS); + return changes; + } catch (TimeoutException e) { + throw new AssertionError(String.format( + "Data tree change notifications not received. Expected: %s. Actual: %s - %s", + expChangeCount, accumulatedChanges.size(), accumulatedChanges), e); + } catch (InterruptedException | ExecutionException e) { + throw new AssertionError("Data tree change notifications failed", e); + } + } + + void verifyChangeEvents() { + Collection changes = new ArrayList<>(changes()); + Iterator iter = changes.iterator(); + while (iter.hasNext()) { + DataTreeCandidate dataTreeModification = iter.next(); + for (Function matcher: matchers) { + if (matcher.apply(dataTreeModification)) { + iter.remove(); + break; + } + } + } + + if (!changes.isEmpty()) { + DataTreeCandidate mod = changes.iterator().next(); + fail(String.format("Received unexpected notification: type: %s, path: %s, before: %s, after: %s", + mod.getRootNode().getModificationType(), mod.getRootPath(), + mod.getRootNode().getDataBefore(), mod.getRootNode().getDataAfter())); + } + } + + void verifyNoChangeEvent() { + try { + Object unexpected = internalListener.future.get(500, TimeUnit.MILLISECONDS); + fail("Got unexpected Data tree change notifications: " + unexpected); + } catch (TimeoutException e) { + // Expected + } catch (InterruptedException | ExecutionException e) { + throw new AssertionError("Data tree change notifications failed", e); + } + } @Override - public void onDataChanged(final AsyncDataChangeEvent> change) { - if (postSetup) { - receivedChange.set(change); + public void onDataTreeChanged(Collection changes) { + synchronized (accumulatedChanges) { + accumulatedChanges.addAll(changes); + if (expChangeCount == accumulatedChanges.size()) { + future.set(new ArrayList<>(accumulatedChanges)); + } } } } public static final WriteTransactionCustomizer simpleWrite(final YangInstanceIdentifier path, final NormalizedNode data) { - return new WriteTransactionCustomizer() { - - @Override - public void customize(final DOMStoreReadWriteTransaction tx) { - tx.write(path, data); - } - }; + return tx -> tx.write(path, data); } public static final WriteTransactionCustomizer simpleMerge(final YangInstanceIdentifier path, final NormalizedNode data) { - return new WriteTransactionCustomizer() { - - @Override - public void customize(final DOMStoreReadWriteTransaction tx) { - tx.merge(path, data); - } - }; + return tx -> tx.merge(path, data); } public static final WriteTransactionCustomizer simpleDelete(final YangInstanceIdentifier path) { - return new WriteTransactionCustomizer() { - @Override - public void customize(final DOMStoreReadWriteTransaction tx) { - tx.delete(path); - } - }; + return tx -> tx.delete(path); } }