Bug 7271: Use mdsal AbstractDOMStoreTreeChangePublisher in CDS
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / test / java / org / opendaylight / controller / cluster / datastore / DataTreeChangeListenerSupportTest.java
1 /*
2  * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.cluster.datastore;
9
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;
22
23 import akka.actor.ActorRef;
24 import akka.actor.ActorSelection;
25 import akka.pattern.Patterns;
26 import akka.testkit.JavaTestKit;
27 import akka.testkit.TestActorRef;
28 import akka.util.Timeout;
29 import com.google.common.base.Throwables;
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.CloseDataTreeChangeListenerRegistration;
37 import org.opendaylight.controller.cluster.datastore.messages.CloseDataTreeChangeListenerRegistrationReply;
38 import org.opendaylight.controller.cluster.datastore.messages.RegisterDataTreeChangeListener;
39 import org.opendaylight.controller.cluster.datastore.messages.RegisterDataTreeChangeListenerReply;
40 import org.opendaylight.controller.cluster.datastore.utils.MockDataTreeChangeListener;
41 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
42 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
43 import scala.concurrent.Await;
44 import scala.concurrent.duration.Duration;
45
46 /**
47  * Unit tests for DataTreeChangeListenerSupport.
48  *
49  * @author Thomas Pantelis
50  */
51 public class DataTreeChangeListenerSupportTest extends AbstractShardTest {
52     private Shard shard;
53     private TestActorRef<Shard> shardActor;
54
55     @Override
56     @Before
57     public void setUp() {
58         super.setUp();
59         createShard();
60     }
61
62     @Override
63     @After
64     public void tearDown() {
65         super.tearDown();
66         actorFactory.close();
67     }
68
69     @Test
70     public void testChangeListenerWithNoInitialData() throws Exception {
71         MockDataTreeChangeListener listener = registerChangeListener(TEST_PATH, 0).getKey();
72
73         listener.expectNoMoreChanges("Unexpected initial change event");
74     }
75
76     @Test
77     public void testInitialChangeListenerEventWithContainerPath() throws Exception {
78         writeToStore(shard.getDataStore(), TEST_PATH, ImmutableNodes.containerNode(TEST_QNAME));
79
80         Entry<MockDataTreeChangeListener, ActorSelection> entry = registerChangeListener(TEST_PATH, 1);
81         MockDataTreeChangeListener listener = entry.getKey();
82
83         listener.waitForChangeEvents();
84         listener.verifyNotifiedData(TEST_PATH);
85
86         listener.reset(1);
87
88         writeToStore(shard.getDataStore(), TEST_PATH, ImmutableNodes.containerNode(TEST_QNAME));
89         listener.waitForChangeEvents();
90         listener.verifyNotifiedData(TEST_PATH);
91
92         listener.reset(1);
93         JavaTestKit kit = new JavaTestKit(getSystem());
94         entry.getValue().tell(CloseDataTreeChangeListenerRegistration.getInstance(), kit.getRef());
95         kit.expectMsgClass(JavaTestKit.duration("5 seconds"), CloseDataTreeChangeListenerRegistrationReply.class);
96
97         writeToStore(shard.getDataStore(), TEST_PATH, ImmutableNodes.containerNode(TEST_QNAME));
98         listener.verifyNoNotifiedData(TEST_PATH);
99     }
100
101     @Test
102     public void testInitialChangeListenerEventWithListPath() throws Exception {
103         mergeToStore(shard.getDataStore(), TEST_PATH, testNodeWithOuter(1, 2));
104
105         MockDataTreeChangeListener listener = registerChangeListener(OUTER_LIST_PATH, 1).getKey();
106
107         listener.waitForChangeEvents();
108         listener.verifyNotifiedData(OUTER_LIST_PATH);
109     }
110
111     @Test
112     public void testInitialChangeListenerEventWithWildcardedListPath() throws Exception {
113         mergeToStore(shard.getDataStore(), TEST_PATH, testNodeWithOuter(1, 2));
114
115         MockDataTreeChangeListener listener =
116                 registerChangeListener(OUTER_LIST_PATH.node(OUTER_LIST_QNAME), 1).getKey();
117
118         listener.waitForChangeEvents();
119         listener.verifyNotifiedData(outerEntryPath(1), outerEntryPath(2));
120     }
121
122     @Test
123     public void testInitialChangeListenerEventWithNestedWildcardedListsPath() throws Exception {
124         mergeToStore(shard.getDataStore(), TEST_PATH, testNodeWithOuter(outerNode(
125                 outerNodeEntry(1, innerNode("one", "two")), outerNodeEntry(2, innerNode("three", "four")))));
126
127         MockDataTreeChangeListener listener = registerChangeListener(
128                 OUTER_LIST_PATH.node(OUTER_LIST_QNAME).node(INNER_LIST_QNAME).node(INNER_LIST_QNAME), 1).getKey();
129
130         listener.waitForChangeEvents();
131         listener.verifyNotifiedData(innerEntryPath(1, "one"), innerEntryPath(1, "two"), innerEntryPath(2, "three"),
132                 innerEntryPath(2, "four"));
133
134         // Register for a specific outer list entry
135
136         MockDataTreeChangeListener listener2 = registerChangeListener(
137                 OUTER_LIST_PATH.node(outerEntryKey(1)).node(INNER_LIST_QNAME).node(INNER_LIST_QNAME), 1).getKey();
138
139         listener2.waitForChangeEvents();
140         listener2.verifyNotifiedData(innerEntryPath(1, "one"), innerEntryPath(1, "two"));
141         listener2.verifyNoNotifiedData(innerEntryPath(2, "three"), innerEntryPath(2, "four"));
142
143         listener.reset(1);
144         listener2.reset(1);
145
146         mergeToStore(shard.getDataStore(), TEST_PATH, testNodeWithOuter(outerNode(
147                 outerNodeEntry(1, innerNode("three")))));
148
149         listener.waitForChangeEvents();
150         listener.verifyNotifiedData(innerEntryPath(1, "three"));
151
152         listener2.waitForChangeEvents();
153         listener2.verifyNotifiedData(innerEntryPath(1, "three"));
154     }
155
156     @SuppressWarnings("checkstyle:IllegalCatch")
157     private Entry<MockDataTreeChangeListener, ActorSelection> registerChangeListener(final YangInstanceIdentifier path,
158             final int expectedEvents) {
159         MockDataTreeChangeListener listener = new MockDataTreeChangeListener(expectedEvents);
160         ActorRef dclActor = actorFactory.createActor(DataTreeChangeListenerActor.props(listener));
161
162         try {
163             RegisterDataTreeChangeListenerReply reply = (RegisterDataTreeChangeListenerReply)
164                 Await.result(Patterns.ask(shardActor, new RegisterDataTreeChangeListener(path, dclActor, false),
165                     new Timeout(5, TimeUnit.SECONDS)), Duration.create(5, TimeUnit.SECONDS));
166             return new SimpleEntry<>(listener, getSystem().actorSelection(reply.getListenerRegistrationPath()));
167
168         } catch (Exception e) {
169             Throwables.propagate(e);
170             return null;
171         }
172     }
173
174     private void createShard() {
175         shardActor = actorFactory.createTestActor(newShardProps());
176         ShardTestKit.waitUntilLeader(shardActor);
177         shard = shardActor.underlyingActor();
178     }
179 }