blob: cc923ffdad7c00a0b1d31b8f781f80182e570d80 [file] [log] [blame]
package org.apache.helix.controller.stages;
/*
* 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 com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.apache.helix.HelixDataAccessor;
import org.apache.helix.HelixProperty;
import org.apache.helix.MockAccessor;
import org.apache.helix.PropertyKey;
import org.apache.helix.controller.dataproviders.ResourceControllerDataProvider;
import org.apache.helix.model.ClusterConfig;
import org.apache.helix.model.IdealState;
import org.apache.helix.model.IdealState.IdealStateProperty;
import org.apache.helix.model.IdealState.RebalanceMode;
import org.apache.helix.model.Resource;
import org.apache.helix.model.StateModelDefinition;
import org.apache.helix.tools.StateModelConfigGenerator;
import org.testng.Assert;
import org.testng.annotations.Test;
public class TestResourceValidationStage {
private static final String PARTICIPANT = "localhost_1234";
private static final String STATE = "OFFLINE";
@Test
public void testIdealStateValidity() throws Exception {
MockAccessor accessor = new MockAccessor();
accessor.setProperty(accessor.keyBuilder().clusterConfig(), new ClusterConfig("TestCluster"));
// create some ideal states
String masterSlaveCustomResource = "masterSlaveCustomResource";
String onlineOfflineFullAutoResource = "onlineOfflineFullAutoResource";
String masterSlaveSemiAutoInvalidResource = "masterSlaveSemiAutoInvalidResource";
createIS(accessor, masterSlaveCustomResource, "MasterSlave", RebalanceMode.CUSTOMIZED);
createIS(accessor, onlineOfflineFullAutoResource, "OnlineOffline", RebalanceMode.FULL_AUTO);
createIS(accessor, masterSlaveSemiAutoInvalidResource, "MasterSlave", RebalanceMode.SEMI_AUTO);
// create some ideal state specs
createISSpec(accessor, masterSlaveCustomResource + "_spec", "MasterSlave",
RebalanceMode.CUSTOMIZED);
createISSpec(accessor, onlineOfflineFullAutoResource + "_spec", "OnlineOffline",
RebalanceMode.FULL_AUTO);
// add some state models
addStateModels(accessor);
// refresh the cache
ClusterEvent event = new ClusterEvent(ClusterEventType.Unknown);
ResourceControllerDataProvider cache = new ResourceControllerDataProvider();
cache.refresh(accessor);
event.addAttribute(AttributeName.ControllerDataProvider.name(), cache);
// run resource computation
new ResourceComputationStage().process(event);
Map<String, Resource> resourceMap =
event.getAttribute(AttributeName.RESOURCES_TO_REBALANCE.name());
Assert.assertTrue(resourceMap.containsKey(masterSlaveCustomResource));
Assert.assertTrue(resourceMap.containsKey(onlineOfflineFullAutoResource));
Assert.assertTrue(resourceMap.containsKey(masterSlaveSemiAutoInvalidResource));
// run resource validation
new ResourceValidationStage().process(event);
Map<String, Resource> finalResourceMap =
event.getAttribute(AttributeName.RESOURCES.name());
Assert.assertTrue(finalResourceMap.containsKey(masterSlaveCustomResource));
Assert.assertTrue(finalResourceMap.containsKey(onlineOfflineFullAutoResource));
Assert.assertFalse(finalResourceMap.containsKey(masterSlaveSemiAutoInvalidResource));
}
@Test
public void testNoSpec() throws Exception {
MockAccessor accessor = new MockAccessor();
accessor.setProperty(accessor.keyBuilder().clusterConfig(), new ClusterConfig("TestCluster"));
// create an ideal state and no spec
String masterSlaveCustomResource = "masterSlaveCustomResource";
createIS(accessor, masterSlaveCustomResource, "MasterSlave", RebalanceMode.CUSTOMIZED);
// add some state models
addStateModels(accessor);
// refresh the cache
ClusterEvent event = new ClusterEvent(ClusterEventType.Unknown);
ResourceControllerDataProvider cache = new ResourceControllerDataProvider();
cache.refresh(accessor);
event.addAttribute(AttributeName.ControllerDataProvider.name(), cache);
// run resource computation
new ResourceComputationStage().process(event);
Map<String, Resource> resourceMap = event.getAttribute(AttributeName.RESOURCES.name());
Assert.assertTrue(resourceMap.containsKey(masterSlaveCustomResource));
// run resource validation
new ResourceValidationStage().process(event);
Map<String, Resource> finalResourceMap = event.getAttribute(AttributeName.RESOURCES.name());
Assert.assertTrue(finalResourceMap.containsKey(masterSlaveCustomResource));
}
@Test
public void testMissingStateModel() throws Exception {
MockAccessor accessor = new MockAccessor();
accessor.setProperty(accessor.keyBuilder().clusterConfig(), new ClusterConfig("TestCluster"));
// create an ideal state and no spec
String masterSlaveCustomResource = "masterSlaveCustomResource";
String leaderStandbyCustomResource = "leaderStandbyCustomResource";
createIS(accessor, masterSlaveCustomResource, "MasterSlave", RebalanceMode.CUSTOMIZED);
createIS(accessor, leaderStandbyCustomResource, "LeaderStandby", RebalanceMode.CUSTOMIZED);
// add some state models (but not leader standby)
addStateModels(accessor);
// refresh the cache
ClusterEvent event = new ClusterEvent(ClusterEventType.Unknown);
ResourceControllerDataProvider cache = new ResourceControllerDataProvider();
cache.refresh(accessor);
event.addAttribute(AttributeName.ControllerDataProvider.name(), cache);
// run resource computation
new ResourceComputationStage().process(event);
Map<String, Resource> resourceMap = event.getAttribute(AttributeName.RESOURCES.name());
Assert.assertTrue(resourceMap.containsKey(masterSlaveCustomResource));
Assert.assertTrue(resourceMap.containsKey(leaderStandbyCustomResource));
// run resource validation
new ResourceValidationStage().process(event);
Map<String, Resource> finalResourceMap = event.getAttribute(AttributeName.RESOURCES.name());
Assert.assertTrue(finalResourceMap.containsKey(masterSlaveCustomResource));
Assert.assertFalse(finalResourceMap.containsKey(leaderStandbyCustomResource));
}
private void createIS(HelixDataAccessor accessor, String resourceId, String stateModelDefRef,
RebalanceMode rebalanceMode) {
IdealState idealState = new IdealState(resourceId);
idealState.setRebalanceMode(rebalanceMode);
idealState.setStateModelDefRef(stateModelDefRef);
idealState.setNumPartitions(1);
idealState.setReplicas("1");
idealState.getRecord().setListField(resourceId + "_0", ImmutableList.of(PARTICIPANT));
idealState.getRecord().setMapField(resourceId + "_0", ImmutableMap.of(PARTICIPANT, STATE));
accessor.setProperty(accessor.keyBuilder().idealStates(resourceId), idealState);
}
private void createISSpec(HelixDataAccessor accessor, String specId, String stateModelDefRef,
RebalanceMode rebalanceMode) {
PropertyKey propertyKey = accessor.keyBuilder().clusterConfig();
HelixProperty property = accessor.getProperty(propertyKey);
if (property == null) {
property = new HelixProperty("sampleClusterConfig");
}
String key = "IdealStateRule!" + specId;
String value =
IdealStateProperty.REBALANCE_MODE.toString() + "=" + rebalanceMode.toString() + ","
+ IdealStateProperty.STATE_MODEL_DEF_REF.toString() + "=" + stateModelDefRef;
property.getRecord().setSimpleField(key, value);
accessor.setProperty(propertyKey, property);
}
private void addStateModels(HelixDataAccessor accessor) {
StateModelDefinition masterSlave =
new StateModelDefinition(StateModelConfigGenerator.generateConfigForMasterSlave());
accessor.setProperty(accessor.keyBuilder().stateModelDef(masterSlave.getId()), masterSlave);
StateModelDefinition onlineOffline =
new StateModelDefinition(StateModelConfigGenerator.generateConfigForOnlineOffline());
accessor.setProperty(accessor.keyBuilder().stateModelDef(onlineOffline.getId()), onlineOffline);
}
}