BUG-9145: rework singleton service group state tracking
[mdsal.git] / singleton-service / mdsal-singleton-dom-impl / src / test / java / org / opendaylight / mdsal / singleton / dom / impl / ClusterSingletonServiceGroupImplTest.java
index bf1421435458268edf8edb406631cd0ae3b0d2cb..83ed842d504ebe388338ae3bf5860c863010d72d 100644 (file)
@@ -8,18 +8,25 @@
 
 package org.opendaylight.mdsal.singleton.dom.impl;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
+import static org.opendaylight.mdsal.singleton.dom.impl.AbstractClusterSingletonServiceProviderImpl.CLOSE_SERVICE_ENTITY_TYPE;
+import static org.opendaylight.mdsal.singleton.dom.impl.AbstractClusterSingletonServiceProviderImpl.SERVICE_ENTITY_TYPE;
+
 import com.google.common.util.concurrent.Futures;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import org.junit.Assert;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.concurrent.ExecutionException;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException;
 import org.opendaylight.mdsal.eos.common.api.EntityOwnershipChangeState;
 import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipCandidateRegistration;
 import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipChange;
@@ -28,21 +35,19 @@ import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipService;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
-import org.opendaylight.mdsal.singleton.dom.impl.ClusterSingletonServiceGroup;
-import org.opendaylight.mdsal.singleton.dom.impl.ClusterSingletonServiceGroupImpl;
 import org.opendaylight.mdsal.singleton.dom.impl.util.TestEntity;
 import org.opendaylight.mdsal.singleton.dom.impl.util.TestInstanceIdentifier;
 
 /**
- * Testing {@link ClusterSingletonServiceGroupImpl}
+ * Testing {@link ClusterSingletonServiceGroupImpl}.
  */
 public class ClusterSingletonServiceGroupImplTest {
-
-    private static final String SERVICE_ENTITY_TYPE = "org.opendaylight.mdsal.ServiceEntityType";
-    private static final String CLOSE_SERVICE_ENTITY_TYPE = "org.opendaylight.mdsal.AsyncServiceCloseEntityType";
     private static final String SERVICE_IDENTIFIER = "TestServiceIdent";
     private static final ServiceGroupIdentifier SERVICE_GROUP_IDENT = ServiceGroupIdentifier.create(SERVICE_IDENTIFIER);
 
+    private static final TestEntity MAIN_ENTITY = new TestEntity(SERVICE_ENTITY_TYPE, SERVICE_IDENTIFIER);
+    private static final TestEntity CLOSE_ENTITY = new TestEntity(CLOSE_SERVICE_ENTITY_TYPE, SERVICE_IDENTIFIER);
+
     @Mock
     private ClusterSingletonService mockClusterSingletonService;
     @Mock
@@ -52,405 +57,338 @@ public class ClusterSingletonServiceGroupImplTest {
     @Mock
     private GenericEntityOwnershipCandidateRegistration<?, ?> mockCloseEntityCandReg;
     @Mock
-    private GenericEntityOwnershipListener<TestInstanceIdentifier,GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity>> mockEosListener;
+    private GenericEntityOwnershipListener<TestInstanceIdentifier,
+        GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity>> mockEosListener;
 
     @Mock
-    private GenericEntityOwnershipService<TestInstanceIdentifier,TestEntity, GenericEntityOwnershipListener<TestInstanceIdentifier,GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity>>> mockEosService;
-
-    private ClusterSingletonServiceGroupImpl<TestInstanceIdentifier,TestEntity,GenericEntityOwnershipChange<TestInstanceIdentifier,TestEntity>,
-                                         GenericEntityOwnershipListener<TestInstanceIdentifier, GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity>>,
-                                         GenericEntityOwnershipService<TestInstanceIdentifier, TestEntity, GenericEntityOwnershipListener<TestInstanceIdentifier,
-                                         GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity>>>> singletonServiceGroup;
-
-    private final TestEntity mainEntity = new TestEntity(SERVICE_ENTITY_TYPE, SERVICE_IDENTIFIER);
-    private final TestEntity closeEntity = new TestEntity(CLOSE_SERVICE_ENTITY_TYPE, SERVICE_IDENTIFIER);
-    private final ConcurrentMap<String, ClusterSingletonServiceGroup<?, ?, ?>> map = new ConcurrentHashMap<>();
+    private GenericEntityOwnershipService<TestInstanceIdentifier,TestEntity,
+        GenericEntityOwnershipListener<TestInstanceIdentifier,
+            GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity>>> mockEosService;
+
+    private ClusterSingletonServiceGroupImpl<TestInstanceIdentifier,TestEntity,
+        GenericEntityOwnershipChange<TestInstanceIdentifier,TestEntity>,
+            GenericEntityOwnershipListener<TestInstanceIdentifier,
+                GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity>>,
+                    GenericEntityOwnershipService<TestInstanceIdentifier, TestEntity,
+                        GenericEntityOwnershipListener<TestInstanceIdentifier,
+                            GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity>>>> singletonServiceGroup;
 
     /**
-     * Initialization functionality for every Tests in this suite
+     * Initialization functionality for every Tests in this suite.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException unexpected exception.
      */
-   @Before
-   public void setup() throws Exception {
-       MockitoAnnotations.initMocks(this);
+    @Before
+    public void setup() throws CandidateAlreadyRegisteredException {
+        MockitoAnnotations.initMocks(this);
 
-       doReturn(mockEntityCandReg).when(mockEosService).registerCandidate(mainEntity);
-       doReturn(mockCloseEntityCandReg).when(mockEosService).registerCandidate(closeEntity);
-       doNothing().when(mockEntityCandReg).close();
-       doNothing().when(mockCloseEntityCandReg).close();
-       doNothing().when(mockClusterSingletonService).instantiateServiceInstance();
-       doReturn(Futures.immediateFuture(null)).when(mockClusterSingletonService).closeServiceInstance();
+        doReturn(mockEntityCandReg).when(mockEosService).registerCandidate(MAIN_ENTITY);
+        doReturn(mockCloseEntityCandReg).when(mockEosService).registerCandidate(CLOSE_ENTITY);
+        doNothing().when(mockEntityCandReg).close();
+        doNothing().when(mockCloseEntityCandReg).close();
+        doNothing().when(mockClusterSingletonService).instantiateServiceInstance();
+        doReturn(Futures.immediateFuture(null)).when(mockClusterSingletonService).closeServiceInstance();
 
         doReturn(SERVICE_GROUP_IDENT).when(mockClusterSingletonService).getIdentifier();
         doReturn(SERVICE_GROUP_IDENT).when(mockClusterSingletonServiceSecond).getIdentifier();
 
-       singletonServiceGroup = new ClusterSingletonServiceGroupImpl(SERVICE_IDENTIFIER, mainEntity, closeEntity, mockEosService, map);
+        singletonServiceGroup = new ClusterSingletonServiceGroupImpl<>(SERVICE_IDENTIFIER, MAIN_ENTITY, CLOSE_ENTITY,
+            mockEosService);
     }
 
     /**
-     * Test NULL ServiceIdent input for new ServiceGroup instance
-     *
-     * @throws Exception - unexpected exception
+     * Test NULL ServiceIdent input for new ServiceGroup instance.
      */
-    @Test(expected = IllegalArgumentException.class)
-    public void instantiationClusterSingletonServiceGroupNullIdentTest() throws Exception {
-        singletonServiceGroup = new ClusterSingletonServiceGroupImpl(null, mainEntity, closeEntity, mockEosService, map);
+    @Test(expected = NullPointerException.class)
+    public void instantiationClusterSingletonServiceGroupNullIdentTest() {
+        new ClusterSingletonServiceGroupImpl<>(null, MAIN_ENTITY, CLOSE_ENTITY, mockEosService);
     }
 
     /**
-     * Test empty ServiceIdent input for new ServiceGroup instance
-     *
-     * @throws Exception - unexpected exception
+     * Test empty ServiceIdent input for new ServiceGroup instance.
      */
     @Test(expected = IllegalArgumentException.class)
-    public void instantiationClusterSingletonServiceGroupEmptyIdentTest() throws Exception {
-        singletonServiceGroup = new ClusterSingletonServiceGroupImpl("", mainEntity, closeEntity, mockEosService, map);
-    }
-
-    /**
-     * Test NULL MainEntity input for new ServiceGroup instance
-     *
-     * @throws Exception - unexpected exception
-     */
-    @Test(expected = NullPointerException.class)
-    public void instantiationClusterSingletonServiceGroupNullMainEntityTest() throws Exception {
-        singletonServiceGroup = new ClusterSingletonServiceGroupImpl(SERVICE_IDENTIFIER, null, closeEntity, mockEosService, map);
+    public void instantiationClusterSingletonServiceGroupEmptyIdentTest() {
+        new ClusterSingletonServiceGroupImpl<>("", MAIN_ENTITY, CLOSE_ENTITY, mockEosService);
     }
 
     /**
-     * Test NULL MainEntity input for new ServiceGroup instance
-     *
-     * @throws Exception - unexpected exception
+     * Test NULL MainEntity input for new ServiceGroup instance.
      */
     @Test(expected = NullPointerException.class)
-    public void instantiationClusterSingletonServiceGroupNullCloseEntityTest() throws Exception {
-        singletonServiceGroup = new ClusterSingletonServiceGroupImpl(SERVICE_IDENTIFIER, mainEntity, null, mockEosService, map);
+    public void instantiationClusterSingletonServiceGroupNullMainEntityTest() {
+        new ClusterSingletonServiceGroupImpl<>(SERVICE_IDENTIFIER, null, CLOSE_ENTITY, mockEosService);
     }
 
     /**
-     * Test NULL MainEntity input for new ServiceGroup instance
-     *
-     * @throws Exception - unexpected exception
+     * Test NULL CloseEntity input for new ServiceGroup instance.
      */
     @Test(expected = NullPointerException.class)
-    public void instantiationClusterSingletonServiceGroupNullEOS_Test() throws Exception {
-        singletonServiceGroup = new ClusterSingletonServiceGroupImpl(SERVICE_IDENTIFIER, mainEntity, closeEntity, null, map);
+    public void instantiationClusterSingletonServiceGroupNullCloseEntityTest() {
+        new ClusterSingletonServiceGroupImpl<>(SERVICE_IDENTIFIER, MAIN_ENTITY, null, mockEosService);
     }
 
     /**
-     * Test NULL MainEntity input for new ServiceGroup instance
-     *
-     * @throws Exception - unexpected exception
+     * Test NULL EntityOwnershipService input for new ServiceGroup instance.
      */
     @Test(expected = NullPointerException.class)
-    public void instantiationClusterSingletonServiceGroupNullMapRefTest() throws Exception {
-        singletonServiceGroup = new ClusterSingletonServiceGroupImpl(SERVICE_IDENTIFIER, mainEntity, closeEntity, mockEosService, null);
+    public void instantiationClusterSingletonServiceGroupNullEOS_Test() {
+        new ClusterSingletonServiceGroupImpl<>(SERVICE_IDENTIFIER, MAIN_ENTITY, CLOSE_ENTITY, null);
     }
 
     /**
-     * Test GoldPath for initialization ServiceGroup
-     *
-     * @throws Exception - unexpected exception
+     * Test GoldPath for initialization ServiceGroup.
      */
     @Test
-    public void initializationClusterSingletonServiceGroupTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        verify(mockEosService).registerCandidate(mainEntity);
+    public void initializationClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
     }
 
     /**
-     * Test GoldPath for NO-TO-SLAVE entity Candidate role change
+     * Test GoldPath for NO-TO-SLAVE entity Candidate role change.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void initializationSlaveTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void initializationSlaveTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToSlave());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService, never()).registerCandidate(closeEntity);
+        verify(mockEosService, never()).registerCandidate(CLOSE_ENTITY);
     }
 
     /**
-     * Test GoldPath for NO-TO-SLAVE but without MASTER entity Candidate role change
+     * Test GoldPath for NO-TO-SLAVE but without MASTER entity Candidate role change.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void initializationNoMasterTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void initializationNoMasterTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToSlaveNoMaster());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService, never()).registerCandidate(closeEntity);
+        verify(mockEosService, never()).registerCandidate(CLOSE_ENTITY);
     }
 
     /**
-     * Test GoldPath for InJeopardy entity Candidate role change
+     * Test GoldPath for InJeopardy entity Candidate role change.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void initializationInJeopardyTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        map.putIfAbsent(SERVICE_IDENTIFIER, singletonServiceGroup);
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void initializationInJeopardyTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToJeopardy());
-        final ClusterSingletonServiceGroup<?, ?, ?> serviceGroup = map.get(SERVICE_IDENTIFIER);
-        Assert.assertNull(serviceGroup);
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService, never()).registerCandidate(closeEntity);
+        verify(mockEosService, never()).registerCandidate(CLOSE_ENTITY);
     }
 
     /**
-     * Test GoldPath for registration SingletonService
+     * Test GoldPath for registration SingletonService.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void serviceRegistrationClusterSingletonServiceGroupTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void serviceRegistrationClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
     }
 
     /**
-     * Test GoldPath for registration SingletonService
+     * Test GoldPath for registration SingletonService.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void serviceRegistrationClusterSingletonServiceGroupTwoServiceTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
-        final ClusterSingletonServiceRegistration reg2 = singletonServiceGroup
-                .registerService(mockClusterSingletonServiceSecond);
-        Assert.assertNotNull(reg2);
+    public void serviceRegistrationClusterSingletonServiceGroupTwoServiceTest()
+            throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
+        singletonServiceGroup.registerService(mockClusterSingletonServiceSecond);
     }
 
     /**
      * Test GoldPath for unregistration SingletonService don't call closeServiceInstance
-     * without mastership and don't remove ServiceGroup from map
+     * without mastership and don't remove ServiceGroup from map.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void serviceUnregistrationClusterSingletonServiceGroupTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        map.putIfAbsent(SERVICE_IDENTIFIER, singletonServiceGroup);
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
-        reg.close();
+    public void serviceUnregistrationClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
+        assertTrue(singletonServiceGroup.unregisterService(mockClusterSingletonService));
         verify(mockClusterSingletonService, never()).closeServiceInstance();
-        final ClusterSingletonServiceGroup<?, ?, ?> serviceGroup = map.get(SERVICE_IDENTIFIER);
-        Assert.assertNull(serviceGroup);
     }
 
     /**
      * Test GoldPath for unregistration SingletonService don't call closeServiceInstance
-     * without mastership and don't remove ServiceGroup from map
+     *     without mastership and don't remove ServiceGroup from map.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void serviceUnregistrationClusterSingletonServiceGroupTwoServicesTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        map.putIfAbsent(SERVICE_IDENTIFIER, singletonServiceGroup);
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
-        final ClusterSingletonServiceRegistration reg2 = singletonServiceGroup
-                .registerService(mockClusterSingletonServiceSecond);
-        Assert.assertNotNull(reg2);
-        reg.close();
+    public void serviceUnregistrationClusterSingletonServiceGroupTwoServicesTest()
+            throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
+        singletonServiceGroup.registerService(mockClusterSingletonServiceSecond);
+        assertFalse(singletonServiceGroup.unregisterService(mockClusterSingletonService));
         verify(mockClusterSingletonService, never()).closeServiceInstance();
-        final ClusterSingletonServiceGroup<?, ?, ?> serviceGroup = map.get(SERVICE_IDENTIFIER);
-        Assert.assertNotNull(serviceGroup);
     }
 
     /**
-     * Test GoldPath get Slave role for registered main entity
+     * Test GoldPath get Slave role for registered main entity.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void getSlaveClusterSingletonServiceGroupTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void getSlaveClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToSlave());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
     }
 
     /**
-     * Test GoldPath get Master role for registered main entity
+     * Test GoldPath get Master role for registered main entity.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void tryToTakeLeaderClusterSingletonServiceGroupTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void tryToTakeLeaderClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToMaster());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService).registerCandidate(closeEntity);
+        verify(mockEosService).registerCandidate(CLOSE_ENTITY);
     }
 
     /**
-     * Test GoldPath get Master role for registered close entity
+     * Test GoldPath get Master role for registered close entity.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void takeMasterClusterSingletonServiceGroupTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void takeMasterClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToMaster());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService).registerCandidate(closeEntity);
+        verify(mockEosService).registerCandidate(CLOSE_ENTITY);
         singletonServiceGroup.ownershipChanged(getDoubleEntityToMaster());
         verify(mockClusterSingletonService).instantiateServiceInstance();
     }
 
     /**
      * Test GoldPath get Master role for registered entity but initial Slave
-     * role for closeEntity
+     *     role for closeEntity.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void waitToTakeMasterClusterSingletonServiceGroupTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        map.putIfAbsent(SERVICE_IDENTIFIER, singletonServiceGroup);
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void waitToTakeMasterClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToMaster());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService).registerCandidate(closeEntity);
+        verify(mockEosService).registerCandidate(CLOSE_ENTITY);
         singletonServiceGroup.ownershipChanged(getInitDoubleEntityToSlave());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
         verify(mockClusterSingletonService, never()).closeServiceInstance();
-        final ClusterSingletonServiceGroup<?, ?, ?> serviceGroup = map.get(SERVICE_IDENTIFIER);
-        Assert.assertNotNull(serviceGroup);
     }
 
     /**
-     * Test inJeopardy validation during wait phase for Master role for closeEntity
+     * Test inJeopardy validation during wait phase for Master role for closeEntity.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void inJeopardyInWaitPhaseClusterSingletonServiceGroupTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        map.putIfAbsent(SERVICE_IDENTIFIER, singletonServiceGroup);
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void inJeopardyInWaitPhaseClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToMaster());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService).registerCandidate(closeEntity);
+        verify(mockEosService).registerCandidate(CLOSE_ENTITY);
         singletonServiceGroup.ownershipChanged(getEntityToJeopardy());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
         verify(mockClusterSingletonService, never()).closeServiceInstance();
-        final ClusterSingletonServiceGroup<?, ?, ?> serviceGroup = map.get(SERVICE_IDENTIFIER);
-        Assert.assertNull(serviceGroup);
     }
 
     /**
-     * Test inJeopardy validation during wait phase for Master role for closeEntity
+     * Test inJeopardy validation during wait phase for Master role for closeEntity.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void inJeopardyInWaitPhaseClusterSingletonServiceGroupTwoServiceTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        map.putIfAbsent(SERVICE_IDENTIFIER, singletonServiceGroup);
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
-        final ClusterSingletonServiceRegistration reg2 = singletonServiceGroup
-                .registerService(mockClusterSingletonServiceSecond);
-        Assert.assertNotNull(reg2);
+    public void inJeopardyInWaitPhaseClusterSingletonServiceGroupTwoServiceTest()
+            throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
+        singletonServiceGroup.registerService(mockClusterSingletonServiceSecond);
         singletonServiceGroup.ownershipChanged(getEntityToMaster());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService).registerCandidate(closeEntity);
+        verify(mockEosService).registerCandidate(CLOSE_ENTITY);
         singletonServiceGroup.ownershipChanged(getEntityToJeopardy());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
         verify(mockClusterSingletonService, never()).closeServiceInstance();
-        final ClusterSingletonServiceGroup<?, ?, ?> serviceGroup = map.get(SERVICE_IDENTIFIER);
-        Assert.assertNull(serviceGroup);
     }
 
     /**
-     * Test inJeopardy validation for holding leadership
+     * Test inJeopardy validation for holding leadership.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void inJeopardyLeaderClusterSingletonServiceGroupTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        map.putIfAbsent(SERVICE_IDENTIFIER, singletonServiceGroup);
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void inJeopardyLeaderClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToMaster());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService).registerCandidate(closeEntity);
+        verify(mockEosService).registerCandidate(CLOSE_ENTITY);
         singletonServiceGroup.ownershipChanged(getDoubleEntityToMaster());
         verify(mockClusterSingletonService).instantiateServiceInstance();
+
+        // Base entity in jeopardy should not matter...
         singletonServiceGroup.ownershipChanged(getEntityToJeopardy());
+        verify(mockClusterSingletonService, never()).closeServiceInstance();
+
+        // ... application state is actually guarded by cleanup
+        singletonServiceGroup.ownershipChanged(getDoubleEntityToJeopardy());
         verify(mockClusterSingletonService).closeServiceInstance();
-        final ClusterSingletonServiceGroup<?, ?, ?> serviceGroup = map.get(SERVICE_IDENTIFIER);
-        Assert.assertNull(serviceGroup);
     }
 
     /**
-     * Test GoldPath for SLAVE-TO-MASTER entity Candidate role change
+     * Test GoldPath for SLAVE-TO-MASTER entity Candidate role change.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void lostLeaderClusterSingletonServiceGroupTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void lostLeaderClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToMaster());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService).registerCandidate(closeEntity);
+        verify(mockEosService).registerCandidate(CLOSE_ENTITY);
         singletonServiceGroup.ownershipChanged(getDoubleEntityToMaster());
         verify(mockClusterSingletonService).instantiateServiceInstance();
         singletonServiceGroup.ownershipChanged(getEntityToSlave());
@@ -459,116 +397,146 @@ public class ClusterSingletonServiceGroupImplTest {
 
     /**
      * Test checks validation Error processing for SLAVE-TO-MASTER entity Candidate role change.
-     * Not initialized provider has to close and remove all singletonServices from Group and
-     * Group itself remove too.
-     *
-     * @throws Exception - unexpected exception
+     *     Not initialized provider has to close and remove all singletonServices from Group and
+     *     Group itself remove too.
      */
-    @Test
-    public void tryToTakeLeaderForNotInitializedGroupTest() throws Exception {
-        map.putIfAbsent(SERVICE_IDENTIFIER, singletonServiceGroup);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNull(reg);
-        final ClusterSingletonServiceGroup<?, ?, ?> serviceGroup = map.get(SERVICE_IDENTIFIER);
-        Assert.assertNull(serviceGroup);
+    @Test(expected = RuntimeException.class)
+    public void tryToTakeLeaderForNotInitializedGroupTest() {
+        singletonServiceGroup.registerService(mockClusterSingletonService);
     }
 
     /**
-     * Test checks closing procesing for close {@link ClusterSingletonServiceRegistration}
+     * Test checks closing processing for close {@link ClusterSingletonServiceRegistration}.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void checkClosingRegistrationTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        map.putIfAbsent(SERVICE_IDENTIFIER, singletonServiceGroup);
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void checkClosingRegistrationTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToMaster());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService).registerCandidate(closeEntity);
+        verify(mockEosService).registerCandidate(CLOSE_ENTITY);
         singletonServiceGroup.ownershipChanged(getDoubleEntityToMaster());
         verify(mockClusterSingletonService).instantiateServiceInstance();
-        reg.close();
+        assertTrue(singletonServiceGroup.unregisterService(mockClusterSingletonService));
+        verify(mockClusterSingletonService, never()).closeServiceInstance();
+        singletonServiceGroup.ownershipChanged(getEntityToSlaveNoMaster());
         verify(mockClusterSingletonService).closeServiceInstance();
     }
 
     /**
-     * Test checks validation Error processing for MASTER-TO-SLAVE closeEntity Candidate role change
+     * Test checks validation Error processing for MASTER-TO-SLAVE closeEntity Candidate role change.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void checkClosingUnexpectedDoubleEntityForMasterOwnershipChangeRegistrationTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        map.putIfAbsent(SERVICE_IDENTIFIER, singletonServiceGroup);
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void checkClosingUnexpectedDoubleEntityForMasterOwnershipChangeRegistrationTest()
+            throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToMaster());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService).registerCandidate(closeEntity);
+        verify(mockEosService).registerCandidate(CLOSE_ENTITY);
         singletonServiceGroup.ownershipChanged(getDoubleEntityToMaster());
         verify(mockClusterSingletonService).instantiateServiceInstance();
         singletonServiceGroup.ownershipChanged(getDoubleEntityToSlave());
         verify(mockClusterSingletonService).closeServiceInstance();
-        final ClusterSingletonServiceGroup<?, ?, ?> serviceGroup = map.get(SERVICE_IDENTIFIER);
-        Assert.assertNull(serviceGroup);
     }
 
     /**
      * Test checks validation Error processing for MASTER-TO-SLAVE closeEntity Candidate role change
-     * without closeEntity registration
+     *     without closeEntity registration.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void checkClosingUnexpectedDoubleEntityForSlaveOwnershipChangeRegistrationTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        map.putIfAbsent(SERVICE_IDENTIFIER, singletonServiceGroup);
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void checkClosingUnexpectedDoubleEntityForSlaveOwnershipChangeRegistrationTest()
+            throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToSlave());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService, never()).registerCandidate(closeEntity);
+        verify(mockEosService, never()).registerCandidate(CLOSE_ENTITY);
         singletonServiceGroup.ownershipChanged(getDoubleEntityToSlave());
         verify(mockClusterSingletonService, never()).closeServiceInstance();
-        final ClusterSingletonServiceGroup<?, ?, ?> serviceGroup = map.get(SERVICE_IDENTIFIER);
-        Assert.assertNull(serviceGroup);
     }
 
-    private GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getEntityToMaster() {
-        return new GenericEntityOwnershipChange<>(mainEntity, EntityOwnershipChangeState.from(false, true, true));
+    @Test
+    public void testRegisterCloseShutdown() throws CandidateAlreadyRegisteredException, InterruptedException,
+            ExecutionException {
+        initializeGroupAndStartService();
+
+        assertTrue(singletonServiceGroup.unregisterService(mockClusterSingletonService));
+        verify(mockClusterSingletonService, never()).closeServiceInstance();
+        verify(mockEntityCandReg, never()).close();
+
+        final ListenableFuture<?> future = singletonServiceGroup.closeClusterSingletonGroup();
+        assertNotNull(future);
+        assertFalse(future.isDone());
+        verify(mockClusterSingletonService, never()).closeServiceInstance();
+        verify(mockEntityCandReg).close();
+
+        singletonServiceGroup.ownershipChanged(getEntityToSlave());
+        verify(mockClusterSingletonService).closeServiceInstance();
+        verify(mockCloseEntityCandReg).close();
+
+        singletonServiceGroup.ownershipChanged(getDoubleEntityToSlave());
+        assertTrue(future.isDone());
+        assertNull(future.get());
+    }
+
+    private void initialize() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
     }
 
-    private GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getEntityToSlave() {
-        return new GenericEntityOwnershipChange<>(mainEntity, EntityOwnershipChangeState.from(true, false, true));
+    private void initializeGroupAndStartService() throws CandidateAlreadyRegisteredException {
+        initialize();
+        singletonServiceGroup.registerService(mockClusterSingletonService);
+        singletonServiceGroup.ownershipChanged(getEntityToMaster());
+        verify(mockEosService).registerCandidate(CLOSE_ENTITY);
+        singletonServiceGroup.ownershipChanged(getDoubleEntityToMaster());
+        verify(mockClusterSingletonService).instantiateServiceInstance();
     }
 
-    private GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getEntityToSlaveNoMaster() {
-        return new GenericEntityOwnershipChange<>(mainEntity, EntityOwnershipChangeState.from(true, false, false));
+    private static GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getEntityToMaster() {
+        return new GenericEntityOwnershipChange<>(MAIN_ENTITY, EntityOwnershipChangeState.LOCAL_OWNERSHIP_GRANTED);
     }
 
-    private GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getDoubleEntityToMaster() {
-        return new GenericEntityOwnershipChange<>(closeEntity, EntityOwnershipChangeState.from(false, true, true));
+    private static GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getEntityToSlave() {
+        return new GenericEntityOwnershipChange<>(MAIN_ENTITY,
+                EntityOwnershipChangeState.LOCAL_OWNERSHIP_LOST_NEW_OWNER);
     }
 
-    private GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getDoubleEntityToSlave() {
-        return new GenericEntityOwnershipChange<>(closeEntity, EntityOwnershipChangeState.from(true, false, true));
+    private static GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getEntityToSlaveNoMaster() {
+        return new GenericEntityOwnershipChange<>(MAIN_ENTITY,
+                EntityOwnershipChangeState.LOCAL_OWNERSHIP_LOST_NO_OWNER);
     }
 
-    private GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getInitDoubleEntityToSlave() {
-        return new GenericEntityOwnershipChange<>(closeEntity, EntityOwnershipChangeState.from(false, false, true));
+    private static GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getEntityToJeopardy() {
+        return new GenericEntityOwnershipChange<>(MAIN_ENTITY,
+                EntityOwnershipChangeState.REMOTE_OWNERSHIP_LOST_NO_OWNER, true);
     }
 
-    private GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getEntityToJeopardy() {
-        return new GenericEntityOwnershipChange<>(mainEntity, EntityOwnershipChangeState.from(false, false, false), true);
+    private static GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getDoubleEntityToMaster() {
+        return new GenericEntityOwnershipChange<>(CLOSE_ENTITY, EntityOwnershipChangeState.LOCAL_OWNERSHIP_GRANTED);
     }
 
+    private static GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getDoubleEntityToSlave() {
+        return new GenericEntityOwnershipChange<>(CLOSE_ENTITY,
+                EntityOwnershipChangeState.LOCAL_OWNERSHIP_LOST_NEW_OWNER);
+    }
+
+    private static GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getInitDoubleEntityToSlave() {
+        return new GenericEntityOwnershipChange<>(CLOSE_ENTITY, EntityOwnershipChangeState.REMOTE_OWNERSHIP_CHANGED);
+    }
+
+    private static GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getDoubleEntityToJeopardy() {
+        return new GenericEntityOwnershipChange<>(CLOSE_ENTITY,
+                EntityOwnershipChangeState.REMOTE_OWNERSHIP_LOST_NO_OWNER, true);
+    }
 }