Bug 1225: Added DataBroker and DataChangeListener test suite. 26/8926/2
authorTony Tkacik <ttkacik@cisco.com>
Thu, 10 Jul 2014 15:24:07 +0000 (17:24 +0200)
committerTony Tkacik <ttkacik@cisco.com>
Fri, 11 Jul 2014 10:01:08 +0000 (12:01 +0200)
Change-Id: I53a06845024936253f576e5095b3d00c15a47e99
Signed-off-by: Tony Tkacik <ttkacik@cisco.com>
opendaylight/commons/opendaylight/pom.xml
opendaylight/md-sal/sal-binding-broker/pom.xml
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/BindingNormalizedCodecTest.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/ListInsertionDataChangeListenerTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/WriteTransactionTest.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AbstractDataBrokerTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AbstractDataChangeListenerTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AbstractSchemaAwareTest.java [moved from opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/AbstractSchemaAwareTest.java with 64% similarity]
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AssertCollections.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/DataBrokerTestCustomizer.java [new file with mode: 0644]
opendaylight/md-sal/sal-test-model/src/main/java/org/opendaylight/controller/md/sal/test/model/util/ListsBindingUtils.java [new file with mode: 0644]

index bf84183b75b755b9099374d3d2365432a9621288..28c23c8259cd9ca76492fb154b52e0767b67d98f 100644 (file)
         <artifactId>sal-restconf-broker</artifactId>
         <version>${mdsal.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>sal-test-model</artifactId>
+        <version>${mdsal.version}</version>
+      </dependency>
 
       <!-- SAL Extension bundles -->
       <dependency>
index 2f3410dedc8a7222b27c5ec3f6ad7e0a536d6d19..74cceb1cbd55fc786b78e3f111b2a82a60bd8751 100644 (file)
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>sal-test-model</artifactId>
-      <version>${project.version}</version>
+      <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.slf4j</groupId>
index 5ad474a9a3455872452005179973f618426bf29c..6b05b1046f66c427c506457c27bb8bad7d6ac689 100644 (file)
@@ -5,9 +5,9 @@ import javassist.ClassPool;
 
 import org.junit.Test;
 import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
+import org.opendaylight.controller.md.sal.binding.test.AbstractSchemaAwareTest;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeComplexUsesAugment;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeLeafOnlyAugment;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeLeafOnlyUsesAugment;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
@@ -24,7 +24,6 @@ public class BindingNormalizedCodecTest extends AbstractSchemaAwareTest {
     private static final InstanceIdentifier<TopLevelList> BA_TOP_LEVEL_LIST = InstanceIdentifier
             .builder(Top.class).child(TopLevelList.class, TOP_FOO_KEY).toInstance();
     private static final InstanceIdentifier<TreeLeafOnlyAugment> BA_TREE_LEAF_ONLY = BA_TOP_LEVEL_LIST.augmentation(TreeLeafOnlyAugment.class);
-    private static final InstanceIdentifier<TreeLeafOnlyUsesAugment> BA_TREE_LEAF_ONLY_USES = BA_TOP_LEVEL_LIST.augmentation(TreeLeafOnlyUsesAugment.class);
     private static final InstanceIdentifier<TreeComplexUsesAugment> BA_TREE_COMPLEX_USES = BA_TOP_LEVEL_LIST.augmentation(TreeComplexUsesAugment.class);
     private static final QName SIMPLE_VALUE_QNAME = QName.create(TreeComplexUsesAugment.QNAME, "simple-value");
 
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/ListInsertionDataChangeListenerTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/ListInsertionDataChangeListenerTest.java
new file mode 100644 (file)
index 0000000..05bc857
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.binding.impl.test;
+import static org.junit.Assert.assertFalse;
+import static org.opendaylight.controller.md.sal.binding.test.AssertCollections.assertContains;
+import static org.opendaylight.controller.md.sal.binding.test.AssertCollections.assertEmpty;
+import static org.opendaylight.controller.md.sal.binding.test.AssertCollections.assertNotContains;
+import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
+import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.TOP_BAR_KEY;
+import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.TOP_FOO_KEY;
+import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.top;
+import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.topLevelList;
+
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.binding.test.AbstractDataChangeListenerTest;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ *
+ * This testsuite tests explanation for data change scope and data modifications
+ * which were described in
+ * https://lists.opendaylight.org/pipermail/controller-dev/2014-July/005541.html
+ *
+ *
+ */
+public class ListInsertionDataChangeListenerTest extends AbstractDataChangeListenerTest{
+
+    private static final InstanceIdentifier<Top> TOP = InstanceIdentifier.create(Top.class);
+    private static final InstanceIdentifier<TopLevelList> WILDCARDED = TOP.child(TopLevelList.class);
+    private static final InstanceIdentifier<TopLevelList> TOP_FOO = TOP.child(TopLevelList.class, TOP_FOO_KEY);
+    private static final InstanceIdentifier<TopLevelList> TOP_BAR = TOP.child(TopLevelList.class, TOP_BAR_KEY);
+
+
+    @Override
+    protected void setupWithDataBroker(final DataBroker dataBroker) {
+        WriteTransaction initialTx = dataBroker.newWriteOnlyTransaction();
+        initialTx.put(CONFIGURATION, TOP, top(topLevelList(TOP_FOO_KEY)));
+        assertCommit(initialTx.commit());
+    }
+
+    @Test
+    public void replaceTopNodeSubtreeListeners() {
+        TestListener topListener = createListener(CONFIGURATION, TOP, DataChangeScope.SUBTREE);
+        TestListener allListener = createListener(CONFIGURATION, WILDCARDED, DataChangeScope.SUBTREE);
+        TestListener fooListener = createListener(CONFIGURATION, TOP_FOO, DataChangeScope.SUBTREE);
+        TestListener barListener = createListener(CONFIGURATION, TOP_BAR, DataChangeScope.SUBTREE);
+
+        ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction();
+        writeTx.put(CONFIGURATION, TOP, top(topLevelList(TOP_BAR_KEY)));
+        assertCommit(writeTx.commit());
+        AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> top = topListener.event();
+        AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> all = allListener.event();
+        AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> foo = fooListener.event();
+        AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> bar = barListener.event();
+
+        // Listener for TOP element
+        assertContains(top.getOriginalData(), TOP,TOP_FOO);
+        assertContains(top.getCreatedData(), TOP_BAR);
+        assertContains(top.getUpdatedData(), TOP);
+        assertContains(top.getRemovedPaths(), TOP_FOO);
+
+        /*
+         *  Listener for all list items
+         *
+         *  Updated should be empty, since no list item was
+         *  updated, items were only removed and added
+         */
+        assertContains(all.getOriginalData(), TOP_FOO);
+        assertContains(all.getCreatedData(), TOP_BAR);
+        assertEmpty(all.getUpdatedData());
+        assertContains(all.getRemovedPaths(), TOP_FOO);
+
+
+        /*
+         *  Listener for all Foo item
+         *
+         *  This one should see only Foo item removed
+         */
+        assertContains(foo.getOriginalData(), TOP_FOO);
+        assertEmpty(foo.getCreatedData());
+        assertEmpty(foo.getUpdatedData());
+        assertContains(foo.getRemovedPaths(), TOP_FOO);
+
+        /*
+         *  Listener for bar list items
+         *
+         *  Updated should be empty, since no list item was
+         *  updated, items were only removed and added
+         */
+        assertEmpty(bar.getOriginalData());
+        assertContains(bar.getCreatedData(), TOP_BAR);
+        assertEmpty(bar.getUpdatedData());
+        assertEmpty(bar.getRemovedPaths());
+    }
+
+    @Test
+    public void mergeTopNodeSubtreeListeners() {
+        TestListener topListener = createListener(CONFIGURATION, TOP, DataChangeScope.SUBTREE);
+        TestListener allListener = createListener(CONFIGURATION, WILDCARDED, DataChangeScope.SUBTREE);
+        TestListener fooListener = createListener(CONFIGURATION, TOP_FOO, DataChangeScope.SUBTREE);
+        TestListener barListener = createListener(CONFIGURATION, TOP_BAR, DataChangeScope.SUBTREE);
+
+        ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction();
+        writeTx.merge(CONFIGURATION, TOP, top(topLevelList(TOP_BAR_KEY)));
+        assertCommit(writeTx.commit());
+
+        verifyBarOnlyAdded(topListener,allListener,fooListener,barListener);
+    }
+
+    @Test
+    public void putTopBarNodeSubtreeListeners() {
+        TestListener topListener = createListener(CONFIGURATION, TOP, DataChangeScope.SUBTREE);
+        TestListener allListener = createListener(CONFIGURATION, WILDCARDED, DataChangeScope.SUBTREE);
+        TestListener fooListener = createListener(CONFIGURATION, TOP_FOO, DataChangeScope.SUBTREE);
+        TestListener barListener = createListener(CONFIGURATION, TOP_BAR, DataChangeScope.SUBTREE);
+
+        ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction();
+        writeTx.put(CONFIGURATION, TOP_BAR, topLevelList(TOP_BAR_KEY));
+        assertCommit(writeTx.commit());
+
+        verifyBarOnlyAdded(topListener,allListener,fooListener,barListener);
+    }
+
+    @Test
+    public void mergeTopBarNodeSubtreeListeners() {
+        TestListener topListener = createListener(CONFIGURATION, TOP, DataChangeScope.SUBTREE);
+        TestListener allListener = createListener(CONFIGURATION, WILDCARDED, DataChangeScope.SUBTREE);
+        TestListener fooListener = createListener(CONFIGURATION, TOP_FOO, DataChangeScope.SUBTREE);
+        TestListener barListener = createListener(CONFIGURATION, TOP_BAR, DataChangeScope.SUBTREE);
+
+        ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction();
+        writeTx.merge(CONFIGURATION, TOP_BAR, topLevelList(TOP_BAR_KEY));
+        assertCommit(writeTx.commit());
+
+        verifyBarOnlyAdded(topListener,allListener,fooListener,barListener);
+    }
+
+    private void verifyBarOnlyAdded(final TestListener top, final TestListener all, final TestListener foo,
+            final TestListener bar) {
+
+        assertFalse(foo.hasEvent());
+
+        // Listener for TOP element
+        assertContains(top.event().getOriginalData(), TOP);
+        assertNotContains(top.event().getOriginalData(),TOP_FOO);
+        assertContains(top.event().getCreatedData(), TOP_BAR);
+        assertContains(top.event().getUpdatedData(), TOP);
+        assertEmpty(top.event().getRemovedPaths());
+
+        /*
+         *  Listener for all list items
+         *
+         *  Updated should be empty, since no list item was
+         *  updated, items were only removed and added
+         */
+        assertEmpty(all.event().getOriginalData());
+        assertContains(all.event().getCreatedData(), TOP_BAR);
+        assertEmpty(all.event().getUpdatedData());
+        assertEmpty(all.event().getRemovedPaths());
+
+        /*
+         *  Listener for all Foo item
+         *
+         *  Foo Listener should not have foo event
+         */
+        assertFalse(foo.hasEvent());
+
+        /*
+         *  Listener for bar list items
+         *
+         *  Updated should be empty, since no list item was
+         *  updated, items were only removed and added
+         */
+        assertEmpty(bar.event().getOriginalData());
+        assertContains(bar.event().getCreatedData(), TOP_BAR);
+        assertEmpty(bar.event().getUpdatedData());
+        assertEmpty(bar.event().getRemovedPaths());
+    }
+
+}
index ad6e1a77cea9c5294852fe7524c5ef6606c65d95..43e951423c0a2bfdecef87969abd01c51816d28e 100644 (file)
@@ -12,42 +12,29 @@ import static org.junit.Assert.assertEquals;
 import java.util.concurrent.ExecutionException;
 
 import org.junit.Test;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest;
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.TopBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
 
-public class WriteTransactionTest extends AbstractDataServiceTest {
+public class WriteTransactionTest extends AbstractDataBrokerTest {
 
-    private DataBroker dataBroker;
-
-    private static final InstanceIdentifier<Nodes> NODES_PATH = InstanceIdentifier.create(Nodes.class);
-
-    private static final NodeKey NODE_KEY = new NodeKey(new NodeId("foo"));
-
-    private static final InstanceIdentifier<Node> NODE_PATH = NODES_PATH.child(Node.class, NODE_KEY);
-
-    @Override
-    public void setUp() {
-        super.setUp();
-
-        dataBroker = testContext.getDataBroker();
-    }
+    private static final InstanceIdentifier<Top> TOP_PATH = InstanceIdentifier.create(Top.class);
+    private static final TopLevelListKey TOP_LIST_KEY = new TopLevelListKey("foo");
+    private static final InstanceIdentifier<TopLevelList> NODE_PATH = TOP_PATH.child(TopLevelList.class, TOP_LIST_KEY);
 
     @Test
     public void test() throws InterruptedException, ExecutionException {
-        WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
-        writeTx.put(LogicalDatastoreType.OPERATIONAL, NODES_PATH, new NodesBuilder().build());
-        writeTx.put(LogicalDatastoreType.OPERATIONAL, NODE_PATH, new NodeBuilder().setKey(NODE_KEY).build());
+        WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.OPERATIONAL, TOP_PATH, new TopBuilder().build());
+        writeTx.put(LogicalDatastoreType.OPERATIONAL, NODE_PATH, new TopLevelListBuilder().setKey(TOP_LIST_KEY).build());
         assertEquals(TransactionStatus.COMMITED, writeTx.commit().get().getResult());
     }
 
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AbstractDataBrokerTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AbstractDataBrokerTest.java
new file mode 100644 (file)
index 0000000..7f23ac2
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.binding.test;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class AbstractDataBrokerTest extends AbstractSchemaAwareTest {
+
+    private DataBrokerTestCustomizer testCustomizer;
+    private DataBroker dataBroker;
+    private DOMDataBroker domBroker;
+
+
+    @Override
+    protected void setupWithSchema(final SchemaContext context) {
+        testCustomizer = createDataBrokerTestCustomizer();
+        dataBroker = testCustomizer.createDataBroker();
+        domBroker = testCustomizer.createDOMDataBroker();
+        testCustomizer.updateSchema(context);
+        setupWithDataBroker(dataBroker);
+    }
+
+    protected void setupWithDataBroker(final DataBroker dataBroker) {
+        // Intentionally left No-op, subclasses may customize it
+    }
+
+   protected DataBrokerTestCustomizer createDataBrokerTestCustomizer() {
+        return new DataBrokerTestCustomizer();
+    }
+
+    public DataBroker getDataBroker() {
+        return dataBroker;
+    }
+
+    public DOMDataBroker getDomBroker() {
+        return domBroker;
+    }
+
+    protected static final void assertCommit(final ListenableFuture<RpcResult<TransactionStatus>> commit) {
+        try {
+            assertEquals(TransactionStatus.COMMITED,commit.get(500, TimeUnit.MILLISECONDS).getResult());
+        } catch (InterruptedException | ExecutionException | TimeoutException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AbstractDataChangeListenerTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AbstractDataChangeListenerTest.java
new file mode 100644 (file)
index 0000000..7742f37
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.binding.test;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+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.LogicalDatastoreType;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.util.concurrent.SettableFuture;
+
+public abstract class AbstractDataChangeListenerTest extends AbstractDataBrokerTest {
+
+    protected static final class TestListener implements DataChangeListener {
+
+        private final SettableFuture<AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject>> event;
+        private boolean capture = false;
+
+        private TestListener() {
+            event = SettableFuture.create();
+        }
+
+        @Override
+        public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> arg) {
+            if (capture) {
+                event.set(arg);
+            }
+        }
+
+        public AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> event() {
+            try {
+                return event.get(500, TimeUnit.MILLISECONDS);
+            } catch (InterruptedException | TimeoutException | ExecutionException e) {
+                throw new IllegalStateException(e);
+            }
+        }
+
+        public boolean hasEvent() {
+            return event.isDone();
+        }
+
+        public void startCapture() {
+            this.capture = true;
+        }
+    }
+
+    protected final TestListener createListener(final LogicalDatastoreType store, final InstanceIdentifier<?> path,
+            final DataChangeScope scope) {
+        TestListener listener = new TestListener();
+        getDataBroker().registerDataChangeListener(store, path, listener, scope);
+        listener.startCapture();
+        return listener;
+    }
+}
@@ -1,4 +1,11 @@
-package org.opendaylight.controller.md.sal.binding.impl.test;
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.binding.test;
 
 import org.junit.Before;
 import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
@@ -26,7 +33,12 @@ public abstract class AbstractSchemaAwareTest  {
         setupWithSchema(schemaContext);
     }
 
-
+    /**
+     * Setups test with Schema context.
+     * This method is called before {@link #setupWithSchemaService(SchemaService)}
+     *
+     * @param context
+     */
     protected abstract void setupWithSchema(SchemaContext context);
 
 }
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AssertCollections.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AssertCollections.java
new file mode 100644 (file)
index 0000000..25b91bc
--- /dev/null
@@ -0,0 +1,42 @@
+package org.opendaylight.controller.md.sal.binding.test;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.junit.Assert;
+
+public class AssertCollections {
+
+    public static void assertEmpty(final Collection<?> set) {
+        Assert.assertTrue(set.isEmpty());
+    }
+
+    public static void assertEmpty(final Map<?,?> set) {
+        Assert.assertTrue(set.isEmpty());
+    }
+
+    public static void assertContains(final Collection<?> set, final Object... values) {
+        for (Object key : values) {
+            Assert.assertTrue(set.contains(key));
+        }
+
+    }
+
+    public static void assertNotContains(final Collection<?> set, final Object... values) {
+        for (Object key : values) {
+            Assert.assertFalse(set.contains(key));
+        }
+    }
+
+    public static void assertContains(final Map<?,?> map, final Object... values) {
+        for (Object key : values) {
+            Assert.assertTrue(map.containsKey(key));
+        }
+    }
+
+    public static void assertNotContains(final Map<?,?> map, final Object... values) {
+        for (Object key : values) {
+            Assert.assertFalse(map.containsKey(key));
+        }
+    }
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/DataBrokerTestCustomizer.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/DataBrokerTestCustomizer.java
new file mode 100644 (file)
index 0000000..79aa6b6
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.binding.test;
+
+import javassist.ClassPool;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.impl.ForwardedBindingDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.broker.impl.DOMDataBrokerImpl;
+import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
+import org.opendaylight.controller.sal.binding.test.util.MockSchemaService;
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.controller.sal.core.spi.data.DOMStore;
+import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
+public class DataBrokerTestCustomizer {
+
+    private DOMDataBroker domDataBroker;
+    private final RuntimeGeneratedMappingServiceImpl mappingService;
+    private final MockSchemaService schemaService;
+    private ImmutableMap<LogicalDatastoreType, DOMStore> datastores;
+
+    public ImmutableMap<LogicalDatastoreType, DOMStore> createDatastores() {
+        return ImmutableMap.<LogicalDatastoreType, DOMStore>builder()
+                .put(LogicalDatastoreType.OPERATIONAL, createOperationalDatastore())
+                .put(LogicalDatastoreType.CONFIGURATION,createConfigurationDatastore())
+                .build();
+    }
+
+    public DataBrokerTestCustomizer() {
+        schemaService = new MockSchemaService();
+        mappingService = new RuntimeGeneratedMappingServiceImpl(ClassPool.getDefault());
+    }
+
+    public DOMStore createConfigurationDatastore() {
+        InMemoryDOMDataStore store = new InMemoryDOMDataStore("CFG", MoreExecutors.sameThreadExecutor());
+        schemaService.registerSchemaServiceListener(store);
+        return store;
+    }
+
+    public DOMStore createOperationalDatastore() {
+        InMemoryDOMDataStore store = new InMemoryDOMDataStore("OPER", MoreExecutors.sameThreadExecutor());
+        schemaService.registerSchemaServiceListener(store);
+        return store;
+    }
+
+    public DOMDataBroker createDOMDataBroker() {
+        return new DOMDataBrokerImpl(getDatastores(), getCommitCoordinatorExecutor());
+    }
+
+    public ListeningExecutorService getCommitCoordinatorExecutor() {
+        return MoreExecutors.sameThreadExecutor();
+    }
+
+    public DataBroker createDataBroker() {
+        return new ForwardedBindingDataBroker(getDOMDataBroker(), getMappingService(), getSchemaService());
+    }
+
+    private SchemaService getSchemaService() {
+        return schemaService;
+    }
+
+    private BindingIndependentMappingService getMappingService() {
+        return mappingService;
+    }
+
+    private DOMDataBroker getDOMDataBroker() {
+        if(domDataBroker == null) {
+            domDataBroker = createDOMDataBroker();
+        }
+        return domDataBroker;
+    }
+
+    private ImmutableMap<LogicalDatastoreType, DOMStore> getDatastores() {
+        if(datastores == null) {
+            datastores = createDatastores();
+        }
+        return datastores;
+    }
+
+    public void updateSchema(final SchemaContext ctx) {
+        schemaService.changeSchema(ctx);
+        mappingService.onGlobalContextUpdated(ctx);
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-test-model/src/main/java/org/opendaylight/controller/md/sal/test/model/util/ListsBindingUtils.java b/opendaylight/md-sal/sal-test-model/src/main/java/org/opendaylight/controller/md/sal/test/model/util/ListsBindingUtils.java
new file mode 100644 (file)
index 0000000..a0c23ae
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.test.model.util;
+
+import java.util.Arrays;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeComplexUsesAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeComplexUsesAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.complex.from.grouping.ListViaUses;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.complex.from.grouping.ListViaUsesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.complex.from.grouping.ListViaUsesKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.TopBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.top.level.list.NestedList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.top.level.list.NestedListKey;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.collect.ImmutableList;
+
+public class ListsBindingUtils {
+
+    private static final InstanceIdentifier<Top> TOP_PATH = InstanceIdentifier.create(Top.class);
+
+    private ListsBindingUtils() {
+        throw new UnsupportedOperationException();
+    }
+
+    public static final TopLevelListKey TOP_FOO_KEY = new TopLevelListKey("foo");
+    public static final TopLevelListKey TOP_BAR_KEY = new TopLevelListKey("bar");
+    public static final ListViaUsesKey USES_ONE_KEY = new ListViaUsesKey("one");
+    public static final ListViaUsesKey USES_TWO_KEY = new ListViaUsesKey("two");
+
+
+    public static InstanceIdentifier<TopLevelList> path(final TopLevelListKey key) {
+        return TOP_PATH.child(TopLevelList.class, key);
+    }
+
+    public static InstanceIdentifier<NestedList> path(final TopLevelListKey top,final NestedListKey nested) {
+        return path(top).child(NestedList.class, nested);
+    }
+
+    public static InstanceIdentifier<ListViaUses> path(final TopLevelListKey top,final ListViaUsesKey uses) {
+        return path(top).augmentation(TreeComplexUsesAugment.class).child(ListViaUses.class, uses);
+    }
+
+    public static <T extends DataObject & Augmentation<TopLevelList>> InstanceIdentifier<T> path(final TopLevelListKey key, final Class<T> augmentation) {
+        return path(key).augmentation(augmentation);
+    }
+
+    public static Top top(final TopLevelList... listItems) {
+        return new TopBuilder().setTopLevelList(Arrays.asList(listItems)).build();
+    }
+
+    public static TopLevelList topLevelList(final TopLevelListKey key) {
+        return new TopLevelListBuilder().setKey(key).build();
+    }
+
+    public static TopLevelList topLevelList(final TopLevelListKey key, final TreeComplexUsesAugment augment) {
+        TopLevelListBuilder builder = new TopLevelListBuilder().setKey(key);
+        builder.addAugmentation(TreeComplexUsesAugment.class, augment);
+        return builder.build();
+    }
+
+    public static TreeComplexUsesAugment complexUsesAugment(final ListViaUsesKey... keys) {
+        ImmutableList.Builder<ListViaUses> listViaUses = ImmutableList.<ListViaUses> builder();
+        for (ListViaUsesKey key : keys) {
+            listViaUses.add(new ListViaUsesBuilder().setKey(key).build());
+        }
+        return new TreeComplexUsesAugmentBuilder().setListViaUses(listViaUses.build()).build();
+    }
+
+}