Add OnDemandShardState to report additional Shard state
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / test / java / org / opendaylight / controller / cluster / datastore / DataChangeListenerSupportTest.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.junit.Assert.assertEquals;
11 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.INNER_LIST_QNAME;
12 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.OUTER_CONTAINER_PATH;
13 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.OUTER_CONTAINER_QNAME;
14 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.OUTER_LIST_PATH;
15 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.OUTER_LIST_QNAME;
16 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.TEST_PATH;
17 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.TEST_QNAME;
18 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.innerEntryPath;
19 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.innerNode;
20 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.outerEntryKey;
21 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.outerEntryPath;
22 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.outerNode;
23 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.outerNodeEntry;
24 import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.testNodeWithOuter;
25
26 import akka.actor.ActorRef;
27 import akka.testkit.TestActorRef;
28 import org.junit.After;
29 import org.junit.Before;
30 import org.junit.Test;
31 import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListener;
32 import org.opendaylight.controller.cluster.datastore.utils.MockDataChangeListener;
33 import org.opendaylight.controller.cluster.raft.TestActorFactory;
34 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
35 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
36 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
37 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
38
39 /**
40  * Unit tests for DataChangeListenerSupport.
41  *
42  * @author Thomas Pantelis
43  */
44 public class DataChangeListenerSupportTest extends AbstractShardTest {
45     private final TestActorFactory actorFactory = new TestActorFactory(getSystem());
46
47     private Shard shard;
48     private DataChangeListenerSupport support;
49
50     @Before
51     public void setup() throws InterruptedException {
52         shard = createShard();
53         support = new DataChangeListenerSupport(shard);
54     }
55
56     @Override
57     @After
58     public void tearDown() {
59         super.tearDown();
60         actorFactory.close();
61     }
62
63     @Test
64     public void testChangeListenerWithNoInitialData() throws Exception {
65         MockDataChangeListener listener = registerChangeListener(TEST_PATH, DataChangeScope.ONE, 0, true);
66
67         listener.expectNoMoreChanges("Unexpected initial change event");
68     }
69
70     @Test
71     public void testInitialChangeListenerEventWithContainerPath() throws Exception {
72         writeToStore(shard.getDataStore(), TEST_PATH, ImmutableNodes.containerNode(TEST_QNAME));
73
74         MockDataChangeListener listener = registerChangeListener(TEST_PATH, DataChangeScope.ONE, 1, true);
75
76         listener.waitForChangeEvents(TEST_PATH);
77     }
78
79     @Test
80     public void testInitialChangeListenerEventWithListPath() throws Exception {
81         mergeToStore(shard.getDataStore(), TEST_PATH, testNodeWithOuter(1, 2));
82
83         MockDataChangeListener listener = registerChangeListener(OUTER_LIST_PATH, DataChangeScope.ONE, 1, true);
84
85         listener.waitForChangeEvents();
86         assertEquals("Outer entry 1 present", true, NormalizedNodes.findNode(
87                 listener.getCreatedData(0, OUTER_LIST_PATH), outerEntryKey(1)).isPresent());
88         assertEquals("Outer entry 2 present", true, NormalizedNodes.findNode(
89                 listener.getCreatedData(0, OUTER_LIST_PATH), outerEntryKey(2)).isPresent());
90     }
91
92     @Test
93     public void testInitialChangeListenerEventWithWildcardedListPath() throws Exception {
94         mergeToStore(shard.getDataStore(), TEST_PATH, testNodeWithOuter(1, 2));
95         writeToStore(shard.getDataStore(), OUTER_CONTAINER_PATH, ImmutableNodes.containerNode(OUTER_CONTAINER_QNAME));
96
97         MockDataChangeListener listener = registerChangeListener(OUTER_LIST_PATH.node(OUTER_LIST_QNAME),
98                 DataChangeScope.ONE, 1, true);
99
100         listener.waitForChangeEvents();
101         listener.verifyCreatedData(0, outerEntryPath(1));
102         listener.verifyCreatedData(0, outerEntryPath(2));
103         listener.verifyNoCreatedData(0, OUTER_CONTAINER_PATH);
104     }
105
106     @Test
107     public void testInitialChangeListenerEventWithNestedWildcardedListsPath() throws Exception {
108         mergeToStore(shard.getDataStore(), TEST_PATH, testNodeWithOuter(outerNode(
109                 outerNodeEntry(1, innerNode("one", "two")), outerNodeEntry(2, innerNode("three", "four")))));
110
111         MockDataChangeListener listener = registerChangeListener(
112                 OUTER_LIST_PATH.node(OUTER_LIST_QNAME).node(INNER_LIST_QNAME).node(INNER_LIST_QNAME),
113                 DataChangeScope.ONE, 1, true);
114
115         listener.waitForChangeEvents();
116         listener.verifyCreatedData(0, innerEntryPath(1, "one"));
117         listener.verifyCreatedData(0, innerEntryPath(1, "two"));
118         listener.verifyCreatedData(0, innerEntryPath(2, "three"));
119         listener.verifyCreatedData(0, innerEntryPath(2, "four"));
120
121         // Register for a specific outer list entry
122
123         MockDataChangeListener listener2 = registerChangeListener(
124                 OUTER_LIST_PATH.node(outerEntryKey(1)).node(INNER_LIST_QNAME).node(INNER_LIST_QNAME),
125                 DataChangeScope.ONE, 1, true);
126
127         listener2.waitForChangeEvents();
128         listener2.verifyCreatedData(0, innerEntryPath(1, "one"));
129         listener2.verifyCreatedData(0, innerEntryPath(1, "two"));
130         listener2.verifyNoCreatedData(0, innerEntryPath(2, "three"));
131         listener2.verifyNoCreatedData(0, innerEntryPath(2, "four"));
132     }
133
134     @Test
135     public void testInitialChangeListenerEventWhenNotInitiallyLeader() throws Exception {
136         mergeToStore(shard.getDataStore(), TEST_PATH, testNodeWithOuter(outerNode(
137                 outerNodeEntry(1, innerNode("one", "two")), outerNodeEntry(2, innerNode("three", "four")))));
138
139         MockDataChangeListener listener = registerChangeListener(
140                 OUTER_LIST_PATH.node(OUTER_LIST_QNAME).node(INNER_LIST_QNAME).node(INNER_LIST_QNAME),
141                 DataChangeScope.ONE, 0, false);
142
143         listener.expectNoMoreChanges("Unexpected initial change event");
144         listener.reset(1);
145
146         support.onLeadershipChange(true, true);
147
148         listener.waitForChangeEvents();
149         listener.verifyCreatedData(0, innerEntryPath(1, "one"));
150         listener.verifyCreatedData(0, innerEntryPath(1, "two"));
151         listener.verifyCreatedData(0, innerEntryPath(2, "three"));
152         listener.verifyCreatedData(0, innerEntryPath(2, "four"));
153     }
154
155     private MockDataChangeListener registerChangeListener(final YangInstanceIdentifier path, final DataChangeScope scope,
156             final int expectedEvents, final boolean isLeader) {
157         MockDataChangeListener listener = new MockDataChangeListener(expectedEvents);
158         ActorRef dclActor = actorFactory.createActor(DataChangeListener.props(listener, path));
159
160         support.onMessage(new RegisterChangeListener(path, dclActor, scope, false), isLeader, true);
161         return listener;
162     }
163
164     private Shard createShard() {
165         TestActorRef<Shard> actor = actorFactory.createTestActor(newShardProps());
166         return actor.underlyingActor();
167     }
168 }