Migrate ActorUtils to java.util.Optional
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / test / java / org / opendaylight / controller / cluster / sharding / CDSShardAccessImplTest.java
1 /*
2  * Copyright (c) 2017 Cisco 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.sharding;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertTrue;
12 import static org.junit.Assert.fail;
13 import static org.mockito.ArgumentMatchers.any;
14 import static org.mockito.ArgumentMatchers.eq;
15 import static org.mockito.Mockito.doNothing;
16 import static org.mockito.Mockito.doReturn;
17 import static org.mockito.Mockito.doThrow;
18 import static org.mockito.Mockito.mock;
19 import static org.mockito.Mockito.verify;
20 import static org.mockito.Mockito.verifyNoMoreInteractions;
21
22 import akka.actor.ActorRef;
23 import akka.dispatch.Futures;
24 import java.util.Optional;
25 import java.util.concurrent.TimeUnit;
26 import org.junit.Before;
27 import org.junit.Test;
28 import org.opendaylight.controller.cluster.datastore.AbstractActorTest;
29 import org.opendaylight.controller.cluster.datastore.DatastoreContext;
30 import org.opendaylight.controller.cluster.datastore.exceptions.LocalShardNotFoundException;
31 import org.opendaylight.controller.cluster.datastore.utils.ActorUtils;
32 import org.opendaylight.controller.cluster.dom.api.LeaderLocation;
33 import org.opendaylight.controller.cluster.dom.api.LeaderLocationListener;
34 import org.opendaylight.controller.cluster.dom.api.LeaderLocationListenerRegistration;
35 import org.opendaylight.controller.cluster.raft.LeadershipTransferFailedException;
36 import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
37 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
38 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
39 import scala.concurrent.Future;
40 import scala.concurrent.duration.FiniteDuration;
41
42 public class CDSShardAccessImplTest extends AbstractActorTest {
43
44     private static final DOMDataTreeIdentifier TEST_ID =
45             new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH);
46
47     private CDSShardAccessImpl shardAccess;
48     private ActorUtils context;
49
50     @Before
51     public void setUp() {
52         context = mock(ActorUtils.class);
53         final DatastoreContext datastoreContext = DatastoreContext.newBuilder().build();
54         doReturn(Optional.of(getSystem().deadLetters())).when(context).findLocalShard(any());
55         doReturn(datastoreContext).when(context).getDatastoreContext();
56         doReturn(getSystem()).when(context).getActorSystem();
57         shardAccess = new CDSShardAccessImpl(TEST_ID, context);
58     }
59
60     @Test
61     @SuppressWarnings("checkstyle:IllegalCatch")
62     public void testRegisterLeaderLocationListener() {
63         final LeaderLocationListener listener1 = mock(LeaderLocationListener.class);
64
65         // first registration should be OK
66         shardAccess.registerLeaderLocationListener(listener1);
67
68         // second registration should fail with IllegalArgumentEx
69         try {
70             shardAccess.registerLeaderLocationListener(listener1);
71             fail("Should throw exception");
72         } catch (final Exception e) {
73             assertTrue(e instanceof IllegalArgumentException);
74         }
75
76         // null listener registration should fail with NPE
77         try {
78             shardAccess.registerLeaderLocationListener(null);
79             fail("Should throw exception");
80         } catch (final Exception e) {
81             assertTrue(e instanceof NullPointerException);
82         }
83
84         // registering listener on closed shard access should fail with IllegalStateEx
85         final LeaderLocationListener listener2 = mock(LeaderLocationListener.class);
86         shardAccess.close();
87         try {
88             shardAccess.registerLeaderLocationListener(listener2);
89             fail("Should throw exception");
90         } catch (final Exception ex) {
91             assertTrue(ex instanceof IllegalStateException);
92         }
93     }
94
95     @Test
96     @SuppressWarnings("checkstyle:IllegalCatch")
97     public void testOnLeaderLocationChanged() {
98         final LeaderLocationListener listener1 = mock(LeaderLocationListener.class);
99         doThrow(new RuntimeException("Failed")).when(listener1).onLeaderLocationChanged(any());
100         final LeaderLocationListener listener2 = mock(LeaderLocationListener.class);
101         doNothing().when(listener2).onLeaderLocationChanged(any());
102         final LeaderLocationListener listener3 = mock(LeaderLocationListener.class);
103         doNothing().when(listener3).onLeaderLocationChanged(any());
104
105         final LeaderLocationListenerRegistration<?> reg1 = shardAccess.registerLeaderLocationListener(listener1);
106         final LeaderLocationListenerRegistration<?> reg2 = shardAccess.registerLeaderLocationListener(listener2);
107         final LeaderLocationListenerRegistration<?> reg3 = shardAccess.registerLeaderLocationListener(listener3);
108
109         // Error in listener1 should not affect dispatching change to other listeners
110         shardAccess.onLeaderLocationChanged(LeaderLocation.LOCAL);
111         verify(listener1).onLeaderLocationChanged(eq(LeaderLocation.LOCAL));
112         verify(listener2).onLeaderLocationChanged(eq(LeaderLocation.LOCAL));
113         verify(listener3).onLeaderLocationChanged(eq(LeaderLocation.LOCAL));
114
115         // Closed listeners shouldn't see new leader location changes
116         reg1.close();
117         reg2.close();
118         shardAccess.onLeaderLocationChanged(LeaderLocation.REMOTE);
119         verify(listener3).onLeaderLocationChanged(eq(LeaderLocation.REMOTE));
120         verifyNoMoreInteractions(listener1);
121         verifyNoMoreInteractions(listener2);
122
123         // Closed shard access should not dispatch any new events
124         shardAccess.close();
125         shardAccess.onLeaderLocationChanged(LeaderLocation.UNKNOWN);
126         verifyNoMoreInteractions(listener1);
127         verifyNoMoreInteractions(listener2);
128         verifyNoMoreInteractions(listener3);
129
130         reg3.close();
131     }
132
133     @Test
134     @SuppressWarnings("checkstyle:IllegalCatch")
135     public void testGetShardIdentifier() {
136         assertEquals(shardAccess.getShardIdentifier(), TEST_ID);
137
138         // closed shard access should throw illegal state
139         shardAccess.close();
140         try {
141             shardAccess.getShardIdentifier();
142             fail("Exception expected");
143         } catch (final Exception e) {
144             assertTrue(e instanceof IllegalStateException);
145         }
146     }
147
148     @Test
149     @SuppressWarnings("checkstyle:IllegalCatch")
150     public void testGetLeaderLocation() {
151         // new shard access does not know anything about leader location
152         assertEquals(shardAccess.getLeaderLocation(), LeaderLocation.UNKNOWN);
153
154         // we start getting leader location changes notifications
155         shardAccess.onLeaderLocationChanged(LeaderLocation.LOCAL);
156         assertEquals(shardAccess.getLeaderLocation(), LeaderLocation.LOCAL);
157
158         shardAccess.onLeaderLocationChanged(LeaderLocation.REMOTE);
159         shardAccess.onLeaderLocationChanged(LeaderLocation.UNKNOWN);
160         assertEquals(shardAccess.getLeaderLocation(), LeaderLocation.UNKNOWN);
161
162         // closed shard access throws illegal state
163         shardAccess.close();
164         try {
165             shardAccess.getLeaderLocation();
166             fail("Should have failed with IllegalStateEx");
167         } catch (Exception e) {
168             assertTrue(e instanceof IllegalStateException);
169         }
170     }
171
172     @Test
173     @SuppressWarnings("checkstyle:IllegalCatch")
174     public void testMakeLeaderLocal() throws Exception {
175         final FiniteDuration timeout = new FiniteDuration(5, TimeUnit.SECONDS);
176         final ActorRef localShardRef = mock(ActorRef.class);
177         final Future<ActorRef> localShardRefFuture = Futures.successful(localShardRef);
178         doReturn(localShardRefFuture).when(context).findLocalShardAsync(any());
179
180         // MakeLeaderLocal will reply with success
181         doReturn(Futures.successful(null)).when(context).executeOperationAsync((ActorRef) any(), any(), any());
182         doReturn(getSystem().dispatcher()).when(context).getClientDispatcher();
183         assertEquals(waitOnAsyncTask(shardAccess.makeLeaderLocal(), timeout), null);
184
185         // MakeLeaderLocal will reply with failure
186         doReturn(Futures.failed(new LeadershipTransferFailedException("Failure")))
187                 .when(context).executeOperationAsync((ActorRef) any(), any(), any());
188
189         try {
190             waitOnAsyncTask(shardAccess.makeLeaderLocal(), timeout);
191             fail("makeLeaderLocal operation should not be successful");
192         } catch (final Exception e) {
193             assertTrue(e instanceof LeadershipTransferFailedException);
194         }
195
196         // we don't even find local shard
197         doReturn(Futures.failed(new LocalShardNotFoundException("Local shard not found")))
198                 .when(context).findLocalShardAsync(any());
199
200         try {
201             waitOnAsyncTask(shardAccess.makeLeaderLocal(), timeout);
202             fail("makeLeaderLocal operation should not be successful");
203         } catch (final Exception e) {
204             assertTrue(e instanceof LeadershipTransferFailedException);
205             assertTrue(e.getCause() instanceof LocalShardNotFoundException);
206         }
207
208         // closed shard access should throw IllegalStateEx
209         shardAccess.close();
210         try {
211             shardAccess.makeLeaderLocal();
212             fail("Should have thrown IllegalStateEx. ShardAccess is closed");
213         } catch (final Exception e) {
214             assertTrue(e instanceof IllegalStateException);
215         }
216     }
217 }