View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.hadoop.hbase;
20  
21  import java.io.IOException;
22  import java.util.Properties;
23  import java.util.Set;
24  
25  import org.apache.commons.cli.CommandLine;
26  import org.apache.commons.lang.StringUtils;
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.hadoop.conf.Configuration;
30  import org.apache.hadoop.hbase.chaos.factories.MonkeyFactory;
31  import org.apache.hadoop.hbase.chaos.monkies.ChaosMonkey;
32  import org.apache.hadoop.hbase.util.AbstractHBaseTool;
33  import org.junit.After;
34  import org.junit.Before;
35  
36  /**
37   * Base class for HBase integration tests that want to use the Chaos Monkey.
38   * Usage: bin/hbase <sub_class_of_IntegrationTestBase> <options>
39   * Options: -h,--help Show usage
40   *          -m,--monkey <arg> Which chaos monkey to run
41   *          -monkeyProps <arg> The properties file for specifying chaos monkey properties.
42   *          -ncc Option to not clean up the cluster at the end.
43   */
44  public abstract class IntegrationTestBase extends AbstractHBaseTool {
45  
46    public static final String NO_CLUSTER_CLEANUP_LONG_OPT = "noClusterCleanUp";
47    public static final String MONKEY_LONG_OPT = "monkey";
48    public static final String CHAOS_MONKEY_PROPS = "monkeyProps";
49    private static final Log LOG = LogFactory.getLog(IntegrationTestBase.class);
50  
51    protected IntegrationTestingUtility util;
52    protected ChaosMonkey monkey;
53    protected String monkeyToUse;
54    protected Properties monkeyProps;
55    protected boolean noClusterCleanUp = false;
56  
57    public IntegrationTestBase() {
58      this(null);
59    }
60  
61    public IntegrationTestBase(String monkeyToUse) {
62      this.monkeyToUse = monkeyToUse;
63    }
64  
65    @Override
66    protected void addOptions() {
67      addOptWithArg("m", MONKEY_LONG_OPT, "Which chaos monkey to run");
68      addOptNoArg("ncc", NO_CLUSTER_CLEANUP_LONG_OPT,
69        "Don't clean up the cluster at the end");
70      addOptWithArg(CHAOS_MONKEY_PROPS, "The properties file for specifying chaos "
71          + "monkey properties.");
72    }
73  
74    @Override
75    protected void processOptions(CommandLine cmd) {
76      if (cmd.hasOption(MONKEY_LONG_OPT)) {
77        monkeyToUse = cmd.getOptionValue(MONKEY_LONG_OPT);
78      }
79      if (cmd.hasOption(NO_CLUSTER_CLEANUP_LONG_OPT)) {
80        noClusterCleanUp = true;
81      }
82      monkeyProps = new Properties();
83      if (cmd.hasOption(CHAOS_MONKEY_PROPS)) {
84        String chaosMonkeyPropsFile = cmd.getOptionValue(CHAOS_MONKEY_PROPS);
85        if (StringUtils.isNotEmpty(chaosMonkeyPropsFile)) {
86          try {
87            monkeyProps.load(this.getClass().getClassLoader()
88                .getResourceAsStream(chaosMonkeyPropsFile));
89          } catch (IOException e) {
90            LOG.warn(e);
91            System.exit(EXIT_FAILURE);
92          }
93        }
94      }
95    }
96  
97    @Override
98    public Configuration getConf() {
99      Configuration c = super.getConf();
100     if (c == null && util != null) {
101       conf = util.getConfiguration();
102       c = conf;
103     }
104     return c;
105   }
106 
107   @Override
108   protected int doWork() throws Exception {
109     setUp();
110     int result = -1;
111     try {
112       result = runTestFromCommandLine();
113     } finally {
114       cleanUp();
115     }
116 
117     return result;
118   }
119 
120   @Before
121   public void setUp() throws Exception {
122     setUpCluster();
123     setUpMonkey();
124   }
125 
126   @After
127   public void cleanUp() throws Exception {
128     cleanUpMonkey();
129     cleanUpCluster();
130   }
131 
132   public void setUpMonkey() throws Exception {
133     util = getTestingUtil(getConf());
134     MonkeyFactory fact = MonkeyFactory.getFactory(monkeyToUse);
135     if (fact == null) {
136       fact = getDefaultMonkeyFactory();
137     }
138     monkey = fact.setUtil(util)
139                  .setTableName(getTablename())
140                  .setProperties(monkeyProps)
141                  .setColumnFamilies(getColumnFamilies()).build();
142     startMonkey();
143   }
144 
145   protected MonkeyFactory getDefaultMonkeyFactory() {
146     // Run with no monkey in distributed context, with real monkey in local test context.
147     return MonkeyFactory.getFactory(
148       util.isDistributedCluster() ? MonkeyFactory.CALM : MonkeyFactory.SLOW_DETERMINISTIC);
149   }
150 
151   protected void startMonkey() throws Exception {
152     monkey.start();
153   }
154 
155   public void cleanUpMonkey() throws Exception {
156     cleanUpMonkey("Ending test");
157   }
158 
159   protected void cleanUpMonkey(String why) throws Exception {
160     if (monkey != null && !monkey.isStopped()) {
161       monkey.stop(why);
162       monkey.waitForStop();
163     }
164   }
165 
166   protected IntegrationTestingUtility getTestingUtil(Configuration conf) {
167     if (this.util == null) {
168       if (conf == null) {
169         this.util = new IntegrationTestingUtility();
170         this.setConf(util.getConfiguration());
171       } else {
172         this.util = new IntegrationTestingUtility(conf);
173       }
174     }
175     return util;
176   }
177 
178   public abstract void setUpCluster() throws Exception;
179 
180   public void cleanUpCluster() throws Exception {
181     if (util.isDistributedCluster() &&  (monkey == null || !monkey.isDestructive())) {
182       noClusterCleanUp = true;
183     }
184     if (noClusterCleanUp) {
185       LOG.debug("noClusterCleanUp is set, skip restoring the cluster");
186       return;
187     }
188     LOG.debug("Restoring the cluster");
189     util.restoreCluster();
190     LOG.debug("Done restoring the cluster");
191   }
192 
193   public abstract int runTestFromCommandLine() throws Exception;
194 
195   public abstract TableName getTablename();
196 
197   protected abstract Set<String> getColumnFamilies();
198 }