2 * Copyright (c) 2015 Brocade Communications Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.cluster.datastore;
10 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.INNER_LIST_QNAME;
11 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.OUTER_LIST_PATH;
12 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.OUTER_LIST_QNAME;
13 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.TEST_PATH;
14 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.TEST_QNAME;
15 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.innerEntryPath;
16 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.innerNode;
17 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.outerEntryKey;
18 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.outerEntryPath;
19 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.outerNode;
20 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.outerNodeEntry;
21 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.testNodeWithOuter;
23 import akka.actor.ActorRef;
24 import akka.actor.ActorSelection;
25 import akka.pattern.Patterns;
26 import akka.testkit.TestActorRef;
27 import akka.testkit.javadsl.TestKit;
28 import akka.util.Timeout;
29 import java.time.Duration;
30 import java.util.AbstractMap.SimpleEntry;
31 import java.util.Map.Entry;
32 import java.util.concurrent.TimeUnit;
33 import org.junit.After;
34 import org.junit.Before;
35 import org.junit.Test;
36 import org.opendaylight.controller.cluster.datastore.messages.CloseDataTreeNotificationListenerRegistration;
37 import org.opendaylight.controller.cluster.datastore.messages.CloseDataTreeNotificationListenerRegistrationReply;
38 import org.opendaylight.controller.cluster.datastore.messages.RegisterDataTreeChangeListener;
39 import org.opendaylight.controller.cluster.datastore.messages.RegisterDataTreeNotificationListenerReply;
40 import org.opendaylight.controller.cluster.datastore.utils.MockDataTreeChangeListener;
41 import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
42 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
43 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
44 import org.opendaylight.yangtools.yang.data.spi.node.ImmutableNodes;
45 import org.opendaylight.yangtools.yang.data.tree.api.DataValidationFailedException;
46 import scala.concurrent.Await;
47 import scala.concurrent.duration.FiniteDuration;
50 * Unit tests for DataTreeChangeListenerSupport.
52 * @author Thomas Pantelis
54 public class DataTreeChangeListenerSupportTest extends AbstractShardTest {
56 private TestActorRef<Shard> shardActor;
60 public void setUp() throws Exception {
67 public void tearDown() {
73 public void testChangeListenerWithNoInitialData() {
74 MockDataTreeChangeListener listener = registerChangeListener(TEST_PATH, 0).getKey();
76 listener.expectNoMoreChanges("Unexpected initial change event");
80 public void testInitialChangeListenerEventWithContainerPath() throws DataValidationFailedException {
81 writeToStore(shard.getDataStore(), TEST_PATH, ImmutableNodes.newContainerBuilder()
82 .withNodeIdentifier(new NodeIdentifier(TEST_QNAME))
85 Entry<MockDataTreeChangeListener, ActorSelection> entry = registerChangeListener(TEST_PATH, 1);
86 MockDataTreeChangeListener listener = entry.getKey();
88 listener.waitForChangeEvents();
89 listener.verifyNotifiedData(TEST_PATH);
93 writeToStore(shard.getDataStore(), TEST_PATH, ImmutableNodes.newContainerBuilder()
94 .withNodeIdentifier(new NodeIdentifier(TEST_QNAME))
96 listener.waitForChangeEvents();
97 listener.verifyNotifiedData(TEST_PATH);
100 TestKit kit = new TestKit(getSystem());
101 entry.getValue().tell(CloseDataTreeNotificationListenerRegistration.getInstance(), kit.getRef());
102 kit.expectMsgClass(Duration.ofSeconds(5), CloseDataTreeNotificationListenerRegistrationReply.class);
104 writeToStore(shard.getDataStore(), TEST_PATH, ImmutableNodes.newContainerBuilder()
105 .withNodeIdentifier(new NodeIdentifier(TEST_QNAME))
107 listener.verifyNoNotifiedData(TEST_PATH);
111 public void testInitialChangeListenerEventWithListPath() throws DataValidationFailedException {
112 mergeToStore(shard.getDataStore(), TEST_PATH, testNodeWithOuter(1, 2));
114 MockDataTreeChangeListener listener = registerChangeListener(OUTER_LIST_PATH, 1).getKey();
116 listener.waitForChangeEvents();
117 listener.verifyNotifiedData(OUTER_LIST_PATH);
121 public void testInitialChangeListenerEventWithWildcardedListPath() throws DataValidationFailedException {
122 mergeToStore(shard.getDataStore(), TEST_PATH, testNodeWithOuter(1, 2));
124 MockDataTreeChangeListener listener =
125 registerChangeListener(OUTER_LIST_PATH.node(OUTER_LIST_QNAME), 1).getKey();
127 listener.waitForChangeEvents();
128 listener.verifyNotifiedData(outerEntryPath(1), outerEntryPath(2));
132 public void testInitialChangeListenerEventWithNestedWildcardedListsPath() throws DataValidationFailedException {
133 mergeToStore(shard.getDataStore(), TEST_PATH, testNodeWithOuter(outerNode(
134 outerNodeEntry(1, innerNode("one", "two")), outerNodeEntry(2, innerNode("three", "four")))));
136 MockDataTreeChangeListener listener = registerChangeListener(
137 OUTER_LIST_PATH.node(OUTER_LIST_QNAME).node(INNER_LIST_QNAME).node(INNER_LIST_QNAME), 1).getKey();
139 listener.waitForChangeEvents();
140 listener.verifyNotifiedData(innerEntryPath(1, "one"), innerEntryPath(1, "two"), innerEntryPath(2, "three"),
141 innerEntryPath(2, "four"));
143 // Register for a specific outer list entry
145 MockDataTreeChangeListener listener2 = registerChangeListener(
146 OUTER_LIST_PATH.node(outerEntryKey(1)).node(INNER_LIST_QNAME).node(INNER_LIST_QNAME), 1).getKey();
148 listener2.waitForChangeEvents();
149 listener2.verifyNotifiedData(innerEntryPath(1, "one"), innerEntryPath(1, "two"));
150 listener2.verifyNoNotifiedData(innerEntryPath(2, "three"), innerEntryPath(2, "four"));
155 mergeToStore(shard.getDataStore(), TEST_PATH, testNodeWithOuter(outerNode(
156 outerNodeEntry(1, innerNode("three")))));
158 listener.waitForChangeEvents();
159 listener.verifyNotifiedData(innerEntryPath(1, "three"));
161 listener2.waitForChangeEvents();
162 listener2.verifyNotifiedData(innerEntryPath(1, "three"));
165 @SuppressWarnings("checkstyle:IllegalCatch")
166 private Entry<MockDataTreeChangeListener, ActorSelection> registerChangeListener(final YangInstanceIdentifier path,
167 final int expectedEvents) {
168 MockDataTreeChangeListener listener = new MockDataTreeChangeListener(expectedEvents);
169 ActorRef dclActor = actorFactory.createActor(DataTreeChangeListenerActor.props(listener, TestModel.TEST_PATH));
171 RegisterDataTreeNotificationListenerReply reply;
173 reply = (RegisterDataTreeNotificationListenerReply)
174 Await.result(Patterns.ask(shardActor, new RegisterDataTreeChangeListener(path, dclActor, false),
175 new Timeout(5, TimeUnit.SECONDS)), FiniteDuration.create(5, TimeUnit.SECONDS));
176 } catch (RuntimeException e) {
178 } catch (Exception e) {
179 throw new RuntimeException(e);
181 return new SimpleEntry<>(listener, getSystem().actorSelection(reply.getListenerRegistrationPath()));
184 private void createShard() {
185 shardActor = actorFactory.createTestActor(newShardProps());
186 ShardTestKit.waitUntilLeader(shardActor);
187 shard = shardActor.underlyingActor();