[SDFAB-933] Integrate atomix-3.1.12 and expose demote API

Additionally, this patch adds unit tests for demote and
updates a bunch of testing tools

Change-Id: I9636078b08486c9167ae253f0251f72239ad2802
diff --git a/core/api/src/main/java/org/onosproject/cluster/LeadershipAdminService.java b/core/api/src/main/java/org/onosproject/cluster/LeadershipAdminService.java
index fe9868a..bac18ad 100644
--- a/core/api/src/main/java/org/onosproject/cluster/LeadershipAdminService.java
+++ b/core/api/src/main/java/org/onosproject/cluster/LeadershipAdminService.java
@@ -54,4 +54,15 @@
      * @return mapping from topic to leadership info.
      */
     Map<String, Leadership> getLeaderBoard();
+
+    /**
+     * Attempts to demote a node to the bottom of the candidate list. It is not allowed
+     * to demote the current leader
+     *
+     * @param topic leadership topic
+     * @param nodeId identifier of node to be demoted
+     * @return {@code true} if nodeId is now the bottom candidate. This method returns {@code false}
+     * if {@code nodeId} is not one of the candidates for the topic or if it is the leader.
+     */
+    boolean demote(String topic, NodeId nodeId);
 }
diff --git a/core/api/src/main/java/org/onosproject/cluster/LeadershipStore.java b/core/api/src/main/java/org/onosproject/cluster/LeadershipStore.java
index 0953e38..ebc6b4c 100644
--- a/core/api/src/main/java/org/onosproject/cluster/LeadershipStore.java
+++ b/core/api/src/main/java/org/onosproject/cluster/LeadershipStore.java
@@ -16,6 +16,7 @@
 package org.onosproject.cluster;
 
 import java.util.Map;
+
 import org.onosproject.store.Store;
 
 /**
@@ -79,4 +80,15 @@
      * @return topic to leadership mapping
      */
     Map<String, Leadership> getLeaderships();
+
+    /**
+     * Attempts to demote a node to the bottom of the candidate list. It is not allowed
+     * to demote the current leader
+     *
+     * @param topic leadership topic
+     * @param nodeId identifier of node to be demoted
+     * @return {@code true} if nodeId is now the bottom candidate. This method returns {@code false}
+     * if {@code nodeId} is not one of the candidates for the topic or if it is the leader.
+     */
+    boolean demote(String topic, NodeId nodeId);
 }
\ No newline at end of file
diff --git a/core/api/src/main/java/org/onosproject/mastership/MastershipAdminService.java b/core/api/src/main/java/org/onosproject/mastership/MastershipAdminService.java
index 8e0679b..9af5e2f 100644
--- a/core/api/src/main/java/org/onosproject/mastership/MastershipAdminService.java
+++ b/core/api/src/main/java/org/onosproject/mastership/MastershipAdminService.java
@@ -58,4 +58,13 @@
      */
     void balanceRoles();
 
+    /**
+     * Attempts to demote a node to the bottom of the backup list. It is not allowed
+     * to demote the current master
+     *
+     * @param instance controller instance identifier
+     * @param deviceId device identifier
+     */
+    void demote(NodeId instance, DeviceId deviceId);
+
 }
diff --git a/core/api/src/main/java/org/onosproject/mastership/MastershipStore.java b/core/api/src/main/java/org/onosproject/mastership/MastershipStore.java
index 7f43a15..6a9fbf8 100644
--- a/core/api/src/main/java/org/onosproject/mastership/MastershipStore.java
+++ b/core/api/src/main/java/org/onosproject/mastership/MastershipStore.java
@@ -129,4 +129,13 @@
      * @param nodeId the controller instance identifier
      */
     void relinquishAllRole(NodeId nodeId);
+
+    /**
+     * Attempts to demote a node to the bottom of the backup list. It is not allowed
+     * to demote the current master
+     *
+     * @param instance controller instance identifier
+     * @param deviceId device identifier
+     */
+    void demote(NodeId instance, DeviceId deviceId);
 }
diff --git a/core/api/src/main/java/org/onosproject/store/primitives/DefaultLeaderElector.java b/core/api/src/main/java/org/onosproject/store/primitives/DefaultLeaderElector.java
index 6275a4f..be67325 100644
--- a/core/api/src/main/java/org/onosproject/store/primitives/DefaultLeaderElector.java
+++ b/core/api/src/main/java/org/onosproject/store/primitives/DefaultLeaderElector.java
@@ -91,6 +91,11 @@
     }
 
     @Override
+    public boolean demote(String topic, NodeId nodeId) {
+        return complete(asyncElector.demote(topic, nodeId));
+    }
+
+    @Override
     public void addStatusChangeListener(Consumer<Status> listener) {
         asyncElector.addStatusChangeListener(listener);
     }
diff --git a/core/api/src/main/java/org/onosproject/store/service/AsyncLeaderElector.java b/core/api/src/main/java/org/onosproject/store/service/AsyncLeaderElector.java
index b253e2a..7aee61f 100644
--- a/core/api/src/main/java/org/onosproject/store/service/AsyncLeaderElector.java
+++ b/core/api/src/main/java/org/onosproject/store/service/AsyncLeaderElector.java
@@ -144,4 +144,16 @@
     default LeaderElector asLeaderElector() {
         return asLeaderElector(DistributedPrimitive.DEFAULT_OPERATION_TIMEOUT_MILLIS);
     }
+
+    /**
+     * Attempts to demote a node to the bottom of the candidate list. It is not allowed
+     * to demote the current leader
+     *
+     * @param topic leadership topic
+     * @param nodeId identifier of node to be demoted
+     * @return CompletableFuture that is completed with a boolean when the operation is done. Boolean is true if
+     * node is now the bottom candidate. This operation can fail (i.e. return false) if the node
+     * is not registered to run for election for the topic or it is leader
+     */
+    CompletableFuture<Boolean> demote(String topic, NodeId nodeId);
 }
diff --git a/core/api/src/main/java/org/onosproject/store/service/LeaderElector.java b/core/api/src/main/java/org/onosproject/store/service/LeaderElector.java
index 9ac1a6e..e7604eb 100644
--- a/core/api/src/main/java/org/onosproject/store/service/LeaderElector.java
+++ b/core/api/src/main/java/org/onosproject/store/service/LeaderElector.java
@@ -102,4 +102,15 @@
      * @param consumer listener to remove
      */
     void removeChangeListener(Consumer<Change<Leadership>> consumer);
+
+    /**
+     * Attempts to demote a node to the bottom of the candidate list. It is not allowed
+     * to demote the current leader
+     *
+     * @param topic leadership topic
+     * @param nodeId identifier of node to be demoted
+     * @return {@code true} if nodeId is now the bottom candidate. This method returns {@code false}
+     * if {@code nodeId} is not one of the candidates for the topic or if it is the leader.
+     */
+    boolean demote(String topic, NodeId nodeId);
 }