2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.mdsal.singleton.dom.impl;
10 import static org.junit.Assert.assertFalse;
11 import static org.junit.Assert.assertNotNull;
12 import static org.junit.Assert.assertNull;
13 import static org.junit.Assert.assertThrows;
14 import static org.junit.Assert.assertTrue;
15 import static org.mockito.Mockito.doNothing;
16 import static org.mockito.Mockito.doReturn;
17 import static org.mockito.Mockito.never;
18 import static org.mockito.Mockito.verify;
19 import static org.opendaylight.mdsal.eos.common.api.EntityOwnershipStateChange.LOCAL_OWNERSHIP_GRANTED;
20 import static org.opendaylight.mdsal.eos.common.api.EntityOwnershipStateChange.LOCAL_OWNERSHIP_LOST_NEW_OWNER;
21 import static org.opendaylight.mdsal.eos.common.api.EntityOwnershipStateChange.LOCAL_OWNERSHIP_LOST_NO_OWNER;
22 import static org.opendaylight.mdsal.eos.common.api.EntityOwnershipStateChange.REMOTE_OWNERSHIP_CHANGED;
23 import static org.opendaylight.mdsal.eos.common.api.EntityOwnershipStateChange.REMOTE_OWNERSHIP_LOST_NO_OWNER;
24 import static org.opendaylight.mdsal.singleton.dom.impl.EOSClusterSingletonServiceProvider.CLOSE_SERVICE_ENTITY_TYPE;
25 import static org.opendaylight.mdsal.singleton.dom.impl.EOSClusterSingletonServiceProvider.SERVICE_ENTITY_TYPE;
27 import com.google.common.util.concurrent.Futures;
28 import com.google.common.util.concurrent.ListenableFuture;
29 import java.util.concurrent.ExecutionException;
30 import org.eclipse.jdt.annotation.NonNull;
31 import org.junit.Before;
32 import org.junit.Test;
33 import org.junit.runner.RunWith;
34 import org.mockito.Mock;
35 import org.mockito.junit.MockitoJUnitRunner;
36 import org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException;
37 import org.opendaylight.mdsal.eos.dom.api.DOMEntity;
38 import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipListener;
39 import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipService;
40 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
41 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
42 import org.opendaylight.yangtools.concepts.Registration;
45 * Testing {@link ActiveServiceGroup}.
47 @RunWith(MockitoJUnitRunner.StrictStubs.class)
48 public class ActiveServiceGroupTest {
49 private static final String SERVICE_IDENTIFIER = "TestServiceIdent";
50 private static final ServiceGroupIdentifier SERVICE_GROUP_IDENT = new ServiceGroupIdentifier(SERVICE_IDENTIFIER);
52 public static final @NonNull DOMEntity MAIN_ENTITY = new DOMEntity(SERVICE_ENTITY_TYPE, SERVICE_IDENTIFIER);
53 public static final @NonNull DOMEntity CLOSE_ENTITY = new DOMEntity(CLOSE_SERVICE_ENTITY_TYPE, SERVICE_IDENTIFIER);
56 public ClusterSingletonService mockClusterSingletonService;
58 public ClusterSingletonService mockClusterSingletonServiceSecond;
60 public Registration mockEntityCandReg;
62 public Registration mockCloseEntityCandReg;
64 public DOMEntityOwnershipListener mockEosListener;
66 public DOMEntityOwnershipService mockEosService;
68 private ActiveServiceGroup singletonServiceGroup;
69 private ServiceRegistration firstReg;
70 private ServiceRegistration secondReg;
73 * Initialization functionality for every Tests in this suite.
75 * @throws CandidateAlreadyRegisteredException unexpected exception.
78 public void setup() throws CandidateAlreadyRegisteredException {
79 doReturn(mockEntityCandReg).when(mockEosService).registerCandidate(MAIN_ENTITY);
80 doReturn(mockCloseEntityCandReg).when(mockEosService).registerCandidate(CLOSE_ENTITY);
81 doNothing().when(mockEntityCandReg).close();
82 doNothing().when(mockCloseEntityCandReg).close();
83 doNothing().when(mockClusterSingletonService).instantiateServiceInstance();
84 doReturn(Futures.immediateFuture(null)).when(mockClusterSingletonService).closeServiceInstance();
86 doReturn(SERVICE_GROUP_IDENT).when(mockClusterSingletonService).getIdentifier();
87 doReturn(SERVICE_GROUP_IDENT).when(mockClusterSingletonServiceSecond).getIdentifier();
89 firstReg = new ServiceRegistration(mockClusterSingletonService) {
91 protected void removeRegistration() {
95 secondReg = new ServiceRegistration(mockClusterSingletonServiceSecond) {
97 protected void removeRegistration() {
102 singletonServiceGroup = new ActiveServiceGroup(SERVICE_GROUP_IDENT, MAIN_ENTITY, CLOSE_ENTITY, mockEosService);
106 * Test NULL ServiceIdent input for new ServiceGroup instance.
109 public void instantiationClusterSingletonServiceGroupNullIdentTest() {
110 assertThrows(NullPointerException.class,
111 () -> new ActiveServiceGroup(null, MAIN_ENTITY, CLOSE_ENTITY, mockEosService));
115 * Test NULL MainEntity input for new ServiceGroup instance.
118 public void instantiationClusterSingletonServiceGroupNullMainEntityTest() {
119 assertThrows(NullPointerException.class,
120 () -> new ActiveServiceGroup(SERVICE_GROUP_IDENT, null, CLOSE_ENTITY, mockEosService));
124 * Test NULL CloseEntity input for new ServiceGroup instance.
127 public void instantiationClusterSingletonServiceGroupNullCloseEntityTest() {
128 assertThrows(NullPointerException.class,
129 () -> new ActiveServiceGroup(SERVICE_GROUP_IDENT, MAIN_ENTITY, null, mockEosService));
133 * Test NULL EntityOwnershipService input for new ServiceGroup instance.
136 public void instantiationClusterSingletonServiceGroupNullEOS_Test() {
137 assertThrows(NullPointerException.class,
138 () -> new ActiveServiceGroup(SERVICE_GROUP_IDENT, MAIN_ENTITY, CLOSE_ENTITY, null));
142 * Test GoldPath for initialization ServiceGroup.
145 public void initializationClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
146 singletonServiceGroup.initialize();
147 verify(mockEosService).registerCandidate(MAIN_ENTITY);
151 * Test GoldPath for NO-TO-SLAVE entity Candidate role change.
153 * @throws CandidateAlreadyRegisteredException - unexpected exception
156 public void initializationSlaveTest() throws CandidateAlreadyRegisteredException {
157 singletonServiceGroup.initialize();
158 verify(mockEosService).registerCandidate(MAIN_ENTITY);
159 singletonServiceGroup.registerService(firstReg);
160 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_LOST_NEW_OWNER, false);
161 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
162 verify(mockEosService, never()).registerCandidate(CLOSE_ENTITY);
166 * Test GoldPath for NO-TO-SLAVE but without MASTER entity Candidate role change.
168 * @throws CandidateAlreadyRegisteredException - unexpected exception
171 public void initializationNoMasterTest() throws CandidateAlreadyRegisteredException {
172 singletonServiceGroup.initialize();
173 verify(mockEosService).registerCandidate(MAIN_ENTITY);
174 singletonServiceGroup.registerService(firstReg);
175 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_LOST_NO_OWNER, false);
176 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
177 verify(mockEosService, never()).registerCandidate(CLOSE_ENTITY);
181 * Test GoldPath for InJeopardy entity Candidate role change.
183 * @throws CandidateAlreadyRegisteredException - unexpected exception
186 public void initializationInJeopardyTest() throws CandidateAlreadyRegisteredException {
187 singletonServiceGroup.initialize();
188 verify(mockEosService).registerCandidate(MAIN_ENTITY);
189 singletonServiceGroup.registerService(firstReg);
190 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, REMOTE_OWNERSHIP_LOST_NO_OWNER, true);
191 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
192 verify(mockEosService, never()).registerCandidate(CLOSE_ENTITY);
196 * Test GoldPath for registration SingletonService.
198 * @throws CandidateAlreadyRegisteredException - unexpected exception
201 public void serviceRegistrationClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
202 singletonServiceGroup.initialize();
203 verify(mockEosService).registerCandidate(MAIN_ENTITY);
204 singletonServiceGroup.registerService(firstReg);
208 * Test GoldPath for registration SingletonService.
210 * @throws CandidateAlreadyRegisteredException - unexpected exception
213 public void serviceRegistrationClusterSingletonServiceGroupTwoServiceTest()
214 throws CandidateAlreadyRegisteredException {
215 singletonServiceGroup.initialize();
216 verify(mockEosService).registerCandidate(MAIN_ENTITY);
217 singletonServiceGroup.registerService(firstReg);
218 singletonServiceGroup.registerService(secondReg);
222 * Test GoldPath for unregistration SingletonService don't call closeServiceInstance
223 * without mastership and don't remove ServiceGroup from map.
225 * @throws CandidateAlreadyRegisteredException - unexpected exception
228 public void serviceUnregistrationClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
229 singletonServiceGroup.initialize();
230 verify(mockEosService).registerCandidate(MAIN_ENTITY);
231 singletonServiceGroup.registerService(firstReg);
232 assertNotNull(singletonServiceGroup.unregisterService(firstReg));
233 verify(mockClusterSingletonService, never()).closeServiceInstance();
237 * Test GoldPath for unregistration SingletonService don't call closeServiceInstance
238 * without mastership and don't remove ServiceGroup from map.
240 * @throws CandidateAlreadyRegisteredException - unexpected exception
243 public void serviceUnregistrationClusterSingletonServiceGroupTwoServicesTest()
244 throws CandidateAlreadyRegisteredException {
245 singletonServiceGroup.initialize();
246 verify(mockEosService).registerCandidate(MAIN_ENTITY);
247 singletonServiceGroup.registerService(firstReg);
248 singletonServiceGroup.registerService(secondReg);
249 assertNull(singletonServiceGroup.unregisterService(firstReg));
250 verify(mockClusterSingletonService, never()).closeServiceInstance();
254 * Test GoldPath get Slave role for registered main entity.
256 * @throws CandidateAlreadyRegisteredException - unexpected exception
259 public void getSlaveClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
260 singletonServiceGroup.initialize();
261 verify(mockEosService).registerCandidate(MAIN_ENTITY);
262 singletonServiceGroup.registerService(firstReg);
263 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_LOST_NEW_OWNER, false);
264 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
268 * Test GoldPath get Master role for registered main entity.
270 * @throws CandidateAlreadyRegisteredException - unexpected exception
273 public void tryToTakeLeaderClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
274 singletonServiceGroup.initialize();
275 verify(mockEosService).registerCandidate(MAIN_ENTITY);
276 singletonServiceGroup.registerService(firstReg);
277 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
278 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
279 verify(mockEosService).registerCandidate(CLOSE_ENTITY);
283 * Test GoldPath get Master role for registered close entity.
285 * @throws CandidateAlreadyRegisteredException - unexpected exception
288 public void takeMasterClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
289 singletonServiceGroup.initialize();
290 verify(mockEosService).registerCandidate(MAIN_ENTITY);
291 singletonServiceGroup.registerService(firstReg);
292 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
293 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
294 verify(mockEosService).registerCandidate(CLOSE_ENTITY);
295 singletonServiceGroup.ownershipChanged(CLOSE_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
296 verify(mockClusterSingletonService).instantiateServiceInstance();
300 * Test GoldPath get Master role for registered entity but initial Slave
301 * role for closeEntity.
303 * @throws CandidateAlreadyRegisteredException - unexpected exception
306 public void waitToTakeMasterClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
307 singletonServiceGroup.initialize();
308 verify(mockEosService).registerCandidate(MAIN_ENTITY);
309 singletonServiceGroup.registerService(firstReg);
310 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
311 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
312 verify(mockEosService).registerCandidate(CLOSE_ENTITY);
313 singletonServiceGroup.ownershipChanged(CLOSE_ENTITY, REMOTE_OWNERSHIP_CHANGED, false);
314 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
315 verify(mockClusterSingletonService, never()).closeServiceInstance();
319 * Test inJeopardy validation during wait phase for Master role for closeEntity.
321 * @throws CandidateAlreadyRegisteredException - unexpected exception
324 public void inJeopardyInWaitPhaseClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
325 singletonServiceGroup.initialize();
326 verify(mockEosService).registerCandidate(MAIN_ENTITY);
327 singletonServiceGroup.registerService(firstReg);
328 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
329 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
330 verify(mockEosService).registerCandidate(CLOSE_ENTITY);
331 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, REMOTE_OWNERSHIP_LOST_NO_OWNER, true);
332 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
333 verify(mockClusterSingletonService, never()).closeServiceInstance();
337 * Test inJeopardy validation during wait phase for Master role for closeEntity.
339 * @throws CandidateAlreadyRegisteredException - unexpected exception
342 public void inJeopardyInWaitPhaseClusterSingletonServiceGroupTwoServiceTest()
343 throws CandidateAlreadyRegisteredException {
344 singletonServiceGroup.initialize();
345 verify(mockEosService).registerCandidate(MAIN_ENTITY);
346 singletonServiceGroup.registerService(firstReg);
347 singletonServiceGroup.registerService(secondReg);
348 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
349 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
350 verify(mockEosService).registerCandidate(CLOSE_ENTITY);
351 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, REMOTE_OWNERSHIP_LOST_NO_OWNER, true);
352 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
353 verify(mockClusterSingletonService, never()).closeServiceInstance();
357 * Test inJeopardy validation for holding leadership.
359 * @throws CandidateAlreadyRegisteredException - unexpected exception
362 public void inJeopardyLeaderClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
363 singletonServiceGroup.initialize();
364 verify(mockEosService).registerCandidate(MAIN_ENTITY);
365 singletonServiceGroup.registerService(firstReg);
366 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
367 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
368 verify(mockEosService).registerCandidate(CLOSE_ENTITY);
369 singletonServiceGroup.ownershipChanged(CLOSE_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
370 verify(mockClusterSingletonService).instantiateServiceInstance();
372 // Base entity in jeopardy should not matter...
373 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_GRANTED, true);
374 verify(mockClusterSingletonService, never()).closeServiceInstance();
376 // ... application state is actually guarded by cleanup
377 singletonServiceGroup.ownershipChanged(CLOSE_ENTITY, REMOTE_OWNERSHIP_LOST_NO_OWNER, true);
378 verify(mockClusterSingletonService).closeServiceInstance();
382 * Test GoldPath for SLAVE-TO-MASTER entity Candidate role change.
384 * @throws CandidateAlreadyRegisteredException - unexpected exception
387 public void lostLeaderClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
388 singletonServiceGroup.initialize();
389 verify(mockEosService).registerCandidate(MAIN_ENTITY);
390 singletonServiceGroup.registerService(firstReg);
391 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
392 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
393 verify(mockEosService).registerCandidate(CLOSE_ENTITY);
394 singletonServiceGroup.ownershipChanged(CLOSE_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
395 verify(mockClusterSingletonService).instantiateServiceInstance();
396 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_LOST_NEW_OWNER, false);
397 verify(mockClusterSingletonService).closeServiceInstance();
401 * Test checks validation Error processing for SLAVE-TO-MASTER entity Candidate role change.
402 * Not initialized provider has to close and remove all singletonServices from Group and
403 * Group itself remove too.
405 @Test(expected = IllegalStateException.class)
406 public void tryToTakeLeaderForNotInitializedGroupTest() {
407 singletonServiceGroup.registerService(firstReg);
411 * Test checks closing processing for close {@link ServiceRegistration}.
413 * @throws CandidateAlreadyRegisteredException - unexpected exception
416 public void checkClosingRegistrationTest() throws CandidateAlreadyRegisteredException {
417 singletonServiceGroup.initialize();
418 verify(mockEosService).registerCandidate(MAIN_ENTITY);
419 singletonServiceGroup.registerService(firstReg);
420 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
421 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
422 verify(mockEosService).registerCandidate(CLOSE_ENTITY);
423 singletonServiceGroup.ownershipChanged(CLOSE_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
424 verify(mockClusterSingletonService).instantiateServiceInstance();
425 assertNotNull(singletonServiceGroup.unregisterService(firstReg));
426 verify(mockClusterSingletonService, never()).closeServiceInstance();
427 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_LOST_NO_OWNER, false);
428 verify(mockClusterSingletonService).closeServiceInstance();
432 * Test checks validation Error processing for MASTER-TO-SLAVE closeEntity Candidate role change.
434 * @throws CandidateAlreadyRegisteredException - unexpected exception
437 public void checkClosingUnexpectedDoubleEntityForMasterOwnershipChangeRegistrationTest()
438 throws CandidateAlreadyRegisteredException {
439 singletonServiceGroup.initialize();
440 verify(mockEosService).registerCandidate(MAIN_ENTITY);
441 singletonServiceGroup.registerService(firstReg);
442 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
443 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
444 verify(mockEosService).registerCandidate(CLOSE_ENTITY);
445 singletonServiceGroup.ownershipChanged(CLOSE_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
446 verify(mockClusterSingletonService).instantiateServiceInstance();
447 singletonServiceGroup.ownershipChanged(CLOSE_ENTITY, LOCAL_OWNERSHIP_LOST_NEW_OWNER, false);
448 verify(mockClusterSingletonService).closeServiceInstance();
452 * Test checks validation Error processing for MASTER-TO-SLAVE closeEntity Candidate role change
453 * without closeEntity registration.
455 * @throws CandidateAlreadyRegisteredException - unexpected exception
458 public void checkClosingUnexpectedDoubleEntityForSlaveOwnershipChangeRegistrationTest()
459 throws CandidateAlreadyRegisteredException {
460 singletonServiceGroup.initialize();
461 verify(mockEosService).registerCandidate(MAIN_ENTITY);
462 singletonServiceGroup.registerService(firstReg);
463 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_LOST_NEW_OWNER, false);
464 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
465 verify(mockEosService, never()).registerCandidate(CLOSE_ENTITY);
466 singletonServiceGroup.ownershipChanged(CLOSE_ENTITY, LOCAL_OWNERSHIP_LOST_NEW_OWNER, false);
467 verify(mockClusterSingletonService, never()).closeServiceInstance();
471 public void testRegisterCloseShutdown() throws CandidateAlreadyRegisteredException, InterruptedException,
473 initializeGroupAndStartService();
475 assertNotNull(singletonServiceGroup.unregisterService(firstReg));
476 verify(mockClusterSingletonService, never()).closeServiceInstance();
477 verify(mockEntityCandReg).close();
479 final ListenableFuture<?> future = singletonServiceGroup.closeClusterSingletonGroup();
480 assertNotNull(future);
481 assertFalse(future.isDone());
482 verify(mockClusterSingletonService).closeServiceInstance();
484 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_LOST_NEW_OWNER, false);
485 verify(mockCloseEntityCandReg).close();
487 singletonServiceGroup.ownershipChanged(CLOSE_ENTITY, LOCAL_OWNERSHIP_LOST_NEW_OWNER, false);
488 assertTrue(future.isDone());
489 assertNull(future.get());
492 private void initialize() throws CandidateAlreadyRegisteredException {
493 singletonServiceGroup.initialize();
494 verify(mockEosService).registerCandidate(MAIN_ENTITY);
497 private void initializeGroupAndStartService() throws CandidateAlreadyRegisteredException {
499 singletonServiceGroup.registerService(firstReg);
500 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
501 verify(mockEosService).registerCandidate(CLOSE_ENTITY);
502 singletonServiceGroup.ownershipChanged(CLOSE_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
503 verify(mockClusterSingletonService).instantiateServiceInstance();