Migrate to java.time.Duration
[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.schema.tree.DataValidationFailedException;
44 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
45 import scala.concurrent.Await;
46 import scala.concurrent.duration.FiniteDuration;
47
48 /**
49  * Unit tests for DataTreeChangeListenerSupport.
50  *
51  * @author Thomas Pantelis
52  */
53 public class DataTreeChangeListenerSupportTest extends AbstractShardTest {
54     private Shard shard;
55     private TestActorRef<Shard> shardActor;
56
57     @Override
58     @Before
59     public void setUp() {
60         super.setUp();
61         createShard();
62     }
63
64     @Override
65     @After
66     public void tearDown() {
67         super.tearDown();
68         actorFactory.close();
69     }
70
71     @Test
72     public void testChangeListenerWithNoInitialData() {
73         MockDataTreeChangeListener listener = registerChangeListener(TEST_PATH, 0).getKey();
74
75         listener.expectNoMoreChanges("Unexpected initial change event");
76     }
77
78     @Test
79     public void testInitialChangeListenerEventWithContainerPath() throws DataValidationFailedException {
80         writeToStore(shard.getDataStore(), TEST_PATH, ImmutableNodes.containerNode(TEST_QNAME));
81
82         Entry<MockDataTreeChangeListener, ActorSelection> entry = registerChangeListener(TEST_PATH, 1);
83         MockDataTreeChangeListener listener = entry.getKey();
84
85         listener.waitForChangeEvents();
86         listener.verifyNotifiedData(TEST_PATH);
87
88         listener.reset(1);
89
90         writeToStore(shard.getDataStore(), TEST_PATH, ImmutableNodes.containerNode(TEST_QNAME));
91         listener.waitForChangeEvents();
92         listener.verifyNotifiedData(TEST_PATH);
93
94         listener.reset(1);
95         TestKit kit = new TestKit(getSystem());
96         entry.getValue().tell(CloseDataTreeNotificationListenerRegistration.getInstance(), kit.getRef());
97         kit.expectMsgClass(Duration.ofSeconds(5), CloseDataTreeNotificationListenerRegistrationReply.class);
98
99         writeToStore(shard.getDataStore(), TEST_PATH, ImmutableNodes.containerNode(TEST_QNAME));
100         listener.verifyNoNotifiedData(TEST_PATH);
101     }
102
103     @Test
104     public void testInitialChangeListenerEventWithListPath() throws DataValidationFailedException {
105         mergeToStore(shard.getDataStore(), TEST_PATH, testNodeWithOuter(1, 2));
106
107         MockDataTreeChangeListener listener = registerChangeListener(OUTER_LIST_PATH, 1).getKey();
108
109         listener.waitForChangeEvents();
110         listener.verifyNotifiedData(OUTER_LIST_PATH);
111     }
112
113     @Test
114     public void testInitialChangeListenerEventWithWildcardedListPath() throws DataValidationFailedException {
115         mergeToStore(shard.getDataStore(), TEST_PATH, testNodeWithOuter(1, 2));
116
117         MockDataTreeChangeListener listener =
118                 registerChangeListener(OUTER_LIST_PATH.node(OUTER_LIST_QNAME), 1).getKey();
119
120         listener.waitForChangeEvents();
121         listener.verifyNotifiedData(outerEntryPath(1), outerEntryPath(2));
122     }
123
124     @Test
125     public void testInitialChangeListenerEventWithNestedWildcardedListsPath() throws DataValidationFailedException {
126         mergeToStore(shard.getDataStore(), TEST_PATH, testNodeWithOuter(outerNode(
127                 outerNodeEntry(1, innerNode("one", "two")), outerNodeEntry(2, innerNode("three", "four")))));
128
129         MockDataTreeChangeListener listener = registerChangeListener(
130                 OUTER_LIST_PATH.node(OUTER_LIST_QNAME).node(INNER_LIST_QNAME).node(INNER_LIST_QNAME), 1).getKey();
131
132         listener.waitForChangeEvents();
133         listener.verifyNotifiedData(innerEntryPath(1, "one"), innerEntryPath(1, "two"), innerEntryPath(2, "three"),
134                 innerEntryPath(2, "four"));
135
136         // Register for a specific outer list entry
137
138         MockDataTreeChangeListener listener2 = registerChangeListener(
139                 OUTER_LIST_PATH.node(outerEntryKey(1)).node(INNER_LIST_QNAME).node(INNER_LIST_QNAME), 1).getKey();
140
141         listener2.waitForChangeEvents();
142         listener2.verifyNotifiedData(innerEntryPath(1, "one"), innerEntryPath(1, "two"));
143         listener2.verifyNoNotifiedData(innerEntryPath(2, "three"), innerEntryPath(2, "four"));
144
145         listener.reset(1);
146         listener2.reset(1);
147
148         mergeToStore(shard.getDataStore(), TEST_PATH, testNodeWithOuter(outerNode(
149                 outerNodeEntry(1, innerNode("three")))));
150
151         listener.waitForChangeEvents();
152         listener.verifyNotifiedData(innerEntryPath(1, "three"));
153
154         listener2.waitForChangeEvents();
155         listener2.verifyNotifiedData(innerEntryPath(1, "three"));
156     }
157
158     @SuppressWarnings("checkstyle:IllegalCatch")
159     private Entry<MockDataTreeChangeListener, ActorSelection> registerChangeListener(final YangInstanceIdentifier path,
160             final int expectedEvents) {
161         MockDataTreeChangeListener listener = new MockDataTreeChangeListener(expectedEvents);
162         ActorRef dclActor = actorFactory.createActor(DataTreeChangeListenerActor.props(listener, TestModel.TEST_PATH));
163
164         RegisterDataTreeNotificationListenerReply reply;
165         try {
166             reply = (RegisterDataTreeNotificationListenerReply)
167                     Await.result(Patterns.ask(shardActor, new RegisterDataTreeChangeListener(path, dclActor, false),
168                         new Timeout(5, TimeUnit.SECONDS)), FiniteDuration.create(5, TimeUnit.SECONDS));
169         } catch (RuntimeException e) {
170             throw e;
171         } catch (Exception e) {
172             throw new RuntimeException(e);
173         }
174         return new SimpleEntry<>(listener, getSystem().actorSelection(reply.getListenerRegistrationPath()));
175     }
176
177     private void createShard() {
178         shardActor = actorFactory.createTestActor(newShardProps());
179         ShardTestKit.waitUntilLeader(shardActor);
180         shard = shardActor.underlyingActor();
181     }
182 }