You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@helix.apache.org by hu...@apache.org on 2019/05/22 23:41:25 UTC

[helix] branch master updated (efef0db -> aebb0cf)

This is an automated email from the ASF dual-hosted git repository.

hulee pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/helix.git.


    from efef0db  HELIX-816 use System.currentTimeMillis()
     new ca36fbf  Migrate Helix to Java 8
     new 870cf7c  TASK: Fix cleanupQueue() API
     new f61cbad  TASK: Fix possible NPE in getWorkflowId()
     new 5e6a9ff  TASK: Make isJobQueue backward compatible
     new b436816  Util methods for checking if instance healthy
     new babc471  get instance's pending messages with state model def parameter
     new 0bee2b1  Create util class to make it easier to make rest request
     new 271eb07  Apply the JerseyTestUriRequestBuilder to the TestInstanceAccessor
     new 241baae  Add adminGroup check for write operations
     new efd74f2  Fix helix-ui build failure due to wrong config reference
     new 2d712e1  Dummy check for customized API
     new ae2e3cb  Add Util check instance is already in stable state
     new 7f4044f  Fix node swap test.
     new aebb0cf  Interface design for zone mapping information

The 14 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .gitignore                                         |   3 +-
 .../main/java/org/apache/helix/ConfigAccessor.java |  21 +++
 .../main/java/org/apache/helix/PropertyKey.java    |  11 +-
 .../main/java/org/apache/helix/PropertyType.java   |   9 +-
 .../controller/rebalancer/topology/Topology.java   |   2 +-
 .../org/apache/helix/model/HelixConfigScope.java   |   4 +-
 .../org/apache/helix/model/InstanceConfig.java     |  19 +-
 .../java/org/apache/helix/model/RESTConfig.java    |  51 +++++
 .../java/org/apache/helix/task/TaskDriver.java     |   4 +-
 .../java/org/apache/helix/task/WorkflowConfig.java |   6 +-
 .../apache/helix/util/InstanceValidationUtil.java  | 186 ++++++++++++++++++-
 .../TestConstraintRebalanceStrategy.java           |   2 +-
 .../stages/TestClusterEventBlockingQueue.java      |   4 +-
 .../rebalancer/CrushRebalancers/TestNodeSwap.java  |  22 ++-
 .../helix/integration/task/TestTaskRebalancer.java |   2 +-
 .../org/apache/helix/model/TestInstanceConfig.java |  22 +++
 helix-front/client/app/app.component.ts            |   7 +-
 helix-front/server/config.ts                       |   7 +-
 helix-front/server/controllers/user.ts             |  44 +++--
 helix-rest/pom.xml                                 |  15 ++
 .../helix/rest/common/ZKReadAccessorWrapper.java   |  50 +++++
 .../rest/server/json/cluster/ClusterInfo.java      |  80 ++++++++
 .../rest/server/json/cluster/ClusterTopology.java  |  76 ++++++++
 .../server/resources/helix/InstanceAccessor.java   |  29 ++-
 .../helix/rest/server/service/ClusterService.java  |  25 +++
 .../helix/rest/server/AbstractTestClass.java       |  12 +-
 .../helix/rest/server/TestClusterAccessor.java     |  18 +-
 .../helix/rest/server/TestInstanceAccessor.java    | 205 +++++++++++++++------
 .../apache/helix/rest/server/TestJobAccessor.java  |  22 ++-
 .../helix/rest/server/TestNamespacedAPIAccess.java |  27 +--
 .../helix/rest/server/TestResourceAccessor.java    |  19 +-
 .../apache/helix/rest/server/TestTaskAccessor.java |  14 +-
 .../helix/rest/server/TestWorkflowAccessor.java    |  19 +-
 .../rest/server/json/cluster/TestClusterInfo.java  |  27 +++
 .../server/json/cluster/TestClusterTopology.java   |  29 +++
 .../rest/server/util/JerseyUriRequestBuilder.java  | 150 +++++++++++++++
 pom.xml                                            | 161 ++++++++--------
 37 files changed, 1147 insertions(+), 257 deletions(-)
 create mode 100644 helix-core/src/main/java/org/apache/helix/model/RESTConfig.java
 create mode 100644 helix-rest/src/main/java/org/apache/helix/rest/common/ZKReadAccessorWrapper.java
 create mode 100644 helix-rest/src/main/java/org/apache/helix/rest/server/json/cluster/ClusterInfo.java
 create mode 100644 helix-rest/src/main/java/org/apache/helix/rest/server/json/cluster/ClusterTopology.java
 create mode 100644 helix-rest/src/main/java/org/apache/helix/rest/server/service/ClusterService.java
 create mode 100644 helix-rest/src/test/java/org/apache/helix/rest/server/json/cluster/TestClusterInfo.java
 create mode 100644 helix-rest/src/test/java/org/apache/helix/rest/server/json/cluster/TestClusterTopology.java
 create mode 100644 helix-rest/src/test/java/org/apache/helix/rest/server/util/JerseyUriRequestBuilder.java


[helix] 07/14: Create util class to make it easier to make rest request

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

hulee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/helix.git

commit 0bee2b1e07853cbb206634d4cd65d00c3191fc23
Author: ywang4 <yw...@linkedin.com>
AuthorDate: Fri Feb 22 10:12:20 2019 -0800

    Create util class to make it easier to make rest request
    
    RB=1573157
    G=helix-reviewers
    A=jxue,hulee
    
    Signed-off-by: Hunter Lee <hu...@linkedin.com>
---
 helix-rest/pom.xml                                 |   5 ++
 .../helix/rest/server/TestInstanceAccessor.java    |   5 +-
 .../rest/server/util/JerseyUriRequestBuilder.java  | 100 +++++++++++++++++++++
 3 files changed, 108 insertions(+), 2 deletions(-)

diff --git a/helix-rest/pom.xml b/helix-rest/pom.xml
index ee5bcfd..c3e9403 100644
--- a/helix-rest/pom.xml
+++ b/helix-rest/pom.xml
@@ -62,6 +62,11 @@ under the License.
       <artifactId>helix-core</artifactId>
     </dependency>
     <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+      <version>3.8.1</version>
+    </dependency>
+    <dependency>
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-server</artifactId>
       <version>9.1.0.RC0</version>
diff --git a/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstanceAccessor.java b/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstanceAccessor.java
index 86c52e1..172c848 100644
--- a/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstanceAccessor.java
+++ b/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstanceAccessor.java
@@ -40,6 +40,7 @@ import org.apache.helix.model.InstanceConfig;
 import org.apache.helix.model.Message;
 import org.apache.helix.rest.server.resources.AbstractResource;
 import org.apache.helix.rest.server.resources.helix.InstanceAccessor;
+import org.apache.helix.rest.server.util.JerseyUriRequestBuilder;
 import org.codehaus.jackson.JsonNode;
 import org.testng.Assert;
 import org.testng.annotations.Test;
@@ -67,8 +68,8 @@ public class TestInstanceAccessor extends AbstractTestClass {
     HelixDataAccessor helixDataAccessor = new ZKHelixDataAccessor(CLUSTER_NAME, _baseAccessor);
     helixDataAccessor.setProperty(helixDataAccessor.keyBuilder().message(INSTANCE_NAME, messageId), message);
 
-    String body =
-        get("clusters/" + CLUSTER_NAME + "/instances/" + INSTANCE_NAME + "/messages", null, Response.Status.OK.getStatusCode(), true);
+    String body = new JerseyUriRequestBuilder("clusters/{}/instances/{}/messages")
+        .format(CLUSTER_NAME, INSTANCE_NAME).get(this);
     JsonNode node = OBJECT_MAPPER.readTree(body);
     int newMessageCount =
         node.get(InstanceAccessor.InstanceProperties.total_message_count.name()).getIntValue();
diff --git a/helix-rest/src/test/java/org/apache/helix/rest/server/util/JerseyUriRequestBuilder.java b/helix-rest/src/test/java/org/apache/helix/rest/server/util/JerseyUriRequestBuilder.java
new file mode 100644
index 0000000..b1d91ef
--- /dev/null
+++ b/helix-rest/src/test/java/org/apache/helix/rest/server/util/JerseyUriRequestBuilder.java
@@ -0,0 +1,100 @@
+package org.apache.helix.rest.server.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Response;
+
+import org.apache.commons.lang3.StringUtils;
+import org.glassfish.jersey.test.JerseyTestNg;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Splitter;
+
+
+public class JerseyUriRequestBuilder {
+  private static final String PLACE_HOLDER = "{}";
+
+  private final StringBuilder _uriBuilder;
+  private final Map<String, String> _queryParams;
+  private final int _requiredParameters;
+  private final String _query;
+
+  public JerseyUriRequestBuilder(String uri) {
+    String[] uris = uri.split("\\?");
+    if (uris.length > 1) {
+      _queryParams = Splitter.on('&').trimResults().withKeyValueSeparator("=").split(uris[1]);
+      _query = uris[1];
+    } else {
+      _queryParams = new HashMap<>();
+      _query = "";
+    }
+    _uriBuilder = new StringBuilder(uris[0]);
+    _requiredParameters = StringUtils.countMatches(uris[0], PLACE_HOLDER);
+  }
+
+  public JerseyUriRequestBuilder format(String... parameters) {
+    Preconditions.checkArgument(_requiredParameters == parameters.length);
+    for (String param : parameters) {
+      int index = _uriBuilder.indexOf(PLACE_HOLDER);
+      _uriBuilder.replace(index, index + PLACE_HOLDER.length(), param);
+    }
+
+    return this;
+  }
+
+  private WebTarget buildWebTarget(JerseyTestNg.ContainerPerClassTest container) {
+    WebTarget webTarget = container.target(_uriBuilder.toString());
+    for (Map.Entry<String, String> entry : _queryParams.entrySet()) {
+      webTarget = webTarget.queryParam(entry.getKey(), entry.getValue());
+    }
+
+    return webTarget;
+  }
+
+  public String get(JerseyTestNg.ContainerPerClassTest container, int expectedReturnStatus, boolean expectBodyReturned) {
+    final Response response = buildWebTarget(container).request().get();
+
+    Assert.assertEquals(response.getStatus(), expectedReturnStatus);
+
+    // NOT_FOUND will throw text based html
+    if (expectedReturnStatus != Response.Status.NOT_FOUND.getStatusCode()) {
+      Assert.assertEquals(response.getMediaType().getType(), "application");
+    } else {
+      Assert.assertEquals(response.getMediaType().getType(), "text");
+    }
+
+    String body = response.readEntity(String.class);
+    if (expectBodyReturned) {
+      Assert.assertNotNull(body);
+    }
+
+    return body;
+  }
+
+  public String get(JerseyTestNg.ContainerPerClassTest container) {
+    final Response response = buildWebTarget(container).request().get();
+
+    return response.readEntity(String.class);
+  }
+
+  public String getPath() {
+    if (StringUtils.isEmpty(_query)) {
+      return _uriBuilder.toString();
+    } else {
+      return _uriBuilder.toString() + "?" + _query;
+    }
+  }
+
+  @Test
+  public void testUriBuilderGetPath() {
+    JerseyUriRequestBuilder uriBuilder = new JerseyUriRequestBuilder("clusters/{}/instances/{}/messages?stateModelDef=MasterSlave")
+        .format("TEST-CLUSTER", "instance1");
+    String path = uriBuilder.getPath();
+    Assert.assertEquals(path, "clusters/TEST-CLUSTER/instances/instance1/messages?stateModelDef=MasterSlave");
+    Assert.assertEquals(uriBuilder._queryParams.get("stateModelDef"), "MasterSlave");
+  }
+}


[helix] 12/14: Add Util check instance is already in stable state

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

hulee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/helix.git

commit ae2e3cb4d40f15cd89ba9b99831d0feb1b64bdd8
Author: Junkai Xue <jx...@linkedin.com>
AuthorDate: Fri Mar 15 16:35:01 2019 -0700

    Add Util check instance is already in stable state
    
    We have two choice of checking instance in stable state:
    1. Compare IdealState with ExternalView
    2. Compare IdealState with CurrentState.
    
    Finally choose IS vs EV is because:
    1. We have simple cache in REST, read current state will still cause multiple reads from different hosts for current state. But EV can shared by each host.
    2. EV is the decision maker for router, which is kinda source of truth of real production environment. So EV is the final choice.
    
    RB=1598176
    BUG=HELIX-1676
    G=helix-reviewers
    A=jjwang
    
    Signed-off-by: Hunter Lee <hu...@linkedin.com>
---
 .../apache/helix/util/InstanceValidationUtil.java  | 41 +++++++++++++++++++++-
 1 file changed, 40 insertions(+), 1 deletion(-)

diff --git a/helix-core/src/main/java/org/apache/helix/util/InstanceValidationUtil.java b/helix-core/src/main/java/org/apache/helix/util/InstanceValidationUtil.java
index 81266c2..351c50d 100644
--- a/helix-core/src/main/java/org/apache/helix/util/InstanceValidationUtil.java
+++ b/helix-core/src/main/java/org/apache/helix/util/InstanceValidationUtil.java
@@ -19,6 +19,7 @@ package org.apache.helix.util;
  * under the License.
  */
 
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import org.apache.helix.AccessOption;
@@ -29,6 +30,8 @@ import org.apache.helix.HelixException;
 import org.apache.helix.PropertyKey;
 import org.apache.helix.model.ClusterConfig;
 import org.apache.helix.model.CurrentState;
+import org.apache.helix.model.ExternalView;
+import org.apache.helix.model.IdealState;
 import org.apache.helix.model.InstanceConfig;
 import org.apache.helix.model.LiveInstance;
 import org.apache.helix.model.RESTConfig;
@@ -48,7 +51,7 @@ public class InstanceValidationUtil {
     instanceHealthStatus,
     partitionHealthStatus
   }
-  
+
   private InstanceValidationUtil() {
   }
 
@@ -246,4 +249,40 @@ public class InstanceValidationUtil {
       Map<String, Map<String, String>> partitionHealthMap) {
     return true;
   }
+
+  /**
+   * Check instance is already in the stable state. Here stable means all the ideal state mapping
+   * matches external view (view of current state).
+   *
+   * It requires persist assignment on!
+   *
+   * @param dataAccessor
+   * @param instanceName
+   * @return
+   */
+  public static boolean isInstanceStable(HelixDataAccessor dataAccessor, String instanceName) {
+    PropertyKey.Builder keyBuilder = dataAccessor.keyBuilder();
+    ClusterConfig clusterConfig = dataAccessor.getProperty(keyBuilder.clusterConfig());
+    if (!clusterConfig.isPersistIntermediateAssignment()) {
+      throw new HelixException("isInstanceStable needs persist assignment on!");
+    }
+
+    List<String> idealStateNames = dataAccessor.getChildNames(keyBuilder.idealStates());
+    for (String idealStateName : idealStateNames) {
+      IdealState idealState = dataAccessor.getProperty(keyBuilder.idealStates(idealStateName));
+      ExternalView externalView = dataAccessor.getProperty(keyBuilder.externalView(idealStateName));
+      for (String partition : idealState.getPartitionSet()) {
+        Map<String, String> isPartitionMap = idealState.getInstanceStateMap(partition);
+        Map<String, String> evPartitionMap = externalView.getStateMap(partition);
+        if (isPartitionMap.containsKey(instanceName) && (!evPartitionMap.containsKey(instanceName)
+            || !evPartitionMap.get(instanceName).equals(isPartitionMap.get(instanceName)))) {
+          // only checks the state from IS matches EV. Return false when
+          // 1. This partition not has current state on this instance
+          // 2. The state does not match the state on ideal state
+          return false;
+        }
+      }
+    }
+    return true;
+  }
 }


[helix] 11/14: Dummy check for customized API

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

hulee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/helix.git

commit 2d712e14f35d379af717b7e213853e0c98ae73c3
Author: Junkai Xue <jx...@linkedin.com>
AuthorDate: Tue Mar 12 12:40:41 2019 -0700

    Dummy check for customized API
    
    For this change, it build the dummy check for customized API. It contains following changes:
    1. RESTConfig can setup the customized URL
    2. Define the end point of per participant and per partition.
    3. Add dummy logic that return true for all the check status of customized checks.
    
    RB=1596427
    BUG=HELIX-1678
    G=helix-reviewers
    A=jjwang
    
    Signed-off-by: Hunter Lee <hu...@linkedin.com>
---
 .../main/java/org/apache/helix/ConfigAccessor.java | 21 ++++++++
 .../main/java/org/apache/helix/PropertyKey.java    |  9 ++++
 .../main/java/org/apache/helix/PropertyType.java   |  9 +++-
 .../org/apache/helix/model/HelixConfigScope.java   |  4 +-
 .../java/org/apache/helix/model/RESTConfig.java    | 51 ++++++++++++++++++
 .../apache/helix/util/InstanceValidationUtil.java  | 60 +++++++++++++++++++++-
 .../helix/rest/server/TestInstanceAccessor.java    | 14 +++++
 7 files changed, 164 insertions(+), 4 deletions(-)

diff --git a/helix-core/src/main/java/org/apache/helix/ConfigAccessor.java b/helix-core/src/main/java/org/apache/helix/ConfigAccessor.java
index 53f42fb..1d4c5e8 100644
--- a/helix-core/src/main/java/org/apache/helix/ConfigAccessor.java
+++ b/helix-core/src/main/java/org/apache/helix/ConfigAccessor.java
@@ -34,6 +34,7 @@ import org.apache.helix.model.HelixConfigScope;
 import org.apache.helix.model.HelixConfigScope.ConfigScopeProperty;
 import org.apache.helix.manager.zk.ZKUtil;
 import org.apache.helix.model.InstanceConfig;
+import org.apache.helix.model.RESTConfig;
 import org.apache.helix.model.ResourceConfig;
 import org.apache.helix.model.builder.HelixConfigScopeBuilder;
 import org.apache.helix.util.StringTemplate;
@@ -562,6 +563,26 @@ public class ConfigAccessor {
   }
 
   /**
+   * Get ClusterConfig of the given cluster.
+   *
+   * @param clusterName
+   *
+   * @return
+   */
+  public RESTConfig getRESTConfig(String clusterName) {
+    HelixConfigScope scope =
+        new HelixConfigScopeBuilder(ConfigScopeProperty.REST).forCluster(clusterName).build();
+    ZNRecord record = getConfigZnRecord(scope);
+
+    if (record == null) {
+      LOG.warn("No config found at " + scope.getZkPath());
+      return null;
+    }
+
+    return new RESTConfig(record);
+  }
+
+  /**
    * Set ClusterConfig of the given cluster.
    * The current Cluster config will be replaced with the given clusterConfig.
    * WARNING: This is not thread-safe or concurrent updates safe.
diff --git a/helix-core/src/main/java/org/apache/helix/PropertyKey.java b/helix-core/src/main/java/org/apache/helix/PropertyKey.java
index 03d369b..6350b3c 100644
--- a/helix-core/src/main/java/org/apache/helix/PropertyKey.java
+++ b/helix-core/src/main/java/org/apache/helix/PropertyKey.java
@@ -39,6 +39,7 @@ import org.apache.helix.model.MaintenanceSignal;
 import org.apache.helix.model.Message;
 import org.apache.helix.model.ParticipantHistory;
 import org.apache.helix.model.PauseSignal;
+import org.apache.helix.model.RESTConfig;
 import org.apache.helix.model.ResourceConfig;
 import org.apache.helix.model.StateModelDefinition;
 import org.apache.helix.model.StatusUpdate;
@@ -779,6 +780,14 @@ public class PropertyKey {
       return new PropertyKey(PropertyType.WORKFLOWCONTEXT, WorkflowContext.class, _clusterName,
           workflowName);
     }
+
+    /**
+     * Get a property key associated with {@link ResourceConfig}
+     * @return {@link PropertyKey}
+     */
+    public PropertyKey restConfig() {
+      return new PropertyKey(RESTCONFIGS, RESTConfig.class, _clusterName);
+    }
   }
 
   /**
diff --git a/helix-core/src/main/java/org/apache/helix/PropertyType.java b/helix-core/src/main/java/org/apache/helix/PropertyType.java
index 2381acc..e234a3b 100644
--- a/helix-core/src/main/java/org/apache/helix/PropertyType.java
+++ b/helix-core/src/main/java/org/apache/helix/PropertyType.java
@@ -27,7 +27,8 @@ enum Type {
   INSTANCE,
   CONTROLLER,
   RESOURCE,
-  TASK
+  TASK,
+  REST
 }
 
 /**
@@ -73,7 +74,11 @@ public enum PropertyType {
   WORKFLOW_CONFIG(Type.TASK, true, false, false, false, false),
   WORKFLOW_CONTEXT(Type.TASK, true, false, false, false, false),
   JOB_CONFIG(Type.TASK, true, false, false, false, false),
-  JOB_CONTEXT(Type.TASK, true, false, false, false, false);
+  JOB_CONTEXT(Type.TASK, true, false, false, false, false),
+
+  // REST PROPERTIES
+  RESTCONFIGS(Type.REST, true, false, false, false, true);
+
 
   // @formatter:on
 
diff --git a/helix-core/src/main/java/org/apache/helix/model/HelixConfigScope.java b/helix-core/src/main/java/org/apache/helix/model/HelixConfigScope.java
index 9d3b41a..7c5c91d 100644
--- a/helix-core/src/main/java/org/apache/helix/model/HelixConfigScope.java
+++ b/helix-core/src/main/java/org/apache/helix/model/HelixConfigScope.java
@@ -35,7 +35,8 @@ public class HelixConfigScope {
     PARTICIPANT(2, 0),
     RESOURCE(2, 0),
     PARTITION(2, 1),
-    CONSTRAINT(2, 0);
+    CONSTRAINT(2, 0),
+    REST(2, 0);
 
     final int _zkPathArgNum;
     final int _mapKeyArgNum;
@@ -82,6 +83,7 @@ public class HelixConfigScope {
     template.addEntry(ConfigScopeProperty.CLUSTER, 1, "/{clusterName}/CONFIGS/CLUSTER");
     template.addEntry(ConfigScopeProperty.PARTICIPANT, 1, "/{clusterName}/CONFIGS/PARTICIPANT");
     template.addEntry(ConfigScopeProperty.RESOURCE, 1, "/{clusterName}/CONFIGS/RESOURCE");
+    template.addEntry(ConfigScopeProperty.REST, 2, "/{clusterName}/CONFIGS/REST/{clusterName}");
   }
 
   final ConfigScopeProperty _type;
diff --git a/helix-core/src/main/java/org/apache/helix/model/RESTConfig.java b/helix-core/src/main/java/org/apache/helix/model/RESTConfig.java
new file mode 100644
index 0000000..a47226c
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/model/RESTConfig.java
@@ -0,0 +1,51 @@
+package org.apache.helix.model;
+
+import org.apache.helix.HelixProperty;
+import org.apache.helix.ZNRecord;
+
+public class RESTConfig extends HelixProperty {
+  public enum RESTConfigProperty {
+    CUSTOMIZED_HEALTH_URL // User customized URL for getting participant health status or partition
+                          // health status.
+  }
+
+  /**
+   * Instantiate REST config for a specific cluster
+   * @param cluster the cluster identifier
+   */
+  public RESTConfig(String cluster) {
+    super(cluster);
+  }
+
+  /**
+   * Instantiate REST config with a pre-populated record
+   *
+   * @param record a ZNRecord corresponding to a cluster configuration
+   */
+  public RESTConfig(ZNRecord record) {
+    super(record);
+  }
+
+  /**
+   * Set up the user defined URL for check per participant health / per partition health by combine
+   * URL and final endpoint. It must ended without "/"
+   *
+   * eg: http://*:12345/customized/path/check
+   *
+   * @param customizedHealthURL
+   */
+  public void setCustomizedHealthURL(String customizedHealthURL) {
+    _record.setSimpleField(RESTConfigProperty.CUSTOMIZED_HEALTH_URL.name(), customizedHealthURL);
+  }
+
+  /**
+   * Get user defined URL to construct per participant health / partition health
+   * Return null if it does not exist.
+   *
+   * @return
+   */
+  public String getCustomizedHealthURL() {
+    return _record.getSimpleField(RESTConfigProperty.CUSTOMIZED_HEALTH_URL.name());
+  }
+
+}
diff --git a/helix-core/src/main/java/org/apache/helix/util/InstanceValidationUtil.java b/helix-core/src/main/java/org/apache/helix/util/InstanceValidationUtil.java
index b701864..81266c2 100644
--- a/helix-core/src/main/java/org/apache/helix/util/InstanceValidationUtil.java
+++ b/helix-core/src/main/java/org/apache/helix/util/InstanceValidationUtil.java
@@ -21,7 +21,6 @@ package org.apache.helix.util;
 
 import java.util.List;
 import java.util.Map;
-
 import org.apache.helix.AccessOption;
 import org.apache.helix.ConfigAccessor;
 import org.apache.helix.HelixDataAccessor;
@@ -32,6 +31,7 @@ import org.apache.helix.model.ClusterConfig;
 import org.apache.helix.model.CurrentState;
 import org.apache.helix.model.InstanceConfig;
 import org.apache.helix.model.LiveInstance;
+import org.apache.helix.model.RESTConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -44,6 +44,11 @@ import org.slf4j.LoggerFactory;
 public class InstanceValidationUtil {
   private static final Logger _logger = LoggerFactory.getLogger(InstanceValidationUtil.class);
 
+  public enum HealthStatusType {
+    instanceHealthStatus,
+    partitionHealthStatus
+  }
+  
   private InstanceValidationUtil() {
   }
 
@@ -188,4 +193,57 @@ public class InstanceValidationUtil {
     _logger.warn(String.format("The instance %s is not active", instanceName));
     return false;
   }
+
+  /**
+   * Check the overall health status for instance including:
+   *  1. Per instance health status with application customized key-value entries
+   *  2. Sibling partitions (replicas for same partition holding on different node
+   *     health status for the entire cluster.
+   *
+   * @param configAccessor
+   * @param clustername
+   * @param hostName
+   * @param customizedInputs
+   * @param partitionHealthMap
+   * @return
+   */
+  public static boolean checkCustomizedHealthStatusForInstance(ConfigAccessor configAccessor,
+      String clustername, String hostName, Map<String, String> customizedInputs,
+      Map<String, Map<String, String>> partitionHealthMap, Map<String, String> instanceHealthMap) {
+    boolean isHealthy = true;
+    RESTConfig restConfig = configAccessor.getRESTConfig(clustername);
+    // If user customized URL is not ready, return true as the check
+    if (restConfig == null || restConfig.getCustomizedHealthURL() == null) {
+      return isHealthy;
+    }
+    // TODO : 1. Call REST with customized URL
+    //        2. Parse mapping result with string -> boolean value and return out for per instance
+    //        3. Check sibling nodes for partition health
+    isHealthy =
+        perInstanceHealthCheck(instanceHealthMap) || perPartitionHealthCheck(partitionHealthMap);
+
+    return isHealthy;
+  }
+
+  /**
+   * Fetch the health map based on health type: per instance or per partition
+   * Accessor can used for fetching data from ZK for per partition level.
+   * @param URL
+   * @param accessor
+   * @param healthStatusType
+   * @return
+   */
+  public static Map<String, Map<String, String>> getHealthMapBasedOnType(String URL,
+      HelixDataAccessor accessor, HealthStatusType healthStatusType) {
+    return null;
+  }
+
+  protected static boolean perInstanceHealthCheck(Map<String, String> statusMap) {
+    return true;
+  }
+
+  protected static boolean perPartitionHealthCheck(
+      Map<String, Map<String, String>> partitionHealthMap) {
+    return true;
+  }
 }
diff --git a/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstanceAccessor.java b/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstanceAccessor.java
index 858ea89..be47cab 100644
--- a/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstanceAccessor.java
+++ b/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstanceAccessor.java
@@ -22,6 +22,7 @@ package org.apache.helix.rest.server;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -40,6 +41,7 @@ import org.apache.helix.model.Message;
 import org.apache.helix.rest.server.resources.AbstractResource;
 import org.apache.helix.rest.server.resources.helix.InstanceAccessor;
 import org.apache.helix.rest.server.util.JerseyUriRequestBuilder;
+import org.apache.helix.util.InstanceValidationUtil;
 import org.codehaus.jackson.JsonNode;
 import org.testng.Assert;
 import org.testng.annotations.Test;
@@ -400,4 +402,16 @@ public class TestInstanceAccessor extends AbstractTestClass {
         .expectedReturnStatusCode(Response.Status.NOT_FOUND.getStatusCode())
         .format(CLUSTER_NAME, instanceName).post(this, entity);
   }
+
+  public void testCustomizedChecks() {
+    // TODO: This is fake testing. Only validate it returns true value of this function.
+    // For future, we need test: 1. mock the input of per participant API result to test validate logic
+    //                           2. mock the input of per partition API result to test the sibling
+    //                              check logic
+    System.out.println("Start test :" + TestHelper.getTestMethodName());
+    String instanceName = "TestInstance";
+    Assert.assertTrue(InstanceValidationUtil
+        .checkCustomizedHealthStatusForInstance(_configAccessor, CLUSTER_NAME, instanceName,
+            Collections.EMPTY_MAP, Collections.EMPTY_MAP, Collections.EMPTY_MAP));
+  }
 }


[helix] 05/14: Util methods for checking if instance healthy

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

hulee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/helix.git

commit b43681634820ea5990851efae941e1123c5b4c54
Author: Yi Wang <yw...@linkedin.com>
AuthorDate: Tue Mar 12 16:59:25 2019 -0700

    Util methods for checking if instance healthy
    
    RB=1585486
    G=helix-reviewers
    A=jxue
    
    Signed-off-by: Hunter Lee <hu...@linkedin.com>
---
 .gitignore                                         |  3 +-
 .../main/java/org/apache/helix/PropertyKey.java    |  2 +-
 .../apache/helix/util/InstanceValidationUtil.java  | 87 ++++++++++++++++++++--
 .../helix/rest/common/ZKReadAccessorWrapper.java   | 50 +++++++++++++
 4 files changed, 133 insertions(+), 9 deletions(-)

diff --git a/.gitignore b/.gitignore
index 27c2cdf..5cd0404 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,5 +11,6 @@ target/
 .settings/
 out/
 .DS_Store
-#this directory will be part of release process 
+#this directory will be part of release process
 helix-dev-release/
+.shelf/
diff --git a/helix-core/src/main/java/org/apache/helix/PropertyKey.java b/helix-core/src/main/java/org/apache/helix/PropertyKey.java
index 2ddc8bb..03d369b 100644
--- a/helix-core/src/main/java/org/apache/helix/PropertyKey.java
+++ b/helix-core/src/main/java/org/apache/helix/PropertyKey.java
@@ -22,8 +22,8 @@ package org.apache.helix;
 import static org.apache.helix.PropertyType.*;
 
 import java.util.Arrays;
-
 import java.util.Objects;
+
 import org.apache.helix.model.ClusterConfig;
 import org.apache.helix.model.ClusterConstraints;
 import org.apache.helix.model.ControllerHistory;
diff --git a/helix-core/src/main/java/org/apache/helix/util/InstanceValidationUtil.java b/helix-core/src/main/java/org/apache/helix/util/InstanceValidationUtil.java
index 23aa89b..b701864 100644
--- a/helix-core/src/main/java/org/apache/helix/util/InstanceValidationUtil.java
+++ b/helix-core/src/main/java/org/apache/helix/util/InstanceValidationUtil.java
@@ -25,21 +25,25 @@ import java.util.Map;
 import org.apache.helix.AccessOption;
 import org.apache.helix.ConfigAccessor;
 import org.apache.helix.HelixDataAccessor;
+import org.apache.helix.HelixDefinedState;
+import org.apache.helix.HelixException;
 import org.apache.helix.PropertyKey;
 import org.apache.helix.model.ClusterConfig;
 import org.apache.helix.model.CurrentState;
 import org.apache.helix.model.InstanceConfig;
 import org.apache.helix.model.LiveInstance;
-
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Utility class for validating Helix properties
  * Warning: each method validates one single property of instance individually and independently.
  * One validation wouldn't depend on the results of other validations
- * TODO: integrate on-demand cache if the performance is the bottleneck
- * TODO: manually tested the function, need to add detailed integration test
+ * TODO: add unit tests
  */
 public class InstanceValidationUtil {
+  private static final Logger _logger = LoggerFactory.getLogger(InstanceValidationUtil.class);
+
   private InstanceValidationUtil() {
   }
 
@@ -53,6 +57,7 @@ public class InstanceValidationUtil {
    */
   public static boolean isEnabled(HelixDataAccessor dataAccessor, ConfigAccessor configAccessor,
       String clusterId, String instanceName) {
+    // TODO use static builder instance to reduce GC
     PropertyKey propertyKey = new PropertyKey.Builder(clusterId).instanceConfig(instanceName);
     InstanceConfig instanceConfig = dataAccessor.getProperty(propertyKey);
     ClusterConfig clusterConfig = configAccessor.getClusterConfig(clusterId);
@@ -95,24 +100,92 @@ public class InstanceValidationUtil {
    */
   public static boolean hasResourceAssigned(HelixDataAccessor dataAccessor, String clusterId,
       String instanceName) {
-    PropertyKey liveInstanceKey = new PropertyKey.Builder(clusterId).liveInstance(instanceName);
+    PropertyKey.Builder propertyKeyBuilder = new PropertyKey.Builder(clusterId);
+    PropertyKey liveInstanceKey = propertyKeyBuilder.liveInstance(instanceName);
     LiveInstance liveInstance = dataAccessor.getProperty(liveInstanceKey);
     if (liveInstance != null) {
       String sessionId = liveInstance.getSessionId();
 
       PropertyKey currentStatesKey =
-          new PropertyKey.Builder(clusterId).currentStates(instanceName, sessionId);
+          propertyKeyBuilder.currentStates(instanceName, sessionId);
       List<String> resourceNames = dataAccessor.getChildNames(currentStatesKey);
       for (String resourceName : resourceNames) {
         PropertyKey key =
-            dataAccessor.keyBuilder().currentState(instanceName, sessionId, resourceName);
+            propertyKeyBuilder.currentState(instanceName, sessionId, resourceName);
+        CurrentState currentState = dataAccessor.getProperty(key);
+        if (currentState != null && currentState.getPartitionStateMap().size() > 0) {
+          return true;
+        }
+      }
+    }
+
+    _logger.warn(String.format("The instance %s is not active", instanceName));
+    return false;
+  }
+
+  /**
+   * Method to check if the instance has any disabled partition assigned
+   * @param dataAccessor
+   * @param clusterId
+   * @param instanceName
+   * @return
+   */
+  public static boolean hasDisabledPartitions(HelixDataAccessor dataAccessor, String clusterId,
+      String instanceName) {
+    PropertyKey propertyKey = new PropertyKey.Builder(clusterId).instanceConfig(instanceName);
+    InstanceConfig instanceConfig = dataAccessor.getProperty(propertyKey);
+    if (instanceConfig != null) {
+      return !instanceConfig.getDisabledPartitionsMap().isEmpty();
+    }
+
+    throw new HelixException("Fail to get instance config for " + instanceName);
+  }
+
+  /**
+   * Method to check if the instance has valid configuration
+   * @param dataAccessor
+   * @param clusterId
+   * @param instanceName
+   * @return
+   */
+  public static boolean hasValidConfig(HelixDataAccessor dataAccessor, String clusterId,
+      String instanceName) {
+    PropertyKey propertyKey = new PropertyKey.Builder(clusterId).instanceConfig(instanceName);
+    InstanceConfig instanceConfig = dataAccessor.getProperty(propertyKey);
+    return instanceConfig != null && instanceConfig.isValid();
+  }
+
+  /**
+   * Method to check if the instance has error partitions
+   * @param dataAccessor
+   * @param clusterId
+   * @param instanceName
+   * @return
+   */
+  public static boolean hasErrorPartitions(HelixDataAccessor dataAccessor, String clusterId,
+      String instanceName) {
+    PropertyKey.Builder propertyKeyBuilder = new PropertyKey.Builder(clusterId);
+    PropertyKey liveInstanceKey = propertyKeyBuilder.liveInstance(instanceName);
+    LiveInstance liveInstance = dataAccessor.getProperty(liveInstanceKey);
+    if (liveInstance != null) {
+      String sessionId = liveInstance.getSessionId();
+
+      PropertyKey currentStatesKey =
+          propertyKeyBuilder.currentStates(instanceName, sessionId);
+      List<String> resourceNames = dataAccessor.getChildNames(currentStatesKey);
+      for (String resourceName : resourceNames) {
+        PropertyKey key =
+            propertyKeyBuilder.currentState(instanceName, sessionId, resourceName);
+
         CurrentState currentState = dataAccessor.getProperty(key);
-        if (currentState.getPartitionStateMap().size() > 0) {
+        if (currentState != null
+            && currentState.getPartitionStateMap().containsValue(HelixDefinedState.ERROR.name())) {
           return true;
         }
       }
     }
 
+    _logger.warn(String.format("The instance %s is not active", instanceName));
     return false;
   }
 }
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/common/ZKReadAccessorWrapper.java b/helix-rest/src/main/java/org/apache/helix/rest/common/ZKReadAccessorWrapper.java
new file mode 100644
index 0000000..f8a4f4f
--- /dev/null
+++ b/helix-rest/src/main/java/org/apache/helix/rest/common/ZKReadAccessorWrapper.java
@@ -0,0 +1,50 @@
+package org.apache.helix.rest.common;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.helix.BaseDataAccessor;
+import org.apache.helix.HelixProperty;
+import org.apache.helix.InstanceType;
+import org.apache.helix.PropertyKey;
+import org.apache.helix.ZNRecord;
+import org.apache.helix.manager.zk.ZKHelixDataAccessor;
+
+
+/**
+ * A read-only wrapper of {@link ZKHelixDataAccessor} with transient cache
+ * The caches is of the value from get methods and short lived for the lifecycle of one rest request
+ * TODO: add more cached read method based on needs
+ */
+public class ZKReadAccessorWrapper extends ZKHelixDataAccessor {
+  private final Map<PropertyKey, HelixProperty> _propertyCache = new HashMap<>();
+  private final Map<PropertyKey, List<String>> _batchNameCache = new HashMap<>();
+
+  public ZKReadAccessorWrapper(String clusterName, InstanceType instanceType,
+      BaseDataAccessor<ZNRecord> baseDataAccessor) {
+    super(clusterName, instanceType, baseDataAccessor);
+  }
+
+  @Override
+  public <T extends HelixProperty> T getProperty(PropertyKey key) {
+    if (_propertyCache.containsKey(key)) {
+      return (T) _propertyCache.get(key);
+    }
+    T property = super.getProperty(key);
+    _propertyCache.put(key, property);
+    return property;
+  }
+
+  @Override
+  public List<String> getChildNames(PropertyKey key) {
+    if (_batchNameCache.containsKey(key)) {
+      return _batchNameCache.get(key);
+    }
+
+    List<String> names = super.getChildNames(key);
+    _batchNameCache.put(key, names);
+
+    return names;
+  }
+}


[helix] 09/14: Add adminGroup check for write operations

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

hulee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/helix.git

commit 241baae6831e08eb2807f01fbf670c00b154dbbb
Author: Yi Wang <yw...@linkedin.com>
AuthorDate: Fri Mar 8 15:28:35 2019 -0800

    Add adminGroup check for write operations
    
    ACLOVERRIDE
    RB=1590175
    BUG=HELIX-1682
    G=helix-reviewers
    A=jxue
    
    Signed-off-by: Hunter Lee <hu...@linkedin.com>
---
 helix-front/client/app/app.component.ts |  8 +++---
 helix-front/server/config.ts            |  7 ++----
 helix-front/server/controllers/user.ts  | 44 ++++++++++++++++++++++-----------
 3 files changed, 37 insertions(+), 22 deletions(-)

diff --git a/helix-front/client/app/app.component.ts b/helix-front/client/app/app.component.ts
index 06f7f5e..4c691ae 100644
--- a/helix-front/client/app/app.component.ts
+++ b/helix-front/client/app/app.component.ts
@@ -14,6 +14,7 @@ import { Angulartics2Piwik } from 'angulartics2';
 import { UserService } from './core/user.service';
 import { InputDialogComponent } from './shared/dialog/input-dialog/input-dialog.component';
 import { HelperService } from './shared/helper.service';
+import {LDAP} from "../../server/config";
 
 @Component({
   selector: 'hi-root',
@@ -85,10 +86,11 @@ export class AppComponent implements OnInit {
           this.service
             .login(result.username.value, result.password.value)
             .subscribe(
-              isAuthroized => {
-                if (isAuthroized) {
-                  location.reload();
+              isAuthorized => {
+                if (!isAuthorized) {
+                  this.helper.showError("You're not part of " + LDAP.adminGroup + " group or password incorrect");
                 }
+                this.currentUser = this.service.getCurrentUser();
               },
               error => this.helper.showError(error)
             );
diff --git a/helix-front/server/config.ts b/helix-front/server/config.ts
index 1a4265b..35ee27d 100644
--- a/helix-front/server/config.ts
+++ b/helix-front/server/config.ts
@@ -17,9 +17,6 @@ export const SSL = {
 export const LDAP = {
   uri: 'ldap://example.com',
   base: 'DC=example,DC=com',
-  principalSuffix: '@example.com'
+  principalSuffix: '@example.com',
+  adminGroup: 'admin'
 };
-
-export function CheckAdmin(username: string, callback: (boolean) => void) {
-  callback(username === 'root');
-}
diff --git a/helix-front/server/controllers/user.ts b/helix-front/server/controllers/user.ts
index 980d97c..7727255 100644
--- a/helix-front/server/controllers/user.ts
+++ b/helix-front/server/controllers/user.ts
@@ -1,9 +1,7 @@
-import { Request, Response, Router } from 'express';
-
-import * as request from 'request';
+import {Request, Response, Router} from 'express';
 import * as LdapClient from 'ldapjs';
 
-import { LDAP, CheckAdmin } from '../config';
+import {LDAP} from '../config';
 
 export class UserCtrl {
 
@@ -34,10 +32,10 @@ export class UserCtrl {
     res.json(req.session.isAdmin ? true : false);
   }
 
-  protected login(req: Request, res: Response) {
-    const credential = req.body;
+  protected login(request: Request, response: Response) {
+    const credential = request.body;
     if (!credential.username || !credential.password) {
-      res.status(401).json(false);
+      response.status(401).json(false);
       return;
     }
 
@@ -45,16 +43,34 @@ export class UserCtrl {
     const ldap = LdapClient.createClient({ url: LDAP.uri });
     ldap.bind(credential.username + LDAP.principalSuffix, credential.password, err => {
       if (err) {
-        res.status(401).json(false);
+        response.status(401).json(false);
       } else {
-        // authroized
-        req.session.username = credential.username;
-        CheckAdmin(req.session.username, (isAdmin: boolean) => {
-          req.session.isAdmin = isAdmin;
-          res.json(true);
+        // login success
+        let opts = {
+          filter: '(&(sAMAccountName=' + credential.username + ')(objectcategory=person))',
+          scope: 'sub'
+        };
+
+        ldap.search(LDAP.base, opts, function(err, result) {
+          var isInAdminGroup = false;
+          result.on('searchEntry', function (entry) {
+            if (entry.object && !err) {
+              let groups = entry.object["memberOf"];
+              for (var group of groups) {
+                const groupName = group.split(",", 1)[0].split("=")[1];
+                if (groupName == LDAP.adminGroup) {
+                  isInAdminGroup = true;
+                  break;
+                }
+              }
+            }
+
+            request.session.username = credential.username;
+            request.session.isAdmin = isInAdminGroup;
+            response.json(isInAdminGroup);
+          });
         });
       }
     });
   }
-
 }


[helix] 08/14: Apply the JerseyTestUriRequestBuilder to the TestInstanceAccessor

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

hulee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/helix.git

commit 271eb07c121c842ba02f350fcd18de47cf5e5721
Author: ywang4 <yw...@linkedin.com>
AuthorDate: Mon Feb 25 15:04:50 2019 -0800

    Apply the JerseyTestUriRequestBuilder to the TestInstanceAccessor
    
    RB=1575013
    G=helix-reviewers
    A=jxue
    
    Signed-off-by: Hunter Lee <hu...@linkedin.com>
---
 .../helix/rest/server/TestInstanceAccessor.java    | 141 +++++++++++----------
 .../rest/server/util/JerseyUriRequestBuilder.java  |  94 ++++++++++----
 2 files changed, 147 insertions(+), 88 deletions(-)

diff --git a/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstanceAccessor.java b/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstanceAccessor.java
index 172c848..858ea89 100644
--- a/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstanceAccessor.java
+++ b/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstanceAccessor.java
@@ -22,7 +22,6 @@ package org.apache.helix.rest.server;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -66,10 +65,11 @@ public class TestInstanceAccessor extends AbstractTestClass {
     message.setTgtName("localhost_3");
     message.setTgtSessionId("session_3");
     HelixDataAccessor helixDataAccessor = new ZKHelixDataAccessor(CLUSTER_NAME, _baseAccessor);
-    helixDataAccessor.setProperty(helixDataAccessor.keyBuilder().message(INSTANCE_NAME, messageId), message);
+    helixDataAccessor.setProperty(helixDataAccessor.keyBuilder().message(INSTANCE_NAME, messageId),
+        message);
 
     String body = new JerseyUriRequestBuilder("clusters/{}/instances/{}/messages")
-        .format(CLUSTER_NAME, INSTANCE_NAME).get(this);
+        .isBodyReturnExpected(true).format(CLUSTER_NAME, INSTANCE_NAME).get(this);
     JsonNode node = OBJECT_MAPPER.readTree(body);
     int newMessageCount =
         node.get(InstanceAccessor.InstanceProperties.total_message_count.name()).getIntValue();
@@ -77,7 +77,7 @@ public class TestInstanceAccessor extends AbstractTestClass {
     Assert.assertEquals(newMessageCount, 1);
   }
 
-  @Test (dependsOnMethods = "testGetAllMessages")
+  @Test(dependsOnMethods = "testGetAllMessages")
   public void testGetMessagesByStateModelDef() throws IOException {
     System.out.println("Start test :" + TestHelper.getTestMethodName());
 
@@ -91,19 +91,21 @@ public class TestInstanceAccessor extends AbstractTestClass {
     message.setTgtName("localhost_3");
     message.setTgtSessionId("session_3");
     HelixDataAccessor helixDataAccessor = new ZKHelixDataAccessor(CLUSTER_NAME, _baseAccessor);
-    helixDataAccessor.setProperty(helixDataAccessor.keyBuilder().message(INSTANCE_NAME, messageId), message);
+    helixDataAccessor.setProperty(helixDataAccessor.keyBuilder().message(INSTANCE_NAME, messageId),
+        message);
 
-    String body = get("clusters/" + CLUSTER_NAME + "/instances/" + INSTANCE_NAME + "/messages",
-        ImmutableMap.of("stateModelDef", "MasterSlave"), Response.Status.OK.getStatusCode(), true);
+    String body =
+        new JerseyUriRequestBuilder("clusters/{}/instances/{}/messages?stateModelDef=MasterSlave")
+            .isBodyReturnExpected(true).format(CLUSTER_NAME, INSTANCE_NAME).get(this);
     JsonNode node = OBJECT_MAPPER.readTree(body);
     int newMessageCount =
         node.get(InstanceAccessor.InstanceProperties.total_message_count.name()).getIntValue();
 
     Assert.assertEquals(newMessageCount, 1);
 
-    body = get("clusters/" + CLUSTER_NAME + "/instances/" + INSTANCE_NAME + "/messages",
-        ImmutableMap.of("stateModelDef", "LeaderStandBy"), Response.Status.OK.getStatusCode(),
-        true);
+    body =
+        new JerseyUriRequestBuilder("clusters/{}/instances/{}/messages?stateModelDef=LeaderStandBy")
+            .isBodyReturnExpected(true).format(CLUSTER_NAME, INSTANCE_NAME).get(this);
     node = OBJECT_MAPPER.readTree(body);
     newMessageCount =
         node.get(InstanceAccessor.InstanceProperties.total_message_count.name()).getIntValue();
@@ -111,32 +113,29 @@ public class TestInstanceAccessor extends AbstractTestClass {
     Assert.assertEquals(newMessageCount, 0);
   }
 
-  @Test (dependsOnMethods = "testGetMessagesByStateModelDef")
+  @Test(dependsOnMethods = "testGetMessagesByStateModelDef")
   public void testGetInstances() throws IOException {
     System.out.println("Start test :" + TestHelper.getTestMethodName());
-    String body =
-        get("clusters/" + CLUSTER_NAME + "/instances", null, Response.Status.OK.getStatusCode(), true);
+    String body = new JerseyUriRequestBuilder("clusters/{}/instances").isBodyReturnExpected(true)
+        .format(CLUSTER_NAME).get(this);
 
     JsonNode node = OBJECT_MAPPER.readTree(body);
-    String instancesStr =
-        node.get(InstanceAccessor.InstanceProperties.instances.name()).toString();
+    String instancesStr = node.get(InstanceAccessor.InstanceProperties.instances.name()).toString();
     Assert.assertNotNull(instancesStr);
 
     Set<String> instances = OBJECT_MAPPER.readValue(instancesStr,
         OBJECT_MAPPER.getTypeFactory().constructCollectionType(Set.class, String.class));
-    Assert.assertEquals(instances, _instancesMap.get(CLUSTER_NAME),
-        "Instances from response: " + instances + " vs instances actually: " + _instancesMap
-            .get(CLUSTER_NAME));
+    Assert.assertEquals(instances, _instancesMap.get(CLUSTER_NAME), "Instances from response: "
+        + instances + " vs instances actually: " + _instancesMap.get(CLUSTER_NAME));
   }
 
   @Test(dependsOnMethods = "testGetInstances")
   public void testGetInstance() throws IOException {
     System.out.println("Start test :" + TestHelper.getTestMethodName());
-    String body = get("clusters/" + CLUSTER_NAME + "/instances/" + INSTANCE_NAME, null,
-        Response.Status.OK.getStatusCode(), true);
+    String body = new JerseyUriRequestBuilder("clusters/{}/instances/{}").isBodyReturnExpected(true)
+        .format(CLUSTER_NAME, INSTANCE_NAME).get(this);
     JsonNode node = OBJECT_MAPPER.readTree(body);
-    String instancesCfg =
-        node.get(InstanceAccessor.InstanceProperties.config.name()).toString();
+    String instancesCfg = node.get(InstanceAccessor.InstanceProperties.config.name()).toString();
     Assert.assertNotNull(instancesCfg);
 
     InstanceConfig instanceConfig = new InstanceConfig(toZNRecord(instancesCfg));
@@ -150,8 +149,10 @@ public class TestInstanceAccessor extends AbstractTestClass {
     InstanceConfig instanceConfig = new InstanceConfig(INSTANCE_NAME + "TEST");
     Entity entity = Entity.entity(OBJECT_MAPPER.writeValueAsString(instanceConfig.getRecord()),
         MediaType.APPLICATION_JSON_TYPE);
-    put("clusters/" + CLUSTER_NAME + "/instances/" + INSTANCE_NAME, null, entity,
-        Response.Status.OK.getStatusCode());
+
+    new JerseyUriRequestBuilder("clusters/{}/instances/{}").format(CLUSTER_NAME, INSTANCE_NAME)
+        .put(this, entity);
+
     Assert.assertEquals(instanceConfig,
         _configAccessor.getInstanceConfig(CLUSTER_NAME, INSTANCE_NAME + "TEST"));
   }
@@ -169,38 +170,44 @@ public class TestInstanceAccessor extends AbstractTestClass {
     System.out.println("Start test :" + TestHelper.getTestMethodName());
     // Disable instance
     Entity entity = Entity.entity("", MediaType.APPLICATION_JSON_TYPE);
-    post("clusters/" + CLUSTER_NAME + "/instances/" + INSTANCE_NAME,
-        ImmutableMap.of("command", "disable"), entity, Response.Status.OK.getStatusCode());
+
+    new JerseyUriRequestBuilder("clusters/{}/instances/{}?command=disable")
+        .format(CLUSTER_NAME, INSTANCE_NAME).post(this, entity);
+
     Assert.assertFalse(
         _configAccessor.getInstanceConfig(CLUSTER_NAME, INSTANCE_NAME).getInstanceEnabled());
 
     // Enable instance
-    post("clusters/" + CLUSTER_NAME + "/instances/" + INSTANCE_NAME,
-        ImmutableMap.of("command", "enable"), entity, Response.Status.OK.getStatusCode());
+    new JerseyUriRequestBuilder("clusters/{}/instances/{}?command=enable")
+        .format(CLUSTER_NAME, INSTANCE_NAME).post(this, entity);
+
     Assert.assertTrue(
         _configAccessor.getInstanceConfig(CLUSTER_NAME, INSTANCE_NAME).getInstanceEnabled());
 
     // AddTags
     List<String> tagList = ImmutableList.of("tag3", "tag1", "tag2");
-    entity = Entity.entity(OBJECT_MAPPER.writeValueAsString(ImmutableMap
-            .of(AbstractResource.Properties.id.name(), INSTANCE_NAME,
-                InstanceAccessor.InstanceProperties.instanceTags.name(), tagList)),
+    entity = Entity.entity(
+        OBJECT_MAPPER.writeValueAsString(ImmutableMap.of(AbstractResource.Properties.id.name(),
+            INSTANCE_NAME, InstanceAccessor.InstanceProperties.instanceTags.name(), tagList)),
         MediaType.APPLICATION_JSON_TYPE);
-    post("clusters/" + CLUSTER_NAME + "/instances/" + INSTANCE_NAME,
-        ImmutableMap.of("command", "addInstanceTag"), entity, Response.Status.OK.getStatusCode());
+
+    new JerseyUriRequestBuilder("clusters/{}/instances/{}?command=addInstanceTag")
+        .format(CLUSTER_NAME, INSTANCE_NAME).post(this, entity);
+
     Assert.assertEquals(_configAccessor.getInstanceConfig(CLUSTER_NAME, INSTANCE_NAME).getTags(),
         tagList);
 
     // RemoveTags
     List<String> removeList = new ArrayList<>(tagList);
     removeList.remove("tag2");
-    entity = Entity.entity(OBJECT_MAPPER.writeValueAsString(ImmutableMap
-            .of(AbstractResource.Properties.id.name(), INSTANCE_NAME,
-                InstanceAccessor.InstanceProperties.instanceTags.name(), removeList)),
+    entity = Entity.entity(
+        OBJECT_MAPPER.writeValueAsString(ImmutableMap.of(AbstractResource.Properties.id.name(),
+            INSTANCE_NAME, InstanceAccessor.InstanceProperties.instanceTags.name(), removeList)),
         MediaType.APPLICATION_JSON_TYPE);
-    post("clusters/" + CLUSTER_NAME + "/instances/" + INSTANCE_NAME,
-        ImmutableMap.of("command", "removeInstanceTag"), entity,
-        Response.Status.OK.getStatusCode());
+
+    new JerseyUriRequestBuilder("clusters/{}/instances/{}?command=removeInstanceTag")
+        .format(CLUSTER_NAME, INSTANCE_NAME).post(this, entity);
+
     Assert.assertEquals(_configAccessor.getInstanceConfig(CLUSTER_NAME, INSTANCE_NAME).getTags(),
         ImmutableList.of("tag2"));
 
@@ -235,20 +242,22 @@ public class TestInstanceAccessor extends AbstractTestClass {
 
     // Test enable disable partitions
     String dbName = "_db_0_";
-    List<String> partitionsToDisable = Arrays.asList(
-         CLUSTER_NAME + dbName + "0", CLUSTER_NAME + dbName + "1", CLUSTER_NAME + dbName + "3");
+    List<String> partitionsToDisable = Arrays.asList(CLUSTER_NAME + dbName + "0",
+        CLUSTER_NAME + dbName + "1", CLUSTER_NAME + dbName + "3");
 
-    entity = Entity.entity(OBJECT_MAPPER.writeValueAsString(ImmutableMap
-            .of(AbstractResource.Properties.id.name(), INSTANCE_NAME,
-                InstanceAccessor.InstanceProperties.resource.name(),
-                CLUSTER_NAME + dbName.substring(0, dbName.length() - 1),
-                InstanceAccessor.InstanceProperties.partitions.name(), partitionsToDisable)),
+    entity = Entity.entity(
+        OBJECT_MAPPER.writeValueAsString(ImmutableMap.of(AbstractResource.Properties.id.name(),
+            INSTANCE_NAME, InstanceAccessor.InstanceProperties.resource.name(),
+            CLUSTER_NAME + dbName.substring(0, dbName.length() - 1),
+            InstanceAccessor.InstanceProperties.partitions.name(), partitionsToDisable)),
         MediaType.APPLICATION_JSON_TYPE);
-    post("clusters/" + CLUSTER_NAME + "/instances/" + INSTANCE_NAME,
-        ImmutableMap.of("command", "disablePartitions"), entity,
-        Response.Status.OK.getStatusCode());
+
+    new JerseyUriRequestBuilder("clusters/{}/instances/{}?command=disablePartitions")
+        .format(CLUSTER_NAME, INSTANCE_NAME).post(this, entity);
+
     InstanceConfig instanceConfig = _configAccessor.getInstanceConfig(CLUSTER_NAME, INSTANCE_NAME);
-    Assert.assertEquals(new HashSet<>(instanceConfig.getDisabledPartitionsMap()
+    Assert.assertEquals(
+        new HashSet<>(instanceConfig.getDisabledPartitionsMap()
             .get(CLUSTER_NAME + dbName.substring(0, dbName.length() - 1))),
         new HashSet<>(partitionsToDisable));
     entity = Entity.entity(OBJECT_MAPPER.writeValueAsString(ImmutableMap
@@ -258,8 +267,9 @@ public class TestInstanceAccessor extends AbstractTestClass {
             InstanceAccessor.InstanceProperties.partitions.name(),
             ImmutableList.of(CLUSTER_NAME + dbName + "1"))), MediaType.APPLICATION_JSON_TYPE);
 
-    post("clusters/" + CLUSTER_NAME + "/instances/" + INSTANCE_NAME,
-        ImmutableMap.of("command", "enablePartitions"), entity, Response.Status.OK.getStatusCode());
+    new JerseyUriRequestBuilder("clusters/{}/instances/{}?command=enablePartitions")
+        .format(CLUSTER_NAME, INSTANCE_NAME).post(this, entity);
+
     instanceConfig = _configAccessor.getInstanceConfig(CLUSTER_NAME, INSTANCE_NAME);
     Assert.assertEquals(new HashSet<>(instanceConfig.getDisabledPartitionsMap()
             .get(CLUSTER_NAME + dbName.substring(0, dbName.length() - 1))),
@@ -289,13 +299,12 @@ public class TestInstanceAccessor extends AbstractTestClass {
     // 1. Add these fields by way of "update"
     Entity entity =
         Entity.entity(OBJECT_MAPPER.writeValueAsString(record), MediaType.APPLICATION_JSON_TYPE);
-    post("clusters/" + CLUSTER_NAME + "/instances/" + instanceName + "/configs",
-        Collections.singletonMap("command", "update"), entity, Response.Status.OK.getStatusCode());
+    new JerseyUriRequestBuilder("clusters/{}/instances/{}/configs?command=update")
+        .format(CLUSTER_NAME, INSTANCE_NAME).post(this, entity);
 
     // Check that the fields have been added
-    Assert.assertEquals(record.getSimpleFields(),
-        _configAccessor.getInstanceConfig(CLUSTER_NAME, instanceName).getRecord()
-            .getSimpleFields());
+    Assert.assertEquals(record.getSimpleFields(), _configAccessor
+        .getInstanceConfig(CLUSTER_NAME, instanceName).getRecord().getSimpleFields());
     Assert.assertEquals(record.getListFields(),
         _configAccessor.getInstanceConfig(CLUSTER_NAME, instanceName).getRecord().getListFields());
     Assert.assertEquals(record.getMapFields(),
@@ -312,13 +321,12 @@ public class TestInstanceAccessor extends AbstractTestClass {
 
     entity =
         Entity.entity(OBJECT_MAPPER.writeValueAsString(record), MediaType.APPLICATION_JSON_TYPE);
-    post("clusters/" + CLUSTER_NAME + "/instances/" + instanceName + "/configs",
-        Collections.singletonMap("command", "update"), entity, Response.Status.OK.getStatusCode());
+    new JerseyUriRequestBuilder("clusters/{}/instances/{}/configs?command=update")
+        .format(CLUSTER_NAME, INSTANCE_NAME).post(this, entity);
 
     // Check that the fields have been modified
-    Assert.assertEquals(record.getSimpleFields(),
-        _configAccessor.getInstanceConfig(CLUSTER_NAME, instanceName).getRecord()
-            .getSimpleFields());
+    Assert.assertEquals(record.getSimpleFields(), _configAccessor
+        .getInstanceConfig(CLUSTER_NAME, instanceName).getRecord().getSimpleFields());
     Assert.assertEquals(record.getListFields(),
         _configAccessor.getInstanceConfig(CLUSTER_NAME, instanceName).getRecord().getListFields());
     Assert.assertEquals(record.getMapFields(),
@@ -347,8 +355,8 @@ public class TestInstanceAccessor extends AbstractTestClass {
     // First, add these fields by way of "update"
     Entity entity =
         Entity.entity(OBJECT_MAPPER.writeValueAsString(record), MediaType.APPLICATION_JSON_TYPE);
-    post("clusters/" + CLUSTER_NAME + "/instances/" + instanceName + "/configs",
-        Collections.singletonMap("command", "delete"), entity, Response.Status.OK.getStatusCode());
+    new JerseyUriRequestBuilder("clusters/{}/instances/{}/configs?command=delete")
+        .format(CLUSTER_NAME, INSTANCE_NAME).post(this, entity);
 
     // Check that the keys k1 and k2 have been deleted, and k0 remains
     for (int i = 0; i < 4; i++) {
@@ -388,7 +396,8 @@ public class TestInstanceAccessor extends AbstractTestClass {
 
     Entity entity =
         Entity.entity(OBJECT_MAPPER.writeValueAsString(record), MediaType.APPLICATION_JSON_TYPE);
-    post("clusters/" + CLUSTER_NAME + "/instances/" + instanceName + "/configs", null, entity,
-        Response.Status.NOT_FOUND.getStatusCode());
+    new JerseyUriRequestBuilder("clusters/{}/instances/{}/configs")
+        .expectedReturnStatusCode(Response.Status.NOT_FOUND.getStatusCode())
+        .format(CLUSTER_NAME, instanceName).post(this, entity);
   }
 }
diff --git a/helix-rest/src/test/java/org/apache/helix/rest/server/util/JerseyUriRequestBuilder.java b/helix-rest/src/test/java/org/apache/helix/rest/server/util/JerseyUriRequestBuilder.java
index b1d91ef..a8fde73 100644
--- a/helix-rest/src/test/java/org/apache/helix/rest/server/util/JerseyUriRequestBuilder.java
+++ b/helix-rest/src/test/java/org/apache/helix/rest/server/util/JerseyUriRequestBuilder.java
@@ -3,6 +3,7 @@ package org.apache.helix.rest.server.util;
 import java.util.HashMap;
 import java.util.Map;
 
+import javax.ws.rs.client.Entity;
 import javax.ws.rs.client.WebTarget;
 import javax.ws.rs.core.Response;
 
@@ -15,22 +16,32 @@ import com.google.common.base.Preconditions;
 import com.google.common.base.Splitter;
 
 
+/**
+ * Simplify the REST URI construction for Jersey Test Framework
+ * Example usage:
+ *  new JerseyUriRequestBuilder("clusters/{}/instances/{}?command=disable")
+ *         .format(CLUSTER_NAME, INSTANCE_NAME)
+ *         .post(...);
+ */
 public class JerseyUriRequestBuilder {
   private static final String PLACE_HOLDER = "{}";
 
   private final StringBuilder _uriBuilder;
   private final Map<String, String> _queryParams;
   private final int _requiredParameters;
-  private final String _query;
+  private final String _rawQuery;
+  // default expected status code and if body returned
+  private int _expectedStatusCode = Response.Status.OK.getStatusCode();
+  private boolean _isBodyReturnExpected = false;
 
   public JerseyUriRequestBuilder(String uri) {
     String[] uris = uri.split("\\?");
     if (uris.length > 1) {
       _queryParams = Splitter.on('&').trimResults().withKeyValueSeparator("=").split(uris[1]);
-      _query = uris[1];
+      _rawQuery = uris[1];
     } else {
       _queryParams = new HashMap<>();
-      _query = "";
+      _rawQuery = "";
     }
     _uriBuilder = new StringBuilder(uris[0]);
     _requiredParameters = StringUtils.countMatches(uris[0], PLACE_HOLDER);
@@ -46,55 +57,94 @@ public class JerseyUriRequestBuilder {
     return this;
   }
 
-  private WebTarget buildWebTarget(JerseyTestNg.ContainerPerClassTest container) {
-    WebTarget webTarget = container.target(_uriBuilder.toString());
-    for (Map.Entry<String, String> entry : _queryParams.entrySet()) {
-      webTarget = webTarget.queryParam(entry.getKey(), entry.getValue());
-    }
+  public JerseyUriRequestBuilder expectedReturnStatusCode(int expectedStatusCode) {
+    _expectedStatusCode = expectedStatusCode;
+    return this;
+  }
 
-    return webTarget;
+  public JerseyUriRequestBuilder isBodyReturnExpected(boolean isBodyReturnExpected) {
+    _isBodyReturnExpected = isBodyReturnExpected;
+    return this;
   }
 
-  public String get(JerseyTestNg.ContainerPerClassTest container, int expectedReturnStatus, boolean expectBodyReturned) {
+  /**
+   * Execute get request
+   * @param container
+   * @return
+   */
+  public String get(JerseyTestNg.ContainerPerClassTest container) {
     final Response response = buildWebTarget(container).request().get();
 
-    Assert.assertEquals(response.getStatus(), expectedReturnStatus);
+    Assert.assertEquals(response.getStatus(), _expectedStatusCode);
 
     // NOT_FOUND will throw text based html
-    if (expectedReturnStatus != Response.Status.NOT_FOUND.getStatusCode()) {
+    if (_expectedStatusCode != Response.Status.NOT_FOUND.getStatusCode()) {
       Assert.assertEquals(response.getMediaType().getType(), "application");
     } else {
       Assert.assertEquals(response.getMediaType().getType(), "text");
     }
 
     String body = response.readEntity(String.class);
-    if (expectBodyReturned) {
+    if (_isBodyReturnExpected) {
       Assert.assertNotNull(body);
     }
 
     return body;
   }
 
-  public String get(JerseyTestNg.ContainerPerClassTest container) {
-    final Response response = buildWebTarget(container).request().get();
+  /**
+   * Execute put request
+   * @param container
+   * @param entity
+   */
+  public void put(JerseyTestNg.ContainerPerClassTest container, Entity entity) {
+    final Response response = buildWebTarget(container).request().put(entity);
+    Assert.assertEquals(response.getStatus(), _expectedStatusCode);
+  }
+
+  /**
+   * Execute post request
+   * @param container
+   * @param entity
+   */
+  public void post(JerseyTestNg.ContainerPerClassTest container, Entity entity) {
+    final Response response = buildWebTarget(container).request().post(entity);
+    Assert.assertEquals(response.getStatus(), _expectedStatusCode);
+  }
+
+  /**
+   * Execute delete request
+   * @param container
+   */
+  public void delete(JerseyTestNg.ContainerPerClassTest container) {
+    final Response response = buildWebTarget(container).request().delete();
+    Assert.assertEquals(response.getStatus(), _expectedStatusCode);
+  }
+
+  private WebTarget buildWebTarget(JerseyTestNg.ContainerPerClassTest container) {
+    WebTarget webTarget = container.target(_uriBuilder.toString());
+    for (Map.Entry<String, String> entry : _queryParams.entrySet()) {
+      webTarget = webTarget.queryParam(entry.getKey(), entry.getValue());
+    }
 
-    return response.readEntity(String.class);
+    return webTarget;
   }
 
-  public String getPath() {
-    if (StringUtils.isEmpty(_query)) {
+  private String getPath() {
+    if (StringUtils.isEmpty(_rawQuery)) {
       return _uriBuilder.toString();
     } else {
-      return _uriBuilder.toString() + "?" + _query;
+      return _uriBuilder.toString() + "?" + _rawQuery;
     }
   }
 
   @Test
   public void testUriBuilderGetPath() {
-    JerseyUriRequestBuilder uriBuilder = new JerseyUriRequestBuilder("clusters/{}/instances/{}/messages?stateModelDef=MasterSlave")
+    JerseyUriRequestBuilder uriBuilder = new JerseyUriRequestBuilder("clusters/{}/instances/{}?command=disable")
         .format("TEST-CLUSTER", "instance1");
     String path = uriBuilder.getPath();
-    Assert.assertEquals(path, "clusters/TEST-CLUSTER/instances/instance1/messages?stateModelDef=MasterSlave");
-    Assert.assertEquals(uriBuilder._queryParams.get("stateModelDef"), "MasterSlave");
+    Assert.assertEquals(uriBuilder._uriBuilder.toString(), "clusters/TEST-CLUSTER/instances/instance1");
+    Assert.assertEquals(path, "clusters/TEST-CLUSTER/instances/instance1?command=disable");
+    Assert.assertEquals(uriBuilder._queryParams.get("command"), "disable");
   }
 }


[helix] 13/14: Fix node swap test.

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

hulee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/helix.git

commit 7f4044ffedc8a57ee4c635daf747352f1fcddc37
Author: Jiajun Wang <jj...@linkedin.com>
AuthorDate: Tue Nov 13 16:59:18 2018 -0800

    Fix node swap test.
    
    Add sleep to stablize the test. Several cluster operations require controller reaction before checking.
    
    RB=1484466
    G=helix-reviewers
    A=hrzhang
    
    Signed-off-by: Hunter Lee <hu...@linkedin.com>
---
 .../rebalancer/CrushRebalancers/TestNodeSwap.java   | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/helix-core/src/test/java/org/apache/helix/integration/rebalancer/CrushRebalancers/TestNodeSwap.java b/helix-core/src/test/java/org/apache/helix/integration/rebalancer/CrushRebalancers/TestNodeSwap.java
index 7275481..3d20f0a 100644
--- a/helix-core/src/test/java/org/apache/helix/integration/rebalancer/CrushRebalancers/TestNodeSwap.java
+++ b/helix-core/src/test/java/org/apache/helix/integration/rebalancer/CrushRebalancers/TestNodeSwap.java
@@ -28,6 +28,7 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.helix.ConfigAccessor;
+import org.apache.helix.TestHelper;
 import org.apache.helix.common.ZkTestBase;
 import org.apache.helix.controller.rebalancer.strategy.CrushEdRebalanceStrategy;
 import org.apache.helix.controller.rebalancer.strategy.CrushRebalanceStrategy;
@@ -39,7 +40,6 @@ import org.apache.helix.model.ClusterConfig;
 import org.apache.helix.model.ExternalView;
 import org.apache.helix.model.IdealState;
 import org.apache.helix.model.InstanceConfig;
-import org.apache.helix.model.Partition;
 import org.apache.helix.tools.ClusterVerifiers.HelixClusterVerifier;
 import org.apache.helix.tools.ClusterVerifiers.StrictMatchExternalViewVerifier;
 import org.testng.Assert;
@@ -143,7 +143,7 @@ public class TestNodeSwap extends ZkTestBase {
       _gSetupTool.rebalanceStorageCluster(CLUSTER_NAME, db, _replica);
       _allDBs.add(db);
     }
-    Thread.sleep(300);
+    Thread.sleep(1000);
 
     HelixClusterVerifier _clusterVerifier =
         new StrictMatchExternalViewVerifier.Builder(CLUSTER_NAME).setZkAddr(ZK_ADDR)
@@ -151,7 +151,6 @@ public class TestNodeSwap extends ZkTestBase {
     Assert.assertTrue(_clusterVerifier.verify(5000));
 
     Map<String, ExternalView> record = new HashMap<>();
-
     for (String db : _allDBs) {
       record.put(db,
           _gSetupTool.getClusterManagementTool().getResourceExternalView(CLUSTER_NAME, db));
@@ -163,14 +162,17 @@ public class TestNodeSwap extends ZkTestBase {
     // 1. disable and remove an old node
     MockParticipantManager oldParticipant = _participants.get(0);
     String oldParticipantName = oldParticipant.getInstanceName();
-    oldParticipant.syncStop();
-    InstanceConfig instanceConfig =
+
+    final InstanceConfig instanceConfig =
         _gSetupTool.getClusterManagementTool().getInstanceConfig(CLUSTER_NAME, oldParticipantName);
     // disable the node first
     instanceConfig.setInstanceEnabled(false);
     _gSetupTool.getClusterManagementTool().setInstanceConfig(CLUSTER_NAME, oldParticipantName, instanceConfig);
     Assert.assertTrue(_clusterVerifier.verify(10000));
+
     // then remove it from topology
+    oldParticipant.syncStop();
+    Thread.sleep(2000);
     _gSetupTool.getClusterManagementTool().dropInstance(CLUSTER_NAME, instanceConfig);
 
     // 2. create new participant with same topology
@@ -186,8 +188,11 @@ public class TestNodeSwap extends ZkTestBase {
         new MockParticipantManager(ZK_ADDR, CLUSTER_NAME, newParticipantName);
     participant.syncStart();
     _participants.add(0, participant);
-    Thread.sleep(300);
+    Thread.sleep(2000);
 
+    _clusterVerifier =
+        new StrictMatchExternalViewVerifier.Builder(CLUSTER_NAME).setZkAddr(ZK_ADDR)
+            .setResources(_allDBs).build();
     Assert.assertTrue(_clusterVerifier.verify(5000));
 
     for (String db : _allDBs) {
@@ -203,9 +208,7 @@ public class TestNodeSwap extends ZkTestBase {
           if (instance.equals(newParticipantName)) {
             topoName = oldParticipantName;
           }
-          if (!stateMap.get(instance).equals(oldStateMap.get(topoName))) {
-            Assert.fail("test");
-          }
+          Assert.assertEquals(stateMap.get(instance), oldStateMap.get(topoName));
         }
       }
     }


[helix] 01/14: Migrate Helix to Java 8

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

hulee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/helix.git

commit ca36fbfa3c59f6dc0eec31f312f103749874f7c0
Author: Hunter Lee <hu...@linkedin.com>
AuthorDate: Fri Mar 29 11:56:13 2019 -0700

    Migrate Helix to Java 8
    
    This diff migrates the project to JDK1.8. This diff does not change any functionalities/core logic. It contains a few style changes and redundant code changes.
    Changelist:
    1. Change to Java 8
    2. Upgrade dependencies in pom.xml
    
    RB=1613418
    BUG=HELIX-1742
    G=helix-reviewers
    A=jxue
    
    Signed-off-by: Hunter Lee <hu...@linkedin.com>
---
 .../stages/TestClusterEventBlockingQueue.java      |   4 +-
 .../helix/integration/task/TestTaskRebalancer.java |   2 +-
 pom.xml                                            | 161 +++++++++++----------
 3 files changed, 88 insertions(+), 79 deletions(-)

diff --git a/helix-core/src/test/java/org/apache/helix/controller/stages/TestClusterEventBlockingQueue.java b/helix-core/src/test/java/org/apache/helix/controller/stages/TestClusterEventBlockingQueue.java
index fc7177a..b38572d 100644
--- a/helix-core/src/test/java/org/apache/helix/controller/stages/TestClusterEventBlockingQueue.java
+++ b/helix-core/src/test/java/org/apache/helix/controller/stages/TestClusterEventBlockingQueue.java
@@ -60,7 +60,7 @@ public class TestClusterEventBlockingQueue {
     // test peek
     ClusterEvent peeked = queue.peek();
     Assert.assertEquals(peeked.getEventType(), ClusterEventType.IdealStateChange);
-    Assert.assertEquals(peeked.getAttribute("attr"), 1);
+    Assert.assertEquals((int) peeked.getAttribute("attr"), 1);
     Assert.assertEquals(queue.size(), 2);
 
     // test take the head
@@ -68,7 +68,7 @@ public class TestClusterEventBlockingQueue {
         MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
     ClusterEvent takenEvent1 = safeTake(queue, service);
     Assert.assertEquals(takenEvent1.getEventType(), ClusterEventType.IdealStateChange);
-    Assert.assertEquals(takenEvent1.getAttribute("attr"), 1);
+    Assert.assertEquals((int) takenEvent1.getAttribute("attr"), 1);
     Assert.assertEquals(queue.size(), 1);
 
     // test take the tail
diff --git a/helix-core/src/test/java/org/apache/helix/integration/task/TestTaskRebalancer.java b/helix-core/src/test/java/org/apache/helix/integration/task/TestTaskRebalancer.java
index 6d4f03b..e12b4a9 100644
--- a/helix-core/src/test/java/org/apache/helix/integration/task/TestTaskRebalancer.java
+++ b/helix-core/src/test/java/org/apache/helix/integration/task/TestTaskRebalancer.java
@@ -88,7 +88,7 @@ public class TestTaskRebalancer extends TaskTestBase {
     // Ensure workflow config and context were cleaned up by now
     Assert.assertFalse(_manager.getHelixPropertyStore().exists(workflowPropStoreKey,
         AccessOption.PERSISTENT));
-    Assert.assertEquals(accessor.getProperty(workflowCfgKey), null);
+    Assert.assertNull(accessor.getProperty(workflowCfgKey));
   }
 
   private void basic(long jobCompletionTime) throws Exception {
diff --git a/pom.xml b/pom.xml
index 20fc309..8481470 100644
--- a/pom.xml
+++ b/pom.xml
@@ -237,6 +237,15 @@ under the License.
       </roles>
       <timezone>-8</timezone>
     </developer>
+    <developer>
+      <id>hulee</id>
+      <name>Hunter Lee</name>
+      <email>hulee@apache.org</email>
+      <roles>
+        <role>Committer</role>
+      </roles>
+      <timezone>-8</timezone>
+    </developer>
   </developers>
   <modules>
     <module>helix-core</module>
@@ -338,8 +347,8 @@ under the License.
 
     <sonar.host.url>https://analysis.apache.org/</sonar.host.url>
 
-    <maven-scm-provider-svnjava.version>2.0.5</maven-scm-provider-svnjava.version>
-    <svnkit.version>1.7.5-v1</svnkit.version>
+    <maven-scm-provider-svnjava.version>3.0.0</maven-scm-provider-svnjava.version>
+    <svnkit.version>1.10.0</svnkit.version>
 
     <helix.siteFilePath>${user.home}/helix-site/helix-site-deploy</helix.siteFilePath>
     <!-- you can use javasvn too -->
@@ -421,10 +430,10 @@ under the License.
         <version>${project.version}</version>
       </dependency>
       <dependency>
-         <groupId>org.apache.helix</groupId>
-         <artifactId>helix-core</artifactId>
-         <type>test-jar</type>
-         <version>${project.version}</version>
+        <groupId>org.apache.helix</groupId>
+        <artifactId>helix-core</artifactId>
+        <type>test-jar</type>
+        <version>${project.version}</version>
       </dependency>
       <dependency>
         <groupId>junit</groupId>
@@ -454,8 +463,8 @@ under the License.
           <artifactId>maven-compiler-plugin</artifactId>
           <version>2.5.1</version>
           <configuration>
-            <source>1.7</source>
-            <target>1.7</target>
+            <source>1.8</source>
+            <target>1.8</target>
           </configuration>
         </plugin>
         <plugin>
@@ -582,14 +591,14 @@ under the License.
           </dependencies>
         </plugin>
         <plugin>
-           <groupId>org.apache.maven.plugins</groupId>
-           <artifactId>maven-surefire-plugin</artifactId>
-           <version>2.14</version>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-surefire-plugin</artifactId>
+          <version>2.14</version>
         </plugin>
         <plugin>
-           <groupId>org.apache.rat</groupId>
-           <artifactId>apache-rat-plugin</artifactId>
-           <version>0.8</version>
+          <groupId>org.apache.rat</groupId>
+          <artifactId>apache-rat-plugin</artifactId>
+          <version>0.8</version>
         </plugin>
       </plugins>
     </pluginManagement>
@@ -614,7 +623,7 @@ under the License.
       <plugin>
         <groupId>org.apache.felix</groupId>
         <artifactId>maven-bundle-plugin</artifactId>
-        <version>2.3.7</version>
+        <version>3.5.0</version>
         <inherited>true</inherited>
         <extensions>true</extensions>
         <configuration>
@@ -653,42 +662,42 @@ under the License.
         <artifactId>maven-source-plugin</artifactId>
       </plugin>
       <plugin>
-         <groupId>org.apache.maven.plugins</groupId>
-         <artifactId>maven-surefire-plugin</artifactId>
-         <!--
-               Configuration for unit/integration tests section 2 of 3 (plugins) STARTS HERE.
-               This is the core piece for being able to manage unit tests and
-               integration (='system') tests within Maven by using surefire.
-               See also: properties section and profiles section.
-         -->
-         <configuration>
-            <argLine>-Xms1024m -Xmx1024m</argLine>
-            <suiteXmlFiles>
-               <suiteXmlFile>src/test/conf/testng.xml</suiteXmlFile>
-            </suiteXmlFiles>
-            <excludes>
-               <exclude>**/integration/**</exclude>
-            </excludes>
-         </configuration>
-         <executions>
-            <execution>
-               <id>integration-tests</id>
-               <phase>integration-test</phase>
-               <goals>
-                  <goal>test</goal>
-               </goals>
-               <configuration>
-                  <skip>${SKIP_INTEGRATION_TESTS}</skip>
-                  <excludes>
-                     <exclude>none</exclude>
-                  </excludes>
-                  <includes>
-                     <include>**/integration/**</include>
-                  </includes>
-               </configuration>
-            </execution>
-         </executions>
-         <!--  Configuration for unit/integration tests section 2 of 3 (plugins) ENDS HERE. -->
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <!--
+              Configuration for unit/integration tests section 2 of 3 (plugins) STARTS HERE.
+              This is the core piece for being able to manage unit tests and
+              integration (='system') tests within Maven by using surefire.
+              See also: properties section and profiles section.
+        -->
+        <configuration>
+          <argLine>-Xms1024m -Xmx1024m</argLine>
+          <suiteXmlFiles>
+            <suiteXmlFile>src/test/conf/testng.xml</suiteXmlFile>
+          </suiteXmlFiles>
+          <excludes>
+            <exclude>**/integration/**</exclude>
+          </excludes>
+        </configuration>
+        <executions>
+          <execution>
+            <id>integration-tests</id>
+            <phase>integration-test</phase>
+            <goals>
+              <goal>test</goal>
+            </goals>
+            <configuration>
+              <skip>${SKIP_INTEGRATION_TESTS}</skip>
+              <excludes>
+                <exclude>none</exclude>
+              </excludes>
+              <includes>
+                <include>**/integration/**</include>
+              </includes>
+            </configuration>
+          </execution>
+        </executions>
+        <!--  Configuration for unit/integration tests section 2 of 3 (plugins) ENDS HERE. -->
       </plugin>
     </plugins>
   </build>
@@ -697,7 +706,7 @@ under the License.
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-changes-plugin</artifactId>
-        <version>2.8</version>
+        <version>2.12.1</version>
         <inherited>false</inherited>
         <configuration>
           <columnNames>Type,Fix Version,Key,Summary,Assignee,Status,Created</columnNames>
@@ -719,7 +728,7 @@ under the License.
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-jxr-plugin</artifactId>
-        <version>2.3</version>
+        <version>3.0.0</version>
         <configuration>
           <aggregate>true</aggregate>
         </configuration>
@@ -727,7 +736,7 @@ under the License.
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-project-info-reports-plugin</artifactId>
-        <version>2.7</version>
+        <version>3.0.0</version>
       </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
@@ -771,7 +780,7 @@ under the License.
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-checkstyle-plugin</artifactId>
-        <version>2.9.1</version>
+        <version>3.0.0</version>
         <inherited>false</inherited>
         <reportSets>
           <reportSet>
@@ -836,26 +845,26 @@ under the License.
         </plugins>
       </build>
     </profile>
-      <!--
-      Configuration for unit/integration tests section 3 of 3 (profiles) STARTS HERE.
-      Use the following profile to run Integration tests. From the command line:
-      mvn clean install -P integration-test
-      or:
-      mvn integration-test -P integration-test
-      * Note that if you do: 'mvn test -P integration-test'
-      integration tests will not run, because the test phase is before the
-      integration phase in the default maven lifecycle.
-      * Also note that unit tests will also be run when integration tests are
-      run, because the integration-test phase is always after the test phase
-      in the default Maven lifecycle.
-      See also: surefire plugin section and properties section.
-      -->
-      <profile>
-         <id>integration-test</id>
-         <properties>
-            <SKIP_INTEGRATION_TESTS>false</SKIP_INTEGRATION_TESTS>
-         </properties>
-      </profile>
-      <!-- Configuration for unit/integration tests section 3 of 3 (profiles) ENDS HERE.-->
+    <!--
+    Configuration for unit/integration tests section 3 of 3 (profiles) STARTS HERE.
+    Use the following profile to run Integration tests. From the command line:
+    mvn clean install -P integration-test
+    or:
+    mvn integration-test -P integration-test
+    * Note that if you do: 'mvn test -P integration-test'
+    integration tests will not run, because the test phase is before the
+    integration phase in the default maven lifecycle.
+    * Also note that unit tests will also be run when integration tests are
+    run, because the integration-test phase is always after the test phase
+    in the default Maven lifecycle.
+    See also: surefire plugin section and properties section.
+    -->
+    <profile>
+      <id>integration-test</id>
+      <properties>
+        <SKIP_INTEGRATION_TESTS>false</SKIP_INTEGRATION_TESTS>
+      </properties>
+    </profile>
+    <!-- Configuration for unit/integration tests section 3 of 3 (profiles) ENDS HERE.-->
   </profiles>
 </project>


[helix] 10/14: Fix helix-ui build failure due to wrong config reference

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

hulee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/helix.git

commit efd74f27e65ae6911e28762b23837a7d457e2a70
Author: Yi Wang <yw...@linkedin.com>
AuthorDate: Tue Mar 12 12:47:04 2019 -0700

    Fix helix-ui build failure due to wrong config reference
    
    RB=1592781
    G=helix-reviewers
    A=lxia,hulee
    
    Signed-off-by: Hunter Lee <hu...@linkedin.com>
---
 helix-front/client/app/app.component.ts | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/helix-front/client/app/app.component.ts b/helix-front/client/app/app.component.ts
index 4c691ae..1b31f6c 100644
--- a/helix-front/client/app/app.component.ts
+++ b/helix-front/client/app/app.component.ts
@@ -14,7 +14,6 @@ import { Angulartics2Piwik } from 'angulartics2';
 import { UserService } from './core/user.service';
 import { InputDialogComponent } from './shared/dialog/input-dialog/input-dialog.component';
 import { HelperService } from './shared/helper.service';
-import {LDAP} from "../../server/config";
 
 @Component({
   selector: 'hi-root',
@@ -88,7 +87,7 @@ export class AppComponent implements OnInit {
             .subscribe(
               isAuthorized => {
                 if (!isAuthorized) {
-                  this.helper.showError("You're not part of " + LDAP.adminGroup + " group or password incorrect");
+                  this.helper.showError("You're not part of helix-admin group or password incorrect");
                 }
                 this.currentUser = this.service.getCurrentUser();
               },


[helix] 03/14: TASK: Fix possible NPE in getWorkflowId()

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

hulee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/helix.git

commit f61cbadd3ecb8461dc3001e6bd47b43382d68c19
Author: Hunter Lee <hu...@linkedin.com>
AuthorDate: Tue Apr 2 18:09:03 2019 -0700

    TASK: Fix possible NPE in getWorkflowId()
    
    Old workflows may not have WorkflowID field set. This makes getWorkflowId() backward-compatible by falling back on its ZNRecord id instead.
    
    RB=1617517
    G=helix-reviewers
    A=jxue
    
    Signed-off-by: Hunter Lee <hu...@linkedin.com>
---
 helix-core/src/main/java/org/apache/helix/task/WorkflowConfig.java | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/helix-core/src/main/java/org/apache/helix/task/WorkflowConfig.java b/helix-core/src/main/java/org/apache/helix/task/WorkflowConfig.java
index 6136175..9f98f6b 100644
--- a/helix-core/src/main/java/org/apache/helix/task/WorkflowConfig.java
+++ b/helix-core/src/main/java/org/apache/helix/task/WorkflowConfig.java
@@ -154,7 +154,8 @@ public class WorkflowConfig extends ResourceConfig {
   }
 
   public String getWorkflowId() {
-    return getSimpleConfig(WorkflowConfigProperty.WorkflowID.name());
+    String workflowId = getSimpleConfig(WorkflowConfigProperty.WorkflowID.name());
+    return workflowId != null ? workflowId : getId();
   }
 
   public JobDag getJobDag() {


[helix] 14/14: Interface design for zone mapping information

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

hulee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/helix.git

commit aebb0cfed286819029875ad60e102851d8d53cf5
Author: Yi Wang <yw...@linkedin.com>
AuthorDate: Tue Mar 19 14:16:16 2019 -0700

    Interface design for zone mapping information
    
    RB=1578905
    BUG=helix-1646
    G=helix-reviewers
    A=jxue
    
    Signed-off-by: Hunter Lee <hu...@linkedin.com>
---
 .../controller/rebalancer/topology/Topology.java   |  2 +-
 .../org/apache/helix/model/InstanceConfig.java     | 19 ++++-
 .../TestConstraintRebalanceStrategy.java           |  2 +-
 .../rebalancer/CrushRebalancers/TestNodeSwap.java  |  3 +-
 .../org/apache/helix/model/TestInstanceConfig.java | 22 ++++++
 helix-rest/pom.xml                                 | 10 +++
 .../rest/server/json/cluster/ClusterInfo.java      | 80 ++++++++++++++++++++++
 .../rest/server/json/cluster/ClusterTopology.java  | 76 ++++++++++++++++++++
 .../helix/rest/server/service/ClusterService.java  | 25 +++++++
 .../rest/server/json/cluster/TestClusterInfo.java  | 27 ++++++++
 .../server/json/cluster/TestClusterTopology.java   | 29 ++++++++
 11 files changed, 290 insertions(+), 5 deletions(-)

diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/topology/Topology.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/topology/Topology.java
index f5b6141..505052e 100644
--- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/topology/Topology.java
+++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/topology/Topology.java
@@ -270,7 +270,7 @@ public class Topology {
 
     for (String ins : _allInstances) {
       InstanceConfig insConfig = _instanceConfigMap.get(ins);
-      String domain = insConfig.getDomain();
+      String domain = insConfig.getDomainAsString();
       if (domain == null) {
         if (insConfig.getInstanceEnabled() && (_clusterConfig.getDisabledInstances() == null
             || !_clusterConfig.getDisabledInstances().containsKey(ins))) {
diff --git a/helix-core/src/main/java/org/apache/helix/model/InstanceConfig.java b/helix-core/src/main/java/org/apache/helix/model/InstanceConfig.java
index 3cc3c58..74ba9d7 100644
--- a/helix-core/src/main/java/org/apache/helix/model/InstanceConfig.java
+++ b/helix-core/src/main/java/org/apache/helix/model/InstanceConfig.java
@@ -35,6 +35,8 @@ import org.apache.helix.util.HelixUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Splitter;
+
 /**
  * Instance configurations
  */
@@ -55,6 +57,7 @@ public class InstanceConfig extends HelixProperty {
     DELAY_REBALANCE_ENABLED,
     MAX_CONCURRENT_TASK
   }
+
   public static final int WEIGHT_NOT_SET = -1;
   public static final int MAX_CONCURRENT_TASK_NOT_SET = -1;
 
@@ -126,11 +129,25 @@ public class InstanceConfig extends HelixProperty {
    * Domain represents a hierarchy identifier for an instance.
    * @return
    */
-  public String getDomain() {
+  public String getDomainAsString() {
     return _record.getSimpleField(InstanceConfigProperty.DOMAIN.name());
   }
 
   /**
+   * Parse the key value pairs of domain and return a map structure
+   * @return
+   */
+  public Map<String, String> getDomainAsMap() {
+    String domain = getDomainAsString();
+    if (domain == null || domain.isEmpty()) {
+      return Collections.emptyMap();
+    }
+
+    return Splitter.on(',').trimResults()
+        .withKeyValueSeparator(Splitter.on('=').limit(2).trimResults()).split(domain);
+  }
+
+  /**
    * Domain represents a hierarchy identifier for an instance.
    * Example:  "cluster=myCluster,zone=myZone1,rack=myRack,host=hostname,instance=instance001".
    * @return
diff --git a/helix-core/src/test/java/org/apache/helix/controller/rebalancer/TestConstraintRebalanceStrategy.java b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/TestConstraintRebalanceStrategy.java
index cb4bb75..a9e53f8 100644
--- a/helix-core/src/test/java/org/apache/helix/controller/rebalancer/TestConstraintRebalanceStrategy.java
+++ b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/TestConstraintRebalanceStrategy.java
@@ -447,7 +447,7 @@ public class TestConstraintRebalanceStrategy {
       domainPartitionMap.clear();
       for (String partition : partitionMap.keySet()) {
         for (String instance : partitionMap.get(partition).keySet()) {
-          String domain = instanceConfigs.get(instance).getDomain().split(",")[0].split("=")[1];
+          String domain = instanceConfigs.get(instance).getDomainAsString().split(",")[0].split("=")[1];
           if (domainPartitionMap.containsKey(domain)) {
             Assert.assertFalse(domainPartitionMap.get(domain).contains(partition));
           } else {
diff --git a/helix-core/src/test/java/org/apache/helix/integration/rebalancer/CrushRebalancers/TestNodeSwap.java b/helix-core/src/test/java/org/apache/helix/integration/rebalancer/CrushRebalancers/TestNodeSwap.java
index 3d20f0a..61e4d55 100644
--- a/helix-core/src/test/java/org/apache/helix/integration/rebalancer/CrushRebalancers/TestNodeSwap.java
+++ b/helix-core/src/test/java/org/apache/helix/integration/rebalancer/CrushRebalancers/TestNodeSwap.java
@@ -28,7 +28,6 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.helix.ConfigAccessor;
-import org.apache.helix.TestHelper;
 import org.apache.helix.common.ZkTestBase;
 import org.apache.helix.controller.rebalancer.strategy.CrushEdRebalanceStrategy;
 import org.apache.helix.controller.rebalancer.strategy.CrushRebalanceStrategy;
@@ -180,7 +179,7 @@ public class TestNodeSwap extends ZkTestBase {
     _gSetupTool.addInstanceToCluster(CLUSTER_NAME, newParticipantName);
     InstanceConfig newConfig =
         configAccessor.getInstanceConfig(CLUSTER_NAME, newParticipantName);
-    newConfig.setDomain(instanceConfig.getDomain());
+    newConfig.setDomain(instanceConfig.getDomainAsString());
     _gSetupTool.getClusterManagementTool()
         .setInstanceConfig(CLUSTER_NAME, newParticipantName, newConfig);
 
diff --git a/helix-core/src/test/java/org/apache/helix/model/TestInstanceConfig.java b/helix-core/src/test/java/org/apache/helix/model/TestInstanceConfig.java
index 69a3d9f..38b1c92 100644
--- a/helix-core/src/test/java/org/apache/helix/model/TestInstanceConfig.java
+++ b/helix-core/src/test/java/org/apache/helix/model/TestInstanceConfig.java
@@ -19,9 +19,13 @@ package org.apache.helix.model;
  * under the License.
  */
 
+import java.util.Map;
+
+import org.apache.helix.ZNRecord;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
+
 /**
  * Created with IntelliJ IDEA.
  * User: zzhang
@@ -36,4 +40,22 @@ public class TestInstanceConfig {
     Assert.assertTrue(config.isValid(),
         "HELIX-65: should not check host/port existence for instance-config");
   }
+
+  @Test
+  public void testGetParsedDomain() {
+    InstanceConfig instanceConfig = new InstanceConfig(new ZNRecord("id"));
+    instanceConfig.setDomain("cluster=myCluster,zone=myZone1,rack=myRack,host=hostname,instance=instance001");
+
+    Map<String, String> parsedDomain = instanceConfig.getDomainAsMap();
+    Assert.assertEquals(parsedDomain.size(), 5);
+    Assert.assertEquals(parsedDomain.get("zone"), "myZone1");
+  }
+
+  @Test
+  public void testGetParsedDomain_emptyDomain() {
+    InstanceConfig instanceConfig = new InstanceConfig(new ZNRecord("id"));
+
+    Map<String, String> parsedDomain = instanceConfig.getDomainAsMap();
+    Assert.assertTrue(parsedDomain.isEmpty());
+  }
 }
diff --git a/helix-rest/pom.xml b/helix-rest/pom.xml
index c3e9403..01eda64 100644
--- a/helix-rest/pom.xml
+++ b/helix-rest/pom.xml
@@ -122,6 +122,16 @@ under the License.
       <version>1.8.5</version>
     </dependency>
     <dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-annotations</artifactId>
+      <version>2.9.5</version>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-databind</artifactId>
+      <version>2.9.5</version>
+    </dependency>
+    <dependency>
       <groupId>commons-cli</groupId>
       <artifactId>commons-cli</artifactId>
       <version>1.2</version>
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/json/cluster/ClusterInfo.java b/helix-rest/src/main/java/org/apache/helix/rest/server/json/cluster/ClusterInfo.java
new file mode 100644
index 0000000..ac1831f
--- /dev/null
+++ b/helix-rest/src/main/java/org/apache/helix/rest/server/json/cluster/ClusterInfo.java
@@ -0,0 +1,80 @@
+package org.apache.helix.rest.server.json.cluster;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.List;
+
+
+public class ClusterInfo {
+  @JsonProperty("id")
+  private final String id;
+  @JsonProperty("controller")
+  private final String controller;
+  @JsonProperty("paused")
+  private final boolean paused;
+  @JsonProperty("maintenance")
+  private final boolean maintenance;
+  @JsonProperty("resources")
+  private final List<String> idealStates;
+  @JsonProperty("instances")
+  private final List<String> instances;
+  @JsonProperty("liveInstances")
+  private final List<String> liveInstances;
+
+  private ClusterInfo(Builder builder) {
+    id = builder.id;
+    controller = builder.controller;
+    paused = builder.paused;
+    maintenance = builder.maintenance;
+    idealStates = builder.idealStates;
+    instances = builder.instances;
+    liveInstances = builder.liveInstances;
+  }
+
+  public static final class Builder {
+    private String id;
+    private String controller;
+    private boolean paused;
+    private boolean maintenance;
+    private List<String> idealStates;
+    private List<String> instances;
+    private List<String> liveInstances;
+
+    public Builder(String id) {
+      this.id = id;
+    }
+
+    public Builder controller(String controller) {
+      this.controller = controller;
+      return this;
+    }
+
+    public Builder paused(boolean paused) {
+      this.paused = paused;
+      return this;
+    }
+
+    public Builder maintenance(boolean maintenance) {
+      this.maintenance = maintenance;
+      return this;
+    }
+
+    public Builder idealStates(List<String> idealStates) {
+      this.idealStates = idealStates;
+      return this;
+    }
+
+    public Builder instances(List<String> instances) {
+      this.instances = instances;
+      return this;
+    }
+
+    public Builder liveInstances(List<String> liveInstances) {
+      this.liveInstances = liveInstances;
+      return this;
+    }
+
+    public ClusterInfo build() {
+      return new ClusterInfo(this);
+    }
+  }
+}
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/json/cluster/ClusterTopology.java b/helix-rest/src/main/java/org/apache/helix/rest/server/json/cluster/ClusterTopology.java
new file mode 100644
index 0000000..a04f65f
--- /dev/null
+++ b/helix-rest/src/main/java/org/apache/helix/rest/server/json/cluster/ClusterTopology.java
@@ -0,0 +1,76 @@
+package org.apache.helix.rest.server.json.cluster;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+
+/**
+ * POJO class that can be easily convert to JSON object
+ * The Cluster Topology represents the hierarchy of the cluster:
+ * Cluster
+ * - Zone
+ * -- Rack
+ * --- Instance
+ * ---- Partition
+ * Each layer consists its id and metadata
+ */
+public class ClusterTopology {
+  @JsonProperty("id")
+  private final String clusterId;
+  @JsonProperty("zones")
+  private List<Zone> zones;
+
+  public ClusterTopology(String clusterId, List<Zone> zones) {
+    this.clusterId = clusterId;
+    this.zones = zones;
+  }
+
+  public static final class Zone {
+    @JsonProperty("id")
+    private final String id;
+    @JsonProperty("instances")
+    private List<Instance> instances;
+
+    public Zone(String id) {
+      this.id = id;
+    }
+
+    public Zone(String id, List<Instance> instances) {
+      this.id = id;
+      this.instances = instances;
+    }
+
+    public List<Instance> getInstances() {
+      return instances;
+    }
+
+    public void setInstances(List<Instance> instances) {
+      this.instances = instances;
+    }
+  }
+
+  public static final class Instance {
+    @JsonProperty("id")
+    private final String id;
+    @JsonProperty("partitions")
+    private List<String> partitions;
+
+    public Instance(String id) {
+      this.id = id;
+    }
+
+    public Instance(String id, List<String> partitions) {
+      this.id = id;
+      this.partitions = partitions;
+    }
+
+    public List<String> getPartitions() {
+      return partitions;
+    }
+
+    public void setPartitions(List<String> partitions) {
+      this.partitions = partitions;
+    }
+  }
+}
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/service/ClusterService.java b/helix-rest/src/main/java/org/apache/helix/rest/server/service/ClusterService.java
new file mode 100644
index 0000000..7234099
--- /dev/null
+++ b/helix-rest/src/main/java/org/apache/helix/rest/server/service/ClusterService.java
@@ -0,0 +1,25 @@
+package org.apache.helix.rest.server.service;
+
+import org.apache.helix.rest.server.json.cluster.ClusterInfo;
+import org.apache.helix.rest.server.json.cluster.ClusterTopology;
+
+
+/**
+ * A rest wrapper service that provides information about cluster
+ * TODO add more business logic and simplify the workload on ClusterAccessor
+ */
+public interface ClusterService {
+  /**
+   * Get cluster topology
+   * @param cluster
+   * @return
+   */
+  ClusterTopology getClusterTopology(String cluster);
+
+  /**
+   * Get cluster basic information
+   * @param clusterId
+   * @return
+   */
+  ClusterInfo getClusterInfo(String clusterId);
+}
diff --git a/helix-rest/src/test/java/org/apache/helix/rest/server/json/cluster/TestClusterInfo.java b/helix-rest/src/test/java/org/apache/helix/rest/server/json/cluster/TestClusterInfo.java
new file mode 100644
index 0000000..1b89ec8
--- /dev/null
+++ b/helix-rest/src/test/java/org/apache/helix/rest/server/json/cluster/TestClusterInfo.java
@@ -0,0 +1,27 @@
+package org.apache.helix.rest.server.json.cluster;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.ImmutableList;
+
+public class TestClusterInfo {
+  @Test
+  public void whenSerializingClusterInfo() throws JsonProcessingException {
+    ClusterInfo clusterInfo = new ClusterInfo.Builder("cluster0")
+        .controller("controller")
+        .idealStates(ImmutableList.of("idealState0"))
+        .instances(ImmutableList.of("instance0"))
+        .maintenance(true)
+        .paused(true)
+        .liveInstances(ImmutableList.of("instance0"))
+        .build();
+    ObjectMapper mapper = new ObjectMapper();
+    String result = mapper.writeValueAsString(clusterInfo);
+
+    Assert.assertEquals(result,
+        "{\"id\":\"cluster0\",\"controller\":\"controller\",\"paused\":true,\"maintenance\":true,\"resources\":[\"idealState0\"],\"instances\":[\"instance0\"],\"liveInstances\":[\"instance0\"]}");
+  }
+}
diff --git a/helix-rest/src/test/java/org/apache/helix/rest/server/json/cluster/TestClusterTopology.java b/helix-rest/src/test/java/org/apache/helix/rest/server/json/cluster/TestClusterTopology.java
new file mode 100644
index 0000000..a2b90fe
--- /dev/null
+++ b/helix-rest/src/test/java/org/apache/helix/rest/server/json/cluster/TestClusterTopology.java
@@ -0,0 +1,29 @@
+package org.apache.helix.rest.server.json.cluster;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.ImmutableList;
+
+public class TestClusterTopology {
+
+  @Test
+  public void whenSerializingClusterTopology() throws IOException {
+    List<String> partitions = ImmutableList.of("db0", "db1");
+    List<ClusterTopology.Instance> instances =
+        ImmutableList.of(new ClusterTopology.Instance("instance", partitions));
+
+    List<ClusterTopology.Zone> zones = ImmutableList.of(new ClusterTopology.Zone("zone", instances));
+
+    ClusterTopology clusterTopology = new ClusterTopology("cluster0", zones);
+    ObjectMapper mapper = new ObjectMapper();
+    String result = mapper.writeValueAsString(clusterTopology);
+
+    Assert.assertEquals(result,
+        "{\"id\":\"cluster0\",\"zones\":[{\"id\":\"zone\",\"instances\":[{\"id\":\"instance\",\"partitions\":[\"db0\",\"db1\"]}]}]}");
+  }
+}


[helix] 02/14: TASK: Fix cleanupQueue() API

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

hulee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/helix.git

commit 870cf7cd824efbcd6e01a975e7f5bf6b5c6470d8
Author: Hunter Lee <hu...@linkedin.com>
AuthorDate: Tue Apr 2 14:17:23 2019 -0700

    TASK: Fix cleanupQueue() API
    
    This API is meant for JobQueues only. However, it was checking only using isTerminable(), which is a deprecated flag for whether a workflow is a queue or not.
    
    Changelist:
    1. Add isJobQueue() check in cleanupQueue() in TaskDriver
    
    RB=1616870
    G=helix-reviewers
    A=jxue
    
    Signed-off-by: Hunter Lee <hu...@linkedin.com>
---
 helix-core/src/main/java/org/apache/helix/task/TaskDriver.java | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/helix-core/src/main/java/org/apache/helix/task/TaskDriver.java b/helix-core/src/main/java/org/apache/helix/task/TaskDriver.java
index f31c68b..c8921d8 100644
--- a/helix-core/src/main/java/org/apache/helix/task/TaskDriver.java
+++ b/helix-core/src/main/java/org/apache/helix/task/TaskDriver.java
@@ -517,7 +517,6 @@ public class TaskDriver {
   /**
    * Remove all jobs that are in final states (ABORTED, FAILED, COMPLETED) from the job queue. The
    * job config, job context will be removed from Zookeeper.
-   *
    * @param queue The name of job queue
    */
   public void cleanupQueue(String queue) {
@@ -527,8 +526,7 @@ public class TaskDriver {
       throw new IllegalArgumentException("Queue " + queue + " does not yet exist!");
     }
 
-    boolean isTerminable = workflowConfig.isTerminable();
-    if (isTerminable) {
+    if (!workflowConfig.isJobQueue() || workflowConfig.isTerminable()) {
       throw new IllegalArgumentException(queue + " is not a queue!");
     }
 


[helix] 04/14: TASK: Make isJobQueue backward compatible

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

hulee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/helix.git

commit 5e6a9fff8457c6c58816be39ee4479b0da3a045d
Author: Hunter Lee <hu...@linkedin.com>
AuthorDate: Tue Apr 2 18:23:17 2019 -0700

    TASK: Make isJobQueue backward compatible
    
    Making isJobQueue backward compatible by adding isTerminable() check.
    
    RB=1617516
    G=helix-reviewers
    A=jxue
    
    Signed-off-by: Hunter Lee <hu...@linkedin.com>
---
 helix-core/src/main/java/org/apache/helix/task/WorkflowConfig.java | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/helix-core/src/main/java/org/apache/helix/task/WorkflowConfig.java b/helix-core/src/main/java/org/apache/helix/task/WorkflowConfig.java
index 9f98f6b..aae0c01 100644
--- a/helix-core/src/main/java/org/apache/helix/task/WorkflowConfig.java
+++ b/helix-core/src/main/java/org/apache/helix/task/WorkflowConfig.java
@@ -233,7 +233,8 @@ public class WorkflowConfig extends ResourceConfig {
   }
 
   public boolean isJobQueue() {
-    return _record.getBooleanField(WorkflowConfigProperty.IsJobQueue.name(), DEFAULT_JOB_QUEUE);
+    return _record.getBooleanField(WorkflowConfigProperty.IsJobQueue.name(), DEFAULT_JOB_QUEUE)
+        || !isTerminable();
   }
 
   protected void setJobTypes(Map<String, String> jobTypes) {


[helix] 06/14: get instance's pending messages with state model def parameter

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

hulee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/helix.git

commit babc471bbd81907da73f5f33b2f9f5a035e20177
Author: ywang4 <yw...@linkedin.com>
AuthorDate: Wed Feb 20 14:23:08 2019 -0800

    get instance's pending messages with state model def parameter
    
    Update the get() method in AbstractTestClass in order to take the correct QueryParam
    BUGS=HELIX-1645
    
    RB=1570393
    BUG=HELIX-1645
    G=helix-reviewers
    A=hulee,jxue
    
    Signed-off-by: Hunter Lee <hu...@linkedin.com>
---
 .../server/resources/helix/InstanceAccessor.java   | 29 +++++---
 .../helix/rest/server/AbstractTestClass.java       | 12 +++-
 .../helix/rest/server/TestClusterAccessor.java     | 18 ++---
 .../helix/rest/server/TestInstanceAccessor.java    | 77 ++++++++++++++++++++--
 .../apache/helix/rest/server/TestJobAccessor.java  | 22 ++++---
 .../helix/rest/server/TestNamespacedAPIAccess.java | 27 ++++----
 .../helix/rest/server/TestResourceAccessor.java    | 19 +++---
 .../apache/helix/rest/server/TestTaskAccessor.java | 14 ++--
 .../helix/rest/server/TestWorkflowAccessor.java    | 19 +++---
 9 files changed, 164 insertions(+), 73 deletions(-)

diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/InstanceAccessor.java b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/InstanceAccessor.java
index f55ee89..cfed0e2 100644
--- a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/InstanceAccessor.java
+++ b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/InstanceAccessor.java
@@ -23,6 +23,7 @@ import java.io.IOException;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
@@ -47,12 +48,13 @@ import org.apache.helix.model.LiveInstance;
 import org.apache.helix.model.Message;
 import org.apache.helix.model.ParticipantHistory;
 import org.apache.helix.model.builder.HelixConfigScopeBuilder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.codehaus.jackson.JsonNode;
 import org.codehaus.jackson.node.ArrayNode;
 import org.codehaus.jackson.node.JsonNodeFactory;
 import org.codehaus.jackson.node.ObjectNode;
+import org.eclipse.jetty.util.StringUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 @Path("/clusters/{clusterId}/instances")
 public class InstanceAccessor extends AbstractHelixResource {
@@ -488,7 +490,8 @@ public class InstanceAccessor extends AbstractHelixResource {
   @GET
   @Path("{instanceName}/messages")
   public Response getMessagesOnInstance(@PathParam("clusterId") String clusterId,
-      @PathParam("instanceName") String instanceName) throws IOException {
+      @PathParam("instanceName") String instanceName,
+      @QueryParam("stateModelDef") String stateModelDef) {
     HelixDataAccessor accessor = getDataAccssor(clusterId);
 
     ObjectNode root = JsonNodeFactory.instance.objectNode();
@@ -497,19 +500,27 @@ public class InstanceAccessor extends AbstractHelixResource {
     ArrayNode readMessages = root.putArray(InstanceProperties.read_messages.name());
 
 
-    List<String> messages =
+    List<String> messageNames =
         accessor.getChildNames(accessor.keyBuilder().messages(instanceName));
-    if (messages == null || messages.size() == 0) {
+    if (messageNames == null || messageNames.size() == 0) {
+      _logger.warn("Unable to get any messages on instance: " + instanceName);
       return notFound();
     }
 
-    for (String messageName : messages) {
+    for (String messageName : messageNames) {
       Message message = accessor.getProperty(accessor.keyBuilder().message(instanceName, messageName));
-      if (message.getMsgState() == Message.MessageState.NEW) {
-        newMessages.add(messageName);
+      if (message == null) {
+        _logger.warn("Message is deleted given message name: ", messageName);
+        continue;
+      }
+      // if stateModelDef is valid, keep messages with StateModelDef equals to the parameter
+      if (StringUtil.isNotBlank(stateModelDef) && !stateModelDef.equals(message.getStateModelDef())) {
+        continue;
       }
 
-      if (message.getMsgState() == Message.MessageState.READ) {
+      if (Message.MessageState.NEW.equals(message.getMsgState())) {
+        newMessages.add(messageName);
+      } else if (Message.MessageState.READ.equals(message.getMsgState())) {
         readMessages.add(messageName);
       }
     }
diff --git a/helix-rest/src/test/java/org/apache/helix/rest/server/AbstractTestClass.java b/helix-rest/src/test/java/org/apache/helix/rest/server/AbstractTestClass.java
index 97b735e..01dd7b8 100644
--- a/helix-rest/src/test/java/org/apache/helix/rest/server/AbstractTestClass.java
+++ b/helix-rest/src/test/java/org/apache/helix/rest/server/AbstractTestClass.java
@@ -30,10 +30,12 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.logging.Level;
+
 import javax.ws.rs.client.Entity;
 import javax.ws.rs.client.WebTarget;
 import javax.ws.rs.core.Application;
 import javax.ws.rs.core.Response;
+
 import org.I0Itec.zkclient.ZkServer;
 import org.apache.helix.AccessOption;
 import org.apache.helix.BaseDataAccessor;
@@ -405,8 +407,14 @@ public class AbstractTestClass extends JerseyTestNg.ContainerPerClassTest {
     return OBJECT_MAPPER.reader(ZNRecord.class).readValue(data);
   }
 
-  protected String get(String uri, int expectedReturnStatus, boolean expectBodyReturned) {
-    final Response response = target(uri).request().get();
+  protected String get(String uri, Map<String, String> queryParams, int expectedReturnStatus, boolean expectBodyReturned) {
+    WebTarget webTarget = target(uri);
+    if (queryParams != null) {
+      for (Map.Entry<String, String> entry : queryParams.entrySet()) {
+        webTarget = webTarget.queryParam(entry.getKey(), entry.getValue());
+      }
+    }
+    final Response response = webTarget.request().get();
     Assert.assertEquals(response.getStatus(), expectedReturnStatus);
 
     // NOT_FOUND will throw text based html
diff --git a/helix-rest/src/test/java/org/apache/helix/rest/server/TestClusterAccessor.java b/helix-rest/src/test/java/org/apache/helix/rest/server/TestClusterAccessor.java
index 3d7577a..59da6e1 100644
--- a/helix-rest/src/test/java/org/apache/helix/rest/server/TestClusterAccessor.java
+++ b/helix-rest/src/test/java/org/apache/helix/rest/server/TestClusterAccessor.java
@@ -69,7 +69,7 @@ public class TestClusterAccessor extends AbstractTestClass {
     System.out.println("Start test :" + TestHelper.getTestMethodName());
 
     _auditLogger.clearupLogs();
-    String body = get("clusters", Response.Status.OK.getStatusCode(), true);
+    String body = get("clusters", null, Response.Status.OK.getStatusCode(), true);
     JsonNode node = OBJECT_MAPPER.readTree(body);
     String clustersStr = node.get(ClusterAccessor.ClusterProperties.clusters.name()).toString();
     Assert.assertNotNull(clustersStr);
@@ -255,14 +255,14 @@ public class TestClusterAccessor extends AbstractTestClass {
 
     // verify is in maintenance mode
     String body =
-        get("clusters/" + cluster + "/maintenance", Response.Status.OK.getStatusCode(), true);
+        get("clusters/" + cluster + "/maintenance", null, Response.Status.OK.getStatusCode(), true);
     JsonNode node = OBJECT_MAPPER.readTree(body);
     boolean maintenance =
         node.get(ClusterAccessor.ClusterProperties.maintenance.name()).getBooleanValue();
     Assert.assertTrue(maintenance);
 
     // Check that we could retrieve maintenance signal correctly
-    String signal = get("clusters/" + cluster + "/controller/maintenanceSignal",
+    String signal = get("clusters/" + cluster + "/controller/maintenanceSignal", null,
         Response.Status.OK.getStatusCode(), true);
     Map<String, Object> maintenanceSignalMap =
         OBJECT_MAPPER.readValue(signal, new TypeReference<HashMap<String, Object>>() {
@@ -277,12 +277,12 @@ public class TestClusterAccessor extends AbstractTestClass {
         Entity.entity("", MediaType.APPLICATION_JSON_TYPE), Response.Status.OK.getStatusCode());
 
     // verify no longer in maintenance mode
-    body = get("clusters/" + cluster + "/maintenance", Response.Status.OK.getStatusCode(), true);
+    body = get("clusters/" + cluster + "/maintenance", null, Response.Status.OK.getStatusCode(), true);
     node = OBJECT_MAPPER.readTree(body);
     Assert.assertFalse(
         node.get(ClusterAccessor.ClusterProperties.maintenance.name()).getBooleanValue());
 
-    get("clusters/" + cluster + "/controller/maintenanceSignal",
+    get("clusters/" + cluster + "/controller/maintenanceSignal", null,
         Response.Status.NOT_FOUND.getStatusCode(), false);
   }
 
@@ -293,7 +293,7 @@ public class TestClusterAccessor extends AbstractTestClass {
 
     // Get the leader controller name for the cluster
     String leader =
-        get("clusters/" + cluster + "/controller", Response.Status.OK.getStatusCode(), true);
+        get("clusters/" + cluster + "/controller", null, Response.Status.OK.getStatusCode(), true);
     Map<String, String> leaderMap =
         OBJECT_MAPPER.readValue(leader, new TypeReference<HashMap<String, String>>() {
         });
@@ -302,7 +302,7 @@ public class TestClusterAccessor extends AbstractTestClass {
     Assert.assertNotNull(leader, "Leader name cannot be null!");
 
     // Get the controller leadership history JSON's last entry
-    String leadershipHistory = get("clusters/" + cluster + "/controller/history",
+    String leadershipHistory = get("clusters/" + cluster + "/controller/history", null,
         Response.Status.OK.getStatusCode(), true);
     Map<String, Object> leadershipHistoryMap =
         OBJECT_MAPPER.readValue(leadershipHistory, new TypeReference<HashMap<String, Object>>() {
@@ -330,7 +330,7 @@ public class TestClusterAccessor extends AbstractTestClass {
         Entity.entity(reason, MediaType.APPLICATION_JSON_TYPE), Response.Status.OK.getStatusCode());
 
     // Get the maintenance history JSON's last entry
-    String maintenanceHistory = get("clusters/" + cluster + "/controller/maintenanceHistory",
+    String maintenanceHistory = get("clusters/" + cluster + "/controller/maintenanceHistory", null,
         Response.Status.OK.getStatusCode(), true);
     Map<String, Object> maintenanceHistoryMap =
         OBJECT_MAPPER.readValue(maintenanceHistory, new TypeReference<HashMap<String, Object>>() {
@@ -372,7 +372,7 @@ public class TestClusterAccessor extends AbstractTestClass {
   }
 
   private ClusterConfig getClusterConfigFromRest(String cluster) throws IOException {
-    String body = get("clusters/" + cluster + "/configs", Response.Status.OK.getStatusCode(), true);
+    String body = get("clusters/" + cluster + "/configs", null, Response.Status.OK.getStatusCode(), true);
 
     ZNRecord record = new ObjectMapper().reader(ZNRecord.class).readValue(body);
     ClusterConfig clusterConfigRest = new ClusterConfig(record);
diff --git a/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstanceAccessor.java b/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstanceAccessor.java
index 94c28b2..86c52e1 100644
--- a/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstanceAccessor.java
+++ b/helix-rest/src/test/java/org/apache/helix/rest/server/TestInstanceAccessor.java
@@ -19,8 +19,6 @@ package org.apache.helix.rest.server;
  * under the License.
  */
 
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -28,28 +26,95 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+
 import javax.ws.rs.client.Entity;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+
+import org.apache.helix.HelixDataAccessor;
 import org.apache.helix.HelixException;
 import org.apache.helix.TestHelper;
 import org.apache.helix.ZNRecord;
+import org.apache.helix.manager.zk.ZKHelixDataAccessor;
 import org.apache.helix.model.InstanceConfig;
+import org.apache.helix.model.Message;
 import org.apache.helix.rest.server.resources.AbstractResource;
 import org.apache.helix.rest.server.resources.helix.InstanceAccessor;
 import org.codehaus.jackson.JsonNode;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
 public class TestInstanceAccessor extends AbstractTestClass {
   private final static String CLUSTER_NAME = "TestCluster_0";
   private final static String INSTANCE_NAME = CLUSTER_NAME + "localhost_12918";
 
   @Test
+  public void testGetAllMessages() throws IOException {
+    System.out.println("Start test :" + TestHelper.getTestMethodName());
+
+    String messageId = "msg1";
+    Message message = new Message(Message.MessageType.STATE_TRANSITION, messageId);
+    message.setStateModelDef("MasterSlave");
+    message.setFromState("OFFLINE");
+    message.setToState("SLAVE");
+    message.setResourceName("testResourceName");
+    message.setPartitionName("testResourceName_1");
+    message.setTgtName("localhost_3");
+    message.setTgtSessionId("session_3");
+    HelixDataAccessor helixDataAccessor = new ZKHelixDataAccessor(CLUSTER_NAME, _baseAccessor);
+    helixDataAccessor.setProperty(helixDataAccessor.keyBuilder().message(INSTANCE_NAME, messageId), message);
+
+    String body =
+        get("clusters/" + CLUSTER_NAME + "/instances/" + INSTANCE_NAME + "/messages", null, Response.Status.OK.getStatusCode(), true);
+    JsonNode node = OBJECT_MAPPER.readTree(body);
+    int newMessageCount =
+        node.get(InstanceAccessor.InstanceProperties.total_message_count.name()).getIntValue();
+
+    Assert.assertEquals(newMessageCount, 1);
+  }
+
+  @Test (dependsOnMethods = "testGetAllMessages")
+  public void testGetMessagesByStateModelDef() throws IOException {
+    System.out.println("Start test :" + TestHelper.getTestMethodName());
+
+    String messageId = "msg1";
+    Message message = new Message(Message.MessageType.STATE_TRANSITION, messageId);
+    message.setStateModelDef("MasterSlave");
+    message.setFromState("OFFLINE");
+    message.setToState("SLAVE");
+    message.setResourceName("testResourceName");
+    message.setPartitionName("testResourceName_1");
+    message.setTgtName("localhost_3");
+    message.setTgtSessionId("session_3");
+    HelixDataAccessor helixDataAccessor = new ZKHelixDataAccessor(CLUSTER_NAME, _baseAccessor);
+    helixDataAccessor.setProperty(helixDataAccessor.keyBuilder().message(INSTANCE_NAME, messageId), message);
+
+    String body = get("clusters/" + CLUSTER_NAME + "/instances/" + INSTANCE_NAME + "/messages",
+        ImmutableMap.of("stateModelDef", "MasterSlave"), Response.Status.OK.getStatusCode(), true);
+    JsonNode node = OBJECT_MAPPER.readTree(body);
+    int newMessageCount =
+        node.get(InstanceAccessor.InstanceProperties.total_message_count.name()).getIntValue();
+
+    Assert.assertEquals(newMessageCount, 1);
+
+    body = get("clusters/" + CLUSTER_NAME + "/instances/" + INSTANCE_NAME + "/messages",
+        ImmutableMap.of("stateModelDef", "LeaderStandBy"), Response.Status.OK.getStatusCode(),
+        true);
+    node = OBJECT_MAPPER.readTree(body);
+    newMessageCount =
+        node.get(InstanceAccessor.InstanceProperties.total_message_count.name()).getIntValue();
+
+    Assert.assertEquals(newMessageCount, 0);
+  }
+
+  @Test (dependsOnMethods = "testGetMessagesByStateModelDef")
   public void testGetInstances() throws IOException {
     System.out.println("Start test :" + TestHelper.getTestMethodName());
     String body =
-        get("clusters/" + CLUSTER_NAME + "/instances", Response.Status.OK.getStatusCode(), true);
+        get("clusters/" + CLUSTER_NAME + "/instances", null, Response.Status.OK.getStatusCode(), true);
 
     JsonNode node = OBJECT_MAPPER.readTree(body);
     String instancesStr =
@@ -66,7 +131,7 @@ public class TestInstanceAccessor extends AbstractTestClass {
   @Test(dependsOnMethods = "testGetInstances")
   public void testGetInstance() throws IOException {
     System.out.println("Start test :" + TestHelper.getTestMethodName());
-    String body = get("clusters/" + CLUSTER_NAME + "/instances/" + INSTANCE_NAME,
+    String body = get("clusters/" + CLUSTER_NAME + "/instances/" + INSTANCE_NAME, null,
         Response.Status.OK.getStatusCode(), true);
     JsonNode node = OBJECT_MAPPER.readTree(body);
     String instancesCfg =
@@ -170,9 +235,7 @@ public class TestInstanceAccessor extends AbstractTestClass {
     // Test enable disable partitions
     String dbName = "_db_0_";
     List<String> partitionsToDisable = Arrays.asList(
-        new String[] { CLUSTER_NAME + dbName + "0", CLUSTER_NAME + dbName + "1",
-            CLUSTER_NAME + dbName + "3"
-        });
+         CLUSTER_NAME + dbName + "0", CLUSTER_NAME + dbName + "1", CLUSTER_NAME + dbName + "3");
 
     entity = Entity.entity(OBJECT_MAPPER.writeValueAsString(ImmutableMap
             .of(AbstractResource.Properties.id.name(), INSTANCE_NAME,
diff --git a/helix-rest/src/test/java/org/apache/helix/rest/server/TestJobAccessor.java b/helix-rest/src/test/java/org/apache/helix/rest/server/TestJobAccessor.java
index d1178ee..82416fb 100644
--- a/helix-rest/src/test/java/org/apache/helix/rest/server/TestJobAccessor.java
+++ b/helix-rest/src/test/java/org/apache/helix/rest/server/TestJobAccessor.java
@@ -19,12 +19,12 @@ package org.apache.helix.rest.server;
  * under the License.
  */
 
-import com.google.common.collect.ImmutableMap;
 import java.io.IOException;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
+
 import javax.ws.rs.client.Entity;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
@@ -43,6 +43,8 @@ import org.codehaus.jackson.type.TypeReference;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
+import com.google.common.collect.ImmutableMap;
+
 public class TestJobAccessor extends AbstractTestClass {
   private final static String CLUSTER_NAME = "TestCluster_0";
   private final static String WORKFLOW_NAME = WORKFLOW_PREFIX + 0;
@@ -58,7 +60,7 @@ public class TestJobAccessor extends AbstractTestClass {
   public void testGetJobs() throws IOException {
     System.out.println("Start test :" + TestHelper.getTestMethodName());
 
-    String body = get("clusters/" + CLUSTER_NAME + "/workflows/" + WORKFLOW_NAME + "/jobs",
+    String body = get("clusters/" + CLUSTER_NAME + "/workflows/" + WORKFLOW_NAME + "/jobs", null,
         Response.Status.OK.getStatusCode(), true);
     JsonNode node = OBJECT_MAPPER.readTree(body);
     String jobsStr = node.get(JobAccessor.JobProperties.Jobs.name()).toString();
@@ -74,7 +76,7 @@ public class TestJobAccessor extends AbstractTestClass {
     System.out.println("Start test :" + TestHelper.getTestMethodName());
 
     String body =
-        get("clusters/" + CLUSTER_NAME + "/workflows/" + WORKFLOW_NAME + "/jobs/" + JOB_NAME,
+        get("clusters/" + CLUSTER_NAME + "/workflows/" + WORKFLOW_NAME + "/jobs/" + JOB_NAME, null,
             Response.Status.OK.getStatusCode(), true);
     JsonNode node = OBJECT_MAPPER.readTree(body);
     Assert.assertNotNull(node.get(JobAccessor.JobProperties.JobConfig.name()));
@@ -91,7 +93,7 @@ public class TestJobAccessor extends AbstractTestClass {
 
     String body =
         get("clusters/" + CLUSTER_NAME + "/workflows/" + WORKFLOW_NAME + "/jobs/" + JOB_NAME
-            + "/configs", Response.Status.OK.getStatusCode(), true);
+            + "/configs", null, Response.Status.OK.getStatusCode(), true);
     JsonNode node = OBJECT_MAPPER.readTree(body);
     String workflowId = node.get("simpleFields").get("WorkflowID").getTextValue();
     Assert.assertEquals(workflowId, WORKFLOW_NAME);
@@ -104,7 +106,7 @@ public class TestJobAccessor extends AbstractTestClass {
 
     String body =
         get("clusters/" + CLUSTER_NAME + "/workflows/" + WORKFLOW_NAME + "/jobs/" + JOB_NAME
-            + "/context", Response.Status.OK.getStatusCode(), true);
+            + "/context", null, Response.Status.OK.getStatusCode(), true);
     JsonNode node = OBJECT_MAPPER.readTree(body);
     Assert.assertEquals(node.get("mapFields").get("0").get("STATE").getTextValue(),
         TaskPartitionState.COMPLETED.name());
@@ -145,7 +147,7 @@ public class TestJobAccessor extends AbstractTestClass {
 
     // Empty user content
     String body =
-        get(uri, Response.Status.OK.getStatusCode(), true);
+        get(uri, null, Response.Status.OK.getStatusCode(), true);
     Map<String, String> contentStore = OBJECT_MAPPER.readValue(body, new TypeReference<Map<String, String>>() {});
     Assert.assertTrue(contentStore.isEmpty());
 
@@ -156,7 +158,7 @@ public class TestJobAccessor extends AbstractTestClass {
     post(uri, ImmutableMap.of("command", "update"), entity, Response.Status.OK.getStatusCode());
 
     // update (add items) workflow content store
-    body = get(uri, Response.Status.OK.getStatusCode(), true);
+    body = get(uri, null, Response.Status.OK.getStatusCode(), true);
     contentStore = OBJECT_MAPPER.readValue(body, new TypeReference<Map<String, String>>() {});
     Assert.assertEquals(contentStore, map1);
 
@@ -165,7 +167,7 @@ public class TestJobAccessor extends AbstractTestClass {
     map1.put("k2", "v2");
     entity = Entity.entity(OBJECT_MAPPER.writeValueAsString(map1), MediaType.APPLICATION_JSON_TYPE);
     post(uri, ImmutableMap.of("command", "update"), entity, Response.Status.OK.getStatusCode());
-    body = get(uri, Response.Status.OK.getStatusCode(), true);
+    body = get(uri, null, Response.Status.OK.getStatusCode(), true);
     contentStore = OBJECT_MAPPER.readValue(body, new TypeReference<Map<String, String>>() {});
     Assert.assertEquals(contentStore, map1);
   }
@@ -181,8 +183,8 @@ public class TestJobAccessor extends AbstractTestClass {
     Map<String, String> validCmd = ImmutableMap.of("command", "update");
     Map<String, String> invalidCmd = ImmutableMap.of("command", "delete"); // cmd not supported
 
-    get(invalidURI1, Response.Status.NOT_FOUND.getStatusCode(), false);
-    get(invalidURI2, Response.Status.NOT_FOUND.getStatusCode(), false);
+    get(invalidURI1, null, Response.Status.NOT_FOUND.getStatusCode(), false);
+    get(invalidURI2, null, Response.Status.NOT_FOUND.getStatusCode(), false);
 
     post(invalidURI1, validCmd, validEntity, Response.Status.NOT_FOUND.getStatusCode());
     post(invalidURI2, validCmd, validEntity, Response.Status.NOT_FOUND.getStatusCode());
diff --git a/helix-rest/src/test/java/org/apache/helix/rest/server/TestNamespacedAPIAccess.java b/helix-rest/src/test/java/org/apache/helix/rest/server/TestNamespacedAPIAccess.java
index c77f939..9ebad96 100644
--- a/helix-rest/src/test/java/org/apache/helix/rest/server/TestNamespacedAPIAccess.java
+++ b/helix-rest/src/test/java/org/apache/helix/rest/server/TestNamespacedAPIAccess.java
@@ -19,21 +19,24 @@ package org.apache.helix.rest.server;
  * under the License.
  */
 
-import com.google.common.collect.ImmutableMap;
 import java.io.IOException;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+
 import javax.ws.rs.client.Entity;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+
 import org.apache.helix.PropertyKey;
 import org.apache.helix.rest.common.HelixRestNamespace;
 import org.codehaus.jackson.map.ObjectMapper;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
+import com.google.common.collect.ImmutableMap;
+
 public class TestNamespacedAPIAccess extends AbstractTestClass {
   ObjectMapper _mapper = new ObjectMapper();
 
@@ -46,11 +49,11 @@ public class TestNamespacedAPIAccess extends AbstractTestClass {
     // Assume other api end points will behave the same way
     put(String.format("/namespaces/%s/clusters/%s", HelixRestNamespace.DEFAULT_NAMESPACE_NAME, testClusterName1), null,
         Entity.entity("", MediaType.APPLICATION_JSON_TYPE), Response.Status.CREATED.getStatusCode());
-    get(String.format("/clusters/%s", testClusterName1), Response.Status.OK.getStatusCode(), false);
+    get(String.format("/clusters/%s", testClusterName1), null, Response.Status.OK.getStatusCode(), false);
 
     put(String.format("/clusters/%s", testClusterName2), null, Entity.entity("", MediaType.APPLICATION_JSON_TYPE),
         Response.Status.CREATED.getStatusCode());
-    get(String.format("/namespaces/%s/clusters/%s", HelixRestNamespace.DEFAULT_NAMESPACE_NAME, testClusterName2),
+    get(String.format("/namespaces/%s/clusters/%s", HelixRestNamespace.DEFAULT_NAMESPACE_NAME, testClusterName2), null,
         Response.Status.OK.getStatusCode(), false);
   }
 
@@ -62,14 +65,14 @@ public class TestNamespacedAPIAccess extends AbstractTestClass {
     // Create cluster in test namespace and verify it's only appears in test namespace
     put(String.format("/namespaces/%s/clusters/%s", TEST_NAMESPACE, testClusterName), null,
         Entity.entity("", MediaType.APPLICATION_JSON_TYPE), Response.Status.CREATED.getStatusCode());
-    get(String.format("/namespaces/%s/clusters/%s", TEST_NAMESPACE, testClusterName),
+    get(String.format("/namespaces/%s/clusters/%s", TEST_NAMESPACE, testClusterName), null,
         Response.Status.OK.getStatusCode(), false);
-    get(String.format("/clusters/%s", testClusterName), Response.Status.NOT_FOUND.getStatusCode(), false);
+    get(String.format("/clusters/%s", testClusterName), null, Response.Status.NOT_FOUND.getStatusCode(), false);
 
     // Create cluster with same name in different namespacces
     put(String.format("/clusters/%s", testClusterName), null, Entity.entity("", MediaType.APPLICATION_JSON_TYPE),
         Response.Status.CREATED.getStatusCode());
-    get(String.format("/clusters/%s", testClusterName), Response.Status.OK.getStatusCode(), false);
+    get(String.format("/clusters/%s", testClusterName), null, Response.Status.OK.getStatusCode(), false);
 
     // Modify cluster in default namespace
     post(String.format("/clusters/%s", testClusterName), ImmutableMap.of("command", "disable"),
@@ -83,21 +86,21 @@ public class TestNamespacedAPIAccess extends AbstractTestClass {
     // Verify that deleting cluster in one namespace will not affect the other
     delete(String.format("/namespaces/%s/clusters/%s", TEST_NAMESPACE, testClusterName),
         Response.Status.OK.getStatusCode());
-    get(String.format("/namespaces/%s/clusters/%s", TEST_NAMESPACE, testClusterName),
+    get(String.format("/namespaces/%s/clusters/%s", TEST_NAMESPACE, testClusterName), null,
         Response.Status.NOT_FOUND.getStatusCode(), false);
-    get(String.format("/clusters/%s", testClusterName), Response.Status.OK.getStatusCode(), false);
+    get(String.format("/clusters/%s", testClusterName), null, Response.Status.OK.getStatusCode(), false);
   }
 
   @Test
   public void testNamespaceServer() throws IOException {
     // Default endpoints should not have any namespace information returned
-    get("/", Response.Status.NOT_FOUND.getStatusCode(), false);
+    get("/", null, Response.Status.NOT_FOUND.getStatusCode(), false);
 
     // Get invalid namespace should return not found
-    get("/namespaces/invalid-namespace", Response.Status.NOT_FOUND.getStatusCode(), false);
+    get("/namespaces/invalid-namespace", null, Response.Status.NOT_FOUND.getStatusCode(), false);
 
     // list namespace should return a list of all namespaces
-    String body = get("/namespaces", Response.Status.OK.getStatusCode(), true);
+    String body = get("/namespaces", null, Response.Status.OK.getStatusCode(), true);
     List<Map<String, String>> namespaceMaps = _mapper
         .readValue(body, _mapper.getTypeFactory().constructCollectionType(List.class, Map.class));
     Assert.assertEquals(namespaceMaps.size(), 2);
@@ -126,7 +129,7 @@ public class TestNamespacedAPIAccess extends AbstractTestClass {
     Assert.assertTrue(expectedNamespaceNames.isEmpty());
 
     // Accessing root of namespaced API endpoint shall return information of that namespace
-    body = get(String.format("/namespaces/%s", HelixRestNamespace.DEFAULT_NAMESPACE_NAME),
+    body = get(String.format("/namespaces/%s", HelixRestNamespace.DEFAULT_NAMESPACE_NAME), null,
         Response.Status.OK.getStatusCode(), true);
     Map<String, String> namespace = _mapper.readValue(body,
         _mapper.getTypeFactory().constructMapType(Map.class, String.class, String.class));
diff --git a/helix-rest/src/test/java/org/apache/helix/rest/server/TestResourceAccessor.java b/helix-rest/src/test/java/org/apache/helix/rest/server/TestResourceAccessor.java
index 5aea447..a90de7b 100644
--- a/helix-rest/src/test/java/org/apache/helix/rest/server/TestResourceAccessor.java
+++ b/helix-rest/src/test/java/org/apache/helix/rest/server/TestResourceAccessor.java
@@ -19,7 +19,6 @@ package org.apache.helix.rest.server;
  * under the License.
  */
 
-import com.google.common.collect.ImmutableMap;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -29,9 +28,11 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+
 import javax.ws.rs.client.Entity;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+
 import org.apache.helix.AccessOption;
 import org.apache.helix.HelixDataAccessor;
 import org.apache.helix.HelixManager;
@@ -50,6 +51,8 @@ import org.codehaus.jackson.type.TypeReference;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
+import com.google.common.collect.ImmutableMap;
+
 public class TestResourceAccessor extends AbstractTestClass {
   private final static String CLUSTER_NAME = "TestCluster_0";
   private final static String RESOURCE_NAME = CLUSTER_NAME + "_db_0";
@@ -60,7 +63,7 @@ public class TestResourceAccessor extends AbstractTestClass {
     System.out.println("Start test :" + TestHelper.getTestMethodName());
 
     String body =
-        get("clusters/" + CLUSTER_NAME + "/resources", Response.Status.OK.getStatusCode(), true);
+        get("clusters/" + CLUSTER_NAME + "/resources", null, Response.Status.OK.getStatusCode(), true);
 
     JsonNode node = OBJECT_MAPPER.readTree(body);
     String idealStates =
@@ -77,7 +80,7 @@ public class TestResourceAccessor extends AbstractTestClass {
   @Test(dependsOnMethods = "testGetResources")
   public void testGetResource() throws IOException {
     System.out.println("Start test :" + TestHelper.getTestMethodName());
-    String body = get("clusters/" + CLUSTER_NAME + "/resources/" + RESOURCE_NAME,
+    String body = get("clusters/" + CLUSTER_NAME + "/resources/" + RESOURCE_NAME, null,
         Response.Status.OK.getStatusCode(), true);
 
     JsonNode node = OBJECT_MAPPER.readTree(body);
@@ -125,7 +128,7 @@ public class TestResourceAccessor extends AbstractTestClass {
   public void testResourceConfig() throws IOException {
     System.out.println("Start test :" + TestHelper.getTestMethodName());
 
-    String body = get("clusters/" + CLUSTER_NAME + "/resources/" + RESOURCE_NAME + "/configs",
+    String body = get("clusters/" + CLUSTER_NAME + "/resources/" + RESOURCE_NAME + "/configs", null,
         Response.Status.OK.getStatusCode(), true);
     ResourceConfig resourceConfig = new ResourceConfig(toZNRecord(body));
     Assert.assertEquals(resourceConfig,
@@ -136,7 +139,7 @@ public class TestResourceAccessor extends AbstractTestClass {
   public void testIdealState() throws IOException {
     System.out.println("Start test :" + TestHelper.getTestMethodName());
 
-    String body = get("clusters/" + CLUSTER_NAME + "/resources/" + RESOURCE_NAME + "/idealState",
+    String body = get("clusters/" + CLUSTER_NAME + "/resources/" + RESOURCE_NAME + "/idealState", null,
         Response.Status.OK.getStatusCode(), true);
     IdealState idealState = new IdealState(toZNRecord(body));
     Assert.assertEquals(idealState,
@@ -147,7 +150,7 @@ public class TestResourceAccessor extends AbstractTestClass {
   public void testExternalView() throws IOException {
     System.out.println("Start test :" + TestHelper.getTestMethodName());
 
-    String body = get("clusters/" + CLUSTER_NAME + "/resources/" + RESOURCE_NAME + "/externalView",
+    String body = get("clusters/" + CLUSTER_NAME + "/resources/" + RESOURCE_NAME + "/externalView", null,
         Response.Status.OK.getStatusCode(), true);
     ExternalView externalView = new ExternalView(toZNRecord(body));
     Assert.assertEquals(externalView, _gSetupTool.getClusterManagementTool()
@@ -181,7 +184,7 @@ public class TestResourceAccessor extends AbstractTestClass {
     createDummyMapping(clusterName, resourceName, idealStateParams, partitionReplicaStates);
 
     // Get the result of getPartitionHealth
-    String body = get("clusters/" + clusterName + "/resources/" + resourceName + "/health",
+    String body = get("clusters/" + clusterName + "/resources/" + resourceName + "/health", null,
         Response.Status.OK.getStatusCode(), true);
 
     JsonNode node = OBJECT_MAPPER.readTree(body);
@@ -241,7 +244,7 @@ public class TestResourceAccessor extends AbstractTestClass {
     createDummyMapping(clusterName, resourceNameUnhealthy, idealStateParams, partitionReplicaStates_2);
 
     // Get the result of getResourceHealth
-    String body = get("clusters/" + clusterName + "/resources/health", Response.Status.OK.getStatusCode(),
+    String body = get("clusters/" + clusterName + "/resources/health", null, Response.Status.OK.getStatusCode(),
         true);
 
     JsonNode node = OBJECT_MAPPER.readTree(body);
diff --git a/helix-rest/src/test/java/org/apache/helix/rest/server/TestTaskAccessor.java b/helix-rest/src/test/java/org/apache/helix/rest/server/TestTaskAccessor.java
index 575eae3..813f052 100644
--- a/helix-rest/src/test/java/org/apache/helix/rest/server/TestTaskAccessor.java
+++ b/helix-rest/src/test/java/org/apache/helix/rest/server/TestTaskAccessor.java
@@ -23,7 +23,7 @@ public class TestTaskAccessor extends AbstractTestClass {
 
     // Empty user content
     String body =
-        get(uri, Response.Status.OK.getStatusCode(), true);
+        get(uri, null, Response.Status.OK.getStatusCode(), true);
     Map<String, String>
         contentStore = OBJECT_MAPPER.readValue(body, new TypeReference<Map<String, String>>() {});
     Assert.assertTrue(contentStore.isEmpty());
@@ -37,11 +37,11 @@ public class TestTaskAccessor extends AbstractTestClass {
     post(uriTaskDoesNotExist, ImmutableMap.of("command", "update"), entity, Response.Status.OK.getStatusCode());
 
     // get after post should work
-    body = get(uri, Response.Status.OK.getStatusCode(), true);
+    body = get(uri, null, Response.Status.OK.getStatusCode(), true);
     contentStore = OBJECT_MAPPER.readValue(body, new TypeReference<Map<String, String>>() {
     });
     Assert.assertEquals(contentStore, map1);
-    body = get(uriTaskDoesNotExist, Response.Status.OK.getStatusCode(), true);
+    body = get(uriTaskDoesNotExist, null, Response.Status.OK.getStatusCode(), true);
     contentStore = OBJECT_MAPPER.readValue(body, new TypeReference<Map<String, String>>() {
     });
     Assert.assertEquals(contentStore, map1);
@@ -52,7 +52,7 @@ public class TestTaskAccessor extends AbstractTestClass {
     map1.put("k2", "v2");
     entity = Entity.entity(OBJECT_MAPPER.writeValueAsString(map1), MediaType.APPLICATION_JSON_TYPE);
     post(uri, ImmutableMap.of("command", "update"), entity, Response.Status.OK.getStatusCode());
-    body = get(uri, Response.Status.OK.getStatusCode(), true);
+    body = get(uri, null, Response.Status.OK.getStatusCode(), true);
     contentStore = OBJECT_MAPPER.readValue(body, new TypeReference<Map<String, String>>() {
     });
     Assert.assertEquals(contentStore, map1);
@@ -70,9 +70,9 @@ public class TestTaskAccessor extends AbstractTestClass {
     Map<String, String> validCmd = ImmutableMap.of("command", "update");
     Map<String, String> invalidCmd = ImmutableMap.of("command", "delete"); // cmd not supported
 
-    get(invalidURI1, Response.Status.NOT_FOUND.getStatusCode(), false);
-    get(invalidURI2, Response.Status.NOT_FOUND.getStatusCode(), false);
-    get(invalidURI3, Response.Status.NOT_FOUND.getStatusCode(), false);
+    get(invalidURI1, null, Response.Status.NOT_FOUND.getStatusCode(), false);
+    get(invalidURI2, null, Response.Status.NOT_FOUND.getStatusCode(), false);
+    get(invalidURI3, null, Response.Status.NOT_FOUND.getStatusCode(), false);
 
     post(invalidURI1, validCmd, validEntity, Response.Status.NOT_FOUND.getStatusCode());
     post(invalidURI2, validCmd, validEntity, Response.Status.NOT_FOUND.getStatusCode());
diff --git a/helix-rest/src/test/java/org/apache/helix/rest/server/TestWorkflowAccessor.java b/helix-rest/src/test/java/org/apache/helix/rest/server/TestWorkflowAccessor.java
index 0f88841..56a8853 100644
--- a/helix-rest/src/test/java/org/apache/helix/rest/server/TestWorkflowAccessor.java
+++ b/helix-rest/src/test/java/org/apache/helix/rest/server/TestWorkflowAccessor.java
@@ -5,9 +5,11 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
+
 import javax.ws.rs.client.Entity;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+
 import org.apache.helix.TestHelper;
 import org.apache.helix.rest.server.resources.helix.WorkflowAccessor;
 import org.apache.helix.task.JobQueue;
@@ -18,7 +20,6 @@ import org.apache.helix.task.TaskState;
 import org.apache.helix.task.WorkflowConfig;
 import org.codehaus.jackson.JsonNode;
 import org.codehaus.jackson.type.TypeReference;
-import org.glassfish.jersey.server.spi.ResponseErrorMapper;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
@@ -44,7 +45,7 @@ public class TestWorkflowAccessor extends AbstractTestClass {
     System.out.println("Start test :" + TestHelper.getTestMethodName());
 
     String body =
-        get("clusters/" + CLUSTER_NAME + "/workflows", Response.Status.OK.getStatusCode(), true);
+        get("clusters/" + CLUSTER_NAME + "/workflows", null, Response.Status.OK.getStatusCode(), true);
     JsonNode node = OBJECT_MAPPER.readTree(body);
     String workflowsStr = node.get(WorkflowAccessor.WorkflowProperties.Workflows.name()).toString();
     Set<String> workflows = OBJECT_MAPPER.readValue(workflowsStr,
@@ -55,7 +56,7 @@ public class TestWorkflowAccessor extends AbstractTestClass {
   @Test(dependsOnMethods = "testGetWorkflows")
   public void testGetWorkflow() throws IOException {
     System.out.println("Start test :" + TestHelper.getTestMethodName());
-    String body = get("clusters/" + CLUSTER_NAME + "/workflows/" + WORKFLOW_NAME,
+    String body = get("clusters/" + CLUSTER_NAME + "/workflows/" + WORKFLOW_NAME, null,
         Response.Status.OK.getStatusCode(), true);
     JsonNode node = OBJECT_MAPPER.readTree(body);
     Assert.assertNotNull(node.get(WorkflowAccessor.WorkflowProperties.WorkflowConfig.name()));
@@ -76,7 +77,7 @@ public class TestWorkflowAccessor extends AbstractTestClass {
   public void testGetWorkflowConfig() throws IOException {
     System.out.println("Start test :" + TestHelper.getTestMethodName());
 
-    String body = get("clusters/" + CLUSTER_NAME + "/workflows/" + WORKFLOW_NAME + "/configs",
+    String body = get("clusters/" + CLUSTER_NAME + "/workflows/" + WORKFLOW_NAME + "/configs", null,
         Response.Status.OK.getStatusCode(), true);
     JsonNode node = OBJECT_MAPPER.readTree(body);
     String workflowId = node.get("WorkflowID").getTextValue();
@@ -87,7 +88,7 @@ public class TestWorkflowAccessor extends AbstractTestClass {
   public void testGetWorkflowContext() throws IOException {
     System.out.println("Start test :" + TestHelper.getTestMethodName());
 
-    String body = get("clusters/" + CLUSTER_NAME + "/workflows/" + WORKFLOW_NAME + "/context",
+    String body = get("clusters/" + CLUSTER_NAME + "/workflows/" + WORKFLOW_NAME + "/context", null,
         Response.Status.OK.getStatusCode(), true);
     JsonNode node = OBJECT_MAPPER.readTree(body);
     Assert.assertEquals(node.get("STATE").getTextValue(),
@@ -151,7 +152,7 @@ public class TestWorkflowAccessor extends AbstractTestClass {
     String uri = "clusters/" + CLUSTER_NAME + "/workflows/Workflow_0/userContent";
 
     String body =
-        get(uri, Response.Status.OK.getStatusCode(), true);
+        get(uri, null, Response.Status.OK.getStatusCode(), true);
     Map<String, String> contentStore = OBJECT_MAPPER.readValue(body, new TypeReference<Map<String, String>>() {});
     Assert.assertTrue(contentStore.isEmpty());
 
@@ -161,7 +162,7 @@ public class TestWorkflowAccessor extends AbstractTestClass {
     post(uri, ImmutableMap.of("command", "update"), entity, Response.Status.OK.getStatusCode());
 
     // update (add items) workflow content store
-    body = get(uri, Response.Status.OK.getStatusCode(), true);
+    body = get(uri, null, Response.Status.OK.getStatusCode(), true);
     contentStore = OBJECT_MAPPER.readValue(body, new TypeReference<Map<String, String>>() {});
     Assert.assertEquals(contentStore, map1);
 
@@ -170,7 +171,7 @@ public class TestWorkflowAccessor extends AbstractTestClass {
     map1.put("k2", "v2");
     entity = Entity.entity(OBJECT_MAPPER.writeValueAsString(map1), MediaType.APPLICATION_JSON_TYPE);
     post(uri, ImmutableMap.of("command", "update"), entity, Response.Status.OK.getStatusCode());
-    body = get(uri, Response.Status.OK.getStatusCode(), true);
+    body = get(uri, null, Response.Status.OK.getStatusCode(), true);
     contentStore = OBJECT_MAPPER.readValue(body, new TypeReference<Map<String, String>>() {});
     Assert.assertEquals(contentStore, map1);
   }
@@ -185,7 +186,7 @@ public class TestWorkflowAccessor extends AbstractTestClass {
     Map<String, String> validCmd = ImmutableMap.of("command", "update");
     Map<String, String> invalidCmd = ImmutableMap.of("command", "delete"); // cmd not supported
 
-    get(invalidURI, Response.Status.NOT_FOUND.getStatusCode(), false);
+    get(invalidURI, null, Response.Status.NOT_FOUND.getStatusCode(), false);
     post(invalidURI, validCmd, validEntity, Response.Status.NOT_FOUND.getStatusCode());
 
     post(validURI, invalidCmd, validEntity, Response.Status.BAD_REQUEST.getStatusCode());