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 7d7001b54ee3a7bc2954878c34447ba8a338c0c1 Author: Yi Wang <[email protected]> AuthorDate: Wed Mar 20 16:46:22 2019 -0700 Single stoppable API impl RB=1603158 G=helix-reviewers A=jxue,hulee Signed-off-by: Hunter Lee <[email protected]> --- .../helix/manager/zk/ZKHelixDataAccessor.java | 8 +++ .../java/org/apache/helix/model/ClusterConfig.java | 11 --- .../org/apache/helix/model/TestClusterConfig.java | 18 ----- .../apache/helix/rest/client/CustomRestClient.java | 43 ++++++++++++ .../helix/rest/client/CustomRestClientFactory.java | 35 ++++++++++ .../helix/rest/client/CustomRestClientImpl.java | 38 ++++++++++ ...rWrapper.java => HelixDataAccessorWrapper.java} | 10 +-- .../rest/server/json/instance/StoppableCheck.java | 69 +++++++++++++++++++ .../server/resources/helix/InstanceAccessor.java | 35 ++++++++++ .../helix/rest/server/service/InstanceService.java | 34 +++++++++ .../rest/server/service/InstanceServiceImpl.java | 80 ++++++++++++++++++++++ .../helix/rest/server/TestInstanceAccessor.java | 14 ++++ .../server/json/instance/TestStoppableCheck.java | 56 +++++++++++++++ .../rest/server/util/JerseyUriRequestBuilder.java | 3 +- 14 files changed, 417 insertions(+), 37 deletions(-) diff --git a/helix-core/src/main/java/org/apache/helix/manager/zk/ZKHelixDataAccessor.java b/helix-core/src/main/java/org/apache/helix/manager/zk/ZKHelixDataAccessor.java index c871573..51f16ac 100644 --- a/helix-core/src/main/java/org/apache/helix/manager/zk/ZKHelixDataAccessor.java +++ b/helix-core/src/main/java/org/apache/helix/manager/zk/ZKHelixDataAccessor.java @@ -72,6 +72,14 @@ public class ZKHelixDataAccessor implements HelixDataAccessor { _propertyKeyBuilder = new PropertyKey.Builder(_clusterName); } + /* Copy constructor */ + public ZKHelixDataAccessor(ZKHelixDataAccessor dataAccessor) { + _clusterName = dataAccessor._clusterName; + _instanceType = dataAccessor._instanceType; + _baseDataAccessor = dataAccessor._baseDataAccessor; + _propertyKeyBuilder = new PropertyKey.Builder(_clusterName); + } + @Override public boolean createStateModelDef(StateModelDefinition stateModelDef) { String path = PropertyPathBuilder.stateModelDef(_clusterName, stateModelDef.getId()); diff --git a/helix-core/src/main/java/org/apache/helix/model/ClusterConfig.java b/helix-core/src/main/java/org/apache/helix/model/ClusterConfig.java index ec9b1d3..bbbaa72 100644 --- a/helix-core/src/main/java/org/apache/helix/model/ClusterConfig.java +++ b/helix-core/src/main/java/org/apache/helix/model/ClusterConfig.java @@ -338,17 +338,6 @@ public class ClusterConfig extends HelixProperty { } /** - * Get cluster topology by level. - * E.g, {zone, rack, host, instance} - * @return - */ - public String[] getTopologyLevel() { - String topology = getTopology(); - String[] parts = topology.split(TOPOLOGY_SPLITTER); - return Arrays.copyOfRange(parts, 1, parts.length); - } - - /** * Set cluster fault zone type, this should be set combined with {@link #setTopology(String)}. * @param faultZoneType */ diff --git a/helix-core/src/test/java/org/apache/helix/model/TestClusterConfig.java b/helix-core/src/test/java/org/apache/helix/model/TestClusterConfig.java deleted file mode 100644 index 0b4fb0a..0000000 --- a/helix-core/src/test/java/org/apache/helix/model/TestClusterConfig.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.apache.helix.model; - -import org.testng.Assert; -import org.testng.annotations.Test; - - -public class TestClusterConfig { - - @Test - public void testGetZoneId() { - ClusterConfig clusterConfig = new ClusterConfig("test"); - clusterConfig.setTopology("/zone/rack/host/instance"); - - String[] levels = clusterConfig.getTopologyLevel(); - - Assert.assertEquals(levels.length, 4); - } -} diff --git a/helix-rest/src/main/java/org/apache/helix/rest/client/CustomRestClient.java b/helix-rest/src/main/java/org/apache/helix/rest/client/CustomRestClient.java new file mode 100644 index 0000000..f8ce0e5 --- /dev/null +++ b/helix-rest/src/main/java/org/apache/helix/rest/client/CustomRestClient.java @@ -0,0 +1,43 @@ +package org.apache.helix.rest.client; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.Map; + + +/** + * Interface for interacting with client side rest endpoints + */ +public interface CustomRestClient { + /** + * Get stoppable check result on instance + * + * @param customPayloads generic payloads required from client side and helix only works as proxy + * @return a map where key is custom stoppable check name and boolean value indicates if the check succeeds + */ + Map<String, Boolean> getInstanceStoppableCheck(Map<String, String> customPayloads); + /** + * Get stoppable check result on partition + * + * @param customPayloads generic payloads required from client side and helix only works as proxy + * @return a map where key is custom stoppable check name and boolean value indicates if the check succeeds + */ + Map<String, Boolean> getPartitionStoppableCheck(Map<String, String> customPayloads); +} diff --git a/helix-rest/src/main/java/org/apache/helix/rest/client/CustomRestClientFactory.java b/helix-rest/src/main/java/org/apache/helix/rest/client/CustomRestClientFactory.java new file mode 100644 index 0000000..acbfef7 --- /dev/null +++ b/helix-rest/src/main/java/org/apache/helix/rest/client/CustomRestClientFactory.java @@ -0,0 +1,35 @@ +package org.apache.helix.rest.client; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * The memory efficient factory to create instances for {@link CustomRestClient} + */ +public class CustomRestClientFactory { + private static final String INSTANCE_HEALTH_STATUS = "/instanceHealthStatus"; + private static final String PARTITION_HEALTH_STATUS = "/partitionHealthStatus"; + + private CustomRestClientFactory() {} + + public static CustomRestClient get(String jsonContent) { + //TODO: add implementation + return new CustomRestClientImpl(); + } +} diff --git a/helix-rest/src/main/java/org/apache/helix/rest/client/CustomRestClientImpl.java b/helix-rest/src/main/java/org/apache/helix/rest/client/CustomRestClientImpl.java new file mode 100644 index 0000000..133a338 --- /dev/null +++ b/helix-rest/src/main/java/org/apache/helix/rest/client/CustomRestClientImpl.java @@ -0,0 +1,38 @@ +package org.apache.helix.rest.client; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.HashMap; +import java.util.Map; + + +//TODO: add implementation details +class CustomRestClientImpl implements CustomRestClient { + + @Override + public Map<String, Boolean> getInstanceStoppableCheck(Map<String, String> customPayloads) { + return new HashMap<>(); + } + + @Override + public Map<String, Boolean> getPartitionStoppableCheck(Map<String, String> customPayloads) { + return new HashMap<>(); + } +} 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/HelixDataAccessorWrapper.java similarity index 76% rename from helix-rest/src/main/java/org/apache/helix/rest/common/ZKReadAccessorWrapper.java rename to helix-rest/src/main/java/org/apache/helix/rest/common/HelixDataAccessorWrapper.java index f8a4f4f..1a26831 100644 --- a/helix-rest/src/main/java/org/apache/helix/rest/common/ZKReadAccessorWrapper.java +++ b/helix-rest/src/main/java/org/apache/helix/rest/common/HelixDataAccessorWrapper.java @@ -4,11 +4,8 @@ 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; @@ -17,13 +14,12 @@ import org.apache.helix.manager.zk.ZKHelixDataAccessor; * 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 { +public final class HelixDataAccessorWrapper 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); + public HelixDataAccessorWrapper(ZKHelixDataAccessor dataAccessor) { + super(dataAccessor); } @Override diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/json/instance/StoppableCheck.java b/helix-rest/src/main/java/org/apache/helix/rest/server/json/instance/StoppableCheck.java new file mode 100644 index 0000000..8dd1d31 --- /dev/null +++ b/helix-rest/src/main/java/org/apache/helix/rest/server/json/instance/StoppableCheck.java @@ -0,0 +1,69 @@ +package org.apache.helix.rest.server.json.instance; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.collect.ImmutableMap; + + +public class StoppableCheck { + private static final String HELIX_CHECK_PREFIX = "Helix:"; + private static final String CUSTOM_CHECK_PREFIX = "Custom:"; + + @JsonProperty("stoppable") + private boolean isStoppable; + @JsonProperty("failedChecks") + private List<String> failedChecks; + + public StoppableCheck(boolean isStoppable, List<String> failedChecks) { + this.isStoppable = isStoppable; + this.failedChecks = failedChecks; + } + + public static StoppableCheck mergeStoppableChecks(Map<String, Boolean> helixChecks, Map<String, Boolean> customChecks) { + Map<String, Boolean> mergedResult = ImmutableMap.<String, Boolean>builder() + .putAll(appendPrefix(helixChecks, HELIX_CHECK_PREFIX)) + .putAll(appendPrefix(customChecks, CUSTOM_CHECK_PREFIX)) + .build(); + + List<String> failedChecks = new ArrayList<>(); + for (Map.Entry<String, Boolean> entry : mergedResult.entrySet()) { + if (!entry.getValue()) { + failedChecks.add(entry.getKey()); + } + } + + return new StoppableCheck(failedChecks.isEmpty(), failedChecks); + } + + private static Map<String, Boolean> appendPrefix(Map<String, Boolean> checks, String prefix) { + Map<String, Boolean> result = new HashMap<>(); + for (Map.Entry<String, Boolean> entry : checks.entrySet()) { + result.put(prefix + entry.getKey(), entry.getValue()); + } + + return result; + } +} 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 cfed0e2..db44ff9 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 @@ -20,10 +20,12 @@ package org.apache.helix.rest.server.resources.helix; */ import java.io.IOException; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; @@ -31,6 +33,7 @@ import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.apache.helix.ConfigAccessor; @@ -38,6 +41,7 @@ import org.apache.helix.HelixAdmin; import org.apache.helix.HelixDataAccessor; import org.apache.helix.HelixException; import org.apache.helix.ZNRecord; +import org.apache.helix.manager.zk.ZKHelixDataAccessor; import org.apache.helix.model.ClusterConfig; import org.apache.helix.model.CurrentState; import org.apache.helix.model.Error; @@ -48,6 +52,12 @@ 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.apache.helix.rest.client.CustomRestClient; +import org.apache.helix.rest.client.CustomRestClientFactory; +import org.apache.helix.rest.common.HelixDataAccessorWrapper; +import org.apache.helix.rest.server.json.instance.StoppableCheck; +import org.apache.helix.rest.server.service.InstanceService; +import org.apache.helix.rest.server.service.InstanceServiceImpl; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.node.ArrayNode; import org.codehaus.jackson.node.JsonNodeFactory; @@ -56,6 +66,8 @@ import org.eclipse.jetty.util.StringUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.fasterxml.jackson.databind.ObjectMapper; + @Path("/clusters/{clusterId}/instances") public class InstanceAccessor extends AbstractHelixResource { private final static Logger _logger = LoggerFactory.getLogger(InstanceAccessor.class); @@ -185,6 +197,29 @@ public class InstanceAccessor extends AbstractHelixResource { return JSONRepresentation(instanceMap); } + @POST + @Path("{instanceName}/stoppable") + @Consumes(MediaType.APPLICATION_JSON) + public Response isInstanceStoppable(String jsonContent, + @PathParam("clusterId") String clusterId, @PathParam("instanceName") String instanceName) throws IOException { + ObjectMapper objectMapper = new ObjectMapper(); + HelixDataAccessor dataAccessor = getDataAccssor(clusterId); + // TODO reduce GC by dependency injection + InstanceService instanceService = new InstanceServiceImpl( + new HelixDataAccessorWrapper((ZKHelixDataAccessor) dataAccessor), getConfigAccessor()); + + Map<String, Boolean> helixStoppableCheck = + instanceService.getInstanceStoppableCheck(clusterId, instanceName); + CustomRestClient customClient = CustomRestClientFactory.get(jsonContent); + // TODO add the json content parse logic + Map<String, Boolean> customStoppableCheck = + customClient.getInstanceStoppableCheck(Collections.<String, String> emptyMap()); + StoppableCheck stoppableCheck = + StoppableCheck.mergeStoppableChecks(helixStoppableCheck, customStoppableCheck); + + return OK(objectMapper.writeValueAsString(stoppableCheck)); + } + @PUT @Path("{instanceName}") public Response addInstance(@PathParam("clusterId") String clusterId, diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/service/InstanceService.java b/helix-rest/src/main/java/org/apache/helix/rest/server/service/InstanceService.java new file mode 100644 index 0000000..664d9c0 --- /dev/null +++ b/helix-rest/src/main/java/org/apache/helix/rest/server/service/InstanceService.java @@ -0,0 +1,34 @@ +package org.apache.helix.rest.server.service; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.Map; + + +public interface InstanceService { + /** + * Get the current instance stoppable checks based on Helix own business logic + * + * @param clusterId + * @param instanceName + * @return a map where key is stoppable check name and boolean value represents whether the check succeeds + */ + Map<String, Boolean> getInstanceStoppableCheck(String clusterId, String instanceName); +} diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/service/InstanceServiceImpl.java b/helix-rest/src/main/java/org/apache/helix/rest/server/service/InstanceServiceImpl.java new file mode 100644 index 0000000..d179c27 --- /dev/null +++ b/helix-rest/src/main/java/org/apache/helix/rest/server/service/InstanceServiceImpl.java @@ -0,0 +1,80 @@ +package org.apache.helix.rest.server.service; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.HashMap; +import java.util.Map; + +import org.apache.helix.ConfigAccessor; +import org.apache.helix.HelixDataAccessor; +import org.apache.helix.HelixException; +import org.apache.helix.util.InstanceValidationUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class InstanceServiceImpl implements InstanceService { + private static final Logger _logger = LoggerFactory.getLogger(InstanceServiceImpl.class); + + private final HelixDataAccessor _dataAccessor; + private final ConfigAccessor _configAccessor; + + public InstanceServiceImpl(HelixDataAccessor dataAccessor, ConfigAccessor configAccessor) { + _dataAccessor = dataAccessor; + _configAccessor = configAccessor; + } + + @Override + public Map<String, Boolean> getInstanceStoppableCheck(String clusterId, String instanceName) { + Map<String, Boolean> healthStatus = new HashMap<>(); + healthStatus.put(HealthStatus.HAS_VALID_CONFIG.name(), InstanceValidationUtil.hasValidConfig(_dataAccessor, clusterId, instanceName)); + if (!healthStatus.get(HealthStatus.HAS_VALID_CONFIG.name())) { + _logger.error("The instance {} doesn't have valid configuration", instanceName); + return healthStatus; + } + + // Any exceptions occurred below due to invalid instance config shouldn't happen + healthStatus.put(HealthStatus.IS_ENABLED.name(), InstanceValidationUtil.isEnabled(_dataAccessor, _configAccessor, clusterId, instanceName)); + healthStatus.put(HealthStatus.IS_ALIVE.name(), InstanceValidationUtil.isAlive(_dataAccessor, clusterId, instanceName)); + healthStatus.put(HealthStatus.HAS_RESOURCE_ASSIGNED.name(), InstanceValidationUtil.hasResourceAssigned(_dataAccessor, clusterId, instanceName)); + healthStatus.put(HealthStatus.HAS_DISABLED_PARTITIONS.name(), InstanceValidationUtil.hasDisabledPartitions(_dataAccessor, clusterId, instanceName)); + healthStatus.put(HealthStatus.HAS_ERROR_PARTITIONS.name(), InstanceValidationUtil.hasErrorPartitions(_dataAccessor, clusterId, instanceName)); + + try { + boolean isStable = InstanceValidationUtil.isInstanceStable(_dataAccessor, instanceName); + healthStatus.put(HealthStatus.IS_STABLE.name(), isStable); + } catch (HelixException e) { + _logger.error("Failed to check instance is stable, message: {}", e.getMessage()); + // TODO action on the stable check exception + } + + return healthStatus; + } + + private enum HealthStatus { + IS_ALIVE, + IS_ENABLED, + HAS_RESOURCE_ASSIGNED, + HAS_DISABLED_PARTITIONS, + HAS_VALID_CONFIG, + HAS_ERROR_PARTITIONS, + IS_STABLE + } +} 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 be47cab..54f85d6 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 @@ -25,6 +25,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import javax.ws.rs.client.Entity; @@ -54,6 +55,19 @@ public class TestInstanceAccessor extends AbstractTestClass { private final static String INSTANCE_NAME = CLUSTER_NAME + "localhost_12918"; @Test + public void testIsInstanceStoppable() throws IOException { + System.out.println("Start test :" + TestHelper.getTestMethodName()); + Map<String, String> params = ImmutableMap.of("client", "espresso"); + Entity entity = + Entity.entity(OBJECT_MAPPER.writeValueAsString(params), MediaType.APPLICATION_JSON_TYPE); + Response response = new JerseyUriRequestBuilder("clusters/{}/instances/{}/stoppable") + .format(CLUSTER_NAME, INSTANCE_NAME).post(this, entity); + String checkResult = response.readEntity(String.class); + Assert.assertEquals(checkResult, + "{\"stoppable\":false,\"failedChecks\":[\"Helix:HAS_DISABLED_PARTITIONS\",\"Helix:HAS_RESOURCE_ASSIGNED\",\"Helix:HAS_ERROR_PARTITIONS\",\"Helix:IS_ALIVE\"]}"); + } + + @Test (dependsOnMethods = "testIsInstanceStoppable") public void testGetAllMessages() throws IOException { System.out.println("Start test :" + TestHelper.getTestMethodName()); diff --git a/helix-rest/src/test/java/org/apache/helix/rest/server/json/instance/TestStoppableCheck.java b/helix-rest/src/test/java/org/apache/helix/rest/server/json/instance/TestStoppableCheck.java new file mode 100644 index 0000000..25702cf --- /dev/null +++ b/helix-rest/src/test/java/org/apache/helix/rest/server/json/instance/TestStoppableCheck.java @@ -0,0 +1,56 @@ +package org.apache.helix.rest.server.json.instance; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.Map; + +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; +import com.google.common.collect.ImmutableMap; + + +public class TestStoppableCheck { + + @Test + public void whenSerializingStoppableCheck() throws JsonProcessingException { + StoppableCheck stoppableCheck = new StoppableCheck(false, ImmutableList.of("failedCheck")); + + ObjectMapper mapper = new ObjectMapper(); + String result = mapper.writeValueAsString(stoppableCheck); + + Assert.assertEquals(result, "{\"stoppable\":false,\"failedChecks\":[\"failedCheck\"]}"); + } + + @Test + public void testMergeStoppableChecks() throws JsonProcessingException { + Map<String, Boolean> helixCheck = ImmutableMap.of("check0", false, "check1", false); + Map<String, Boolean> customCheck = ImmutableMap.of("check1", true, "check2", true); + + StoppableCheck stoppableCheck = StoppableCheck.mergeStoppableChecks(helixCheck, customCheck); + ObjectMapper mapper = new ObjectMapper(); + String result = mapper.writeValueAsString(stoppableCheck); + + Assert.assertEquals(result, "{\"stoppable\":false,\"failedChecks\":[\"Helix:check1\",\"Helix:check0\"]}"); + } +} 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 a8fde73..e0642b3 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 @@ -107,9 +107,10 @@ public class JerseyUriRequestBuilder { * @param container * @param entity */ - public void post(JerseyTestNg.ContainerPerClassTest container, Entity entity) { + public Response post(JerseyTestNg.ContainerPerClassTest container, Entity entity) { final Response response = buildWebTarget(container).request().post(entity); Assert.assertEquals(response.getStatus(), _expectedStatusCode); + return response; } /**
