| /** |
| * 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. |
| */ |
| |
| package org.apache.hadoop.hbase; |
| |
| import java.io.IOException; |
| |
| import org.apache.hadoop.conf.Configuration; |
| import org.apache.hadoop.util.ReflectionUtils; |
| |
| /** |
| * Facility for <strong>integration/system</strong> tests. This extends {@link HBaseTestingUtility} |
| * and adds-in the functionality needed by integration and system tests. This class understands |
| * distributed and pseudo-distributed/local cluster deployments, and abstracts those from the tests |
| * in this module. |
| * <p> |
| * IntegrationTestingUtility is constructed and used by the integration tests, but the tests |
| * themselves should not assume a particular deployment. They can rely on the methods in this |
| * class and HBaseCluster. Before the testing begins, the test should initialize the cluster by |
| * calling {@link #initializeCluster(int)}. |
| * <p> |
| * The cluster that is used defaults to a mini cluster, but it can be forced to use a distributed |
| * cluster by calling {@link #setUseDistributedCluster(Configuration)}. This method is invoked by |
| * test drivers (maven, IntegrationTestsDriver, etc) before initializing the cluster |
| * via {@link #initializeCluster(int)}. Individual tests should not directly call |
| * {@link #setUseDistributedCluster(Configuration)}. |
| */ |
| public class IntegrationTestingUtility extends HBaseTestingUtility { |
| |
| public IntegrationTestingUtility() { |
| this(HBaseConfiguration.create()); |
| } |
| |
| public IntegrationTestingUtility(Configuration conf) { |
| super(conf); |
| } |
| |
| /** |
| * Configuration that controls whether this utility assumes a running/deployed cluster. |
| * This is different than "hbase.cluster.distributed" since that parameter indicates whether the |
| * cluster is in an actual distributed environment, while this shows that there is a |
| * deployed (distributed or pseudo-distributed) cluster running, and we do not need to |
| * start a mini-cluster for tests. |
| */ |
| public static final String IS_DISTRIBUTED_CLUSTER = "hbase.test.cluster.distributed"; |
| |
| /** Config for pluggable hbase cluster manager */ |
| private static final String HBASE_CLUSTER_MANAGER_CLASS = "hbase.it.clustermanager.class"; |
| private static final Class<? extends ClusterManager> DEFAULT_HBASE_CLUSTER_MANAGER_CLASS = |
| HBaseClusterManager.class; |
| |
| /** |
| * Initializes the state of the cluster. It starts a new in-process mini cluster, OR |
| * if we are given an already deployed distributed cluster it initializes the state. |
| * @param numSlaves Number of slaves to start up if we are booting a mini cluster. Otherwise |
| * we check whether this many nodes are available and throw an exception if not. |
| */ |
| public void initializeCluster(int numSlaves) throws Exception { |
| if (isDistributedCluster()) { |
| createDistributedHBaseCluster(); |
| checkNodeCount(numSlaves); |
| } else { |
| startMiniCluster(numSlaves); |
| } |
| } |
| |
| /** |
| * Checks whether we have more than numSlaves nodes. Throws an |
| * exception otherwise. |
| */ |
| public void checkNodeCount(int numSlaves) throws Exception { |
| HBaseCluster cluster = getHBaseClusterInterface(); |
| if (cluster.getClusterStatus().getServers().size() < numSlaves) { |
| throw new Exception("Cluster does not have enough nodes:" + numSlaves); |
| } |
| } |
| |
| /** |
| * Restores the cluster to the initial state if it is a distributed cluster, otherwise, shutdowns the |
| * mini cluster. |
| */ |
| public void restoreCluster() throws IOException { |
| if (isDistributedCluster()) { |
| getHBaseClusterInterface().restoreInitialStatus(); |
| } else { |
| try { |
| shutdownMiniCluster(); |
| } catch (Exception e) { |
| // re-wrap into IOException |
| throw new IOException(e); |
| } |
| } |
| } |
| |
| /** |
| * Sets the configuration property to use a distributed cluster for the integration tests. Test drivers |
| * should use this to enforce cluster deployment. |
| */ |
| public static void setUseDistributedCluster(Configuration conf) { |
| conf.setBoolean(IS_DISTRIBUTED_CLUSTER, true); |
| System.setProperty(IS_DISTRIBUTED_CLUSTER, "true"); |
| } |
| |
| /** |
| * @return whether we are interacting with a distributed cluster as opposed to and in-process mini |
| * cluster or a local cluster. |
| * @see IntegrationTestingUtility#setUseDistributedCluster(Configuration) |
| */ |
| public boolean isDistributedCluster() { |
| Configuration conf = getConfiguration(); |
| boolean isDistributedCluster = false; |
| isDistributedCluster = Boolean.parseBoolean(System.getProperty(IS_DISTRIBUTED_CLUSTER, "false")); |
| if (!isDistributedCluster) { |
| isDistributedCluster = conf.getBoolean(IS_DISTRIBUTED_CLUSTER, false); |
| } |
| return isDistributedCluster; |
| } |
| |
| public void createDistributedHBaseCluster() throws IOException { |
| Configuration conf = getConfiguration(); |
| Class<? extends ClusterManager> clusterManagerClass = conf.getClass(HBASE_CLUSTER_MANAGER_CLASS, |
| DEFAULT_HBASE_CLUSTER_MANAGER_CLASS, ClusterManager.class); |
| ClusterManager clusterManager = ReflectionUtils.newInstance( |
| clusterManagerClass, conf); |
| setHBaseCluster(new DistributedHBaseCluster(conf, clusterManager)); |
| getHBaseAdmin(); |
| } |
| |
| } |