BUG-8858: rework singleton group locking 20/61420/19
authorRobert Varga <robert.varga@pantheon.tech>
Wed, 9 Aug 2017 11:54:12 +0000 (13:54 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Tue, 5 Sep 2017 08:43:07 +0000 (10:43 +0200)
Group locking relied on a single semaphore held for long periods
of time, with undeterministic locking in face of timing variance.

This patch reworks the logic to properly lock and manage object
lifecycle. It also expands the test suite to cover cleanup scenarios,
while removing test duplication.

The test suite is expanded slightly to assert that asynchronous
service group cleanup does not interfere with user's ability to
reuse the same group.

Change-Id: I68eb6d0b59b2ab0e1cf98dc374e029fad3d19734
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
12 files changed:
singleton-service/mdsal-singleton-dom-impl/src/main/java/org/opendaylight/mdsal/singleton/dom/impl/AbstractClusterSingletonServiceProviderImpl.java
singleton-service/mdsal-singleton-dom-impl/src/main/java/org/opendaylight/mdsal/singleton/dom/impl/AbstractClusterSingletonServiceRegistration.java [new file with mode: 0644]
singleton-service/mdsal-singleton-dom-impl/src/main/java/org/opendaylight/mdsal/singleton/dom/impl/ClusterSingletonServiceGroup.java
singleton-service/mdsal-singleton-dom-impl/src/main/java/org/opendaylight/mdsal/singleton/dom/impl/ClusterSingletonServiceGroupImpl.java
singleton-service/mdsal-singleton-dom-impl/src/main/java/org/opendaylight/mdsal/singleton/dom/impl/ClusterSingletonServiceRegistrationDelegator.java [deleted file]
singleton-service/mdsal-singleton-dom-impl/src/main/java/org/opendaylight/mdsal/singleton/dom/impl/PlaceholderGroup.java [new file with mode: 0644]
singleton-service/mdsal-singleton-dom-impl/src/test/java/org/opendaylight/mdsal/singleton/dom/impl/AbstractDOMClusterServiceProviderTest.java [new file with mode: 0644]
singleton-service/mdsal-singleton-dom-impl/src/test/java/org/opendaylight/mdsal/singleton/dom/impl/ClusterSingletonServiceGroupImplTest.java
singleton-service/mdsal-singleton-dom-impl/src/test/java/org/opendaylight/mdsal/singleton/dom/impl/ClusterSingletonServiceRegistrationDelegatorTest.java [deleted file]
singleton-service/mdsal-singleton-dom-impl/src/test/java/org/opendaylight/mdsal/singleton/dom/impl/DOMClusterSingletonServiceProviderAsyncImplTest.java
singleton-service/mdsal-singleton-dom-impl/src/test/java/org/opendaylight/mdsal/singleton/dom/impl/DOMClusterSingletonServiceProviderImplTest.java
singleton-service/mdsal-singleton-dom-impl/src/test/resources/simplelogger.properties [new file with mode: 0644]

index 6c29b330b6a15a4f498e21c6b8542bac7c991ec0..0ecf7e01d661e24df8df81eb08ab92f2396bc2f4 100644 (file)
@@ -8,18 +8,24 @@
 
 package org.opendaylight.mdsal.singleton.dom.impl;
 
+import static com.google.common.base.Verify.verify;
+import static com.google.common.base.Verify.verifyNotNull;
+
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
+import com.google.common.base.Verify;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 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.CandidateAlreadyRegisteredException;
 import org.opendaylight.mdsal.eos.common.api.GenericEntity;
 import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipChange;
 import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipListener;
@@ -52,15 +58,15 @@ public abstract class AbstractClusterSingletonServiceProviderImpl<P extends Path
         R extends GenericEntityOwnershipListenerRegistration<P, G>>
         implements ClusterSingletonServiceProvider, GenericEntityOwnershipListener<P, C> {
 
-    private static final Logger LOG = LoggerFactory
-            .getLogger(AbstractClusterSingletonServiceProviderImpl.class.getName());
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractClusterSingletonServiceProviderImpl.class);
 
-    private static final String SERVICE_ENTITY_TYPE = "org.opendaylight.mdsal.ServiceEntityType";
-    private static final String CLOSE_SERVICE_ENTITY_TYPE = "org.opendaylight.mdsal.AsyncServiceCloseEntityType";
+    @VisibleForTesting
+    static final String SERVICE_ENTITY_TYPE = "org.opendaylight.mdsal.ServiceEntityType";
+    @VisibleForTesting
+    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<>();
+    private final Map<String, ClusterSingletonServiceGroup<P, E, C>> serviceGroupMap = new ConcurrentHashMap<>();
 
     /* EOS Entity Listeners Registration */
     private R serviceEntityListenerReg;
@@ -79,60 +85,142 @@ public abstract class AbstractClusterSingletonServiceProviderImpl<P extends Path
      * 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());
+        LOG.debug("Initialization method for ClusterSingletonService Provider {}", this);
         this.serviceEntityListenerReg = registerListener(SERVICE_ENTITY_TYPE, entityOwnershipService);
         this.asyncCloseEntityListenerReg = registerListener(CLOSE_SERVICE_ENTITY_TYPE, entityOwnershipService);
     }
 
     @Override
-    public final ClusterSingletonServiceRegistration registerClusterSingletonService(
+    public final synchronized 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);
+        LOG.debug("Call registrationService {} method for ClusterSingletonService Provider {}", service, this);
 
         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();
+        Preconditions.checkArgument(!Strings.isNullOrEmpty(serviceIdentifier),
+                "ClusterSingletonService identifier may not be null nor empty");
+
+        final ClusterSingletonServiceGroup<P, E, C> serviceGroup;
+        ClusterSingletonServiceGroup<P, E, C> existing = serviceGroupMap.get(serviceIdentifier);
+        if (existing == null) {
+            serviceGroup = createGroup(serviceIdentifier, new ArrayList<>(1));
+            serviceGroupMap.put(serviceIdentifier, serviceGroup);
+
+            try {
+                initializeOrRemoveGroup(serviceGroup);
+            } catch (CandidateAlreadyRegisteredException e) {
+                throw new IllegalArgumentException("Service group already registered", e);
+            }
+        } else {
+            serviceGroup = existing;
+        }
+
+        serviceGroup.registerService(service);
+        return new AbstractClusterSingletonServiceRegistration(service) {
+            @Override
+            protected void removeRegistration() {
+                // We need to bounce the unregistration through a ordered lock in order not to deal with asynchronous
+                // shutdown of the group and user registering it again.
+                AbstractClusterSingletonServiceProviderImpl.this.removeRegistration(serviceIdentifier, service);
+            }
+        };
+    }
+
+    private ClusterSingletonServiceGroup<P, E, C> createGroup(final String serviceIdentifier,
+            final List<ClusterSingletonService> services) {
+        return new ClusterSingletonServiceGroupImpl<>(serviceIdentifier, entityOwnershipService,
+                createEntity(SERVICE_ENTITY_TYPE, serviceIdentifier),
+                createEntity(CLOSE_SERVICE_ENTITY_TYPE, serviceIdentifier), services);
+    }
+
+    private void initializeOrRemoveGroup(final ClusterSingletonServiceGroup<P, E, C> group)
+            throws CandidateAlreadyRegisteredException {
+        try {
+            group.initialize();
+        } catch (CandidateAlreadyRegisteredException e) {
+            serviceGroupMap.remove(group.getIdentifier(), group);
+            throw e;
+        }
+    }
+
+    void removeRegistration(final String serviceIdentifier, final ClusterSingletonService service) {
+
+        final PlaceholderGroup<P, E, C> placeHolder;
+        final ListenableFuture<?> future;
+        synchronized (this) {
+            final ClusterSingletonServiceGroup<P, E, C> lookup = verifyNotNull(serviceGroupMap.get(serviceIdentifier));
+            if (!lookup.unregisterService(service)) {
+                return;
+            }
+
+            // Close the group and replace it with a placeholder
+            LOG.debug("Closing service group {}", serviceIdentifier);
+            future = lookup.closeClusterSingletonGroup();
+            placeHolder = new PlaceholderGroup<>(lookup, future);
+
+            final String identifier = service.getIdentifier().getValue();
+            verify(serviceGroupMap.replace(identifier, lookup, placeHolder));
+            LOG.debug("Replaced group {} with {}", serviceIdentifier, placeHolder);
+        }
+
+        future.addListener(() -> finishShutdown(placeHolder), MoreExecutors.directExecutor());
+    }
+
+    synchronized void finishShutdown(final PlaceholderGroup<P, E, C> placeHolder) {
+        final String identifier = placeHolder.getIdentifier();
+        LOG.debug("Service group {} closed", identifier);
+
+        final List<ClusterSingletonService> services = placeHolder.getServices();
+        if (services.isEmpty()) {
+            // No services, we are all done
+            if (serviceGroupMap.remove(identifier, placeHolder)) {
+                LOG.debug("Service group {} removed", placeHolder);
+            } else {
+                LOG.debug("Service group {} superseded by {}", placeHolder, serviceGroupMap.get(identifier));
+            }
+            return;
+        }
+
+        // Placeholder is being retired, we are reusing its services as the seed for the group.
+        final ClusterSingletonServiceGroup<P, E, C> group = createGroup(identifier, services);
+        Verify.verify(serviceGroupMap.replace(identifier, placeHolder, group));
+        placeHolder.setSuccessor(group);
+        LOG.debug("Service group upgraded from {} to {}", placeHolder, group);
+
+        try {
+            initializeOrRemoveGroup(group);
+        } catch (CandidateAlreadyRegisteredException e) {
+            LOG.error("Failed to register delayed group {}, it will remain inoperational", identifier, e);
         }
-        return serviceGroup.registerService(service);
     }
 
     @Override
     public final void close() {
-        LOG.debug("Close method for ClusterSingletonService Provider {}", this.getClass().getName());
+        LOG.debug("Close method for ClusterSingletonService Provider {}", this);
 
         if (serviceEntityListenerReg != null) {
             serviceEntityListenerReg.close();
             serviceEntityListenerReg = null;
         }
 
-        final List<ListenableFuture<List<Void>>> listGroupCloseListFuture = new ArrayList<>();
+        final List<ListenableFuture<?>> 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>>>() {
+        final ListenableFuture<List<Object>> finalCloseFuture = Futures.allAsList(listGroupCloseListFuture);
+        Futures.addCallback(finalCloseFuture, new FutureCallback<List<?>>() {
 
             @Override
-            public void onSuccess(final List<List<Void>> result) {
-                cleaningProvider(null);
+            public void onSuccess(final List<?> result) {
+                cleanup();
             }
 
             @Override
             public void onFailure(final Throwable throwable) {
-                cleaningProvider(throwable);
+                LOG.warn("Unexpected problem by closing ClusterSingletonServiceProvider {}",
+                    AbstractClusterSingletonServiceProviderImpl.this, throwable);
+                cleanup();
             }
         });
     }
@@ -178,15 +266,9 @@ public abstract class AbstractClusterSingletonServiceProviderImpl<P extends Path
 
     /**
      * Method is called async. from close method in end of Provider lifecycle.
-     *
-     * @param throwable Throwable (needs for log)
      */
-    protected final void cleaningProvider(@Nullable final Throwable throwable) {
-        LOG.debug("Final cleaning ClusterSingletonServiceProvider {}", this.getClass().getName());
-        if (throwable != null) {
-            LOG.warn("Unexpected problem by closing ClusterSingletonServiceProvider {}",
-                    this.getClass().getName(), throwable);
-        }
+    final void cleanup() {
+        LOG.debug("Final cleaning ClusterSingletonServiceProvider {}", this);
         if (asyncCloseEntityListenerReg != null) {
             asyncCloseEntityListenerReg.close();
             asyncCloseEntityListenerReg = null;
diff --git a/singleton-service/mdsal-singleton-dom-impl/src/main/java/org/opendaylight/mdsal/singleton/dom/impl/AbstractClusterSingletonServiceRegistration.java b/singleton-service/mdsal-singleton-dom-impl/src/main/java/org/opendaylight/mdsal/singleton/dom/impl/AbstractClusterSingletonServiceRegistration.java
new file mode 100644 (file)
index 0000000..7f339c8
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies, s.r.o. 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.singleton.common.api.ClusterSingletonService;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+
+abstract class AbstractClusterSingletonServiceRegistration extends AbstractObjectRegistration<ClusterSingletonService>
+    implements ClusterSingletonServiceRegistration {
+
+    AbstractClusterSingletonServiceRegistration(final ClusterSingletonService instance) {
+        super(instance);
+    }
+}
index c5bb86ef75abfc9dd7cd785973845248b3064a3f..8682ef08f318b5b7639a9a2a42db38ac227e5a25 100644 (file)
@@ -9,39 +9,36 @@
 package org.opendaylight.mdsal.singleton.dom.impl;
 
 import com.google.common.util.concurrent.ListenableFuture;
-import java.util.List;
+import org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException;
 import org.opendaylight.mdsal.eos.common.api.GenericEntity;
 import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipChange;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
+import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.concepts.Path;
 
 /**
- * {@link ClusterSingletonServiceGroup} maintains a group of {@link ClusterSingletonService}
- * instancies. All EntityOwnershipChange notifications have to applied to all registered
- * services at the same time in the same manner.
- * So this interface represents a single cluster service group instance." - remove this
- * sentence. All registered services have only one instantiated service instance in a cluster
- * at one time on same Cluster Node. This is realized via a double candidate approach where
- * a service group instance maintains a candidate registration for ownership of the service
- * entity in the cluster and also a registration that acts as a guard to ensure a service
- * group instance has fully closed prior to relinquishing service ownership. To achieve
- * ownership of the service group, a service group candidate must hold ownership
- * of both these entities.
+ * {@link ClusterSingletonServiceGroup} maintains a group of {@link ClusterSingletonService} instances.
+ * All EntityOwnershipChange notifications have to applied to all registered services at the same time in the same
+ * manner. All registered services have only one instantiated service instance in a cluster at one time on same
+ * Cluster Node. This is realized via a double candidate approach where a service group instance maintains a candidate
+ * registration for ownership of the service entity in the cluster and also a registration that acts as a guard to
+ * ensure a service group instance has fully closed prior to relinquishing service ownership. To achieve ownership
+ * of the service group, a service group candidate must hold ownership of both these entities.
  *
  * @param <P> the instance identifier path type
  * @param <E> the GenericEntity type
  * @param <C> the GenericEntityOwnershipChange type
  */
-interface ClusterSingletonServiceGroup<P extends Path<P>, E extends GenericEntity<P>,
-                                       C extends GenericEntityOwnershipChange<P, E>> {
+abstract class ClusterSingletonServiceGroup<P extends Path<P>, E extends GenericEntity<P>,
+                                       C extends GenericEntityOwnershipChange<P, E>> implements Identifiable<String> {
 
     /**
      * This method must be called once on startup to initialize this group and
      * register the relevant group entity candidate. It means create relevant
      * Group Entity Candidate Registration.
      */
-    void initializationClusterSingletonGroup();
+    abstract void initialize() throws CandidateAlreadyRegisteredException;
 
     /**
      * This method registers a service instance for this service group. If the local node has
@@ -49,9 +46,8 @@ interface ClusterSingletonServiceGroup<P extends Path<P>, E extends GenericEntit
      * method is called. Otherwise, the method is called once the local node gains ownership.
      *
      * @param service instance
-     * @return closable {@link ClusterSingletonServiceRegistration}
      */
-    ClusterSingletonServiceRegistration registerService(ClusterSingletonService service);
+    abstract void registerService(ClusterSingletonService service);
 
     /**
      * Method provides possibility to restart some service from group without change
@@ -62,15 +58,16 @@ interface ClusterSingletonServiceGroup<P extends Path<P>, E extends GenericEntit
      * without clustering.
      *
      * @param service instance
+     * @return True if this was the last service registered
      */
-    void unregisterService(ClusterSingletonService service);
+    abstract boolean unregisterService(ClusterSingletonService service);
 
     /**
      * Method implementation has to apply ownershipChange for all registered services.
      *
      * @param ownershipChange change role for ClusterSingletonServiceGroup
      */
-    void ownershipChanged(C ownershipChange);
+    abstract void ownershipChanged(C ownershipChange);
 
     /**
      * Closes this service group. All registered service providers are also closed. Please be careful
@@ -78,7 +75,6 @@ interface ClusterSingletonServiceGroup<P extends Path<P>, E extends GenericEntit
      *
      * @return {@link ListenableFuture} in list for all Future from closing {@link ClusterSingletonService}
      */
-    ListenableFuture<List<Void>> closeClusterSingletonGroup();
-
+    abstract ListenableFuture<?> closeClusterSingletonGroup();
 }
 
index 0d4920bed3da77739960b054104b817382a0fbaf..82897e6c60366571ee430dd1e675b93194ca9fa8 100644 (file)
@@ -9,36 +9,45 @@
 package org.opendaylight.mdsal.singleton.dom.impl;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
 import com.google.common.base.Verify;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
 import java.util.ArrayList;
-import java.util.LinkedList;
 import java.util.List;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
-import javax.annotation.Nullable;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.ReentrantLock;
+import javax.annotation.CheckReturnValue;
 import javax.annotation.concurrent.GuardedBy;
 import org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException;
-import org.opendaylight.mdsal.eos.common.api.EntityOwnershipChangeState;
 import org.opendaylight.mdsal.eos.common.api.GenericEntity;
 import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipCandidateRegistration;
 import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipChange;
 import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipListener;
 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.yangtools.concepts.Path;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * Implementation of {@link ClusterSingletonServiceGroup}.
+ * Implementation of {@link ClusterSingletonServiceGroup} on top of the Entitiy Ownership Service. Since EOS is atomic
+ * in its operation and singleton services incur startup and most notably cleanup, we need to do something smart here.
+ *
+ * <p>
+ * The implementation takes advantage of the fact that EOS provides stable ownership, i.e. owners are not moved as
+ * a result on new candidates appearing. We use two entities:
+ * - service entity, to which all nodes register
+ * - cleanup entity, which only the service entity owner registers to
+ *
+ * <p>
+ * Once the cleanup entity ownership is acquired, services are started. As long as the cleanup entity is registered,
+ * it should remain the owner. In case a new service owner emerges, the old owner will start the cleanup process,
+ * eventually releasing the cleanup entity. The new owner registers for the cleanup entity -- but will not see it
+ * granted until the old owner finishes the cleanup.
  *
  * @param <P> the instance identifier path type
  * @param <E> the GenericEntity type
@@ -46,218 +55,376 @@ import org.slf4j.LoggerFactory;
  * @param <G> the GenericEntityOwnershipListener type
  * @param <S> the GenericEntityOwnershipService type
  */
-@VisibleForTesting
 final class ClusterSingletonServiceGroupImpl<P extends Path<P>, E extends GenericEntity<P>,
-                                             C extends GenericEntityOwnershipChange<P, E>,
-                                             G extends GenericEntityOwnershipListener<P, C>,
-                                             S extends GenericEntityOwnershipService<P, E, G>>
-        implements ClusterSingletonServiceGroup<P, E, C> {
+        C extends GenericEntityOwnershipChange<P, E>,  G extends GenericEntityOwnershipListener<P, C>,
+        S extends GenericEntityOwnershipService<P, E, G>> extends ClusterSingletonServiceGroup<P, E, C> {
+    private enum State {
+        /**
+         * This group has been freshly allocated and has not been started yet.
+         */
+        INITIAL,
+        /**
+         * Operational state. Service entity is registered, but ownership was not resolved yet.
+         */
+        REGISTERED,
+        /**
+         * Operational state. Service entity confirmed to be follower.
+         */
+        STANDBY,
+        /**
+         * Service entity acquired. Attempting to acquire cleanup entity.
+         */
+        TAKING_OWNERSHIP,
+        /**
+         * Both entities held and user services are being started.
+         */
+        STARTING_SERVICES,
+        /**
+         * Steady state. Both entities held and services have finished starting.
+         */
+        OWNER,
+        /**
+         * User services are being stopped due to either loss of an entity or a shutdown.
+         */
+        STOPPING_SERVICES,
+        /**
+         * We have stopped services and are now relinquishing the cleanup entity.
+         */
+        RELEASING_OWNERSHIP,
+        /**
+         * Terminated, this group cannot be used anymore.
+         */
+        TERMINATED
+    }
 
-    private static final Logger LOG = LoggerFactory.getLogger(ClusterSingletonServiceGroupImpl.class.getName());
+    private static final Logger LOG = LoggerFactory.getLogger(ClusterSingletonServiceGroupImpl.class);
 
     private final S entityOwnershipService;
-    private final String clusterSingletonGroupIdentifier;
-    private final Semaphore clusterLock = new Semaphore(1, true);
+    private final String identifier;
 
     /* Entity instances */
     private final E serviceEntity;
-    private final E doubleCandidateEntity;
-
-    // TODO :it needs to rewrite for StateMachine (INITIALIZED, TRY_TO_TAKE_LEADERSHIP, LEADER, FOLLOWER, TERMINATED)
-    // INITIALIZED : we have registered baseCandidate and we are waiting for first EOS response (!do we really need it?)
-    // FOLLOWER : baseCandidate is registered correctly
-    // TRY_TO_TAKE_LEADERSHIP : guardCandidate is registered correctly
-    // LEADER : both candidate have mastership from EOS
-    // TERMINATED : service go down
-    @GuardedBy("clusterLock")
-    private boolean hasOwnership = false;
-    @GuardedBy("clusterLock")
-    private final List<ClusterSingletonServiceRegistrationDelegator> serviceGroup = new LinkedList<>();
-    private final ConcurrentMap<String, ClusterSingletonServiceGroup<P, E, C>> allServiceGroups;
+    private final E cleanupEntity;
+
+    private final AtomicReference<SettableFuture<Void>> closeFuture = new AtomicReference<>();
+    private final ReentrantLock lock = new ReentrantLock(true);
+
+    @GuardedBy("lock")
+    private final List<ClusterSingletonService> serviceGroup;
+
+    @GuardedBy("lock")
+    private State state = State.INITIAL;
+
+    @GuardedBy("lock")
+    private List<C> capture;
 
     /* EOS Candidate Registrations */
-    private GenericEntityOwnershipCandidateRegistration<P, E> serviceEntityCandidateReg;
-    private GenericEntityOwnershipCandidateRegistration<P, E> asyncCloseEntityCandidateReg;
+    @GuardedBy("lock")
+    private GenericEntityOwnershipCandidateRegistration<P, E> serviceEntityReg;
+    @GuardedBy("lock")
+    private GenericEntityOwnershipCandidateRegistration<P, E> cleanupEntityReg;
 
     /**
-     * Class constructor.
+     * Class constructor. Note: last argument is reused as-is.
      *
-     * @param clusterSingletonServiceGroupIdentifier not empty string as identifier
+     * @param identifier non-empty string as identifier
      * @param mainEntity as Entity instance
      * @param closeEntity as Entity instance
      * @param entityOwnershipService GenericEntityOwnershipService instance
-     * @param allServiceGroups concurrentMap of String and ClusterSingletonServiceGroup type
+     * @param parent parent service
+     * @param services Services list
      */
-    ClusterSingletonServiceGroupImpl(final String clusterSingletonServiceGroupIdentifier, final E mainEntity,
-            final E closeEntity, final S entityOwnershipService,
-            final ConcurrentMap<String, ClusterSingletonServiceGroup<P, E, C>> allServiceGroups) {
-        LOG.debug("New Instance of ClusterSingletonServiceGroup {}", clusterSingletonServiceGroupIdentifier);
-        Preconditions.checkArgument(!Strings.isNullOrEmpty(clusterSingletonServiceGroupIdentifier));
-        this.clusterSingletonGroupIdentifier = clusterSingletonServiceGroupIdentifier;
+    ClusterSingletonServiceGroupImpl(final String identifier, final S entityOwnershipService, final E mainEntity,
+            final E closeEntity, final List<ClusterSingletonService> services) {
+        Preconditions.checkArgument(!identifier.isEmpty(), "Identifier may not be empty");
+        this.identifier = identifier;
         this.entityOwnershipService = Preconditions.checkNotNull(entityOwnershipService);
         this.serviceEntity = Preconditions.checkNotNull(mainEntity);
-        this.doubleCandidateEntity = Preconditions.checkNotNull(closeEntity);
-        this.allServiceGroups = Preconditions.checkNotNull(allServiceGroups);
+        this.cleanupEntity = Preconditions.checkNotNull(closeEntity);
+        this.serviceGroup = Preconditions.checkNotNull(services);
+        LOG.debug("Instantiated new service group for {}", identifier);
+    }
+
+    @VisibleForTesting
+    ClusterSingletonServiceGroupImpl(final String identifier, final E mainEntity,
+            final E closeEntity, final S entityOwnershipService) {
+        this(identifier, entityOwnershipService, mainEntity, closeEntity, new ArrayList<>(1));
+    }
+
+    @Override
+    public String getIdentifier() {
+        return identifier;
     }
 
-    @SuppressWarnings("checkstyle:IllegalCatch")
     @Override
-    public ListenableFuture<List<Void>> closeClusterSingletonGroup() {
-        LOG.debug("Close method for service Provider {}", clusterSingletonGroupIdentifier);
-        boolean needReleaseLock = false;
-        final ListenableFuture<List<Void>> destroyFuture;
+    ListenableFuture<?> closeClusterSingletonGroup() {
+        // Assert our future first
+        final SettableFuture<Void> future = SettableFuture.create();
+        final SettableFuture<Void> existing = closeFuture.getAndSet(future);
+        if (existing != null) {
+            return existing;
+        }
+
+        if (!lock.tryLock()) {
+            // The lock is held, the cleanup will be finished by the owner thread
+            LOG.debug("Singleton group {} cleanup postponed", identifier);
+            return future;
+        }
+
         try {
-            needReleaseLock = clusterLock.tryAcquire(1, TimeUnit.SECONDS);
-        } catch (final Exception e) {
-            LOG.warn("Unexpected Exception for service Provider {} in closing phase.", clusterSingletonGroupIdentifier,
-                    e);
+            lockedClose(future);
         } finally {
-            if (serviceEntityCandidateReg != null) {
-                serviceEntityCandidateReg.close();
-                serviceEntityCandidateReg = null;
-            }
-            final List<ListenableFuture<Void>> serviceCloseFutureList = new ArrayList<>();
-            if (hasOwnership) {
-                for (final ClusterSingletonServiceRegistrationDelegator service : serviceGroup) {
-                    try {
-                        serviceCloseFutureList.add(service.closeServiceInstance());
-                    } catch (final RuntimeException e) {
-                        LOG.warn("Unexpected exception while closing service: {}, resuming with next..",
-                                service.getIdentifier());
-                    }
-                }
-                hasOwnership = false;
-            }
-            destroyFuture = Futures.allAsList(serviceCloseFutureList);
-            final Semaphore finalRelease = needReleaseLock ? clusterLock : null;
-            Futures.addCallback(destroyFuture, newAsyncCloseCallback(finalRelease, true));
+            lock.unlock();
         }
-        return destroyFuture;
+
+        LOG.debug("Service group {} {}", identifier, future.isDone() ? "closed" : "closing");
+        return future;
+    }
+
+    private boolean isClosed() {
+        return closeFuture.get() != null;
+    }
+
+    @GuardedBy("lock")
+    private void updateState(final State newState) {
+        LOG.debug("Service group {} switching from {} to {}", identifier, state, newState);
+        state = Verify.verifyNotNull(newState);
+    }
+
+    @GuardedBy("lock")
+    private void lockedClose(final SettableFuture<Void> future) {
+        if (serviceEntityReg != null) {
+            LOG.debug("Service group {} unregistering", identifier);
+            serviceEntityReg.close();
+            serviceEntityReg = null;
+        }
+
+        switch (state) {
+            case INITIAL:
+                // Not started: not much to do
+                terminate(future);
+                break;
+            case TERMINATED:
+                // Already done: no-op
+                break;
+            case REGISTERED:
+            case STANDBY:
+                LOG.debug("Service group {} terminated", identifier);
+                terminate(future);
+                break;
+            case OWNER:
+                // No-op, we will react to the loss of registration instead.
+                break;
+            case STOPPING_SERVICES:
+                // Waiting for services. Will resume once we get notified.
+                break;
+            case RELEASING_OWNERSHIP:
+                // Waiting for cleanup entity to flip, will resume afterwards.
+                break;
+            case TAKING_OWNERSHIP:
+                // Abort taking of ownership and close
+                LOG.debug("Service group {} aborting ownership bid", identifier);
+                cleanupEntityReg.close();
+                cleanupEntityReg = null;
+                updateState(State.RELEASING_OWNERSHIP);
+                break;
+            default:
+                throw new IllegalStateException("Unhandled state " + state);
+        }
+    }
+
+    @GuardedBy("lock")
+    private void terminate(final SettableFuture<Void> future) {
+        updateState(State.TERMINATED);
+        Verify.verify(future.set(null));
     }
 
-    @SuppressWarnings("checkstyle:IllegalCatch")
     @Override
-    public void initializationClusterSingletonGroup() {
-        LOG.debug("Initialization ClusterSingletonGroup {}", clusterSingletonGroupIdentifier);
-        boolean needReleaseLock = false;
-        boolean needCloseProviderInstance = false;
+    void initialize() throws CandidateAlreadyRegisteredException {
+        LOG.debug("Initialization ClusterSingletonGroup {}", identifier);
+
+        lock.lock();
         try {
-            clusterLock.acquire();
-            needReleaseLock = true;
-            Verify.verify(serviceGroup.isEmpty());
-            Verify.verify(!hasOwnership);
-            Verify.verify(serviceEntityCandidateReg == null);
-            serviceEntityCandidateReg = entityOwnershipService.registerCandidate(serviceEntity);
-        } catch (final RuntimeException | InterruptedException | CandidateAlreadyRegisteredException e) {
-            LOG.debug("Unexpected error by registration service Provider {}", clusterSingletonGroupIdentifier, e);
-            needCloseProviderInstance = true;
-            throw new RuntimeException(e);
+            Preconditions.checkState(state == State.INITIAL, "Unexpected singleton group %s state %s", identifier,
+                    state);
+
+            // Catch events if they fire during this call
+            capture = new ArrayList<>(0);
+            serviceEntityReg = entityOwnershipService.registerCandidate(serviceEntity);
+            state = State.REGISTERED;
+
+            final List<C> captured = capture;
+            capture = null;
+            captured.forEach(this::lockedOwnershipChanged);
         } finally {
-            closeResources(needReleaseLock, needCloseProviderInstance);
+            lock.unlock();
         }
     }
 
-    @SuppressWarnings("checkstyle:IllegalCatch")
+    private void checkNotClosed() {
+        Preconditions.checkState(closeFuture.get() == null, "Service group %s has already been closed",
+                identifier);
+    }
+
     @Override
-    public ClusterSingletonServiceRegistration registerService(final ClusterSingletonService service) {
-        LOG.debug("RegisterService method call for ClusterSingletonServiceGroup {}", clusterSingletonGroupIdentifier);
-        Verify.verify(clusterSingletonGroupIdentifier.equals(service.getIdentifier().getValue()));
-        boolean needReleaseLock = false;
-        boolean needCloseProviderInstance = false;
-        ClusterSingletonServiceRegistrationDelegator reg = null;
+    void registerService(final ClusterSingletonService service) {
+        Verify.verify(identifier.equals(service.getIdentifier().getValue()));
+        checkNotClosed();
+
+        LOG.debug("RegisterService method call for ClusterSingletonServiceGroup {}", identifier);
+
+        lock.lock();
         try {
-            clusterLock.acquire();
-            needReleaseLock = true;
-            Verify.verify(serviceEntityCandidateReg != null);
-            reg = new ClusterSingletonServiceRegistrationDelegator(service, this);
-            serviceGroup.add(reg);
-            if (hasOwnership) {
-                service.instantiateServiceInstance();
+            Preconditions.checkState(state != State.INITIAL, "Service group %s is not initialized yet", identifier);
+            serviceGroup.add(service);
+
+            switch (state) {
+                case OWNER:
+                case STARTING_SERVICES:
+                    service.instantiateServiceInstance();
+                    break;
+                default:
+                    break;
             }
-        } catch (final RuntimeException | InterruptedException e) {
-            LOG.debug("Unexpected error by registration service Provider {}", clusterSingletonGroupIdentifier, e);
-            needCloseProviderInstance = true;
-            throw new RuntimeException(e);
         } finally {
-            closeResources(needReleaseLock, needCloseProviderInstance);
+            lock.unlock();
         }
-        return reg;
     }
 
-    @SuppressWarnings("checkstyle:IllegalCatch")
+    @CheckReturnValue
     @Override
-    public void unregisterService(final ClusterSingletonService service) {
-        LOG.debug("UnregisterService method call for ClusterSingletonServiceGroup {}", clusterSingletonGroupIdentifier);
-        Verify.verify(clusterSingletonGroupIdentifier.equals(service.getIdentifier().getValue()));
-        boolean needReleaseLock = false;
-        boolean needCloseProviderInstance = false;
+    boolean unregisterService(final ClusterSingletonService service) {
+        Verify.verify(identifier.equals(service.getIdentifier().getValue()));
+        checkNotClosed();
+
+        lock.lock();
         try {
-            clusterLock.acquire();
-            needReleaseLock = true;
-            if (serviceGroup.size() > 1) {
-                if (hasOwnership) {
+            // There is a slight problem here, as the type does not match the list type, hence we need to tread
+            // carefully.
+            if (serviceGroup.size() == 1) {
+                Verify.verify(serviceGroup.contains(service));
+                return true;
+            }
+
+            Verify.verify(serviceGroup.remove(service));
+            LOG.debug("Service {} was removed from group.", service.getIdentifier().getValue());
+
+            switch (state) {
+                case OWNER:
+                case STARTING_SERVICES:
                     service.closeServiceInstance();
-                }
-                serviceGroup.remove(service);
-                LOG.debug("Service {} was removed from group.", service.getIdentifier().getValue());
-            } else {
-                needCloseProviderInstance = true;
+                    break;
+                default:
+                    break;
             }
-        } catch (final RuntimeException | InterruptedException e) {
-            LOG.debug("Unexpected error by registration service Provider {}", clusterSingletonGroupIdentifier, e);
-            needCloseProviderInstance = true;
-            throw new RuntimeException(e);
+
+            return false;
         } finally {
-            closeResources(needReleaseLock, needCloseProviderInstance);
+            lock.unlock();
+            finishCloseIfNeeded();
         }
     }
 
-    @SuppressWarnings("checkstyle:IllegalCatch")
     @Override
-    public void ownershipChanged(final C ownershipChange) {
-        LOG.debug("Ownership change {} for ClusterSingletonServiceGroup {}", ownershipChange,
-                clusterSingletonGroupIdentifier);
+    void ownershipChanged(final C ownershipChange) {
+        LOG.debug("Ownership change {} for ClusterSingletonServiceGroup {}", ownershipChange, identifier);
+
+        lock.lock();
         try {
-            if (ownershipChange.inJeopardy()) {
-                LOG.warn("Cluster Node lost connection to another cluster nodes {}", ownershipChange);
-                lostOwnership();
-                return;
+            if (capture != null) {
+                capture.add(ownershipChange);
+            } else {
+                lockedOwnershipChanged(ownershipChange);
             }
-            if (serviceEntity.equals(ownershipChange.getEntity())) {
-                if (EntityOwnershipChangeState.LOCAL_OWNERSHIP_GRANTED.equals(ownershipChange.getState())) {
-                    /*
-                     * SLAVE to MASTER : ownershipChange.getState().isOwner() && !ownershipChange.getState().wasOwner()
-                     */
-                    tryToTakeOwnership();
-                } else if (EntityOwnershipChangeState.LOCAL_OWNERSHIP_LOST_NEW_OWNER.equals(ownershipChange.getState())
-                        || EntityOwnershipChangeState.LOCAL_OWNERSHIP_LOST_NO_OWNER
-                                .equals(ownershipChange.getState())) {
-                    /*
-                     * MASTER to SLAVE : !ownershipChange.getState().isOwner() && ownershipChange.getState().wasOwner()
-                     */
-                    lostOwnership();
-                } else {
-                    /* Not needed notifications */
-                    LOG.debug("Not processed entity OwnershipChange {} in service Provider {}", ownershipChange,
-                            clusterSingletonGroupIdentifier);
+        } finally {
+            lock.unlock();
+            finishCloseIfNeeded();
+        }
+    }
+
+    private void lockedOwnershipChanged(final C ownershipChange) {
+        if (ownershipChange.inJeopardy()) {
+            LOG.warn("Cluster Node lost connection to another cluster nodes {}", ownershipChange);
+            lostOwnership();
+            return;
+        }
+
+        final E entity = ownershipChange.getEntity();
+        if (serviceEntity.equals(entity)) {
+            serviceOwnershipChanged(ownershipChange);
+        } else if (cleanupEntity.equals(entity)) {
+            cleanupCandidateOwnershipChanged(ownershipChange);
+        } else {
+            LOG.warn("Group {} received unrecognized change {}", identifier, ownershipChange);
+        }
+    }
+
+    private void cleanupCandidateOwnershipChanged(final C ownershipChange) {
+        switch (ownershipChange.getState()) {
+            case LOCAL_OWNERSHIP_GRANTED:
+                switch (state) {
+                    case TAKING_OWNERSHIP:
+                        // SLAVE to MASTER
+                        startServices();
+                        return;
+                    default:
+                        break;
                 }
-            } else if (doubleCandidateEntity.equals(ownershipChange.getEntity())) {
-                if (EntityOwnershipChangeState.LOCAL_OWNERSHIP_GRANTED.equals(ownershipChange.getState())) {
-                    /*
-                     * SLAVE to MASTER : ownershipChange.getState().isOwner() && !ownershipChange.getState().wasOwner()
-                     */
-                    takeOwnership();
-                } else {
-                    /* Not needed notifications */
-                    LOG.debug("Not processed doubleCandidate OwnershipChange {} in service Provider {}",
-                            ownershipChange, clusterSingletonGroupIdentifier);
+                break;
+            case LOCAL_OWNERSHIP_LOST_NEW_OWNER:
+            case LOCAL_OWNERSHIP_LOST_NO_OWNER:
+                switch (state) {
+                    case RELEASING_OWNERSHIP:
+                        // Slight cheat: if we are closing down, we just need to notify the future
+                        updateState(isClosed() ? State.INITIAL : State.STANDBY);
+                        return;
+                    case STARTING_SERVICES:
+                    case OWNER:
+                    case TAKING_OWNERSHIP:
+                        LOG.warn("Group {} lost cleanup ownership in state {}", identifier, state);
+                        return;
+                    default:
+                        break;
                 }
-            } else {
-                LOG.warn("Unexpected EntityOwnershipChangeEvent for entity {}", ownershipChange);
+
+                break;
+            case LOCAL_OWNERSHIP_RETAINED_WITH_NO_CHANGE:
+            case REMOTE_OWNERSHIP_CHANGED:
+            case REMOTE_OWNERSHIP_LOST_NO_OWNER:
+            default:
+                break;
+        }
+
+        LOG.debug("Group {} in state {} ignoring cleanup OwnershipChange {}", identifier, state, ownershipChange);
+    }
+
+    private void serviceOwnershipChanged(final C ownershipChange) {
+        switch (ownershipChange.getState()) {
+            case LOCAL_OWNERSHIP_GRANTED:
+                // SLAVE to MASTER : ownershipChange.getState().isOwner() && !ownershipChange.getState().wasOwner()
+                takeOwnership();
+                break;
+            case LOCAL_OWNERSHIP_LOST_NEW_OWNER:
+            case LOCAL_OWNERSHIP_LOST_NO_OWNER:
+                // MASTER to SLAVE : !ownershipChange.getState().isOwner() && ownershipChange.getState().wasOwner()
+                lostOwnership();
+                break;
+            default:
+                // Not needed notifications
+                LOG.debug("Group {} in state {} not processed entity OwnershipChange {}", identifier, state,
+                    ownershipChange);
+        }
+    }
+
+    private void finishCloseIfNeeded() {
+        final SettableFuture<Void> future = closeFuture.get();
+        if (future != null) {
+            lock.lock();
+            try {
+                lockedClose(future);
+            } finally {
+                lock.unlock();
             }
-        } catch (final Exception e) {
-            LOG.error("Unexpected Exception for service Provider {}", clusterSingletonGroupIdentifier, e);
-            // TODO : think about close ... is it necessary?
         }
     }
 
@@ -265,56 +432,44 @@ final class ClusterSingletonServiceGroupImpl<P extends Path<P>, E extends Generi
      * Help method to registered DoubleCandidateEntity. It is first step
      * before the actual instance take Leadership.
      */
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    private void tryToTakeOwnership() {
-        LOG.debug("TryToTakeLeadership method for service Provider {}", clusterSingletonGroupIdentifier);
-        boolean needReleaseLock = false;
-        boolean needCloseProviderInstance = false;
+    private void takeOwnership() {
+        if (isClosed()) {
+            LOG.debug("Service group {} is closed, not taking ownership", identifier);
+            return;
+        }
+
+        LOG.debug("Group {} taking ownership", identifier);
+
+        updateState(State.TAKING_OWNERSHIP);
         try {
-            clusterLock.acquire();
-            needReleaseLock = true;
-            if (serviceEntityCandidateReg != null) {
-                Verify.verify(asyncCloseEntityCandidateReg == null);
-                asyncCloseEntityCandidateReg = entityOwnershipService.registerCandidate(doubleCandidateEntity);
-            } else {
-                LOG.debug("Service {} is closed, so don't to tryTakeLeadership", clusterSingletonGroupIdentifier);
-            }
-        } catch (final Exception e) {
-            LOG.error("Unexpected exception state for service Provider {} in TryToTakeLeadership",
-                    clusterSingletonGroupIdentifier, e);
-            needCloseProviderInstance = true;
-        } finally {
-            closeResources(needReleaseLock, needCloseProviderInstance);
+            cleanupEntityReg = entityOwnershipService.registerCandidate(cleanupEntity);
+        } catch (CandidateAlreadyRegisteredException e) {
+            LOG.error("Service group {} failed to take ownership", identifier, e);
         }
     }
 
     /*
-     * Help method calls setupService method for create single cluster-wide service instance.
+     * Help method calls instantiateServiceInstance method for create single cluster-wide service instance.
      */
     @SuppressWarnings("checkstyle:IllegalCatch")
-    private void takeOwnership() {
-        LOG.debug("TakeLeadership method for service Provider {}", clusterSingletonGroupIdentifier);
-        boolean needReleaseLock = false;
-        boolean needCloseProviderInstance = false;
-        try {
-            clusterLock.acquire();
-            needReleaseLock = true;
-            if (serviceEntityCandidateReg != null) {
-                Verify.verify(asyncCloseEntityCandidateReg != null);
-                for (final ClusterSingletonServiceRegistrationDelegator service : serviceGroup) {
-                    service.instantiateServiceInstance();
-                }
-                hasOwnership = true;
-            } else {
-                LOG.debug("Service {} is closed, so don't take leadership", clusterSingletonGroupIdentifier);
-            }
-        } catch (final RuntimeException | InterruptedException e) {
-            LOG.error("Unexpected exception state for service Provider {} in TakeLeadership",
-                    clusterSingletonGroupIdentifier, e);
-            needCloseProviderInstance = true;
-        } finally {
-            closeResources(needReleaseLock, needCloseProviderInstance);
+    private void startServices() {
+        if (isClosed()) {
+            LOG.debug("Service group {} is closed, not starting services", identifier);
+            return;
         }
+
+        LOG.debug("Service group {} starting services", identifier);
+        serviceGroup.forEach(service -> {
+            LOG.debug("Starting service {}", service);
+            try {
+                service.instantiateServiceInstance();
+            } catch (Exception e) {
+                LOG.warn("Service group {} service {} failed to start, attempting to continue", identifier, service, e);
+            }
+        });
+
+        LOG.debug("Service group {} services started", identifier);
+        updateState(State.OWNER);
     }
 
     /*
@@ -322,110 +477,84 @@ final class ClusterSingletonServiceGroupImpl<P extends Path<P>, E extends Generi
      * The last async. step has to close DoubleCandidateRegistration reference what should initialize
      * new election for DoubleCandidateEntity.
      */
-    @SuppressWarnings("checkstyle:IllegalCatch")
     private void lostOwnership() {
-        LOG.debug("LostLeadership method for service Provider {}", clusterSingletonGroupIdentifier);
-        boolean needReleaseLock = false;
-        boolean needCloseProviderInstance = false;
-        try {
-            clusterLock.acquire();
-            needReleaseLock = true;
-            final List<ListenableFuture<Void>> serviceCloseFutureList = new ArrayList<>();
-            if (hasOwnership) {
-                Verify.verify(asyncCloseEntityCandidateReg != null);
-                for (final ClusterSingletonServiceRegistrationDelegator service : serviceGroup) {
-                    try {
-                        serviceCloseFutureList.add(service.closeServiceInstance());
-                    } catch (final RuntimeException e) {
-                        LOG.error("Unexpected exception while closing service: {}, resuming with next..",
-                                service.getIdentifier());
-                    }
-                }
-                hasOwnership = false;
-            }
-
-            final ListenableFuture<List<Void>> destroyFuture = Futures.allAsList(serviceCloseFutureList);
-            if (serviceEntityCandidateReg != null) {
-                // we don't want to remove this instance from map
-                Futures.addCallback(destroyFuture, newAsyncCloseCallback(clusterLock, false));
-            } else {
-                // we have to remove this ClusterSingletonServiceGroup instance from map
-                Futures.addCallback(destroyFuture, newAsyncCloseCallback(clusterLock, true));
-            }
-            /*
-             * We wish to stop all possible EOS activities before we don't close
-             * a close candidate registration that acts as a guard. So we don't want
-             * to release Semaphore (clusterLock) before we are not fully finished.
-             * Semaphore lock release has to be realized as FutureCallback after a service
-             * instance has fully closed prior to relinquishing service ownership.
-             */
-            needReleaseLock = false;
-        } catch (final InterruptedException e) {
-            LOG.error("Unexpected exception state for service Provider {} in LostLeadership",
-                    clusterSingletonGroupIdentifier, e);
-            needCloseProviderInstance = true;
-        } finally {
-            closeResources(needReleaseLock, needCloseProviderInstance);
+        LOG.debug("Service group {} lost ownership in state {}", identifier, state);
+        switch (state) {
+            case REGISTERED:
+                updateState(State.STANDBY);
+                break;
+            case OWNER:
+                stopServices();
+                break;
+            case STARTING_SERVICES:
+            case STOPPING_SERVICES:
+                // No-op, as these will re-check state before proceeding
+                break;
+            case TAKING_OWNERSHIP:
+                cleanupEntityReg.close();
+                cleanupEntityReg = null;
+                updateState(State.STANDBY);
+                break;
+            case INITIAL:
+            case TERMINATED:
+            default:
+                LOG.info("Service group {} ignoring lost ownership in state {},", identifier, state);
+                break;
         }
     }
 
-    /*
-     * Help method for finalization every acquired functionality
-     */
-    @GuardedBy("clusterLock")
-    private void closeResources(final boolean needReleaseLock, final boolean needCloseProvider) {
-        if (needCloseProvider) {
-            // The Game Over for this ClusterSingletonServiceGroup instance
-            if (serviceEntityCandidateReg != null) {
-                serviceEntityCandidateReg.close();
-                serviceEntityCandidateReg = null;
-            }
-            // Remove instance immediately because actual state is follower or initialization
-            if (asyncCloseEntityCandidateReg == null) {
-                allServiceGroups.remove(clusterSingletonGroupIdentifier, this);
-            }
-        }
+    @SuppressWarnings("checkstyle:IllegalCatch")
+    void stopServices() {
+        updateState(State.STOPPING_SERVICES);
 
-        if (needReleaseLock) {
-            clusterLock.release();
-        }
-    }
+        final List<ListenableFuture<Void>> serviceCloseFutureList = new ArrayList<>(serviceGroup.size());
+        for (final ClusterSingletonService service : serviceGroup) {
+            final ListenableFuture<Void> future;
 
-    /*
-     * Help method creates FutureCallback for suspend Future
-     */
-    private FutureCallback<List<Void>> newAsyncCloseCallback(@Nullable final Semaphore semaphore,
-            final boolean isInCloseProcess) {
-        final Consumer<Throwable> closeEntityCandidateRegistration = (@Nullable final Throwable throwable) -> {
-            if (throwable != null) {
-                LOG.warn("Unexpected error closing service instance {}", clusterSingletonGroupIdentifier, throwable);
-            } else {
-                LOG.debug("Destroy service Instance {} is success", clusterSingletonGroupIdentifier);
-            }
-            if (asyncCloseEntityCandidateReg != null) {
-                asyncCloseEntityCandidateReg.close();
-                asyncCloseEntityCandidateReg = null;
-            }
-            if (isInCloseProcess) {
-                allServiceGroups.remove(clusterSingletonGroupIdentifier, this);
+            try {
+                future = service.closeServiceInstance();
+            } catch (Exception e) {
+                LOG.warn("Service group {} service {} failed to stop, attempting to continue", identifier,
+                    service, e);
+                continue;
             }
-            if (semaphore != null) {
-                semaphore.release();
-            }
-        };
 
-        return new FutureCallback<List<Void>>() {
+            serviceCloseFutureList.add(future);
+        }
 
+        Futures.addCallback(Futures.allAsList(serviceCloseFutureList), new FutureCallback<List<Void>>() {
             @Override
-            public void onSuccess(final List<Void> result) {
-                closeEntityCandidateRegistration.accept(null);
+            public void onFailure(final Throwable cause) {
+                LOG.warn("Service group {} service stopping reported error", identifier, cause);
+                onServicesStopped();
             }
 
             @Override
-            public void onFailure(final Throwable throwable) {
-                closeEntityCandidateRegistration.accept(throwable);
+            public void onSuccess(final List<Void> nulls) {
+                onServicesStopped();
             }
-        };
+        });
     }
 
+    void onServicesStopped() {
+        LOG.debug("Service group {} finished stopping services", identifier);
+        lock.lock();
+        try {
+            if (cleanupEntityReg != null) {
+                updateState(State.RELEASING_OWNERSHIP);
+                cleanupEntityReg.close();
+                cleanupEntityReg = null;
+            } else {
+                updateState(State.STANDBY);
+            }
+        } finally {
+            lock.unlock();
+            finishCloseIfNeeded();
+        }
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this).add("identifier", identifier).add("state", state).toString();
+    }
 }
diff --git a/singleton-service/mdsal-singleton-dom-impl/src/main/java/org/opendaylight/mdsal/singleton/dom/impl/ClusterSingletonServiceRegistrationDelegator.java b/singleton-service/mdsal-singleton-dom-impl/src/main/java/org/opendaylight/mdsal/singleton/dom/impl/ClusterSingletonServiceRegistrationDelegator.java
deleted file mode 100644 (file)
index 8728298..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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 com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.ListenableFuture;
-import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
-import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
-import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
-
-/**
- * Package protected help class represent a Delegator for {@link ClusterSingletonService}
- * instance and {@link ClusterSingletonServiceRegistration} implementation.
- * Close registration means remove {@link ClusterSingletonService} instance from internal
- * ClusterSingletonServiceGroup list reference.
- *
- *<p>
- * Close {@link ClusterSingletonServiceRegistration} is prepared for a possible restart
- * service or application in osgi container. Any another services from group can not be
- * stopped.
- */
-class ClusterSingletonServiceRegistrationDelegator
-        implements ClusterSingletonServiceRegistration, ClusterSingletonService {
-
-    private final ClusterSingletonService service;
-    private final ClusterSingletonServiceGroup<?, ?, ?> group;
-
-    ClusterSingletonServiceRegistrationDelegator(final ClusterSingletonService service,
-            final ClusterSingletonServiceGroup<?, ?, ?> group) {
-        this.service = Preconditions.checkNotNull(service);
-        this.group = Preconditions.checkNotNull(group);
-    }
-
-    @Override
-    public void close() throws Exception {
-        group.unregisterService(this);
-    }
-
-    @Override
-    public void instantiateServiceInstance() {
-        service.instantiateServiceInstance();
-    }
-
-    @Override
-    public ListenableFuture<Void> closeServiceInstance() {
-        return service.closeServiceInstance();
-    }
-
-    @Override
-    public ServiceGroupIdentifier getIdentifier() {
-        return service.getIdentifier();
-    }
-
-    public String getServiceGroupIdentifier() {
-        return service.getIdentifier().getValue();
-    }
-}
\ No newline at end of file
diff --git a/singleton-service/mdsal-singleton-dom-impl/src/main/java/org/opendaylight/mdsal/singleton/dom/impl/PlaceholderGroup.java b/singleton-service/mdsal-singleton-dom-impl/src/main/java/org/opendaylight/mdsal/singleton/dom/impl/PlaceholderGroup.java
new file mode 100644 (file)
index 0000000..ea50afe
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies, s.r.o. 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 com.google.common.base.Verify.verify;
+import static com.google.common.base.Verify.verifyNotNull;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException;
+import org.opendaylight.mdsal.eos.common.api.GenericEntity;
+import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipChange;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
+import org.opendaylight.yangtools.concepts.Path;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Intermediate place-holder to catch user requests while asynchronous shutdown of previous incarnation of
+ * a {@link ClusterSingletonServiceGroup} finishes.
+ */
+final class PlaceholderGroup<P extends Path<P>, E extends GenericEntity<P>,
+        C extends GenericEntityOwnershipChange<P, E>> extends ClusterSingletonServiceGroup<P, E, C> {
+    private static final Logger LOG = LoggerFactory.getLogger(PlaceholderGroup.class);
+
+    private final List<ClusterSingletonService> services = new ArrayList<>(0);
+    private final ClusterSingletonServiceGroup<P, E, C> previous;
+    private final ListenableFuture<?> closeFuture;
+
+    private volatile ClusterSingletonServiceGroup<P, E, C> successor;
+
+    PlaceholderGroup(final ClusterSingletonServiceGroup<P, E, C> previous, final ListenableFuture<?> closeFuture) {
+        this.previous = requireNonNull(previous);
+        this.closeFuture = requireNonNull(closeFuture);
+    }
+
+    @Override
+    public String getIdentifier() {
+        return previous.getIdentifier();
+    }
+
+    @Override
+    void initialize() throws CandidateAlreadyRegisteredException {
+        throw new UnsupportedOperationException("This should never be invoked");
+    }
+
+    @Override
+    void registerService(final ClusterSingletonService service) {
+        verifyNoSuccessor();
+        services.add(service);
+        LOG.debug("{}: added service {}", this, service);
+    }
+
+    @Override
+    boolean unregisterService(final ClusterSingletonService service) {
+        verifyNoSuccessor();
+        services.remove(service);
+        LOG.debug("{}: removed service {}", this, service);
+        return false;
+    }
+
+    @Override
+    void ownershipChanged(final C ownershipChange) {
+        // This really should not happen, but let's be defensive
+        final ClusterSingletonServiceGroup<P, E, C> local = successor;
+        (local == null ? previous : local).ownershipChanged(ownershipChange);
+    }
+
+    @Override
+    ListenableFuture<?> closeClusterSingletonGroup() {
+        final ClusterSingletonServiceGroup<P, E, C> local = successor;
+        return local == null ? closeFuture : local.closeClusterSingletonGroup();
+    }
+
+    // Note: this is a leaked structure, the caller can reuse it at will, but has to regard
+    List<ClusterSingletonService> getServices() {
+        verifyNoSuccessor();
+        LOG.trace("{}: returning services {}", this, services);
+        return services;
+    }
+
+    void setSuccessor(final ClusterSingletonServiceGroup<P, E, C> successor) {
+        verifyNoSuccessor();
+        this.successor = verifyNotNull(successor);
+        LOG.debug("{}: successor set to {}", this, successor);
+    }
+
+    private void verifyNoSuccessor() {
+        verify(successor == null, "Placeholder already superseded by %s", successor);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this).add("id", getIdentifier()).toString();
+    }
+}
diff --git a/singleton-service/mdsal-singleton-dom-impl/src/test/java/org/opendaylight/mdsal/singleton/dom/impl/AbstractDOMClusterServiceProviderTest.java b/singleton-service/mdsal-singleton-dom-impl/src/test/java/org/opendaylight/mdsal/singleton/dom/impl/AbstractDOMClusterServiceProviderTest.java
new file mode 100644 (file)
index 0000000..eff1025
--- /dev/null
@@ -0,0 +1,608 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies, s.r.o. 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.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+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 static org.opendaylight.mdsal.singleton.dom.impl.AbstractClusterSingletonServiceProviderImpl.CLOSE_SERVICE_ENTITY_TYPE;
+import static org.opendaylight.mdsal.singleton.dom.impl.AbstractClusterSingletonServiceProviderImpl.SERVICE_ENTITY_TYPE;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+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;
+
+/**
+ * Abstract {@link DOMClusterSingletonServiceProviderImpl} testing substrate.
+ */
+public abstract class AbstractDOMClusterServiceProviderTest {
+    /**
+     * Base states for AbstractClusterProjectProvider.
+     */
+    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,
+    }
+
+    static class TestClusterSingletonService implements ClusterSingletonService {
+        private static final ServiceGroupIdentifier SERVICE_ID = ServiceGroupIdentifier.create(SERVICE_NAME);
+
+        private TestClusterSingletonServiceState serviceState = TestClusterSingletonServiceState.INITIALIZED;
+
+        @Override
+        public final ServiceGroupIdentifier getIdentifier() {
+            return SERVICE_ID;
+        }
+
+        @Override
+        public final void instantiateServiceInstance() {
+            this.serviceState = TestClusterSingletonServiceState.STARTED;
+        }
+
+        final TestClusterSingletonServiceState getServiceState() {
+            return serviceState;
+        }
+
+        @Override
+        public ListenableFuture<Void> closeServiceInstance() {
+            this.serviceState = TestClusterSingletonServiceState.DESTROYED;
+            return Futures.immediateFuture(null);
+        }
+    }
+
+    static final String SERVICE_NAME = "testServiceName";
+    static final DOMEntity ENTITY = new DOMEntity(SERVICE_ENTITY_TYPE, SERVICE_NAME);
+    static final DOMEntity DOUBLE_ENTITY = new DOMEntity(CLOSE_SERVICE_ENTITY_TYPE, SERVICE_NAME);
+
+    @Mock
+    protected DOMEntityOwnershipService mockEos;
+    @Mock
+    protected DOMEntityOwnershipCandidateRegistration mockEntityCandReg;
+    @Mock
+    protected DOMEntityOwnershipCandidateRegistration mockDoubleEntityCandReg;
+    @Mock
+    protected DOMEntityOwnershipListenerRegistration mockEosEntityListReg;
+    @Mock
+    protected DOMEntityOwnershipListenerRegistration mockEosDoubleEntityListReg;
+
+    protected DOMClusterSingletonServiceProviderImpl clusterSingletonServiceProvider;
+    protected TestClusterSingletonService clusterSingletonService;
+    protected TestClusterSingletonService clusterSingletonService2;
+
+    @Before
+    public void setup() throws CandidateAlreadyRegisteredException {
+        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(DOUBLE_ENTITY);
+
+        clusterSingletonServiceProvider = new DOMClusterSingletonServiceProviderImpl(mockEos);
+        clusterSingletonServiceProvider.initializeProvider();
+        verify(mockEos).registerListener(SERVICE_ENTITY_TYPE, clusterSingletonServiceProvider);
+        verify(mockEos).registerListener(CLOSE_SERVICE_ENTITY_TYPE, clusterSingletonServiceProvider);
+
+        clusterSingletonService = instantiateService();
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonService2 = instantiateService();
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+    }
+
+    TestClusterSingletonService instantiateService() {
+        return new TestClusterSingletonService();
+    }
+
+    static final DOMEntityOwnershipChange getEntityToMaster() {
+        return new DOMEntityOwnershipChange(ENTITY, EntityOwnershipChangeState.LOCAL_OWNERSHIP_GRANTED);
+    }
+
+    static final DOMEntityOwnershipChange getEntityToSlave() {
+        return new DOMEntityOwnershipChange(ENTITY, EntityOwnershipChangeState.LOCAL_OWNERSHIP_LOST_NEW_OWNER);
+    }
+
+    static final DOMEntityOwnershipChange getInitEntityToSlave() {
+        return new DOMEntityOwnershipChange(ENTITY, EntityOwnershipChangeState.REMOTE_OWNERSHIP_CHANGED);
+    }
+
+    static final DOMEntityOwnershipChange getInitEntityToSlaveNoMaster() {
+        return new DOMEntityOwnershipChange(ENTITY, EntityOwnershipChangeState.REMOTE_OWNERSHIP_LOST_NO_OWNER);
+    }
+
+    static final DOMEntityOwnershipChange getDoubleEntityToMaster() {
+        return new DOMEntityOwnershipChange(DOUBLE_ENTITY, EntityOwnershipChangeState.LOCAL_OWNERSHIP_GRANTED);
+    }
+
+    static final DOMEntityOwnershipChange getInitDoubleEntityToSlave() {
+        return new DOMEntityOwnershipChange(DOUBLE_ENTITY, EntityOwnershipChangeState.REMOTE_OWNERSHIP_CHANGED);
+    }
+
+    static final DOMEntityOwnershipChange getDoubleEntityToSlave() {
+        return new DOMEntityOwnershipChange(DOUBLE_ENTITY, EntityOwnershipChangeState.LOCAL_OWNERSHIP_LOST_NEW_OWNER);
+    }
+
+    static final DOMEntityOwnershipChange getEntityToJeopardy() {
+        return new DOMEntityOwnershipChange(ENTITY, EntityOwnershipChangeState.REMOTE_OWNERSHIP_LOST_NO_OWNER, true);
+    }
+
+    /**
+     * Test checks NullPointer for null {@link DOMEntityOwnershipService} input value.
+     */
+    @Test(expected = NullPointerException.class)
+    public void initializationClusterSingletonServiceProviderNullInputTest() {
+        new DOMClusterSingletonServiceProviderImpl(null).close();
+    }
+
+    /**
+     * Test GoldPath for close {@link DOMClusterSingletonServiceProviderImpl}.
+     *
+     * @throws Exception if the condition does not meet
+     */
+    @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.
+     */
+    @Test
+    public void makeEntityClusterSingletonServiceProviderTest() {
+        final DOMEntity testEntity = clusterSingletonServiceProvider.createEntity(SERVICE_ENTITY_TYPE, SERVICE_NAME);
+        assertEquals(ENTITY, testEntity);
+        final DOMEntity testDbEn = clusterSingletonServiceProvider.createEntity(CLOSE_SERVICE_ENTITY_TYPE,
+                SERVICE_NAME);
+        assertEquals(DOUBLE_ENTITY, testDbEn);
+    }
+
+    /**
+     * Test parser ServiceIdentifier from Entity.
+     */
+    @Test
+    public void getIdentifierClusterSingletonServiceProviderTest() {
+        final String entityIdentifier = clusterSingletonServiceProvider.getServiceIdentifierFromEntity(ENTITY);
+        assertEquals(SERVICE_NAME, entityIdentifier);
+        final String doubleEntityId = clusterSingletonServiceProvider.getServiceIdentifierFromEntity(DOUBLE_ENTITY);
+        assertEquals(SERVICE_NAME, doubleEntityId);
+    }
+
+    /**
+     * Test GoldPath for initialization {@link ClusterSingletonService}.
+     *
+     * @throws CandidateAlreadyRegisteredException if the condition does not meet
+     */
+    @Test
+    public void initializationClusterSingletonServiceTest() throws CandidateAlreadyRegisteredException {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        assertNotNull(reg);
+        verify(mockEos).registerCandidate(ENTITY);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for initialization with init ownership result SLAVE {@link ClusterSingletonService}.
+     *
+     * @throws CandidateAlreadyRegisteredException if the condition does not meet
+     */
+    @Test
+    public void slaveInitClusterSingletonServiceTest() throws CandidateAlreadyRegisteredException {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        assertNotNull(reg);
+        verify(mockEos).registerCandidate(ENTITY);
+        clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlave());
+        verify(mockEos, never()).registerCandidate(DOUBLE_ENTITY);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for initialization with init ownership result SLAVE, but NO-MASTER {@link ClusterSingletonService}.
+     *
+     * @throws CandidateAlreadyRegisteredException if the condition does not meet
+     */
+    @Test
+    public void slaveInitNoMasterClusterSingletonServiceTest() throws CandidateAlreadyRegisteredException {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        assertNotNull(reg);
+        verify(mockEos).registerCandidate(ENTITY);
+        clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlaveNoMaster());
+        verify(mockEos, never()).registerCandidate(DOUBLE_ENTITY);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for initialization with init ownership result MASTER {@link ClusterSingletonService}.
+     *
+     * @throws CandidateAlreadyRegisteredException if the condition does not meet
+     */
+    @Test
+    public void masterInitClusterSingletonServiceTest() throws CandidateAlreadyRegisteredException {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        assertNotNull(reg);
+        verify(mockEos).registerCandidate(ENTITY);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for initialization with init ownership result MASTER {@link ClusterSingletonService}.
+     *
+     * @throws CandidateAlreadyRegisteredException if the condition does not meet
+     */
+    @Test
+    public void masterInitSlaveDoubleCandidateClusterSingletonServiceTest() throws CandidateAlreadyRegisteredException {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        assertNotNull(reg);
+        verify(mockEos).registerCandidate(ENTITY);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
+        clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for takeLeadership with ownership result MASTER {@link ClusterSingletonService}.
+     *
+     * @throws CandidateAlreadyRegisteredException if the condition does not meet
+     */
+    @Test
+    public void takeLeadershipClusterSingletonServiceTest() throws CandidateAlreadyRegisteredException {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        assertNotNull(reg);
+        verify(mockEos).registerCandidate(ENTITY);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for initialization with init ownership result MASTER {@link ClusterSingletonService}.
+     *
+     * @throws CandidateAlreadyRegisteredException if the condition does not meet
+     */
+    @Test
+    public void masterInitClusterSingletonServiceTwoServicesTest() throws CandidateAlreadyRegisteredException {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        assertNotNull(reg);
+        verify(mockEos).registerCandidate(ENTITY);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService2);
+        assertNotNull(reg2);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for takeLeadership with ownership result MASTER {@link ClusterSingletonService}.
+     *
+     * @throws CandidateAlreadyRegisteredException if the condition does not meet
+     */
+    @Test
+    public void takeLeadershipClusterSingletonServiceTwoAddDuringWaitPhaseServicesTest()
+            throws CandidateAlreadyRegisteredException {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        assertNotNull(reg);
+        verify(mockEos).registerCandidate(ENTITY);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
+        final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService2);
+        assertNotNull(reg2);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+    }
+
+    /**
+     * Test checks CandidateAlreadyRegisteredException processing in initialization phase.
+     *
+     * @throws CandidateAlreadyRegisteredException if the condition does not meet
+     */
+    @Test(expected = RuntimeException.class)
+    public void initializationClusterSingletonServiceCandidateAlreadyRegistredTest()
+            throws CandidateAlreadyRegisteredException {
+        doThrow(CandidateAlreadyRegisteredException.class).when(mockEos).registerCandidate(ENTITY);
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        assertNull(reg);
+    }
+
+    /**
+     * Test GoldPath for lostLeadership during tryToTakeLeadership with ownership result MASTER
+     * {@link ClusterSingletonService}.
+     *
+     * @throws CandidateAlreadyRegisteredException if the condition does not meet
+     */
+    @Test
+    public void lostLeadershipDuringTryToTakeLeadershipClusterSingletonServiceTest()
+            throws CandidateAlreadyRegisteredException {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        assertNotNull(reg);
+        verify(mockEos).registerCandidate(ENTITY);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test GoldPath for lostLeadership with ownership result MASTER-TO-SLAVE {@link ClusterSingletonService}.
+     *
+     * @throws CandidateAlreadyRegisteredException if the condition does not meet
+     */
+    @Test
+    public void lostLeadershipClusterSingletonServiceTest() throws CandidateAlreadyRegisteredException {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        assertNotNull(reg);
+        verify(mockEos).registerCandidate(ENTITY);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
+        assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test checks inJeopardy Cluster Node state for Slave Instance.
+     *
+     * @throws CandidateAlreadyRegisteredException if the condition does not meet
+     */
+    @Test
+    public void inJeopardySlaveTest() throws CandidateAlreadyRegisteredException {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        assertNotNull(reg);
+        verify(mockEos).registerCandidate(ENTITY);
+        clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlave());
+        verify(mockEos, never()).registerCandidate(DOUBLE_ENTITY);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToJeopardy());
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg, never()).close();
+        verify(mockDoubleEntityCandReg, never()).close();
+    }
+
+    /**
+     * Test GoldPath for takeLeadership with ownership result MASTER {@link ClusterSingletonService}.
+     *
+     * @throws CandidateAlreadyRegisteredException if the condition does not meet
+     */
+    @Test
+    public void takeLeadershipClusterSingletonServiceTowServicesTest() throws CandidateAlreadyRegisteredException {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        assertNotNull(reg);
+        verify(mockEos).registerCandidate(ENTITY);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService2);
+        assertNotNull(reg2);
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+    }
+
+    /**
+     * Test checks close processing for {@link ClusterSingletonServiceRegistration}.
+     *
+     * @throws Exception if the condition does not meet
+     */
+    @Test
+    public void closeClusterSingletonServiceRegistrationNoRoleTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        assertNotNull(reg);
+        verify(mockEos).registerCandidate(ENTITY);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        reg.close();
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg).close();
+        verify(mockDoubleEntityCandReg, never()).close();
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test checks close processing for {@link ClusterSingletonServiceRegistration}.
+     *
+     * @throws Exception if the condition does not meet
+     */
+    @Test
+    public void closeClusterSingletonServiceRegistrationNoRoleTwoServicesTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        assertNotNull(reg);
+        verify(mockEos).registerCandidate(ENTITY);
+        final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService2);
+        assertNotNull(reg2);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+        reg.close();
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg, never()).close();
+        verify(mockDoubleEntityCandReg, never()).close();
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+    }
+
+    /**
+     * Test checks close processing for {@link ClusterSingletonServiceRegistration}.
+     *
+     * @throws Exception if the condition does not meet
+     */
+    @Test
+    public void closeClusterSingletonServiceRegistrationSlaveTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        assertNotNull(reg);
+        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();
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+    }
+
+    /**
+     * Test checks close processing for {@link ClusterSingletonServiceRegistration}.
+     *
+     * @throws Exception if the condition does not meet
+     */
+    @Test
+    public void closeClusterSingletonServiceRegistrationSlaveTwoServicesTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        assertNotNull(reg);
+        verify(mockEos).registerCandidate(ENTITY);
+        final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService2);
+        assertNotNull(reg2);
+        clusterSingletonServiceProvider.ownershipChanged(getInitEntityToSlave());
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+        reg.close();
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg, never()).close();
+        verify(mockDoubleEntityCandReg, never()).close();
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+    }
+
+    /**
+     * Test checks close processing for {@link ClusterSingletonServiceRegistration}.
+     *
+     * @throws Exception if the condition does not meet
+     */
+    @Test
+    public void closeClusterSingletonServiceRegistrationMasterTwoServicesTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        assertNotNull(reg);
+        final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService2);
+        assertNotNull(reg2);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+        verify(mockEos).registerCandidate(ENTITY);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+        reg.close();
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg, never()).close();
+        verify(mockDoubleEntityCandReg, never()).close();
+        assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+    }
+
+    /**
+     * Test checks validation Error processing for SLAVE-TO-MASTER entity Candidate role change.
+     *
+     * @throws Exception if the condition does not meet
+     */
+    @Test
+    public void tryToTakeLeaderForClosedServiceRegistrationTest() throws Exception {
+        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService);
+        assertNotNull(reg);
+        final ClusterSingletonServiceRegistration reg2 = clusterSingletonServiceProvider
+                .registerClusterSingletonService(clusterSingletonService2);
+        assertNotNull(reg2);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+        verify(mockEos).registerCandidate(ENTITY);
+        reg.close();
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        verify(mockEntityCandReg, never()).close();
+        verify(mockDoubleEntityCandReg, never()).close();
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
+    }
+}
index 27e2dafeccafb9549534ee7b42a7703469dc48b4..4f45ce379fd715658ae26af5efac10898b64329c 100644 (file)
@@ -8,20 +8,25 @@
 
 package org.opendaylight.mdsal.singleton.dom.impl;
 
-import static org.mockito.Mockito.atLeastOnce;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
+import static org.opendaylight.mdsal.singleton.dom.impl.AbstractClusterSingletonServiceProviderImpl.CLOSE_SERVICE_ENTITY_TYPE;
+import static org.opendaylight.mdsal.singleton.dom.impl.AbstractClusterSingletonServiceProviderImpl.SERVICE_ENTITY_TYPE;
 
 import com.google.common.util.concurrent.Futures;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import org.junit.Assert;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.concurrent.ExecutionException;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException;
 import org.opendaylight.mdsal.eos.common.api.EntityOwnershipChangeState;
 import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipCandidateRegistration;
 import org.opendaylight.mdsal.eos.common.api.GenericEntityOwnershipChange;
@@ -37,12 +42,12 @@ import org.opendaylight.mdsal.singleton.dom.impl.util.TestInstanceIdentifier;
  * Testing {@link ClusterSingletonServiceGroupImpl}.
  */
 public class ClusterSingletonServiceGroupImplTest {
-
-    private static final String SERVICE_ENTITY_TYPE = "org.opendaylight.mdsal.ServiceEntityType";
-    private static final String CLOSE_SERVICE_ENTITY_TYPE = "org.opendaylight.mdsal.AsyncServiceCloseEntityType";
     private static final String SERVICE_IDENTIFIER = "TestServiceIdent";
     private static final ServiceGroupIdentifier SERVICE_GROUP_IDENT = ServiceGroupIdentifier.create(SERVICE_IDENTIFIER);
 
+    private static final TestEntity MAIN_ENTITY = new TestEntity(SERVICE_ENTITY_TYPE, SERVICE_IDENTIFIER);
+    private static final TestEntity CLOSE_ENTITY = new TestEntity(CLOSE_SERVICE_ENTITY_TYPE, SERVICE_IDENTIFIER);
+
     @Mock
     private ClusterSingletonService mockClusterSingletonService;
     @Mock
@@ -68,21 +73,17 @@ public class ClusterSingletonServiceGroupImplTest {
                         GenericEntityOwnershipListener<TestInstanceIdentifier,
                             GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity>>>> singletonServiceGroup;
 
-    private final TestEntity mainEntity = new TestEntity(SERVICE_ENTITY_TYPE, SERVICE_IDENTIFIER);
-    private final TestEntity closeEntity = new TestEntity(CLOSE_SERVICE_ENTITY_TYPE, SERVICE_IDENTIFIER);
-    private final ConcurrentMap<String, ClusterSingletonServiceGroup<?, ?, ?>> map = new ConcurrentHashMap<>();
-
     /**
      * Initialization functionality for every Tests in this suite.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException unexpected exception.
      */
     @Before
-    public void setup() throws Exception {
+    public void setup() throws CandidateAlreadyRegisteredException {
         MockitoAnnotations.initMocks(this);
 
-        doReturn(mockEntityCandReg).when(mockEosService).registerCandidate(mainEntity);
-        doReturn(mockCloseEntityCandReg).when(mockEosService).registerCandidate(closeEntity);
+        doReturn(mockEntityCandReg).when(mockEosService).registerCandidate(MAIN_ENTITY);
+        doReturn(mockCloseEntityCandReg).when(mockEosService).registerCandidate(CLOSE_ENTITY);
         doNothing().when(mockEntityCandReg).close();
         doNothing().when(mockCloseEntityCandReg).close();
         doNothing().when(mockClusterSingletonService).instantiateServiceInstance();
@@ -91,226 +92,172 @@ public class ClusterSingletonServiceGroupImplTest {
         doReturn(SERVICE_GROUP_IDENT).when(mockClusterSingletonService).getIdentifier();
         doReturn(SERVICE_GROUP_IDENT).when(mockClusterSingletonServiceSecond).getIdentifier();
 
-        singletonServiceGroup = new ClusterSingletonServiceGroupImpl(
-            SERVICE_IDENTIFIER, mainEntity, closeEntity, mockEosService, map);
+        singletonServiceGroup = new ClusterSingletonServiceGroupImpl<>(SERVICE_IDENTIFIER, MAIN_ENTITY, CLOSE_ENTITY,
+            mockEosService);
     }
 
     /**
      * Test NULL ServiceIdent input for new ServiceGroup instance.
-     *
-     * @throws Exception - unexpected exception
      */
-    @Test(expected = IllegalArgumentException.class)
-    public void instantiationClusterSingletonServiceGroupNullIdentTest() throws Exception {
-        singletonServiceGroup = new ClusterSingletonServiceGroupImpl(
-                null, mainEntity, closeEntity, mockEosService, map);
+    @Test(expected = NullPointerException.class)
+    public void instantiationClusterSingletonServiceGroupNullIdentTest() {
+        new ClusterSingletonServiceGroupImpl<>(null, MAIN_ENTITY, CLOSE_ENTITY, mockEosService);
     }
 
     /**
      * Test empty ServiceIdent input for new ServiceGroup instance.
-     *
-     * @throws Exception - unexpected exception
      */
     @Test(expected = IllegalArgumentException.class)
-    public void instantiationClusterSingletonServiceGroupEmptyIdentTest() throws Exception {
-        singletonServiceGroup = new ClusterSingletonServiceGroupImpl("", mainEntity, closeEntity, mockEosService, map);
-    }
-
-    /**
-     * Test NULL MainEntity input for new ServiceGroup instance.
-     *
-     * @throws Exception - unexpected exception
-     */
-    @Test(expected = NullPointerException.class)
-    public void instantiationClusterSingletonServiceGroupNullMainEntityTest() throws Exception {
-        singletonServiceGroup = new ClusterSingletonServiceGroupImpl(
-                SERVICE_IDENTIFIER, null, closeEntity, mockEosService, map);
+    public void instantiationClusterSingletonServiceGroupEmptyIdentTest() {
+        new ClusterSingletonServiceGroupImpl<>("", MAIN_ENTITY, CLOSE_ENTITY, mockEosService);
     }
 
     /**
      * Test NULL MainEntity input for new ServiceGroup instance.
-     *
-     * @throws Exception - unexpected exception
      */
     @Test(expected = NullPointerException.class)
-    public void instantiationClusterSingletonServiceGroupNullCloseEntityTest() throws Exception {
-        singletonServiceGroup = new ClusterSingletonServiceGroupImpl(
-                SERVICE_IDENTIFIER, mainEntity, null, mockEosService, map);
+    public void instantiationClusterSingletonServiceGroupNullMainEntityTest() {
+        new ClusterSingletonServiceGroupImpl<>(SERVICE_IDENTIFIER, null, CLOSE_ENTITY, mockEosService);
     }
 
     /**
-     * Test NULL MainEntity input for new ServiceGroup instance.
-     *
-     * @throws Exception - unexpected exception
+     * Test NULL CloseEntity input for new ServiceGroup instance.
      */
     @Test(expected = NullPointerException.class)
-    public void instantiationClusterSingletonServiceGroupNullEOS_Test() throws Exception {
-        singletonServiceGroup = new ClusterSingletonServiceGroupImpl(
-                SERVICE_IDENTIFIER, mainEntity, closeEntity, null, map);
+    public void instantiationClusterSingletonServiceGroupNullCloseEntityTest() {
+        new ClusterSingletonServiceGroupImpl<>(SERVICE_IDENTIFIER, MAIN_ENTITY, null, mockEosService);
     }
 
     /**
-     * Test NULL MainEntity input for new ServiceGroup instance.
-     *
-     * @throws Exception - unexpected exception
+     * Test NULL EntityOwnershipService input for new ServiceGroup instance.
      */
     @Test(expected = NullPointerException.class)
-    public void instantiationClusterSingletonServiceGroupNullMapRefTest() throws Exception {
-        singletonServiceGroup = new ClusterSingletonServiceGroupImpl(
-                SERVICE_IDENTIFIER, mainEntity, closeEntity, mockEosService, null);
+    public void instantiationClusterSingletonServiceGroupNullEOS_Test() {
+        new ClusterSingletonServiceGroupImpl<>(SERVICE_IDENTIFIER, MAIN_ENTITY, CLOSE_ENTITY, null);
     }
 
     /**
      * Test GoldPath for initialization ServiceGroup.
-     *
-     * @throws Exception - unexpected exception
      */
     @Test
-    public void initializationClusterSingletonServiceGroupTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        verify(mockEosService).registerCandidate(mainEntity);
+    public void initializationClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
     }
 
     /**
      * Test GoldPath for NO-TO-SLAVE entity Candidate role change.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void initializationSlaveTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void initializationSlaveTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToSlave());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService, never()).registerCandidate(closeEntity);
+        verify(mockEosService, never()).registerCandidate(CLOSE_ENTITY);
     }
 
     /**
      * Test GoldPath for NO-TO-SLAVE but without MASTER entity Candidate role change.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void initializationNoMasterTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void initializationNoMasterTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToSlaveNoMaster());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService, never()).registerCandidate(closeEntity);
+        verify(mockEosService, never()).registerCandidate(CLOSE_ENTITY);
     }
 
     /**
      * Test GoldPath for InJeopardy entity Candidate role change.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void initializationInJeopardyTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        map.putIfAbsent(SERVICE_IDENTIFIER, singletonServiceGroup);
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void initializationInJeopardyTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToJeopardy());
-        final ClusterSingletonServiceGroup<?, ?, ?> serviceGroup = map.get(SERVICE_IDENTIFIER);
-        Assert.assertNotNull(serviceGroup);
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService, never()).registerCandidate(closeEntity);
+        verify(mockEosService, never()).registerCandidate(CLOSE_ENTITY);
     }
 
     /**
      * Test GoldPath for registration SingletonService.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void serviceRegistrationClusterSingletonServiceGroupTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void serviceRegistrationClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
     }
 
     /**
      * Test GoldPath for registration SingletonService.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void serviceRegistrationClusterSingletonServiceGroupTwoServiceTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
-        final ClusterSingletonServiceRegistration reg2 = singletonServiceGroup
-                .registerService(mockClusterSingletonServiceSecond);
-        Assert.assertNotNull(reg2);
+    public void serviceRegistrationClusterSingletonServiceGroupTwoServiceTest()
+            throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
+        singletonServiceGroup.registerService(mockClusterSingletonServiceSecond);
     }
 
     /**
      * Test GoldPath for unregistration SingletonService don't call closeServiceInstance
      * without mastership and don't remove ServiceGroup from map.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void serviceUnregistrationClusterSingletonServiceGroupTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        map.putIfAbsent(SERVICE_IDENTIFIER, singletonServiceGroup);
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
-        reg.close();
+    public void serviceUnregistrationClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
+        assertTrue(singletonServiceGroup.unregisterService(mockClusterSingletonService));
         verify(mockClusterSingletonService, never()).closeServiceInstance();
-        final ClusterSingletonServiceGroup<?, ?, ?> serviceGroup = map.get(SERVICE_IDENTIFIER);
-        Assert.assertNull(serviceGroup);
     }
 
     /**
      * Test GoldPath for unregistration SingletonService don't call closeServiceInstance
      *     without mastership and don't remove ServiceGroup from map.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void serviceUnregistrationClusterSingletonServiceGroupTwoServicesTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        map.putIfAbsent(SERVICE_IDENTIFIER, singletonServiceGroup);
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
-        final ClusterSingletonServiceRegistration reg2 = singletonServiceGroup
-                .registerService(mockClusterSingletonServiceSecond);
-        Assert.assertNotNull(reg2);
-        reg.close();
+    public void serviceUnregistrationClusterSingletonServiceGroupTwoServicesTest()
+            throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
+        singletonServiceGroup.registerService(mockClusterSingletonServiceSecond);
+        assertFalse(singletonServiceGroup.unregisterService(mockClusterSingletonService));
         verify(mockClusterSingletonService, never()).closeServiceInstance();
-        final ClusterSingletonServiceGroup<?, ?, ?> serviceGroup = map.get(SERVICE_IDENTIFIER);
-        Assert.assertNotNull(serviceGroup);
     }
 
     /**
      * Test GoldPath get Slave role for registered main entity.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void getSlaveClusterSingletonServiceGroupTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void getSlaveClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToSlave());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
     }
@@ -318,35 +265,31 @@ public class ClusterSingletonServiceGroupImplTest {
     /**
      * Test GoldPath get Master role for registered main entity.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void tryToTakeLeaderClusterSingletonServiceGroupTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void tryToTakeLeaderClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToMaster());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService).registerCandidate(closeEntity);
+        verify(mockEosService).registerCandidate(CLOSE_ENTITY);
     }
 
     /**
      * Test GoldPath get Master role for registered close entity.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void takeMasterClusterSingletonServiceGroupTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void takeMasterClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToMaster());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService).registerCandidate(closeEntity);
+        verify(mockEosService).registerCandidate(CLOSE_ENTITY);
         singletonServiceGroup.ownershipChanged(getDoubleEntityToMaster());
         verify(mockClusterSingletonService).instantiateServiceInstance();
     }
@@ -355,114 +298,91 @@ public class ClusterSingletonServiceGroupImplTest {
      * Test GoldPath get Master role for registered entity but initial Slave
      *     role for closeEntity.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void waitToTakeMasterClusterSingletonServiceGroupTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        map.putIfAbsent(SERVICE_IDENTIFIER, singletonServiceGroup);
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void waitToTakeMasterClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToMaster());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService).registerCandidate(closeEntity);
+        verify(mockEosService).registerCandidate(CLOSE_ENTITY);
         singletonServiceGroup.ownershipChanged(getInitDoubleEntityToSlave());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
         verify(mockClusterSingletonService, never()).closeServiceInstance();
-        final ClusterSingletonServiceGroup<?, ?, ?> serviceGroup = map.get(SERVICE_IDENTIFIER);
-        Assert.assertNotNull(serviceGroup);
     }
 
     /**
      * Test inJeopardy validation during wait phase for Master role for closeEntity.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void inJeopardyInWaitPhaseClusterSingletonServiceGroupTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        map.putIfAbsent(SERVICE_IDENTIFIER, singletonServiceGroup);
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void inJeopardyInWaitPhaseClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToMaster());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService).registerCandidate(closeEntity);
+        verify(mockEosService).registerCandidate(CLOSE_ENTITY);
         singletonServiceGroup.ownershipChanged(getEntityToJeopardy());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
         verify(mockClusterSingletonService, never()).closeServiceInstance();
-        final ClusterSingletonServiceGroup<?, ?, ?> serviceGroup = map.get(SERVICE_IDENTIFIER);
-        Assert.assertNotNull(serviceGroup);
     }
 
     /**
      * Test inJeopardy validation during wait phase for Master role for closeEntity.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void inJeopardyInWaitPhaseClusterSingletonServiceGroupTwoServiceTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        map.putIfAbsent(SERVICE_IDENTIFIER, singletonServiceGroup);
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
-        final ClusterSingletonServiceRegistration reg2 = singletonServiceGroup
-                .registerService(mockClusterSingletonServiceSecond);
-        Assert.assertNotNull(reg2);
+    public void inJeopardyInWaitPhaseClusterSingletonServiceGroupTwoServiceTest()
+            throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
+        singletonServiceGroup.registerService(mockClusterSingletonServiceSecond);
         singletonServiceGroup.ownershipChanged(getEntityToMaster());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService).registerCandidate(closeEntity);
+        verify(mockEosService).registerCandidate(CLOSE_ENTITY);
         singletonServiceGroup.ownershipChanged(getEntityToJeopardy());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
         verify(mockClusterSingletonService, never()).closeServiceInstance();
-        final ClusterSingletonServiceGroup<?, ?, ?> serviceGroup = map.get(SERVICE_IDENTIFIER);
-        Assert.assertNotNull(serviceGroup);
     }
 
     /**
      * Test inJeopardy validation for holding leadership.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void inJeopardyLeaderClusterSingletonServiceGroupTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        map.putIfAbsent(SERVICE_IDENTIFIER, singletonServiceGroup);
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void inJeopardyLeaderClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToMaster());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService).registerCandidate(closeEntity);
+        verify(mockEosService).registerCandidate(CLOSE_ENTITY);
         singletonServiceGroup.ownershipChanged(getDoubleEntityToMaster());
         verify(mockClusterSingletonService).instantiateServiceInstance();
         singletonServiceGroup.ownershipChanged(getEntityToJeopardy());
         verify(mockClusterSingletonService).closeServiceInstance();
-        final ClusterSingletonServiceGroup<?, ?, ?> serviceGroup = map.get(SERVICE_IDENTIFIER);
-        Assert.assertNotNull(serviceGroup);
     }
 
     /**
      * Test GoldPath for SLAVE-TO-MASTER entity Candidate role change.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void lostLeaderClusterSingletonServiceGroupTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void lostLeaderClusterSingletonServiceGroupTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToMaster());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService).registerCandidate(closeEntity);
+        verify(mockEosService).registerCandidate(CLOSE_ENTITY);
         singletonServiceGroup.ownershipChanged(getDoubleEntityToMaster());
         verify(mockClusterSingletonService).instantiateServiceInstance();
         singletonServiceGroup.ownershipChanged(getEntityToSlave());
@@ -473,119 +393,139 @@ public class ClusterSingletonServiceGroupImplTest {
      * Test checks validation Error processing for SLAVE-TO-MASTER entity Candidate role change.
      *     Not initialized provider has to close and remove all singletonServices from Group and
      *     Group itself remove too.
-     *
-     * @throws Exception - unexpected exception
      */
     @Test(expected = RuntimeException.class)
-    public void tryToTakeLeaderForNotInitializedGroupTest() throws Exception {
-        map.putIfAbsent(SERVICE_IDENTIFIER, singletonServiceGroup);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNull(reg);
-        final ClusterSingletonServiceGroup<?, ?, ?> serviceGroup = map.get(SERVICE_IDENTIFIER);
-        Assert.assertNull(serviceGroup);
+    public void tryToTakeLeaderForNotInitializedGroupTest() {
+        singletonServiceGroup.registerService(mockClusterSingletonService);
     }
 
     /**
-     * Test checks closing procesing for close {@link ClusterSingletonServiceRegistration}.
+     * Test checks closing processing for close {@link ClusterSingletonServiceRegistration}.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void checkClosingRegistrationTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        map.putIfAbsent(SERVICE_IDENTIFIER, singletonServiceGroup);
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void checkClosingRegistrationTest() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToMaster());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService).registerCandidate(closeEntity);
+        verify(mockEosService).registerCandidate(CLOSE_ENTITY);
         singletonServiceGroup.ownershipChanged(getDoubleEntityToMaster());
         verify(mockClusterSingletonService).instantiateServiceInstance();
-        reg.close();
+        assertTrue(singletonServiceGroup.unregisterService(mockClusterSingletonService));
         verify(mockClusterSingletonService, never()).closeServiceInstance();
         singletonServiceGroup.ownershipChanged(getEntityToSlaveNoMaster());
-        verify(mockClusterSingletonService, atLeastOnce()).closeServiceInstance();
-        final ClusterSingletonServiceGroup<?, ?, ?> serviceGroup = map.get(SERVICE_IDENTIFIER);
-        Assert.assertNull(serviceGroup);
+        verify(mockClusterSingletonService).closeServiceInstance();
     }
 
     /**
      * Test checks validation Error processing for MASTER-TO-SLAVE closeEntity Candidate role change.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void checkClosingUnexpectedDoubleEntityForMasterOwnershipChangeRegistrationTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        map.putIfAbsent(SERVICE_IDENTIFIER, singletonServiceGroup);
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void checkClosingUnexpectedDoubleEntityForMasterOwnershipChangeRegistrationTest()
+            throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToMaster());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService).registerCandidate(closeEntity);
+        verify(mockEosService).registerCandidate(CLOSE_ENTITY);
         singletonServiceGroup.ownershipChanged(getDoubleEntityToMaster());
         verify(mockClusterSingletonService).instantiateServiceInstance();
         singletonServiceGroup.ownershipChanged(getDoubleEntityToSlave());
         verify(mockClusterSingletonService, never()).closeServiceInstance();
-        final ClusterSingletonServiceGroup<?, ?, ?> serviceGroup = map.get(SERVICE_IDENTIFIER);
-        Assert.assertNotNull(serviceGroup);
     }
 
     /**
      * Test checks validation Error processing for MASTER-TO-SLAVE closeEntity Candidate role change
      *     without closeEntity registration.
      *
-     * @throws Exception - unexpected exception
+     * @throws CandidateAlreadyRegisteredException - unexpected exception
      */
     @Test
-    public void checkClosingUnexpectedDoubleEntityForSlaveOwnershipChangeRegistrationTest() throws Exception {
-        singletonServiceGroup.initializationClusterSingletonGroup();
-        map.putIfAbsent(SERVICE_IDENTIFIER, singletonServiceGroup);
-        verify(mockEosService).registerCandidate(mainEntity);
-        final ClusterSingletonServiceRegistration reg = singletonServiceGroup
-                .registerService(mockClusterSingletonService);
-        Assert.assertNotNull(reg);
+    public void checkClosingUnexpectedDoubleEntityForSlaveOwnershipChangeRegistrationTest()
+            throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+        singletonServiceGroup.registerService(mockClusterSingletonService);
         singletonServiceGroup.ownershipChanged(getEntityToSlave());
         verify(mockClusterSingletonService, never()).instantiateServiceInstance();
-        verify(mockEosService, never()).registerCandidate(closeEntity);
+        verify(mockEosService, never()).registerCandidate(CLOSE_ENTITY);
         singletonServiceGroup.ownershipChanged(getDoubleEntityToSlave());
         verify(mockClusterSingletonService, never()).closeServiceInstance();
-        final ClusterSingletonServiceGroup<?, ?, ?> serviceGroup = map.get(SERVICE_IDENTIFIER);
-        Assert.assertNotNull(serviceGroup);
     }
 
-    private GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getEntityToMaster() {
-        return new GenericEntityOwnershipChange<>(mainEntity, EntityOwnershipChangeState.from(false, true, true));
+    @Test
+    public void testRegisterCloseShutdown() throws CandidateAlreadyRegisteredException, InterruptedException,
+            ExecutionException {
+        initializeGroupAndStartService();
+
+        assertTrue(singletonServiceGroup.unregisterService(mockClusterSingletonService));
+        verify(mockClusterSingletonService, never()).closeServiceInstance();
+        verify(mockEntityCandReg, never()).close();
+
+        final ListenableFuture<?> future = singletonServiceGroup.closeClusterSingletonGroup();
+        assertNotNull(future);
+        assertFalse(future.isDone());
+        verify(mockClusterSingletonService, never()).closeServiceInstance();
+        verify(mockEntityCandReg).close();
+
+        singletonServiceGroup.ownershipChanged(getEntityToSlave());
+        verify(mockClusterSingletonService).closeServiceInstance();
+        verify(mockCloseEntityCandReg).close();
+
+        singletonServiceGroup.ownershipChanged(getDoubleEntityToSlave());
+        assertTrue(future.isDone());
+        assertNull(future.get());
+    }
+
+    private void initialize() throws CandidateAlreadyRegisteredException {
+        singletonServiceGroup.initialize();
+        verify(mockEosService).registerCandidate(MAIN_ENTITY);
+    }
+
+    private void initializeGroupAndStartService() throws CandidateAlreadyRegisteredException {
+        initialize();
+        singletonServiceGroup.registerService(mockClusterSingletonService);
+        singletonServiceGroup.ownershipChanged(getEntityToMaster());
+        verify(mockEosService).registerCandidate(CLOSE_ENTITY);
+        singletonServiceGroup.ownershipChanged(getDoubleEntityToMaster());
+        verify(mockClusterSingletonService).instantiateServiceInstance();
     }
 
-    private GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getEntityToSlave() {
-        return new GenericEntityOwnershipChange<>(mainEntity, EntityOwnershipChangeState.from(true, false, true));
+    private static GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getEntityToMaster() {
+        return new GenericEntityOwnershipChange<>(MAIN_ENTITY, EntityOwnershipChangeState.LOCAL_OWNERSHIP_GRANTED);
     }
 
-    private GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getEntityToSlaveNoMaster() {
-        return new GenericEntityOwnershipChange<>(mainEntity, EntityOwnershipChangeState.from(true, false, false));
+    private static GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getEntityToSlave() {
+        return new GenericEntityOwnershipChange<>(MAIN_ENTITY,
+                EntityOwnershipChangeState.LOCAL_OWNERSHIP_LOST_NEW_OWNER);
     }
 
-    private GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getDoubleEntityToMaster() {
-        return new GenericEntityOwnershipChange<>(closeEntity, EntityOwnershipChangeState.from(false, true, true));
+    private static GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getEntityToSlaveNoMaster() {
+        return new GenericEntityOwnershipChange<>(MAIN_ENTITY,
+                EntityOwnershipChangeState.LOCAL_OWNERSHIP_LOST_NO_OWNER);
     }
 
-    private GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getDoubleEntityToSlave() {
-        return new GenericEntityOwnershipChange<>(closeEntity, EntityOwnershipChangeState.from(true, false, true));
+    private static GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getDoubleEntityToMaster() {
+        return new GenericEntityOwnershipChange<>(CLOSE_ENTITY, EntityOwnershipChangeState.LOCAL_OWNERSHIP_GRANTED);
     }
 
-    private GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getInitDoubleEntityToSlave() {
-        return new GenericEntityOwnershipChange<>(closeEntity, EntityOwnershipChangeState.from(false, false, true));
+    private static GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getDoubleEntityToSlave() {
+        return new GenericEntityOwnershipChange<>(CLOSE_ENTITY,
+                EntityOwnershipChangeState.LOCAL_OWNERSHIP_LOST_NEW_OWNER);
     }
 
-    private GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getEntityToJeopardy() {
-        return new GenericEntityOwnershipChange<>(mainEntity,
-            EntityOwnershipChangeState.from(false, false, false), true);
+    private static GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getInitDoubleEntityToSlave() {
+        return new GenericEntityOwnershipChange<>(CLOSE_ENTITY, EntityOwnershipChangeState.REMOTE_OWNERSHIP_CHANGED);
     }
 
+    private static GenericEntityOwnershipChange<TestInstanceIdentifier, TestEntity> getEntityToJeopardy() {
+        return new GenericEntityOwnershipChange<>(MAIN_ENTITY,
+                EntityOwnershipChangeState.REMOTE_OWNERSHIP_LOST_NO_OWNER, true);
+    }
 }
diff --git a/singleton-service/mdsal-singleton-dom-impl/src/test/java/org/opendaylight/mdsal/singleton/dom/impl/ClusterSingletonServiceRegistrationDelegatorTest.java b/singleton-service/mdsal-singleton-dom-impl/src/test/java/org/opendaylight/mdsal/singleton/dom/impl/ClusterSingletonServiceRegistrationDelegatorTest.java
deleted file mode 100644 (file)
index b16d614..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.verify;
-
-import com.google.common.util.concurrent.Futures;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
-import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
-
-/**
- * Testing {@link ClusterSingletonServiceRegistrationDelegator}.
- */
-public class ClusterSingletonServiceRegistrationDelegatorTest {
-
-    private static final String SERVICE_IDENTIFIER_NAME = "TestServiceIdent";
-    private static final ServiceGroupIdentifier SERVICE_IDENTIFIER = ServiceGroupIdentifier
-            .create(SERVICE_IDENTIFIER_NAME);
-
-    @Mock
-    private ClusterSingletonServiceGroup<?, ?, ?> mockClusterSingletonServiceGroup;
-    @Mock
-    private ClusterSingletonService mockClusterSingletonService;
-
-    private ClusterSingletonServiceRegistrationDelegator delegator;
-
-    /**
-     * Initialization functionality for every Tests in this suite.
-     *
-     * @throws Exception - unexpected setup exception
-     */
-    @Before
-    public void setup() throws Exception {
-        MockitoAnnotations.initMocks(this);
-
-        doNothing().when(mockClusterSingletonServiceGroup)
-                .unregisterService(any(ClusterSingletonServiceRegistrationDelegator.class));
-        doReturn(SERVICE_IDENTIFIER).when(mockClusterSingletonService).getIdentifier();
-        doNothing().when(mockClusterSingletonService).instantiateServiceInstance();
-        doReturn(Futures.immediateFuture(null)).when(mockClusterSingletonService).closeServiceInstance();
-        delegator = new ClusterSingletonServiceRegistrationDelegator(mockClusterSingletonService,
-                mockClusterSingletonServiceGroup);
-    }
-
-    /**
-     * Test create input with {@link ClusterSingletonService} as null.
-     */
-    @Test(expected = NullPointerException.class)
-    public void testSetupNullService() {
-        delegator = new ClusterSingletonServiceRegistrationDelegator(null, mockClusterSingletonServiceGroup);
-    }
-
-    /**
-     * Test create input with {@link ClusterSingletonServiceGroupImpl} as null.
-     */
-    @Test(expected = NullPointerException.class)
-    public void testSetupNullGroup() {
-        delegator = new ClusterSingletonServiceRegistrationDelegator(mockClusterSingletonService, null);
-    }
-
-    /**
-     * Test a method delegation {@link ClusterSingletonService#instantiateServiceInstance()}.
-     */
-    @Test
-    public void testInstatiateServiceDelegMethod() {
-        delegator.instantiateServiceInstance();
-        verify(mockClusterSingletonService).instantiateServiceInstance();
-    }
-
-    /**
-     * Test a method delegation {@link ClusterSingletonService#instantiateServiceInstance()}.
-     */
-    @Test
-    public void testCloseServiceDelegMethod() {
-        delegator.closeServiceInstance();
-        verify(mockClusterSingletonService).closeServiceInstance();
-    }
-
-    /**
-     * Test a method delegation {@link ClusterSingletonService#getIdentifier()}.
-     */
-    @Test
-    public void testGetServiceIdentifierDelegMethod() {
-        final String serviceIdentifier = delegator.getServiceGroupIdentifier();
-        Assert.assertEquals(SERVICE_IDENTIFIER_NAME, serviceIdentifier);
-        verify(mockClusterSingletonService).getIdentifier();
-    }
-
-    /**
-     * Test a close method delegation to
-     *     {@link ClusterSingletonServiceGroupImpl#unregisterService(ClusterSingletonService)}.
-     *
-     * @throws Exception is from AutoclosableInterface
-     */
-    @Test
-    public void testCloseMethod() throws Exception {
-        delegator.close();
-        verify(mockClusterSingletonServiceGroup).unregisterService(delegator);
-    }
-}
index 9636252b9787476066d88468524f0ffb3afbaeda..7e1180fa5b0506556d9b9b2b90921ab0481ba089 100644 (file)
@@ -8,12 +8,9 @@
 
 package org.opendaylight.mdsal.singleton.dom.impl;
 
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.mockito.Mockito.atLeastOnce;
-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;
 
@@ -22,241 +19,50 @@ import com.google.common.util.concurrent.SettableFuture;
 import java.util.Timer;
 import java.util.TimerTask;
 import org.junit.AfterClass;
-import org.junit.Assert;
-import org.junit.Before;
 import org.junit.BeforeClass;
 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 final class DOMClusterSingletonServiceProviderAsyncImplTest {
-
-    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 TestClusterSingletonAsyncServiceInstance clusterSingletonService;
-    private TestClusterSingletonAsyncServiceInstance clusterSingletonService2;
+public final class DOMClusterSingletonServiceProviderAsyncImplTest extends AbstractDOMClusterServiceProviderTest {
+    /*
+     * Test implementation of {@link ClusterSingletonService}
+     */
+    static class TestClusterSingletonAsyncServiceInstance extends TestClusterSingletonService {
+        @Override
+        public ListenableFuture<Void> closeServiceInstance() {
+            super.closeServiceInstance();
 
-    private final DOMEntity entity = new DOMEntity(SERVICE_ENTITY_TYPE, SERVICE_NAME);
-    private final DOMEntity doubleEntity = new DOMEntity(CLOSE_SERVICE_ENTITY_TYPE, SERVICE_NAME);
+            final SettableFuture<Void> future = SettableFuture.create();
+            TIMER.schedule(new TimerTask() {
+                @Override
+                public void run() {
+                    future.set(null);
+                }
+            }, ASYNC_TIME_DELAY_MILLIS);
+            return future;
+        }
+    }
 
-    protected static Timer timer;
-    protected static long ASYNC_TIME_DELAY_SEC = 100L;
+    protected static final long ASYNC_TIME_DELAY_MILLIS = 100L;
+    protected static Timer TIMER;
 
     @BeforeClass
     public static void asyncInitTest() {
-        timer = new Timer();
+        TIMER = new Timer();
     }
 
     @AfterClass
     public static void cleanTest() {
-        timer.cancel();
-    }
-
-    /**
-     * Initialization functionality for every Tests in this suite.
-     *
-     * @throws Exception if the condition does not meet
-     */
-    @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 TestClusterSingletonAsyncServiceInstance();
-        clusterSingletonService2 = new TestClusterSingletonAsyncServiceInstance();
-
-        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
-        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
+        TIMER.cancel();
     }
 
-    /**
-     * Test checks NullPointer for null {@link DOMEntityOwnershipService} input value.
-     *
-     * @throws Exception if the condition does not meet
-     */
-    @Test(expected = NullPointerException.class)
-    public void initializationClusterSingletonServiceProviderNullInputTest() throws Exception {
-        clusterSingletonServiceProvider = new DOMClusterSingletonServiceProviderImpl(null);
-    }
-
-    /**
-     * Test GoldPath for close {@link DOMClusterSingletonServiceProviderImpl}.
-     *
-     * @throws Exception if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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());
+    @Override
+    TestClusterSingletonService instantiateService() {
+        return new TestClusterSingletonAsyncServiceInstance();
     }
 
     /**
@@ -268,145 +74,25 @@ public final class DOMClusterSingletonServiceProviderAsyncImplTest {
     public void takeDoubleLeadershipClusterSingletonServiceTest() throws Exception {
         final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
                 .registerClusterSingletonService(clusterSingletonService);
-        Assert.assertNotNull(reg);
-        verify(mockEos).registerCandidate(entity);
+        assertNotNull(reg);
+        verify(mockEos).registerCandidate(ENTITY);
         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
-        verify(mockEos).registerCandidate(doubleEntity);
-        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
-        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
-        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+        Thread.sleep(ASYNC_TIME_DELAY_MILLIS * 2);
+        verify(mockDoubleEntityCandReg).close();
         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
-        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
-        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
         verify(mockEosDoubleEntityListReg, never()).close();
         verify(mockEosEntityListReg, never()).close();
         verify(mockEntityCandReg, never()).close();
-        verify(mockDoubleEntityCandReg).close();
-    }
-
-    /**
-     * Test GoldPath for initialization with init ownership result MASTER {@link ClusterSingletonService}.
-     *
-     * @throws Exception if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @Test(expected = RuntimeException.class)
-    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 if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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());
     }
 
     /**
@@ -418,18 +104,18 @@ public final class DOMClusterSingletonServiceProviderAsyncImplTest {
     public void unexpectedLostLeadershipDoubleCandidateTest() throws Exception {
         final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
                 .registerClusterSingletonService(clusterSingletonService);
-        Assert.assertNotNull(reg);
-        verify(mockEos).registerCandidate(entity);
+        assertNotNull(reg);
+        verify(mockEos).registerCandidate(ENTITY);
         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
-        verify(mockEos).registerCandidate(doubleEntity);
-        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
-        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
-        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToSlave());
-        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
-        Thread.sleep(ASYNC_TIME_DELAY_SEC * 2);
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        Thread.sleep(ASYNC_TIME_DELAY_MILLIS * 2);
         verify(mockEosDoubleEntityListReg, never()).close();
         verify(mockEntityCandReg, never()).close();
         verify(mockDoubleEntityCandReg, never()).close();
@@ -438,11 +124,11 @@ public final class DOMClusterSingletonServiceProviderAsyncImplTest {
         verify(mockEntityCandReg, atLeastOnce()).close();
         verify(mockDoubleEntityCandReg, never()).close();
         clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
-        Thread.sleep(ASYNC_TIME_DELAY_SEC * 2);
+        Thread.sleep(ASYNC_TIME_DELAY_MILLIS * 2);
         verify(mockEntityCandReg, atLeastOnce()).close();
         verify(mockDoubleEntityCandReg, atLeastOnce()).close();
         verify(mockEosDoubleEntityListReg, never()).close();
-        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
     }
 
     /**
@@ -454,138 +140,24 @@ public final class DOMClusterSingletonServiceProviderAsyncImplTest {
     public void inJeopardyMasterTest() throws Exception {
         final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
                 .registerClusterSingletonService(clusterSingletonService);
-        Assert.assertNotNull(reg);
-        verify(mockEos).registerCandidate(entity);
+        assertNotNull(reg);
+        verify(mockEos).registerCandidate(ENTITY);
         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
-        verify(mockEos).registerCandidate(doubleEntity);
-        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
-        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
-        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getEntityToJeopardy());
-        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
-        Thread.sleep(ASYNC_TIME_DELAY_SEC * 2);
+        assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+        Thread.sleep(ASYNC_TIME_DELAY_MILLIS * 2);
         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 if the condition does not meet
-     */
-    @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 processing for {@link ClusterSingletonServiceRegistration}.
-     *
-     * @throws Exception if the condition does not meet
-     */
-    @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 processing for {@link ClusterSingletonServiceRegistration}.
-     *
-     * @throws Exception if the condition does not meet
-     */
-    @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 processing for {@link ClusterSingletonServiceRegistration}.
-     *
-     * @throws Exception if the condition does not meet
-     */
-    @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 processing for {@link ClusterSingletonServiceRegistration}.
-     *
-     * @throws Exception if the condition does not meet
-     */
-    @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 processing for {@link ClusterSingletonServiceRegistration}.
      *
@@ -595,26 +167,26 @@ public final class DOMClusterSingletonServiceProviderAsyncImplTest {
     public void closeClusterSingletonServiceRegistrationMasterTest() throws Exception {
         final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
                 .registerClusterSingletonService(clusterSingletonService);
-        Assert.assertNotNull(reg);
-        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
-        verify(mockEos).registerCandidate(entity);
+        assertNotNull(reg);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        verify(mockEos).registerCandidate(ENTITY);
         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
-        verify(mockEos).registerCandidate(doubleEntity);
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
-        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
         reg.close();
-        Thread.sleep(ASYNC_TIME_DELAY_SEC * 2);
+        Thread.sleep(ASYNC_TIME_DELAY_MILLIS * 2);
         verify(mockEosEntityListReg, never()).close();
         verify(mockEosDoubleEntityListReg, never()).close();
         verify(mockEntityCandReg, atLeastOnce()).close();
         verify(mockDoubleEntityCandReg, never()).close();
-        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
-        Thread.sleep(ASYNC_TIME_DELAY_SEC * 2);
+        Thread.sleep(ASYNC_TIME_DELAY_MILLIS * 2);
         verify(mockEntityCandReg, atLeastOnce()).close();
         verify(mockDoubleEntityCandReg, atLeastOnce()).close();
         verify(mockEosDoubleEntityListReg, never()).close();
-        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
     }
 
     /**
@@ -626,26 +198,26 @@ public final class DOMClusterSingletonServiceProviderAsyncImplTest {
     public void closeClusterSingletonServiceRegistrationMasterCloseWithNotificationTimesTest() throws Exception {
         final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
                 .registerClusterSingletonService(clusterSingletonService);
-        Assert.assertNotNull(reg);
-        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
-        verify(mockEos).registerCandidate(entity);
+        assertNotNull(reg);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        verify(mockEos).registerCandidate(ENTITY);
         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
-        verify(mockEos).registerCandidate(doubleEntity);
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
-        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
         reg.close();
-        Thread.sleep(ASYNC_TIME_DELAY_SEC * 2);
+        Thread.sleep(ASYNC_TIME_DELAY_MILLIS * 2);
         verify(mockEosEntityListReg, never()).close();
         verify(mockEosDoubleEntityListReg, never()).close();
         verify(mockEntityCandReg, atLeastOnce()).close();
         verify(mockDoubleEntityCandReg, never()).close();
-        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
-        Thread.sleep(ASYNC_TIME_DELAY_SEC * 2);
+        Thread.sleep(ASYNC_TIME_DELAY_MILLIS * 2);
         verify(mockEntityCandReg, atLeastOnce()).close();
         verify(mockDoubleEntityCandReg, atLeastOnce()).close();
         verify(mockEosDoubleEntityListReg, never()).close();
-        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
     }
 
     /**
@@ -657,178 +229,26 @@ public final class DOMClusterSingletonServiceProviderAsyncImplTest {
     public void closeClusterSingletonServiceRegistrationMasterCloseCoupleTimesTest() throws Exception {
         final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
                 .registerClusterSingletonService(clusterSingletonService);
-        Assert.assertNotNull(reg);
-        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
-        verify(mockEos).registerCandidate(entity);
+        assertNotNull(reg);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        verify(mockEos).registerCandidate(ENTITY);
         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
-        verify(mockEos).registerCandidate(doubleEntity);
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
-        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
         reg.close();
         reg.close();
-        Thread.sleep(ASYNC_TIME_DELAY_SEC * 2);
+        Thread.sleep(ASYNC_TIME_DELAY_MILLIS * 2);
         verify(mockEosEntityListReg, never()).close();
         verify(mockEosDoubleEntityListReg, never()).close();
         verify(mockEntityCandReg, atLeastOnce()).close();
         verify(mockDoubleEntityCandReg, never()).close();
-        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
-        Thread.sleep(ASYNC_TIME_DELAY_SEC * 2);
+        Thread.sleep(ASYNC_TIME_DELAY_MILLIS * 2);
         verify(mockEntityCandReg, atLeastOnce()).close();
         verify(mockDoubleEntityCandReg, atLeastOnce()).close();
         verify(mockEosDoubleEntityListReg, never()).close();
-        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
-    }
-
-    /**
-     * Test checks close processing for {@link ClusterSingletonServiceRegistration}.
-     *
-     * @throws Exception if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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
-     */
-    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 TestClusterSingletonAsyncServiceInstance implements ClusterSingletonService {
-
-        private final ServiceGroupIdentifier serviceId = ServiceGroupIdentifier.create(SERVICE_NAME);
-        private TestClusterSingletonServiceState serviceState;
-        protected SettableFuture<Void> future;
-
-        TestClusterSingletonAsyncServiceInstance() {
-            this.serviceState = TestClusterSingletonServiceState.INITIALIZED;
-        }
-
-        @Override
-        public void instantiateServiceInstance() {
-            this.serviceState = TestClusterSingletonServiceState.STARTED;
-        }
-
-        @Override
-        public ListenableFuture<Void> closeServiceInstance() {
-            this.serviceState = TestClusterSingletonServiceState.DESTROYED;
-            future = SettableFuture.create();
-            timer.schedule(new TimerTask() {
-
-                @Override
-                public void run() {
-                    future.set(null);
-                }
-            }, ASYNC_TIME_DELAY_SEC);
-            return future;
-        }
-
-        public TestClusterSingletonServiceState getServiceState() {
-            return serviceState;
-        }
-
-        @Override
-        public ServiceGroupIdentifier getIdentifier() {
-            return serviceId;
-        }
+        assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
     }
 }
index 628395f2841bf9d15e47bb136a9657688eebdca6..67236c8047fb7d57d2683f1daa765e5132ef9a65 100644 (file)
 
 package org.opendaylight.mdsal.singleton.dom.impl;
 
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.mockito.Mockito.atLeastOnce;
-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.reset;
 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.
+ * Synchronous test suite.
  */
-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);
-
+public class DOMClusterSingletonServiceProviderImplTest extends AbstractDOMClusterServiceProviderTest {
     /**
      * Initialization functionality for every Tests in this suite.
      *
-     * @throws Exception if the condition does not meet
+     * @throws CandidateAlreadyRegisteredException if the condition does not meet
      */
+    @Override
     @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 if the condition does not meet
-     */
-    @Test(expected = NullPointerException.class)
-    public void initializationClusterSingletonServiceProviderNullInputTest() throws Exception {
-        clusterSingletonServiceProvider = new DOMClusterSingletonServiceProviderImpl(null);
-    }
-
-    /**
-     * Test GoldPath for close {@link DOMClusterSingletonServiceProviderImpl}.
-     *
-     * @throws Exception if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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());
+    public void setup() throws CandidateAlreadyRegisteredException {
+        super.setup();
     }
 
     /**
@@ -271,127 +45,26 @@ public class DOMClusterSingletonServiceProviderImplTest {
     public void takeDoubleLeadershipClusterSingletonServiceTest() throws Exception {
         final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
                 .registerClusterSingletonService(clusterSingletonService);
-        Assert.assertNotNull(reg);
-        verify(mockEos).registerCandidate(entity);
+        assertNotNull(reg);
+        verify(mockEos).registerCandidate(ENTITY);
         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
-        verify(mockEos).registerCandidate(doubleEntity);
-        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
-        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
-        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
-        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
-        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
         verify(mockEosDoubleEntityListReg, never()).close();
         verify(mockEosEntityListReg, never()).close();
         verify(mockEntityCandReg, never()).close();
         verify(mockDoubleEntityCandReg).close();
     }
 
-    /**
-     * Test GoldPath for takeLeadership with ownership result MASTER {@link ClusterSingletonService}.
-     *
-     * @throws Exception if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @Test(expected = RuntimeException.class)
-    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 if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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 unexpected change for MASTER-TO-SLAVE double Candidate role change.
      *
@@ -401,17 +74,17 @@ public class DOMClusterSingletonServiceProviderImplTest {
     public void unexpectedLostLeadershipDoubleCandidateTest() throws Exception {
         final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
                 .registerClusterSingletonService(clusterSingletonService);
-        Assert.assertNotNull(reg);
-        verify(mockEos).registerCandidate(entity);
+        assertNotNull(reg);
+        verify(mockEos).registerCandidate(ENTITY);
         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
-        verify(mockEos).registerCandidate(doubleEntity);
-        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
-        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
-        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToSlave());
-        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
         verify(mockEosDoubleEntityListReg, never()).close();
         verify(mockEntityCandReg, never()).close();
         verify(mockDoubleEntityCandReg, never()).close();
@@ -420,12 +93,12 @@ public class DOMClusterSingletonServiceProviderImplTest {
         verify(mockEosDoubleEntityListReg, never()).close();
         verify(mockEntityCandReg, atLeastOnce()).close();
         verify(mockDoubleEntityCandReg, never()).close();
-        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
         verify(mockEntityCandReg, atLeastOnce()).close();
         verify(mockDoubleEntityCandReg, atLeastOnce()).close();
         verify(mockEosDoubleEntityListReg, never()).close();
-        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
     }
 
     /**
@@ -437,160 +110,46 @@ public class DOMClusterSingletonServiceProviderImplTest {
     public void inJeopardyMasterTest() throws Exception {
         final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
                 .registerClusterSingletonService(clusterSingletonService);
-        Assert.assertNotNull(reg);
-        verify(mockEos).registerCandidate(entity);
+        assertNotNull(reg);
+        verify(mockEos).registerCandidate(ENTITY);
         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
-        verify(mockEos).registerCandidate(doubleEntity);
-        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
-        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
-        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getEntityToJeopardy());
-        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+        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 if the condition does not meet
-     */
-    @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 processing for {@link ClusterSingletonServiceRegistration}.
      *
      * @throws Exception if the condition does not meet
      */
     @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 if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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 if the condition does not meet
-     */
-    @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);
+        assertNotNull(reg);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        verify(mockEos).registerCandidate(ENTITY);
         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
-        verify(mockEos).registerCandidate(doubleEntity);
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
-        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
         reg.close();
         clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
         verify(mockEosEntityListReg, never()).close();
         verify(mockEosDoubleEntityListReg, never()).close();
         verify(mockEntityCandReg).close();
         verify(mockDoubleEntityCandReg).close();
-        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
     }
 
     /**
@@ -602,24 +161,24 @@ public class DOMClusterSingletonServiceProviderImplTest {
     public void closeClusterSingletonServiceRegistrationMasterCloseWithNotificationTimesTest() throws Exception {
         final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
                 .registerClusterSingletonService(clusterSingletonService);
-        Assert.assertNotNull(reg);
-        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
-        verify(mockEos).registerCandidate(entity);
+        assertNotNull(reg);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        verify(mockEos).registerCandidate(ENTITY);
         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
-        verify(mockEos).registerCandidate(doubleEntity);
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
-        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
         reg.close();
         verify(mockEosEntityListReg, never()).close();
         verify(mockEosDoubleEntityListReg, never()).close();
         verify(mockEntityCandReg, atLeastOnce()).close();
         verify(mockDoubleEntityCandReg, never()).close();
-        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
         verify(mockEntityCandReg, atLeastOnce()).close();
         verify(mockDoubleEntityCandReg, atLeastOnce()).close();
         verify(mockEosDoubleEntityListReg, never()).close();
-        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
     }
 
     /**
@@ -631,170 +190,79 @@ public class DOMClusterSingletonServiceProviderImplTest {
     public void closeClusterSingletonServiceRegistrationMasterCloseCoupleTimesTest() throws Exception {
         final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
                 .registerClusterSingletonService(clusterSingletonService);
-        Assert.assertNotNull(reg);
-        Assert.assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
-        verify(mockEos).registerCandidate(entity);
+        assertNotNull(reg);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        verify(mockEos).registerCandidate(ENTITY);
         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
-        verify(mockEos).registerCandidate(doubleEntity);
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
-        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
         reg.close();
         reg.close();
         verify(mockEosEntityListReg, never()).close();
         verify(mockEosDoubleEntityListReg, never()).close();
         verify(mockEntityCandReg, atLeastOnce()).close();
         verify(mockDoubleEntityCandReg, never()).close();
-        Assert.assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
         clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
         verify(mockEntityCandReg, atLeastOnce()).close();
         verify(mockDoubleEntityCandReg, atLeastOnce()).close();
         verify(mockEosDoubleEntityListReg, never()).close();
-        Assert.assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
+        assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
     }
 
+
     /**
-     * Test checks close processing for {@link ClusterSingletonServiceRegistration}.
-     *
-     * @throws Exception if the condition does not meet
+     * Verify that closing a group does not prevent next incarnation of it to be registered and the next incarnation
+     * will become active once the old incarnation finishes cleaning up.
      */
     @Test
-    public void closeClusterSingletonServiceRegistrationMasterTwoServicesTest() throws Exception {
-        final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
+    public void testTwoIncarnations() throws Exception {
+        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);
+        assertNotNull(reg);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
+        verify(mockEos).registerCandidate(ENTITY);
         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
-        verify(mockEos).registerCandidate(doubleEntity);
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
         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());
-    }
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
 
-    /**
-     * Test checks validation Error processing for SLAVE-TO-MASTER entity Candidate role change.
-     *
-     * @throws Exception if the condition does not meet
-     */
-    @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);
+        // Close, triggers unregistration, but we will not continue with it.
         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(mockEntityCandReg).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.
-     */
-    enum TestClusterSingletonServiceState {
+        // Instantiate the next incarnation
+        reset(mockEos);
+        reg = clusterSingletonServiceProvider.registerClusterSingletonService(clusterSingletonService2);
+        verify(mockEos, never()).registerCandidate(ENTITY);
+        assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
 
-        /**
-         * 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 serviceIndent = ServiceGroupIdentifier.create(SERVICE_NAME);
-        private TestClusterSingletonServiceState serviceState;
-
-        TestClusterSingletonServiceInstance() {
-            this.serviceState = TestClusterSingletonServiceState.INITIALIZED;
-        }
-
-        @Override
-        public void instantiateServiceInstance() {
-            this.serviceState = TestClusterSingletonServiceState.STARTED;
-        }
+        // Drive the old incarnation to closure, resetting mocks as needed
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
+        verify(mockEntityCandReg).close();
+        verify(mockDoubleEntityCandReg).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
+        assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
 
-        @Override
-        public ListenableFuture<Void> closeServiceInstance() {
-            this.serviceState = TestClusterSingletonServiceState.DESTROYED;
-            return Futures.immediateFuture(null);
-        }
+        // Reset mocks for reuse. The next change should see the previous group terminate and the next incarnation
+        // to start coming up
+        reset(mockEntityCandReg);
+        reset(mockDoubleEntityCandReg);
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToSlave());
+        verify(mockEos).registerCandidate(ENTITY);
+        clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
+        verify(mockEos).registerCandidate(DOUBLE_ENTITY);
+        clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
+        assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
 
-        public TestClusterSingletonServiceState getServiceState() {
-            return serviceState;
-        }
+        // Check for potential service mixup
+        assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
 
-        @Override
-        public ServiceGroupIdentifier getIdentifier() {
-            return serviceIndent;
-        }
+        verify(mockEosEntityListReg, never()).close();
+        verify(mockEosDoubleEntityListReg, never()).close();
     }
 }
diff --git a/singleton-service/mdsal-singleton-dom-impl/src/test/resources/simplelogger.properties b/singleton-service/mdsal-singleton-dom-impl/src/test/resources/simplelogger.properties
new file mode 100644 (file)
index 0000000..de99e5f
--- /dev/null
@@ -0,0 +1,6 @@
+org.slf4j.simpleLogger.showDateTime=true
+org.slf4j.simpleLogger.dateTimeFormat=hh:mm:ss,S a
+org.slf4j.simpleLogger.logFile=System.out
+org.slf4j.simpleLogger.showShortLogName=true
+org.slf4j.simpleLogger.levelInBrackets=true
+org.slf4j.simpleLogger.log.org.opendaylight.mdsal=debug