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.ClusterSingletonServiceRegistration;
42 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
43 import org.opendaylight.yangtools.concepts.Registration;
46 * Testing {@link ClusterSingletonServiceGroupImpl}.
48 @RunWith(MockitoJUnitRunner.StrictStubs.class)
49 public class ClusterSingletonServiceGroupImplTest {
50 public static final String SERVICE_IDENTIFIER = "TestServiceIdent";
51 public static final ServiceGroupIdentifier SERVICE_GROUP_IDENT = ServiceGroupIdentifier.create(SERVICE_IDENTIFIER);
53 public static final @NonNull DOMEntity MAIN_ENTITY = new DOMEntity(SERVICE_ENTITY_TYPE, SERVICE_IDENTIFIER);
54 public static final @NonNull DOMEntity CLOSE_ENTITY = new DOMEntity(CLOSE_SERVICE_ENTITY_TYPE, SERVICE_IDENTIFIER);
57 public ClusterSingletonService mockClusterSingletonService;
59 public ClusterSingletonService mockClusterSingletonServiceSecond;
61 public Registration mockEntityCandReg;
63 public Registration mockCloseEntityCandReg;
65 public DOMEntityOwnershipListener mockEosListener;
67 public DOMEntityOwnershipService mockEosService;
69 public ClusterSingletonServiceGroupImpl singletonServiceGroup;
71 public ClusterSingletonServiceRegistration firstReg;
72 public ClusterSingletonServiceRegistration secondReg;
75 * Initialization functionality for every Tests in this suite.
77 * @throws CandidateAlreadyRegisteredException unexpected exception.
80 public void setup() throws CandidateAlreadyRegisteredException {
81 doReturn(mockEntityCandReg).when(mockEosService).registerCandidate(MAIN_ENTITY);
82 doReturn(mockCloseEntityCandReg).when(mockEosService).registerCandidate(CLOSE_ENTITY);
83 doNothing().when(mockEntityCandReg).close();
84 doNothing().when(mockCloseEntityCandReg).close();
85 doNothing().when(mockClusterSingletonService).instantiateServiceInstance();
86 doReturn(Futures.immediateFuture(null)).when(mockClusterSingletonService).closeServiceInstance();
88 doReturn(SERVICE_GROUP_IDENT).when(mockClusterSingletonService).getIdentifier();
89 doReturn(SERVICE_GROUP_IDENT).when(mockClusterSingletonServiceSecond).getIdentifier();
91 firstReg = new AbstractClusterSingletonServiceRegistration(mockClusterSingletonService) {
93 protected void removeRegistration() {
97 secondReg = new AbstractClusterSingletonServiceRegistration(mockClusterSingletonServiceSecond) {
99 protected void removeRegistration() {
104 singletonServiceGroup = new ClusterSingletonServiceGroupImpl(SERVICE_IDENTIFIER, MAIN_ENTITY, CLOSE_ENTITY,
109 * Test NULL ServiceIdent input for new ServiceGroup instance.
112 public void instantiationClusterSingletonServiceGroupNullIdentTest() {
113 assertThrows(NullPointerException.class,
114 () -> new ClusterSingletonServiceGroupImpl(null, MAIN_ENTITY, CLOSE_ENTITY, mockEosService));
118 * Test empty ServiceIdent input for new ServiceGroup instance.
121 public void instantiationClusterSingletonServiceGroupEmptyIdentTest() {
122 assertThrows(IllegalArgumentException.class,
123 () -> new ClusterSingletonServiceGroupImpl("", MAIN_ENTITY, CLOSE_ENTITY, mockEosService));
127 * Test NULL MainEntity input for new ServiceGroup instance.
130 public void instantiationClusterSingletonServiceGroupNullMainEntityTest() {
131 assertThrows(NullPointerException.class,
132 () -> new ClusterSingletonServiceGroupImpl(SERVICE_IDENTIFIER, null, CLOSE_ENTITY, mockEosService));
136 * Test NULL CloseEntity input for new ServiceGroup instance.
139 public void instantiationClusterSingletonServiceGroupNullCloseEntityTest() {
140 assertThrows(NullPointerException.class,
141 () -> new ClusterSingletonServiceGroupImpl(SERVICE_IDENTIFIER, MAIN_ENTITY, null, mockEosService));
145 * Test NULL EntityOwnershipService input for new ServiceGroup instance.
148 public void instantiationClusterSingletonServiceGroupNullEOS_Test() {
149 assertThrows(NullPointerException.class,
150 () -> new ClusterSingletonServiceGroupImpl(SERVICE_IDENTIFIER, MAIN_ENTITY, CLOSE_ENTITY, null));
154 * Test GoldPath for initialization ServiceGroup.
157 public void initializationClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
158 singletonServiceGroup.initialize();
159 verify(mockEosService).registerCandidate(MAIN_ENTITY);
163 * Test GoldPath for NO-TO-SLAVE entity Candidate role change.
165 * @throws CandidateAlreadyRegisteredException - unexpected exception
168 public void initializationSlaveTest() throws CandidateAlreadyRegisteredException {
169 singletonServiceGroup.initialize();
170 verify(mockEosService).registerCandidate(MAIN_ENTITY);
171 singletonServiceGroup.registerService(firstReg);
172 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_LOST_NEW_OWNER, false);
173 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
174 verify(mockEosService, never()).registerCandidate(CLOSE_ENTITY);
178 * Test GoldPath for NO-TO-SLAVE but without MASTER entity Candidate role change.
180 * @throws CandidateAlreadyRegisteredException - unexpected exception
183 public void initializationNoMasterTest() throws CandidateAlreadyRegisteredException {
184 singletonServiceGroup.initialize();
185 verify(mockEosService).registerCandidate(MAIN_ENTITY);
186 singletonServiceGroup.registerService(firstReg);
187 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_LOST_NO_OWNER, false);
188 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
189 verify(mockEosService, never()).registerCandidate(CLOSE_ENTITY);
193 * Test GoldPath for InJeopardy entity Candidate role change.
195 * @throws CandidateAlreadyRegisteredException - unexpected exception
198 public void initializationInJeopardyTest() throws CandidateAlreadyRegisteredException {
199 singletonServiceGroup.initialize();
200 verify(mockEosService).registerCandidate(MAIN_ENTITY);
201 singletonServiceGroup.registerService(firstReg);
202 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, REMOTE_OWNERSHIP_LOST_NO_OWNER, true);
203 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
204 verify(mockEosService, never()).registerCandidate(CLOSE_ENTITY);
208 * Test GoldPath for registration SingletonService.
210 * @throws CandidateAlreadyRegisteredException - unexpected exception
213 public void serviceRegistrationClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
214 singletonServiceGroup.initialize();
215 verify(mockEosService).registerCandidate(MAIN_ENTITY);
216 singletonServiceGroup.registerService(firstReg);
220 * Test GoldPath for registration SingletonService.
222 * @throws CandidateAlreadyRegisteredException - unexpected exception
225 public void serviceRegistrationClusterSingletonServiceGroupTwoServiceTest()
226 throws CandidateAlreadyRegisteredException {
227 singletonServiceGroup.initialize();
228 verify(mockEosService).registerCandidate(MAIN_ENTITY);
229 singletonServiceGroup.registerService(firstReg);
230 singletonServiceGroup.registerService(secondReg);
234 * Test GoldPath for unregistration SingletonService don't call closeServiceInstance
235 * without mastership and don't remove ServiceGroup from map.
237 * @throws CandidateAlreadyRegisteredException - unexpected exception
240 public void serviceUnregistrationClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
241 singletonServiceGroup.initialize();
242 verify(mockEosService).registerCandidate(MAIN_ENTITY);
243 singletonServiceGroup.registerService(firstReg);
244 assertNotNull(singletonServiceGroup.unregisterService(firstReg));
245 verify(mockClusterSingletonService, never()).closeServiceInstance();
249 * Test GoldPath for unregistration SingletonService don't call closeServiceInstance
250 * without mastership and don't remove ServiceGroup from map.
252 * @throws CandidateAlreadyRegisteredException - unexpected exception
255 public void serviceUnregistrationClusterSingletonServiceGroupTwoServicesTest()
256 throws CandidateAlreadyRegisteredException {
257 singletonServiceGroup.initialize();
258 verify(mockEosService).registerCandidate(MAIN_ENTITY);
259 singletonServiceGroup.registerService(firstReg);
260 singletonServiceGroup.registerService(secondReg);
261 assertNull(singletonServiceGroup.unregisterService(firstReg));
262 verify(mockClusterSingletonService, never()).closeServiceInstance();
266 * Test GoldPath get Slave role for registered main entity.
268 * @throws CandidateAlreadyRegisteredException - unexpected exception
271 public void getSlaveClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
272 singletonServiceGroup.initialize();
273 verify(mockEosService).registerCandidate(MAIN_ENTITY);
274 singletonServiceGroup.registerService(firstReg);
275 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_LOST_NEW_OWNER, false);
276 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
280 * Test GoldPath get Master role for registered main entity.
282 * @throws CandidateAlreadyRegisteredException - unexpected exception
285 public void tryToTakeLeaderClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
286 singletonServiceGroup.initialize();
287 verify(mockEosService).registerCandidate(MAIN_ENTITY);
288 singletonServiceGroup.registerService(firstReg);
289 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
290 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
291 verify(mockEosService).registerCandidate(CLOSE_ENTITY);
295 * Test GoldPath get Master role for registered close entity.
297 * @throws CandidateAlreadyRegisteredException - unexpected exception
300 public void takeMasterClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
301 singletonServiceGroup.initialize();
302 verify(mockEosService).registerCandidate(MAIN_ENTITY);
303 singletonServiceGroup.registerService(firstReg);
304 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
305 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
306 verify(mockEosService).registerCandidate(CLOSE_ENTITY);
307 singletonServiceGroup.ownershipChanged(CLOSE_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
308 verify(mockClusterSingletonService).instantiateServiceInstance();
312 * Test GoldPath get Master role for registered entity but initial Slave
313 * role for closeEntity.
315 * @throws CandidateAlreadyRegisteredException - unexpected exception
318 public void waitToTakeMasterClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
319 singletonServiceGroup.initialize();
320 verify(mockEosService).registerCandidate(MAIN_ENTITY);
321 singletonServiceGroup.registerService(firstReg);
322 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
323 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
324 verify(mockEosService).registerCandidate(CLOSE_ENTITY);
325 singletonServiceGroup.ownershipChanged(CLOSE_ENTITY, REMOTE_OWNERSHIP_CHANGED, false);
326 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
327 verify(mockClusterSingletonService, never()).closeServiceInstance();
331 * Test inJeopardy validation during wait phase for Master role for closeEntity.
333 * @throws CandidateAlreadyRegisteredException - unexpected exception
336 public void inJeopardyInWaitPhaseClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
337 singletonServiceGroup.initialize();
338 verify(mockEosService).registerCandidate(MAIN_ENTITY);
339 singletonServiceGroup.registerService(firstReg);
340 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
341 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
342 verify(mockEosService).registerCandidate(CLOSE_ENTITY);
343 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, REMOTE_OWNERSHIP_LOST_NO_OWNER, true);
344 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
345 verify(mockClusterSingletonService, never()).closeServiceInstance();
349 * Test inJeopardy validation during wait phase for Master role for closeEntity.
351 * @throws CandidateAlreadyRegisteredException - unexpected exception
354 public void inJeopardyInWaitPhaseClusterSingletonServiceGroupTwoServiceTest()
355 throws CandidateAlreadyRegisteredException {
356 singletonServiceGroup.initialize();
357 verify(mockEosService).registerCandidate(MAIN_ENTITY);
358 singletonServiceGroup.registerService(firstReg);
359 singletonServiceGroup.registerService(secondReg);
360 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
361 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
362 verify(mockEosService).registerCandidate(CLOSE_ENTITY);
363 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, REMOTE_OWNERSHIP_LOST_NO_OWNER, true);
364 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
365 verify(mockClusterSingletonService, never()).closeServiceInstance();
369 * Test inJeopardy validation for holding leadership.
371 * @throws CandidateAlreadyRegisteredException - unexpected exception
374 public void inJeopardyLeaderClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
375 singletonServiceGroup.initialize();
376 verify(mockEosService).registerCandidate(MAIN_ENTITY);
377 singletonServiceGroup.registerService(firstReg);
378 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
379 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
380 verify(mockEosService).registerCandidate(CLOSE_ENTITY);
381 singletonServiceGroup.ownershipChanged(CLOSE_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
382 verify(mockClusterSingletonService).instantiateServiceInstance();
384 // Base entity in jeopardy should not matter...
385 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_GRANTED, true);
386 verify(mockClusterSingletonService, never()).closeServiceInstance();
388 // ... application state is actually guarded by cleanup
389 singletonServiceGroup.ownershipChanged(CLOSE_ENTITY, REMOTE_OWNERSHIP_LOST_NO_OWNER, true);
390 verify(mockClusterSingletonService).closeServiceInstance();
394 * Test GoldPath for SLAVE-TO-MASTER entity Candidate role change.
396 * @throws CandidateAlreadyRegisteredException - unexpected exception
399 public void lostLeaderClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
400 singletonServiceGroup.initialize();
401 verify(mockEosService).registerCandidate(MAIN_ENTITY);
402 singletonServiceGroup.registerService(firstReg);
403 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
404 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
405 verify(mockEosService).registerCandidate(CLOSE_ENTITY);
406 singletonServiceGroup.ownershipChanged(CLOSE_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
407 verify(mockClusterSingletonService).instantiateServiceInstance();
408 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_LOST_NEW_OWNER, false);
409 verify(mockClusterSingletonService).closeServiceInstance();
413 * Test checks validation Error processing for SLAVE-TO-MASTER entity Candidate role change.
414 * Not initialized provider has to close and remove all singletonServices from Group and
415 * Group itself remove too.
417 @Test(expected = IllegalStateException.class)
418 public void tryToTakeLeaderForNotInitializedGroupTest() {
419 singletonServiceGroup.registerService(firstReg);
423 * Test checks closing processing for close {@link ClusterSingletonServiceRegistration}.
425 * @throws CandidateAlreadyRegisteredException - unexpected exception
428 public void checkClosingRegistrationTest() throws CandidateAlreadyRegisteredException {
429 singletonServiceGroup.initialize();
430 verify(mockEosService).registerCandidate(MAIN_ENTITY);
431 singletonServiceGroup.registerService(firstReg);
432 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
433 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
434 verify(mockEosService).registerCandidate(CLOSE_ENTITY);
435 singletonServiceGroup.ownershipChanged(CLOSE_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
436 verify(mockClusterSingletonService).instantiateServiceInstance();
437 assertNotNull(singletonServiceGroup.unregisterService(firstReg));
438 verify(mockClusterSingletonService, never()).closeServiceInstance();
439 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_LOST_NO_OWNER, false);
440 verify(mockClusterSingletonService).closeServiceInstance();
444 * Test checks validation Error processing for MASTER-TO-SLAVE closeEntity Candidate role change.
446 * @throws CandidateAlreadyRegisteredException - unexpected exception
449 public void checkClosingUnexpectedDoubleEntityForMasterOwnershipChangeRegistrationTest()
450 throws CandidateAlreadyRegisteredException {
451 singletonServiceGroup.initialize();
452 verify(mockEosService).registerCandidate(MAIN_ENTITY);
453 singletonServiceGroup.registerService(firstReg);
454 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
455 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
456 verify(mockEosService).registerCandidate(CLOSE_ENTITY);
457 singletonServiceGroup.ownershipChanged(CLOSE_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
458 verify(mockClusterSingletonService).instantiateServiceInstance();
459 singletonServiceGroup.ownershipChanged(CLOSE_ENTITY, LOCAL_OWNERSHIP_LOST_NEW_OWNER, false);
460 verify(mockClusterSingletonService).closeServiceInstance();
464 * Test checks validation Error processing for MASTER-TO-SLAVE closeEntity Candidate role change
465 * without closeEntity registration.
467 * @throws CandidateAlreadyRegisteredException - unexpected exception
470 public void checkClosingUnexpectedDoubleEntityForSlaveOwnershipChangeRegistrationTest()
471 throws CandidateAlreadyRegisteredException {
472 singletonServiceGroup.initialize();
473 verify(mockEosService).registerCandidate(MAIN_ENTITY);
474 singletonServiceGroup.registerService(firstReg);
475 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_LOST_NEW_OWNER, false);
476 verify(mockClusterSingletonService, never()).instantiateServiceInstance();
477 verify(mockEosService, never()).registerCandidate(CLOSE_ENTITY);
478 singletonServiceGroup.ownershipChanged(CLOSE_ENTITY, LOCAL_OWNERSHIP_LOST_NEW_OWNER, false);
479 verify(mockClusterSingletonService, never()).closeServiceInstance();
483 public void testRegisterCloseShutdown() throws CandidateAlreadyRegisteredException, InterruptedException,
485 initializeGroupAndStartService();
487 assertNotNull(singletonServiceGroup.unregisterService(firstReg));
488 verify(mockClusterSingletonService, never()).closeServiceInstance();
489 verify(mockEntityCandReg).close();
491 final ListenableFuture<?> future = singletonServiceGroup.closeClusterSingletonGroup();
492 assertNotNull(future);
493 assertFalse(future.isDone());
494 verify(mockClusterSingletonService).closeServiceInstance();
496 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_LOST_NEW_OWNER, false);
497 verify(mockCloseEntityCandReg).close();
499 singletonServiceGroup.ownershipChanged(CLOSE_ENTITY, LOCAL_OWNERSHIP_LOST_NEW_OWNER, false);
500 assertTrue(future.isDone());
501 assertNull(future.get());
504 private void initialize() throws CandidateAlreadyRegisteredException {
505 singletonServiceGroup.initialize();
506 verify(mockEosService).registerCandidate(MAIN_ENTITY);
509 private void initializeGroupAndStartService() throws CandidateAlreadyRegisteredException {
511 singletonServiceGroup.registerService(firstReg);
512 singletonServiceGroup.ownershipChanged(MAIN_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
513 verify(mockEosService).registerCandidate(CLOSE_ENTITY);
514 singletonServiceGroup.ownershipChanged(CLOSE_ENTITY, LOCAL_OWNERSHIP_GRANTED, false);
515 verify(mockClusterSingletonService).instantiateServiceInstance();