Bug 5421 - Single cluster-wide service instances implementation 57/37957/29
authorVaclav Demcak <[email protected]>
Thu, 14 Apr 2016 09:32:29 +0000 (11:32 +0200)
committerTom Pantelis <[email protected]>
Mon, 18 Jul 2016 15:25:56 +0000 (15:25 +0000)
 * add Abstract ClusterSingletonServiceProvider implementation
 * add DOM & biniding ClusterSingletonServiceProvider impl.
 * add junit test suite + import Mockito

Change-Id: If5bac3f61cc3164da1e09c2caf6713c1e3da658a
Signed-off-by: Vaclav Demcak <[email protected]>
13 files changed:
binding/mdsal-binding-api/pom.xml
common/artifacts/pom.xml
common/features/pom.xml
common/features/src/main/features/features.xml
dom/mdsal-dom-api/pom.xml
singleton-service/mdsal-singleton-binding-impl/pom.xml [new file with mode: 0644]
singleton-service/mdsal-singleton-binding-impl/src/main/java/org/opendaylight/mdsal/singleton/binding/impl/ClusterSingletonServiceProviderImpl.java [new file with mode: 0644]
singleton-service/mdsal-singleton-binding-impl/src/test/java/org/opendaylight/mdsal/singleton/binding/impl/ClusterSingletonServiceProviderImplTest.java [new file with mode: 0644]
singleton-service/mdsal-singleton-common-spi/src/main/java/org/opendaylight/mdsal/singleton/common/spi/AbstractClusterSingletonServiceProviderImpl.java
singleton-service/mdsal-singleton-dom-impl/pom.xml [new file with mode: 0644]
singleton-service/mdsal-singleton-dom-impl/src/main/java/org/opendaylight/mdsal/singleton/dom/impl/DOMClusterSingletonServiceProviderImpl.java [new file with mode: 0644]
singleton-service/mdsal-singleton-dom-impl/src/test/java/org/opendaylight/mdsal/singleton/dom/impl/DOMClusterSingletonServiceProviderImplTest.java [new file with mode: 0644]
singleton-service/pom.xml

index c33c4a5ad15c3c5045004a62bb50d06530a1a4f7..c0514f93b1c7b6bc6ecda8373210185d5b158daf 100644 (file)
       <artifactId>commons-lang3</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <scope>test</scope>
+    </dependency>
     <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
index f9eafaaa56345f4bf391b24b2de6f16e0f3711bd..ca993a3e2ff968bb04a5db7ea7225e376e1d24a7 100644 (file)
                 <artifactId>mdsal-singleton-dom-api</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.opendaylight.mdsal</groupId>
+                <artifactId>mdsal-singleton-dom-impl</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.opendaylight.mdsal</groupId>
                 <artifactId>mdsal-singleton-binding-api</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.opendaylight.mdsal</groupId>
+                <artifactId>mdsal-singleton-binding-impl</artifactId>
+                <version>${project.version}</version>
+            </dependency>
         </dependencies>
     </dependencyManagement>
 
index 7369b1c3f4c2191e79b1be8821fcc1d30369e49e..5121b1bcdd7aeda288b97d7a9ea547a47abd2c32 100644 (file)
             <groupId>${project.groupId}</groupId>
             <artifactId>mdsal-eos-binding-adapter</artifactId>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>mdsal-singleton-common-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>mdsal-singleton-common-spi</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>mdsal-singleton-dom-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>mdsal-singleton-dom-impl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>mdsal-singleton-binding-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>mdsal-singleton-binding-impl</artifactId>
+        </dependency>
 
         <!-- Binding MD-SAL & Java Binding -->
         <dependency>
index 394f83d51bfb570d325ad3bd9b27f1080f030cd5..df61d09f9e170266b22707d08793d3a89507a82a 100644 (file)
         <bundle>mvn:org.opendaylight.mdsal/mdsal-eos-common-spi/{{VERSION}}</bundle>
     </feature>
 
-    <feature name='odl-mdsal-eos-dom' version='${project.version}' description='OpenDaylight :: MD-SAL :: EOS :: Common'>
+    <feature name='odl-mdsal-eos-dom' version='${project.version}' description='OpenDaylight :: MD-SAL :: EOS :: DOM'>
         <feature version='${project.version}'>odl-mdsal-eos-common</feature>
         <bundle>mvn:org.opendaylight.mdsal/mdsal-eos-dom-api/{{VERSION}}</bundle>
     </feature>
 
-    <feature name='odl-mdsal-eos-binding' version='${project.version}' description='OpenDaylight :: MD-SAL :: EOS :: Common'>
+    <feature name='odl-mdsal-eos-binding' version='${project.version}' description='OpenDaylight :: MD-SAL :: EOS :: Binding'>
         <feature version='${project.version}'>odl-mdsal-eos-dom</feature>
         <feature version='${project.version}'>odl-mdsal-binding-dom-adapter</feature>
         <bundle>mvn:org.opendaylight.mdsal/mdsal-eos-binding-api/{{VERSION}}</bundle>
         <bundle>mvn:org.opendaylight.mdsal/mdsal-eos-binding-adapter/{{VERSION}}</bundle>
     </feature>
 
+    <feature name='odl-mdsal-singleton-common' version='${project.version}' description='OpenDaylight :: MD-SAL :: Singleton :: Common'>
+        <feature version='${project.version}'>odl-mdsal-eos-common</feature>
+        <bundle>mvn:org.opendaylight.mdsal/mdsal-singleton-common-api/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.mdsal/mdsal-singleton-common-spi/{{VERSION}}</bundle>
+    </feature>
+
+    <feature name='odl-mdsal-singleton-dom' version='${project.version}' description='OpenDaylight :: MD-SAL :: Singleton :: DOM'>
+        <feature version='${project.version}'>odl-mdsal-singleton-common</feature>
+        <feature version='${project.version}'>odl-mdsal-eos-dom</feature>
+        <bundle>mvn:org.opendaylight.mdsal/mdsal-singleton-dom-api/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.mdsal/mdsal-singleton-dom-impl/{{VERSION}}</bundle>
+    </feature>
+
+    <feature name='odl-mdsal-singleton-binding' version='${project.version}' description='OpenDaylight :: MD-SAL :: Singleton :: Binding'>
+        <feature version='${project.version}'>odl-mdsal-singleton-common</feature>
+        <feature version='${project.version}'>odl-mdsal-eos-binding</feature>
+        <bundle>mvn:org.opendaylight.mdsal/mdsal-singleton-binding-api/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.mdsal/mdsal-singleton-binding-impl/{{VERSION}}</bundle>
+    </feature>
+
 </features>
index 311a4bf03f118c510a7e48f7d5090e1f01243761..307de4f3a171e2d1516d8e3f4008b32ab2e75544 100644 (file)
       <artifactId>yang-data-impl</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
   <build>
     <plugins>
diff --git a/singleton-service/mdsal-singleton-binding-impl/pom.xml b/singleton-service/mdsal-singleton-binding-impl/pom.xml
new file mode 100644 (file)
index 0000000..7c26229
--- /dev/null
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.mdsal</groupId>
+    <artifactId>singleton-service</artifactId>
+    <version>2.1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>mdsal-singleton-binding-impl</artifactId>
+  <packaging>bundle</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.mdsal</groupId>
+      <artifactId>mdsal-eos-binding-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal</groupId>
+      <artifactId>mdsal-singleton-common-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal</groupId>
+      <artifactId>mdsal-singleton-common-spi</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal</groupId>
+      <artifactId>mdsal-singleton-binding-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>concepts</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>util</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-common</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>mockito-configuration</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <scm>
+    <connection>scm:git:http://git.opendaylight.org/gerrit/controller.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+  </scm>
+
+  <!--
+      Maven Site Configuration
+
+      The following configuration is necessary for maven-site-plugin to
+      correctly identify the correct deployment path for OpenDaylight Maven
+      sites.
+  -->
+  <url>${odl.site.url}/${project.groupId}/${stream}/${project.artifactId}/</url>
+
+  <distributionManagement>
+    <site>
+      <id>opendaylight-site</id>
+      <url>${nexus.site.url}/${project.artifactId}/</url>
+    </site>
+  </distributionManagement>
+
+</project>
diff --git a/singleton-service/mdsal-singleton-binding-impl/src/main/java/org/opendaylight/mdsal/singleton/binding/impl/ClusterSingletonServiceProviderImpl.java b/singleton-service/mdsal-singleton-binding-impl/src/main/java/org/opendaylight/mdsal/singleton/binding/impl/ClusterSingletonServiceProviderImpl.java
new file mode 100644 (file)
index 0000000..f9fe93a
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.mdsal.singleton.binding.impl;
+
+import org.opendaylight.mdsal.eos.binding.api.Entity;
+import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipChange;
+import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipListener;
+import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipListenerRegistration;
+import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipService;
+import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipService;
+import org.opendaylight.mdsal.singleton.binding.api.ClusterSingletonServiceProvider;
+import org.opendaylight.mdsal.singleton.common.spi.AbstractClusterSingletonServiceProviderImpl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.core.general.entity.rev150930.EntityKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Binding version of {@link AbstractClusterSingletonServiceProviderImpl}
+ */
+public final class ClusterSingletonServiceProviderImpl extends
+        AbstractClusterSingletonServiceProviderImpl<InstanceIdentifier<?>, Entity,
+                                                    EntityOwnershipChange,
+                                                    EntityOwnershipListener,
+                                                    EntityOwnershipService,
+                                                    EntityOwnershipListenerRegistration>
+        implements ClusterSingletonServiceProvider {
+
+    /**
+     * Initialization all needed class internal property for {@link ClusterSingletonServiceProviderImpl}
+     *
+     * @param entityOwnershipService - we need only {@link GenericEntityOwnershipService}
+     */
+    public ClusterSingletonServiceProviderImpl(final EntityOwnershipService entityOwnershipService) {
+        super(entityOwnershipService);
+    }
+
+    @Override
+    protected final Entity createEntity(final String type, final String ident) {
+        return new Entity(type, ident);
+    }
+
+    @Override
+    protected final EntityOwnershipListenerRegistration registerListener(final String type,
+            final EntityOwnershipService eos) {
+        return eos.registerListener(type, this);
+    }
+
+    @Override
+    protected final String getServiceIdentifierFromEntity(final Entity entity) {
+        final InstanceIdentifier<?> ii = entity.getIdentifier();
+        final EntityKey entityKey = ii.firstKeyOf(
+                org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.core.general.entity.rev150930.Entity.class);
+        return entityKey.getName();
+    }
+}
diff --git a/singleton-service/mdsal-singleton-binding-impl/src/test/java/org/opendaylight/mdsal/singleton/binding/impl/ClusterSingletonServiceProviderImplTest.java b/singleton-service/mdsal-singleton-binding-impl/src/test/java/org/opendaylight/mdsal/singleton/binding/impl/ClusterSingletonServiceProviderImplTest.java
new file mode 100644 (file)
index 0000000..4208dd8
--- /dev/null
@@ -0,0 +1,695 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.mdsal.singleton.binding.impl;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.mdsal.eos.binding.api.Entity;
+import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipCandidateRegistration;
+import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipChange;
+import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipListenerRegistration;
+import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipService;
+import org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException;
+import org.opendaylight.mdsal.eos.common.api.EntityOwnershipChangeState;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
+import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
+
+/**
+ * Testing {@link ClusterSingletonServiceProviderImpl}
+ */
+public class ClusterSingletonServiceProviderImplTest {
+
+    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_NAME = "testServiceName";
+
+    @Mock
+    private EntityOwnershipService mockEos;
+    @Mock
+    private EntityOwnershipCandidateRegistration mockEntityCandReg;
+    @Mock
+    private EntityOwnershipCandidateRegistration mockDoubleEntityCandReg;
+    @Mock
+    private EntityOwnershipListenerRegistration mockEosEntityListReg;
+    @Mock
+    private EntityOwnershipListenerRegistration mockEosDoubleEntityListReg;
+
+    private ClusterSingletonServiceProviderImpl clusterSingletonServiceProvider;
+    private TestClusterSingletonServiceInstance clusterSingletonService;
+    private TestClusterSingletonServiceInstance clusterSingletonService2;
+
+    private final Entity entity = new Entity(SERVICE_ENTITY_TYPE, SERVICE_NAME);
+    private final Entity doubleEntity = new Entity(CLOSE_SERVICE_ENTITY_TYPE, SERVICE_NAME);
+
+    /**
+     * Initialization functionality for every Tests in this suite
+     *
+     * @throws Exception
+     */
+    @Before
+    public void setup() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        doNothing().when(mockEosEntityListReg).close();
+        doNothing().when(mockEosDoubleEntityListReg).close();
+        doNothing().when(mockEntityCandReg).close();
+        doNothing().when(mockDoubleEntityCandReg).close();
+        doReturn(mockEosEntityListReg).when(mockEos).registerListener(eq(SERVICE_ENTITY_TYPE),
+                any(ClusterSingletonServiceProviderImpl.class));
+        doReturn(mockEosDoubleEntityListReg).when(mockEos).registerListener(eq(CLOSE_SERVICE_ENTITY_TYPE),
+                any(ClusterSingletonServiceProviderImpl.class));
+        doReturn(mockEntityCandReg).when(mockEos).registerCandidate(entity);
+        doReturn(mockDoubleEntityCandReg).when(mockEos).registerCandidate(doubleEntity);
+
+        clusterSingletonServiceProvider = new ClusterSingletonServiceProviderImpl(mockEos);
+        clusterSingletonServiceProvider.initializeProvider();
+        verify(mockEos).registerListener(SERVICE_ENTITY_TYPE, clusterSingletonServiceProvider);
+        verify(mockEos).registerListener(CLOSE_SERVICE_ENTITY_TYPE, clusterSingletonServiceProvider);
+
+        clusterSingletonService = new TestClusterSingletonServiceInstance();
+        clusterSingletonService2 = new TestClusterSingletonServiceInstance();
+
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+    }
+
+    /**
+     * Test checks NullPointer for null {@link EntityOwnershipService} input value
+     *
+     * @throws Exception
+     */
+    @Test(expected = NullPointerException.class)
+    public void initializationClusterSingletonServiceProviderNullInputTest() throws Exception {
+        clusterSingletonServiceProvider = new ClusterSingletonServiceProviderImpl(null);
+    }
+
+    /**
+     * Test GoldPath for close {@link ClusterSingletonServiceProviderImpl}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void closeClusterSingletonServiceProviderTest() throws Exception {
+        verify(mockEos).registerListener(SERVICE_ENTITY_TYPE, clusterSingletonServiceProvider);
+        verify(mockEos).registerListener(CLOSE_SERVICE_ENTITY_TYPE, clusterSingletonServiceProvider);
+        clusterSingletonServiceProvider.close();
+        verify(mockEosEntityListReg).close();
+        verify(mockEosDoubleEntityListReg).close();
+    }
+
+    /**
+     * Test parser ServiceIdentifier from Entity
+     *
+     * @throws Exception
+     */
+    @Test
+    public void makeEntityClusterSingletonServiceProviderTest() throws Exception {
+        final Entity testEntity = clusterSingletonServiceProvider.createEntity(SERVICE_ENTITY_TYPE, SERVICE_NAME);
+        Assert.assertEquals(entity, testEntity);
+        final Entity testDbEn = clusterSingletonServiceProvider.createEntity(CLOSE_SERVICE_ENTITY_TYPE, SERVICE_NAME);
+        Assert.assertEquals(doubleEntity, testDbEn);
+    }
+
+    /**
+     * Test parser ServiceIdentifier from Entity
+     *
+     * @throws Exception
+     */
+    @Test
+    public void getIdentifierClusterSingletonServiceProviderTest() throws Exception {
+        final String entityIdentifier = clusterSingletonServiceProvider.getServiceIdentifierFromEntity(entity);
+        Assert.assertEquals(SERVICE_NAME, entityIdentifier);
+        final String doubleEntityId = clusterSingletonServiceProvider.getServiceIdentifierFromEntity(doubleEntity);
+        Assert.assertEquals(SERVICE_NAME, doubleEntityId);
+    }
+
+    /**
+     * Test GoldPath for initialization {@link ClusterSingletonService}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void initializationClusterSingletonServiceTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for initialization with init ownership result SLAVE {@link ClusterSingletonService}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void slaveInitClusterSingletonServiceTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlave());
+        verify(mockEos, never()).registerCandidate(doubleEntity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for initialization with init ownership result SLAVE, but NO-MASTER {@link ClusterSingletonService}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void slaveInitNoMasterClusterSingletonServiceTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlaveNoMaster());
+        verify(mockEos, never()).registerCandidate(doubleEntity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for initialization with init ownership result MASTER {@link ClusterSingletonService}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void masterInitClusterSingletonServiceTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for initialization with init ownership result MASTER {@link ClusterSingletonService}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void masterInitSlaveDoubleCandidateClusterSingletonServiceTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for takeLeadership with ownership result MASTER {@link ClusterSingletonService}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void takeLeadershipClusterSingletonServiceTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for initialization with init ownership result MASTER {@link ClusterSingletonService}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void masterInitClusterSingletonServiceTwoServicesTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService2);
+        Assert.assertNotNull(reg2);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for takeLeadership with ownership result MASTER {@link ClusterSingletonService}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void takeLeadershipClusterSingletonServiceTwoAddDuringWaitPhaseServicesTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService2);
+        Assert.assertNotNull(reg2);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for takeLeadership with ownership result MASTER {@link ClusterSingletonService}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void takeLeadershipClusterSingletonServiceTowServicesTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService2);
+        Assert.assertNotNull(reg2);
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+    }
+
+    /**
+     * Test checks CandidateAlreadyRegisteredException processing in initialization phase
+     *
+     * @throws Exception
+     */
+    @Test
+    public void initializationClusterSingletonServiceCandidateAlreadyRegistredTest() throws Exception {
+        doThrow(CandidateAlreadyRegisteredException.class).when(mockEos).registerCandidate(entity);
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNull(reg);
+    }
+
+    /**
+     * Test GoldPath for lostLeadership during tryToTakeLeadership with ownership result MASTER
+     * {@link ClusterSingletonService}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void lostLeadershipDuringTryToTakeLeadershipClusterSingletonServiceTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for lostLeadership with ownership result MASTER-TO-SLAVE {@link ClusterSingletonService}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void lostLeadershipClusterSingletonServiceTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
+        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test checks umexpected change for MASTER-TO-SLAVE double Candidate role change
+     *
+     * @throws Exception
+     */
+    @Test
+    public void unexpectedLostLeadershipDoubleCandidateTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToSlave());
+        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg, never()).close();
+        verify(mockDoubleEntityCandReg).close();
+    }
+
+    /**
+     * Test checks inJeopardy Cluster Node state for Master Instance
+     *
+     * @throws Exception
+     */
+    @Test
+    public void inJeopardyMasterTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToJeopardy());
+        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg, never()).close();
+        verify(mockDoubleEntityCandReg).close();
+    }
+
+    /**
+     * Test checks inJeopardy Cluster Node state for Slave Instance
+     *
+     * @throws Exception
+     */
+    @Test
+    public void inJeopardySlaveTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlave());
+        verify(mockEos, never()).registerCandidate(doubleEntity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToJeopardy());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg, never()).close();
+        verify(mockDoubleEntityCandReg, never()).close();
+    }
+
+    /**
+     * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void closeClusterSingletonServiceRegistrationNoRoleTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        reg.close();
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg).close();
+        verify(mockDoubleEntityCandReg, never()).close();
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void closeClusterSingletonServiceRegistrationNoRoleTwoServicesTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService2);
+        Assert.assertNotNull(reg2);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+        reg.close();
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg, never()).close();
+        verify(mockDoubleEntityCandReg, never()).close();
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+    }
+
+    /**
+     * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void closeClusterSingletonServiceRegistrationSlaveTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlave());
+        reg.close();
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg).close();
+        verify(mockDoubleEntityCandReg, never()).close();
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void closeClusterSingletonServiceRegistrationSlaveTwoServicesTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService2);
+        Assert.assertNotNull(reg2);
+        clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlave());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+        reg.close();
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg, never()).close();
+        verify(mockDoubleEntityCandReg, never()).close();
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+    }
+
+    /**
+     * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void closeClusterSingletonServiceRegistrationMasterTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        reg.close();
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg).close();
+        verify(mockDoubleEntityCandReg).close();
+        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void closeClusterSingletonServiceRegistrationMasterTwoServicesTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService2);
+        Assert.assertNotNull(reg2);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+        reg.close();
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg, never()).close();
+        verify(mockDoubleEntityCandReg, never()).close();
+        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+    }
+
+    /**
+     * Test checks validation Error processing for SLAVE-TO-MASTER entity Candidate role change
+     *
+     * @throws Exception
+     */
+    @Test
+    public void tryToTakeLeaderForClosedServiceRegistrationTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService2);
+        Assert.assertNotNull(reg2);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+        verify(mockEos).registerCandidate(entity);
+        reg.close();
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg, never()).close();
+        verify(mockDoubleEntityCandReg, never()).close();
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+    }
+
+    private EntityOwnershipChange getEntityToMaster() {
+        return new EntityOwnershipChange(entity, EntityOwnershipChangeState.from(false, true, true));
+    }
+
+    private EntityOwnershipChange getEntityToSlave() {
+        return new EntityOwnershipChange(entity, EntityOwnershipChangeState.from(true, false, true));
+    }
+
+    private EntityOwnershipChange getInitEntityToSlave() {
+        return new EntityOwnershipChange(entity, EntityOwnershipChangeState.from(false, false, true));
+    }
+
+    private EntityOwnershipChange getInitEntityToSlaveNoMaster() {
+        return new EntityOwnershipChange(entity, EntityOwnershipChangeState.from(false, false, false));
+    }
+
+    private EntityOwnershipChange getDoubleEntityToMaster() {
+        return new EntityOwnershipChange(doubleEntity, EntityOwnershipChangeState.from(false, true, true));
+    }
+
+    private EntityOwnershipChange getInitDoubleEntityToSlave() {
+        return new EntityOwnershipChange(doubleEntity, EntityOwnershipChangeState.from(false, false, true));
+    }
+
+    private EntityOwnershipChange getDoubleEntityToSlave() {
+        return new EntityOwnershipChange(doubleEntity, EntityOwnershipChangeState.from(true, false, true));
+    }
+
+    private EntityOwnershipChange getEntityToJeopardy() {
+        return new EntityOwnershipChange(entity, EntityOwnershipChangeState.from(false, false, false), true);
+    }
+
+    /**
+     * Base states for AbstractClusterProjectProvider
+     */
+    static enum TestClusterSingletonServiceState {
+        /**
+         * State represents a correct Instantiated process
+         */
+        STARTED,
+        /**
+         * State represents a correct call abstract method instantiatingProject
+         */
+        INITIALIZED,
+        /**
+         * State represents a correct call abstract method destryingProject
+         */
+        DESTROYED;
+    }
+
+    /**
+     * Test implementation of {@link ClusterSingletonService}
+     */
+    class TestClusterSingletonServiceInstance implements ClusterSingletonService {
+
+        private final ServiceGroupIdentifier SERVICE_IDENT = ServiceGroupIdentifier.create(SERVICE_NAME);
+        private TestClusterSingletonServiceState serviceState;
+
+        public TestClusterSingletonServiceInstance() {
+            this.serviceState = TestClusterSingletonServiceState.INITIALIZED;
+        }
+
+        @Override
+        public void instantiateServiceInstance() {
+            this.serviceState = TestClusterSingletonServiceState.STARTED;
+        }
+
+        @Override
+        public ListenableFuture<Void> closeServiceInstance() {
+            this.serviceState = TestClusterSingletonServiceState.DESTROYED;
+            return Futures.immediateFuture(null);
+        }
+
+        public TestClusterSingletonServiceState getServiceState() {
+            return serviceState;
+        }
+
+        @Override
+        public ServiceGroupIdentifier getIdentifier() {
+            return SERVICE_IDENT;
+        }
+    }
+
+}
index 02ee82966bd83b0e7c4058b8b8040af2af7bf723..b18f1e0f667f983e0c634b5ed4573e4254c5a688 100644 (file)
 
 package org.opendaylight.mdsal.singleton.common.spi;
 
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.mdsal.eos.common.api.GenericEntity;
+import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipChange;
+import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipListener;
+import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipListenerRegistration;
+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.CommonClusterSingletonServiceProvider;
+import org.opendaylight.yangtools.concepts.Path;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 /**
  * Abstract class {@link AbstractClusterSingletonServiceProviderImpl} represents implementations of
- * {@link org.opendaylight.mdsal.singleton.common.api.CommonClusterSingletonServiceProvider}.
+ * {@link CommonClusterSingletonServiceProvider} and it implements {@link GenericEntityOwnershipListener}
+ * for providing OwnershipChange for all registered {@link ClusterSingletonServiceGroup} entity
+ * candidate.
+ *
+ * @param <P> the instance identifier path type
+ * @param <E> the GenericEntity type
+ * @param <C> the GenericEntityOwnershipChange type
+ * @param <G> the GenericEntityOwnershipListener type
+ * @param <S> the GenericEntityOwnershipService type
+ * @param <R> the GenericEntityOwnershipListenerRegistration type
  */
-public abstract class AbstractClusterSingletonServiceProviderImpl {
+public abstract class AbstractClusterSingletonServiceProviderImpl<P extends Path<P>, E extends GenericEntity<P>,
+                                                                  C extends GenericEntityOwnershipChange<P, E>,
+                                                                  G extends GenericEntityOwnershipListener<P, C>,
+                                                                  S extends GenericEntityOwnershipService<P, E, G>,
+                                                                  R extends GenericEntityOwnershipListenerRegistration<P, G>>
+        implements CommonClusterSingletonServiceProvider, GenericEntityOwnershipListener<P, C> {
+
+    private static final Logger LOG = LoggerFactory
+            .getLogger(AbstractClusterSingletonServiceProviderImpl.class.getName());
+
+    private static final String SERVICE_ENTITY_TYPE = "org.opendaylight.mdsal.ServiceEntityType";
+    private static final String CLOSE_SERVICE_ENTITY_TYPE = "org.opendaylight.mdsal.AsyncServiceCloseEntityType";
+
+    private final S entityOwnershipService;
+    private final ConcurrentMap<String, ClusterSingletonServiceGroup<P, E, C>> serviceGroupMap = new ConcurrentHashMap<>();
+
+    /* EOS Entity Listeners Registration */
+    private R serviceEntityListenerReg;
+    private R asyncCloseEntityListenerReg;
+
+    /**
+     * Class constructor
+     *
+     * @param entityOwnershipService relevant EOS
+     */
+    protected AbstractClusterSingletonServiceProviderImpl(@Nonnull final S entityOwnershipService) {
+        this.entityOwnershipService = Preconditions.checkNotNull(entityOwnershipService);
+    }
+
+    /**
+     * This method must be called once on startup to initialize this provider.
+     */
+    public final void initializeProvider() {
+        LOG.debug("Initialization method for ClusterSingletonService Provider {}", this.getClass().getName());
+        this.serviceEntityListenerReg = registerListener(SERVICE_ENTITY_TYPE, entityOwnershipService);
+        this.asyncCloseEntityListenerReg = registerListener(CLOSE_SERVICE_ENTITY_TYPE, entityOwnershipService);
+    }
+
+    @Override
+    public final ClusterSingletonServiceRegistration registerClusterSingletonService(
+            @CheckForNull final ClusterSingletonService service) {
+        LOG.debug("Call registrationService {} method for ClusterSingletonService Provider {}", service,
+                this.getClass().getName());
+
+        Preconditions.checkArgument(service != null);
+        Preconditions.checkArgument(!Strings.isNullOrEmpty(service.getIdentifier().getValue()),
+                "ClusterSingletonService idetnifier can not be null. {}", service);
+
+        final String serviceIdentifier = service.getIdentifier().getValue();
+        ClusterSingletonServiceGroup<P, E, C> serviceGroup = serviceGroupMap.get(serviceIdentifier);
+        if (serviceGroup == null) {
+            final E mainEntity = createEntity(SERVICE_ENTITY_TYPE, serviceIdentifier);
+            final E closeEntity = createEntity(CLOSE_SERVICE_ENTITY_TYPE, serviceIdentifier);
+            serviceGroup = new ClusterSingletonServiceGroupImpl<>(serviceIdentifier,
+                    mainEntity, closeEntity, entityOwnershipService, serviceGroupMap);
+            serviceGroupMap.put(service.getIdentifier().getValue(), serviceGroup);
+            serviceGroup.initializationClusterSingletonGroup();
+        }
+        return serviceGroup.registerService(service);
+    }
+
+    @Override
+    public final void close() {
+        LOG.debug("Close method for ClusterSingletonService Provider {}", this.getClass().getName());
+
+        if (serviceEntityListenerReg != null) {
+            serviceEntityListenerReg.close();
+            serviceEntityListenerReg = null;
+        }
+
+        final List<ListenableFuture<List<Void>>> listGroupCloseListFuture = new ArrayList<>();
+
+        for (final ClusterSingletonServiceGroup<P, E, C> serviceGroup : serviceGroupMap.values()) {
+            listGroupCloseListFuture.add(serviceGroup.closeClusterSingletonGroup());
+        }
+
+        final ListenableFuture<List<List<Void>>> finalCloseFuture = Futures.allAsList(listGroupCloseListFuture);
+        Futures.addCallback(finalCloseFuture, new FutureCallback<List<List<Void>>>() {
+
+            @Override
+            public void onSuccess(final List<List<Void>> result) {
+                cleaningProvider(null);
+            }
+
+            @Override
+            public void onFailure(final Throwable t) {
+                cleaningProvider(t);
+            }
+        });
+    }
+
+    @Override
+    public final void ownershipChanged(final C ownershipChange) {
+        LOG.debug("Ownership change for ClusterSingletonService Provider {}", ownershipChange);
+        final String serviceIdentifier = getServiceIdentifierFromEntity(ownershipChange.getEntity());
+        final ClusterSingletonServiceGroup<P, E, C> serviceHolder = serviceGroupMap.get(serviceIdentifier);
+        if (serviceHolder != null) {
+            serviceHolder.ownershipChanged(ownershipChange);
+        } else {
+            LOG.debug("ClusterSingletonServiceGroup was not found for serviceIdentifier {}", serviceIdentifier);
+        }
+    }
+
+    /**
+     * Method implementation registers a defined {@link GenericEntityOwnershipListenerRegistration} type
+     * EntityOwnershipListenerRegistration.
+     *
+     * @param entityType the type of the entity
+     * @param entityOwnershipServiceInst - EOS type
+     * @return instance of EntityOwnershipListenerRegistration
+     */
+    protected abstract R registerListener(final String entityType, final S entityOwnershipServiceInst);
+
+    /**
+     * Creates an extended {@link GenericEntity} instance.
+     *
+     * @param entityType the type of the entity
+     * @param entityIdentifier the identifier of the entity
+     * @return instance of Entity extended GenericEntity type
+     */
+    protected abstract E createEntity(final String entityType, final String entityIdentifier);
+
+    /**
+     * Method is responsible for parsing ServiceGroupIdentifier from E entity.
+     *
+     * @param entity
+     * @return ServiceGroupIdentifier parsed from entity key value.
+     */
+    protected abstract String getServiceIdentifierFromEntity(final E entity);
 
-    // TODO: add implementation
+    /**
+     * Method is called async. from close method in end of Provider lifecycle.
+     *
+     * @param t Throwable (needs for log)
+     */
+    protected final void cleaningProvider(@Nullable final Throwable t) {
+        LOG.debug("Final cleaning ClusterSingletonServiceProvider {}", this.getClass().getName());
+        if (t != null) {
+            LOG.warn("Unexpected problem by closing ClusterSingletonServiceProvider {}", this.getClass().getName(), t);
+        }
+        if (asyncCloseEntityListenerReg != null) {
+            asyncCloseEntityListenerReg.close();
+            asyncCloseEntityListenerReg = null;
+        }
+        serviceGroupMap.clear();
+    }
 }
diff --git a/singleton-service/mdsal-singleton-dom-impl/pom.xml b/singleton-service/mdsal-singleton-dom-impl/pom.xml
new file mode 100644 (file)
index 0000000..8185a91
--- /dev/null
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.mdsal</groupId>
+    <artifactId>singleton-service</artifactId>
+    <version>2.1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>mdsal-singleton-dom-impl</artifactId>
+  <packaging>bundle</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.mdsal</groupId>
+      <artifactId>mdsal-common-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal</groupId>
+      <artifactId>mdsal-singleton-common-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal</groupId>
+      <artifactId>mdsal-singleton-common-spi</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal</groupId>
+      <artifactId>mdsal-singleton-dom-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-data-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-model-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-data-impl</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+      </plugin>
+    </plugins>
+  </build>
+  <scm>
+    <connection>scm:git:http://git.opendaylight.org/gerrit/controller.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+  </scm>
+
+  <!--
+      Maven Site Configuration
+
+      The following configuration is necessary for maven-site-plugin to
+      correctly identify the correct deployment path for OpenDaylight Maven
+      sites.
+  -->
+  <url>${odl.site.url}/${project.groupId}/${stream}/${project.artifactId}/</url>
+
+  <distributionManagement>
+    <site>
+      <id>opendaylight-site</id>
+      <url>${nexus.site.url}/${project.artifactId}/</url>
+    </site>
+  </distributionManagement>
+
+</project>
diff --git a/singleton-service/mdsal-singleton-dom-impl/src/main/java/org/opendaylight/mdsal/singleton/dom/impl/DOMClusterSingletonServiceProviderImpl.java b/singleton-service/mdsal-singleton-dom-impl/src/main/java/org/opendaylight/mdsal/singleton/dom/impl/DOMClusterSingletonServiceProviderImpl.java
new file mode 100644 (file)
index 0000000..b96f800
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.mdsal.singleton.dom.impl;
+
+import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipService;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntity;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipChange;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipListener;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipListenerRegistration;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipService;
+import org.opendaylight.mdsal.singleton.common.spi.AbstractClusterSingletonServiceProviderImpl;
+import org.opendaylight.mdsal.singleton.dom.api.DOMClusterSingletonServiceProvider;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+
+/**
+ * Binding version of {@link AbstractClusterSingletonServiceProviderImpl}
+ */
+public final class DOMClusterSingletonServiceProviderImpl extends
+        AbstractClusterSingletonServiceProviderImpl<YangInstanceIdentifier, DOMEntity,
+                                                    DOMEntityOwnershipChange,
+                                                    DOMEntityOwnershipListener,
+                                                    DOMEntityOwnershipService,
+                                                    DOMEntityOwnershipListenerRegistration>
+        implements DOMClusterSingletonServiceProvider {
+
+    /**
+     * Initialization all needed class internal property for {@link DOMClusterSingletonServiceProviderImpl}
+     *
+     * @param entityOwnershipService - we need only {@link GenericEntityOwnershipService}
+     */
+    public DOMClusterSingletonServiceProviderImpl(final DOMEntityOwnershipService entityOwnershipService) {
+        super(entityOwnershipService);
+    }
+
+    @Override
+    protected final DOMEntity createEntity(final String type, final String ident) {
+        return new DOMEntity(type, ident);
+    }
+
+    @Override
+    protected final DOMEntityOwnershipListenerRegistration registerListener(final String type,
+            final DOMEntityOwnershipService eos) {
+        return eos.registerListener(type, this);
+    }
+
+    @Override
+    protected String getServiceIdentifierFromEntity(final DOMEntity entity) {
+        final YangInstanceIdentifier yii = entity.getIdentifier();
+        final NodeIdentifierWithPredicates niiwp = (NodeIdentifierWithPredicates) yii.getLastPathArgument();
+        return niiwp.getKeyValues().values().iterator().next().toString();
+    }
+}
diff --git a/singleton-service/mdsal-singleton-dom-impl/src/test/java/org/opendaylight/mdsal/singleton/dom/impl/DOMClusterSingletonServiceProviderImplTest.java b/singleton-service/mdsal-singleton-dom-impl/src/test/java/org/opendaylight/mdsal/singleton/dom/impl/DOMClusterSingletonServiceProviderImplTest.java
new file mode 100644 (file)
index 0000000..6a05eb1
--- /dev/null
@@ -0,0 +1,695 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.mdsal.singleton.dom.impl;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.junit.Assert;
+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.dom.api.DOMEntity;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipCandidateRegistration;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipChange;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipListenerRegistration;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipService;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
+import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
+
+/**
+ * Testing {@link DOMClusterSingletonServiceProviderImpl} implementation
+ */
+public class DOMClusterSingletonServiceProviderImplTest {
+
+    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_NAME = "testServiceName";
+
+    @Mock
+    private DOMEntityOwnershipService mockEos;
+    @Mock
+    private DOMEntityOwnershipCandidateRegistration mockEntityCandReg;
+    @Mock
+    private DOMEntityOwnershipCandidateRegistration mockDoubleEntityCandReg;
+    @Mock
+    private DOMEntityOwnershipListenerRegistration mockEosEntityListReg;
+    @Mock
+    private DOMEntityOwnershipListenerRegistration mockEosDoubleEntityListReg;
+
+    private DOMClusterSingletonServiceProviderImpl clusterSingletonServiceProvider;
+    private TestClusterSingletonServiceInstance clusterSingletonService;
+    private TestClusterSingletonServiceInstance clusterSingletonService2;
+
+    private final DOMEntity entity = new DOMEntity(SERVICE_ENTITY_TYPE, SERVICE_NAME);
+    private final DOMEntity doubleEntity = new DOMEntity(CLOSE_SERVICE_ENTITY_TYPE, SERVICE_NAME);
+
+    /**
+     * Initialization functionality for every Tests in this suite
+     *
+     * @throws Exception
+     */
+    @Before
+    public void setup() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        doNothing().when(mockEosEntityListReg).close();
+        doNothing().when(mockEosDoubleEntityListReg).close();
+        doNothing().when(mockEntityCandReg).close();
+        doNothing().when(mockDoubleEntityCandReg).close();
+        doReturn(mockEosEntityListReg).when(mockEos).registerListener(eq(SERVICE_ENTITY_TYPE),
+                any(DOMClusterSingletonServiceProviderImpl.class));
+        doReturn(mockEosDoubleEntityListReg).when(mockEos).registerListener(eq(CLOSE_SERVICE_ENTITY_TYPE),
+                any(DOMClusterSingletonServiceProviderImpl.class));
+        doReturn(mockEntityCandReg).when(mockEos).registerCandidate(entity);
+        doReturn(mockDoubleEntityCandReg).when(mockEos).registerCandidate(doubleEntity);
+
+        clusterSingletonServiceProvider = new DOMClusterSingletonServiceProviderImpl(mockEos);
+        clusterSingletonServiceProvider.initializeProvider();
+        verify(mockEos).registerListener(SERVICE_ENTITY_TYPE, clusterSingletonServiceProvider);
+        verify(mockEos).registerListener(CLOSE_SERVICE_ENTITY_TYPE, clusterSingletonServiceProvider);
+
+        clusterSingletonService = new TestClusterSingletonServiceInstance();
+        clusterSingletonService2 = new TestClusterSingletonServiceInstance();
+
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+    }
+
+    /**
+     * Test checks NullPointer for null {@link DOMEntityOwnershipService} input value
+     *
+     * @throws Exception
+     */
+    @Test(expected = NullPointerException.class)
+    public void initializationClusterSingletonServiceProviderNullInputTest() throws Exception {
+        clusterSingletonServiceProvider = new DOMClusterSingletonServiceProviderImpl(null);
+    }
+
+    /**
+     * Test GoldPath for close {@link DOMClusterSingletonServiceProviderImpl}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void closeClusterSingletonServiceProviderTest() throws Exception {
+        verify(mockEos).registerListener(SERVICE_ENTITY_TYPE, clusterSingletonServiceProvider);
+        verify(mockEos).registerListener(CLOSE_SERVICE_ENTITY_TYPE, clusterSingletonServiceProvider);
+        clusterSingletonServiceProvider.close();
+        verify(mockEosEntityListReg).close();
+        verify(mockEosDoubleEntityListReg).close();
+    }
+
+    /**
+     * Test parser ServiceIdentifier from Entity
+     *
+     * @throws Exception
+     */
+    @Test
+    public void makeEntityClusterSingletonServiceProviderTest() throws Exception {
+        final DOMEntity testEntity = clusterSingletonServiceProvider.createEntity(SERVICE_ENTITY_TYPE, SERVICE_NAME);
+        Assert.assertEquals(entity, testEntity);
+        final DOMEntity testDbEn = clusterSingletonServiceProvider.createEntity(CLOSE_SERVICE_ENTITY_TYPE,
+                SERVICE_NAME);
+        Assert.assertEquals(doubleEntity, testDbEn);
+    }
+
+    /**
+     * Test parser ServiceIdentifier from Entity
+     *
+     * @throws Exception
+     */
+    @Test
+    public void getIdentifierClusterSingletonServiceProviderTest() throws Exception {
+        final String entityIdentifier = clusterSingletonServiceProvider.getServiceIdentifierFromEntity(entity);
+        Assert.assertEquals(SERVICE_NAME, entityIdentifier);
+        final String doubleEntityId = clusterSingletonServiceProvider.getServiceIdentifierFromEntity(doubleEntity);
+        Assert.assertEquals(SERVICE_NAME, doubleEntityId);
+    }
+
+    /**
+     * Test GoldPath for initialization {@link ClusterSingletonService}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void initializationClusterSingletonServiceTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for initialization with init ownership result SLAVE {@link ClusterSingletonService}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void slaveInitClusterSingletonServiceTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlave());
+        verify(mockEos, never()).registerCandidate(doubleEntity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for initialization with init ownership result SLAVE, but NO-MASTER {@link ClusterSingletonService}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void slaveInitNoMasterClusterSingletonServiceTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlaveNoMaster());
+        verify(mockEos, never()).registerCandidate(doubleEntity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for initialization with init ownership result MASTER {@link ClusterSingletonService}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void masterInitClusterSingletonServiceTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for initialization with init ownership result MASTER {@link ClusterSingletonService}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void masterInitSlaveDoubleCandidateClusterSingletonServiceTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for takeLeadership with ownership result MASTER {@link ClusterSingletonService}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void takeLeadershipClusterSingletonServiceTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for initialization with init ownership result MASTER {@link ClusterSingletonService}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void masterInitClusterSingletonServiceTwoServicesTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService2);
+        Assert.assertNotNull(reg2);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for takeLeadership with ownership result MASTER {@link ClusterSingletonService}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void takeLeadershipClusterSingletonServiceTwoAddDuringWaitPhaseServicesTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService2);
+        Assert.assertNotNull(reg2);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for takeLeadership with ownership result MASTER {@link ClusterSingletonService}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void takeLeadershipClusterSingletonServiceTowServicesTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService2);
+        Assert.assertNotNull(reg2);
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+    }
+
+    /**
+     * Test checks CandidateAlreadyRegisteredException processing in initialization phase
+     *
+     * @throws Exception
+     */
+    @Test
+    public void initializationClusterSingletonServiceCandidateAlreadyRegistredTest() throws Exception {
+        doThrow(CandidateAlreadyRegisteredException.class).when(mockEos).registerCandidate(entity);
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNull(reg);
+    }
+
+    /**
+     * Test GoldPath for lostLeadership during tryToTakeLeadership with ownership result MASTER
+     * {@link ClusterSingletonService}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void lostLeadershipDuringTryToTakeLeadershipClusterSingletonServiceTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for lostLeadership with ownership result MASTER-TO-SLAVE {@link ClusterSingletonService}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void lostLeadershipClusterSingletonServiceTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
+        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test checks umexpected change for MASTER-TO-SLAVE double Candidate role change
+     *
+     * @throws Exception
+     */
+    @Test
+    public void unexpectedLostLeadershipDoubleCandidateTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToSlave());
+        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg, never()).close();
+        verify(mockDoubleEntityCandReg).close();
+    }
+
+    /**
+     * Test checks inJeopardy Cluster Node state for Master Instance
+     *
+     * @throws Exception
+     */
+    @Test
+    public void inJeopardyMasterTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToJeopardy());
+        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg, never()).close();
+        verify(mockDoubleEntityCandReg).close();
+    }
+
+    /**
+     * Test checks inJeopardy Cluster Node state for Slave Instance
+     *
+     * @throws Exception
+     */
+    @Test
+    public void inJeopardySlaveTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlave());
+        verify(mockEos, never()).registerCandidate(doubleEntity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToJeopardy());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg, never()).close();
+        verify(mockDoubleEntityCandReg, never()).close();
+    }
+
+    /**
+     * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void closeClusterSingletonServiceRegistrationNoRoleTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        reg.close();
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg).close();
+        verify(mockDoubleEntityCandReg, never()).close();
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void closeClusterSingletonServiceRegistrationNoRoleTwoServicesTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService2);
+        Assert.assertNotNull(reg2);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+        reg.close();
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg, never()).close();
+        verify(mockDoubleEntityCandReg, never()).close();
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+    }
+
+    /**
+     * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void closeClusterSingletonServiceRegistrationSlaveTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlave());
+        reg.close();
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg).close();
+        verify(mockDoubleEntityCandReg, never()).close();
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void closeClusterSingletonServiceRegistrationSlaveTwoServicesTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        verify(mockEos).registerCandidate(entity);
+        final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService2);
+        Assert.assertNotNull(reg2);
+        clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlave());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+        reg.close();
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg, never()).close();
+        verify(mockDoubleEntityCandReg, never()).close();
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+    }
+
+    /**
+     * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void closeClusterSingletonServiceRegistrationMasterTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        reg.close();
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg).close();
+        verify(mockDoubleEntityCandReg).close();
+        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test checks close procesing for {@link ClusterSingletonServiceRegistration}
+     *
+     * @throws Exception
+     */
+    @Test
+    public void closeClusterSingletonServiceRegistrationMasterTwoServicesTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService2);
+        Assert.assertNotNull(reg2);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+        verify(mockEos).registerCandidate(entity);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+        reg.close();
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg, never()).close();
+        verify(mockDoubleEntityCandReg, never()).close();
+        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+    }
+
+    /**
+     * Test checks validation Error processing for SLAVE-TO-MASTER entity Candidate role change
+     *
+     * @throws Exception
+     */
+    @Test
+    public void tryToTakeLeaderForClosedServiceRegistrationTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        Assert.assertNotNull(reg);
+        final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService2);
+        Assert.assertNotNull(reg2);
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+        verify(mockEos).registerCandidate(entity);
+        reg.close();
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(doubleEntity);
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg, never()).close();
+        verify(mockDoubleEntityCandReg, never()).close();
+        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+    }
+
+    private DOMEntityOwnershipChange getEntityToMaster() {
+        return new DOMEntityOwnershipChange(entity, EntityOwnershipChangeState.from(false, true, true));
+    }
+
+    private DOMEntityOwnershipChange getEntityToSlave() {
+        return new DOMEntityOwnershipChange(entity, EntityOwnershipChangeState.from(true, false, true));
+    }
+
+    private DOMEntityOwnershipChange getInitEntityToSlave() {
+        return new DOMEntityOwnershipChange(entity, EntityOwnershipChangeState.from(false, false, true));
+    }
+
+    private DOMEntityOwnershipChange getInitEntityToSlaveNoMaster() {
+        return new DOMEntityOwnershipChange(entity, EntityOwnershipChangeState.from(false, false, false));
+    }
+
+    private DOMEntityOwnershipChange getDoubleEntityToMaster() {
+        return new DOMEntityOwnershipChange(doubleEntity, EntityOwnershipChangeState.from(false, true, true));
+    }
+
+    private DOMEntityOwnershipChange getInitDoubleEntityToSlave() {
+        return new DOMEntityOwnershipChange(doubleEntity, EntityOwnershipChangeState.from(false, false, true));
+    }
+
+    private DOMEntityOwnershipChange getDoubleEntityToSlave() {
+        return new DOMEntityOwnershipChange(doubleEntity, EntityOwnershipChangeState.from(true, false, true));
+    }
+
+    private DOMEntityOwnershipChange getEntityToJeopardy() {
+        return new DOMEntityOwnershipChange(entity, EntityOwnershipChangeState.from(false, false, false), true);
+    }
+
+    /**
+     * Base states for AbstractClusterProjectProvider
+     */
+    static enum TestClusterSingletonServiceState {
+        /**
+         * State represents a correct Instantiated process
+         */
+        STARTED,
+        /**
+         * State represents a correct call abstract method instantiatingProject
+         */
+        INITIALIZED,
+        /**
+         * State represents a correct call abstract method destryingProject
+         */
+        DESTROYED;
+    }
+
+    /**
+     * Test implementation of {@link ClusterSingletonService}
+     */
+    class TestClusterSingletonServiceInstance implements ClusterSingletonService {
+
+        private final ServiceGroupIdentifier SERVICE_IDENT = ServiceGroupIdentifier.create(SERVICE_NAME);
+        private TestClusterSingletonServiceState serviceState;
+
+        public TestClusterSingletonServiceInstance() {
+            this.serviceState = TestClusterSingletonServiceState.INITIALIZED;
+        }
+
+        @Override
+        public void instantiateServiceInstance() {
+            this.serviceState = TestClusterSingletonServiceState.STARTED;
+        }
+
+        @Override
+        public ListenableFuture<Void> closeServiceInstance() {
+            this.serviceState = TestClusterSingletonServiceState.DESTROYED;
+            return Futures.immediateFuture(null);
+        }
+
+        public TestClusterSingletonServiceState getServiceState() {
+            return serviceState;
+        }
+
+        @Override
+        public ServiceGroupIdentifier getIdentifier() {
+            return SERVICE_IDENT;
+        }
+    }
+}
index b965b7125ffc63801893eafe628a200d353cbe04..41bffc1cd015198f9dabb391390fe43eb8508efb 100644 (file)
 
     <modules>
       <module>mdsal-singleton-common-api</module>
+      <module>mdsal-singleton-common-spi</module>
       <module>mdsal-singleton-dom-api</module>
+      <module>mdsal-singleton-dom-impl</module>
       <module>mdsal-singleton-binding-api</module>
-      <module>mdsal-singleton-common-spi</module>
+      <module>mdsal-singleton-binding-impl</module>
     </modules>