1   /**
2    * Copyright 2007 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase;
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.io.PrintWriter;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.hadoop.conf.Configuration;
29  import org.apache.hadoop.fs.FileSystem;
30  import org.apache.hadoop.fs.Path;
31  import org.apache.hadoop.hbase.client.HConnectionManager;
32  import org.apache.hadoop.hbase.client.HTable;
33  import org.apache.hadoop.hbase.util.FSUtils;
34  import org.apache.hadoop.hbase.zookeeper.MiniZooKeeperCluster;
35  import org.apache.hadoop.hdfs.MiniDFSCluster;
36  import org.apache.hadoop.util.ReflectionUtils;
37  
38  /**
39   * Abstract base class for HBase cluster junit tests.  Spins up an hbase
40   * cluster in setup and tears it down again in tearDown.
41   * @deprecated Use junit4 and {@link HBaseTestingUtility}
42   */
43  public abstract class HBaseClusterTestCase extends HBaseTestCase {
44    private static final Log LOG = LogFactory.getLog(HBaseClusterTestCase.class);
45    public MiniHBaseCluster cluster;
46    protected MiniDFSCluster dfsCluster;
47    protected MiniZooKeeperCluster zooKeeperCluster;
48    protected int regionServers;
49    protected boolean startDfs;
50    private boolean openMetaTable = true;
51  
52    /** default constructor */
53    public HBaseClusterTestCase() {
54      this(1);
55    }
56  
57    /**
58     * Start a MiniHBaseCluster with regionServers region servers in-process to
59     * start with. Also, start a MiniDfsCluster before starting the hbase cluster.
60     * The configuration used will be edited so that this works correctly.
61     * @param regionServers number of region servers to start.
62     */
63    public HBaseClusterTestCase(int regionServers) {
64      this(regionServers, true);
65    }
66  
67    /**  in-process to
68     * start with. Optionally, startDfs indicates if a MiniDFSCluster should be
69     * started. If startDfs is false, the assumption is that an external DFS is
70     * configured in hbase-site.xml and is already started, or you have started a
71     * MiniDFSCluster on your own and edited the configuration in memory. (You
72     * can modify the config used by overriding the preHBaseClusterSetup method.)
73     * @param regionServers number of region servers to start.
74     * @param startDfs set to true if MiniDFS should be started
75     */
76    public HBaseClusterTestCase(int regionServers, boolean startDfs) {
77      super();
78      this.startDfs = startDfs;
79      this.regionServers = regionServers;
80    }
81  
82    protected void setOpenMetaTable(boolean val) {
83      openMetaTable = val;
84    }
85  
86    /**
87     * Subclass hook.
88     *
89     * Run after dfs is ready but before hbase cluster is started up.
90     */
91    protected void preHBaseClusterSetup() throws Exception {
92      // continue
93    }
94  
95    /**
96     * Actually start the MiniHBase instance.
97     */
98    protected void hBaseClusterSetup() throws Exception {
99      File testDir = new File(getUnitTestdir(getName()).toString());
100     if (testDir.exists()) testDir.delete();
101 
102     // Note that this is done before we create the MiniHBaseCluster because we
103     // need to edit the config to add the ZooKeeper servers.
104     this.zooKeeperCluster = new MiniZooKeeperCluster();
105     int clientPort = this.zooKeeperCluster.startup(testDir);
106     conf.set("hbase.zookeeper.property.clientPort", Integer.toString(clientPort));
107     Configuration c = new Configuration(this.conf);
108     // start the mini cluster
109     this.cluster = new MiniHBaseCluster(c, regionServers);
110     if (openMetaTable) {
111       // opening the META table ensures that cluster is running
112       new HTable(c, HConstants.META_TABLE_NAME);
113     }
114   }
115 
116   /**
117    * Run after hbase cluster is started up.
118    */
119   protected void postHBaseClusterSetup() throws Exception {
120     // continue
121   }
122 
123   @Override
124   protected void setUp() throws Exception {
125     try {
126       if (this.startDfs) {
127         // This spews a bunch of warnings about missing scheme. TODO: fix.
128         this.dfsCluster = new MiniDFSCluster(0, this.conf, 2, true, true, true,
129           null, null, null, null);
130 
131         // mangle the conf so that the fs parameter points to the minidfs we
132         // just started up
133         FileSystem filesystem = dfsCluster.getFileSystem();
134         conf.set("fs.defaultFS", filesystem.getUri().toString());
135         Path parentdir = filesystem.getHomeDirectory();
136         conf.set(HConstants.HBASE_DIR, parentdir.toString());
137         filesystem.mkdirs(parentdir);
138         FSUtils.setVersion(filesystem, parentdir);
139       }
140 
141       // do the super setup now. if we had done it first, then we would have
142       // gotten our conf all mangled and a local fs started up.
143       super.setUp();
144 
145       // run the pre-cluster setup
146       preHBaseClusterSetup();
147 
148       // start the instance
149       hBaseClusterSetup();
150 
151       // run post-cluster setup
152       postHBaseClusterSetup();
153     } catch (Exception e) {
154       LOG.error("Exception in setup!", e);
155       if (cluster != null) {
156         cluster.shutdown();
157       }
158       if (zooKeeperCluster != null) {
159         zooKeeperCluster.shutdown();
160       }
161       if (dfsCluster != null) {
162         shutdownDfs(dfsCluster);
163       }
164       throw e;
165     }
166   }
167 
168   @Override
169   protected void tearDown() throws Exception {
170     if (!openMetaTable) {
171       // open the META table now to ensure cluster is running before shutdown.
172       new HTable(conf, HConstants.META_TABLE_NAME);
173     }
174     super.tearDown();
175     try {
176       HConnectionManager.deleteConnection(conf, true);
177       if (this.cluster != null) {
178         try {
179           this.cluster.shutdown();
180         } catch (Exception e) {
181           LOG.warn("Closing mini dfs", e);
182         }
183         try {
184           this.zooKeeperCluster.shutdown();
185         } catch (IOException e) {
186           LOG.warn("Shutting down ZooKeeper cluster", e);
187         }
188       }
189       if (startDfs) {
190         shutdownDfs(dfsCluster);
191       }
192     } catch (Exception e) {
193       LOG.error(e);
194     }
195     // ReflectionUtils.printThreadInfo(new PrintWriter(System.out),
196     //  "Temporary end-of-test thread dump debugging HADOOP-2040: " + getName());
197   }
198 
199 
200   /**
201    * Use this utility method debugging why cluster won't go down.  On a
202    * period it throws a thread dump.  Method ends when all cluster
203    * regionservers and master threads are no long alive.
204    */
205   public void threadDumpingJoin() {
206     if (this.cluster.getRegionServerThreads() != null) {
207       for(Thread t: this.cluster.getRegionServerThreads()) {
208         threadDumpingJoin(t);
209       }
210     }
211     threadDumpingJoin(this.cluster.getMaster());
212   }
213 
214   protected void threadDumpingJoin(final Thread t) {
215     if (t == null) {
216       return;
217     }
218     long startTime = System.currentTimeMillis();
219     while (t.isAlive()) {
220       try {
221         Thread.sleep(1000);
222       } catch (InterruptedException e) {
223         LOG.info("Continuing...", e);
224       }
225       if (System.currentTimeMillis() - startTime > 60000) {
226         startTime = System.currentTimeMillis();
227         ReflectionUtils.printThreadInfo(new PrintWriter(System.out),
228             "Automatic Stack Trace every 60 seconds waiting on " +
229             t.getName());
230       }
231     }
232   }
233 }