Migrate some tests to new ImmutableNodes
[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.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;
48
49 /**
50  * Unit tests for DataTreeChangeListenerSupport.
51  *
52  * @author Thomas Pantelis
53  */
54 public class DataTreeChangeListenerSupportTest extends AbstractShardTest {
55     private Shard shard;
56     private TestActorRef<Shard> shardActor;
57
58     @Override
59     @Before
60     public void setUp() throws Exception {
61         super.setUp();
62         createShard();
63     }
64
65     @Override
66     @After
67     public void tearDown() {
68         super.tearDown();
69         actorFactory.close();
70     }
71
72     @Test
73     public void testChangeListenerWithNoInitialData() {
74         MockDataTreeChangeListener listener = registerChangeListener(TEST_PATH, 0).getKey();
75
76         listener.expectNoMoreChanges("Unexpected initial change event");
77     }
78
79     @Test
80     public void testInitialChangeListenerEventWithContainerPath() throws DataValidationFailedException {
81         writeToStore(shard.getDataStore(), TEST_PATH, ImmutableNodes.newContainerBuilder()
82             .withNodeIdentifier(new NodeIdentifier(TEST_QNAME))
83             .build());
84
85         Entry<MockDataTreeChangeListener, ActorSelection> entry = registerChangeListener(TEST_PATH, 1);
86         MockDataTreeChangeListener listener = entry.getKey();
87
88         listener.waitForChangeEvents();
89         listener.verifyNotifiedData(TEST_PATH);
90
91         listener.reset(1);
92
93         writeToStore(shard.getDataStore(), TEST_PATH, ImmutableNodes.newContainerBuilder()
94             .withNodeIdentifier(new NodeIdentifier(TEST_QNAME))
95             .build());
96         listener.waitForChangeEvents();
97         listener.verifyNotifiedData(TEST_PATH);
98
99         listener.reset(1);
100         TestKit kit = new TestKit(getSystem());
101         entry.getValue().tell(CloseDataTreeNotificationListenerRegistration.getInstance(), kit.getRef());
102         kit.expectMsgClass(Duration.ofSeconds(5), CloseDataTreeNotificationListenerRegistrationReply.class);
103
104         writeToStore(shard.getDataStore(), TEST_PATH, ImmutableNodes.newContainerBuilder()
105             .withNodeIdentifier(new NodeIdentifier(TEST_QNAME))
106             .build());
107         listener.verifyNoNotifiedData(TEST_PATH);
108     }
109
110     @Test
111     public void testInitialChangeListenerEventWithListPath() throws DataValidationFailedException {
112         mergeToStore(shard.getDataStore(), TEST_PATH, testNodeWithOuter(1, 2));
113
114         MockDataTreeChangeListener listener = registerChangeListener(OUTER_LIST_PATH, 1).getKey();
115
116         listener.waitForChangeEvents();
117         listener.verifyNotifiedData(OUTER_LIST_PATH);
118     }
119
120     @Test
121     public void testInitialChangeListenerEventWithWildcardedListPath() throws DataValidationFailedException {
122         mergeToStore(shard.getDataStore(), TEST_PATH, testNodeWithOuter(1, 2));
123
124         MockDataTreeChangeListener listener =
125                 registerChangeListener(OUTER_LIST_PATH.node(OUTER_LIST_QNAME), 1).getKey();
126
127         listener.waitForChangeEvents();
128         listener.verifyNotifiedData(outerEntryPath(1), outerEntryPath(2));
129     }
130
131     @Test
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")))));
135
136         MockDataTreeChangeListener listener = registerChangeListener(
137                 OUTER_LIST_PATH.node(OUTER_LIST_QNAME).node(INNER_LIST_QNAME).node(INNER_LIST_QNAME), 1).getKey();
138
139         listener.waitForChangeEvents();
140         listener.verifyNotifiedData(innerEntryPath(1, "one"), innerEntryPath(1, "two"), innerEntryPath(2, "three"),
141                 innerEntryPath(2, "four"));
142
143         // Register for a specific outer list entry
144
145         MockDataTreeChangeListener listener2 = registerChangeListener(
146                 OUTER_LIST_PATH.node(outerEntryKey(1)).node(INNER_LIST_QNAME).node(INNER_LIST_QNAME), 1).getKey();
147
148         listener2.waitForChangeEvents();
149         listener2.verifyNotifiedData(innerEntryPath(1, "one"), innerEntryPath(1, "two"));
150         listener2.verifyNoNotifiedData(innerEntryPath(2, "three"), innerEntryPath(2, "four"));
151
152         listener.reset(1);
153         listener2.reset(1);
154
155         mergeToStore(shard.getDataStore(), TEST_PATH, testNodeWithOuter(outerNode(
156                 outerNodeEntry(1, innerNode("three")))));
157
158         listener.waitForChangeEvents();
159         listener.verifyNotifiedData(innerEntryPath(1, "three"));
160
161         listener2.waitForChangeEvents();
162         listener2.verifyNotifiedData(innerEntryPath(1, "three"));
163     }
164
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));
170
171         RegisterDataTreeNotificationListenerReply reply;
172         try {
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) {
177             throw e;
178         } catch (Exception e) {
179             throw new RuntimeException(e);
180         }
181         return new SimpleEntry<>(listener, getSystem().actorSelection(reply.getListenerRegistrationPath()));
182     }
183
184     private void createShard() {
185         shardActor = actorFactory.createTestActor(newShardProps());
186         ShardTestKit.waitUntilLeader(shardActor);
187         shard = shardActor.underlyingActor();
188     }
189 }