001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase;
019
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertFalse;
022import static org.junit.Assert.assertNotEquals;
023import static org.junit.Assert.assertTrue;
024
025import java.io.File;
026import java.util.List;
027import org.apache.hadoop.conf.Configuration;
028import org.apache.hadoop.fs.FileSystem;
029import org.apache.hadoop.fs.FileUtil;
030import org.apache.hadoop.fs.Path;
031import org.apache.hadoop.hbase.client.Get;
032import org.apache.hadoop.hbase.client.Put;
033import org.apache.hadoop.hbase.client.Result;
034import org.apache.hadoop.hbase.client.Table;
035import org.apache.hadoop.hbase.http.ssl.KeyStoreTestUtil;
036import org.apache.hadoop.hbase.testclassification.LargeTests;
037import org.apache.hadoop.hbase.testclassification.MiscTests;
038import org.apache.hadoop.hbase.util.Bytes;
039import org.apache.hadoop.hbase.zookeeper.MiniZooKeeperCluster;
040import org.apache.hadoop.hdfs.MiniDFSCluster;
041import org.apache.hadoop.security.ssl.SSLFactory;
042import org.junit.ClassRule;
043import org.junit.Rule;
044import org.junit.Test;
045import org.junit.experimental.categories.Category;
046import org.junit.rules.TestName;
047import org.slf4j.Logger;
048import org.slf4j.LoggerFactory;
049
050/**
051 * Test our testing utility class
052 */
053@Category({ MiscTests.class, LargeTests.class })
054public class TestHBaseTestingUtil {
055  private static final int NUMTABLES = 1;
056  private static final int NUMROWS = 100;
057  private static final int NUMREGIONS = 10;
058
059  @ClassRule
060  public static final HBaseClassTestRule CLASS_RULE =
061    HBaseClassTestRule.forClass(TestHBaseTestingUtil.class);
062
063  private static final Logger LOG = LoggerFactory.getLogger(TestHBaseTestingUtil.class);
064
065  @Rule
066  public TestName name = new TestName();
067
068  /**
069   * Basic sanity test that spins up multiple HDFS and HBase clusters that share the same ZK
070   * ensemble. We then create the same table in both and make sure that what we insert in one place
071   * doesn't end up in the other.
072   * @throws Exception on error
073   */
074  @Test
075  public void testMultiClusters() throws Exception {
076    // Create three clusters
077
078    // Cluster 1.
079    HBaseTestingUtil htu1 = new HBaseTestingUtil();
080    // Set a different zk path for each cluster
081    htu1.getConfiguration().set(HConstants.ZOOKEEPER_ZNODE_PARENT, "/1");
082    htu1.startMiniZKCluster();
083
084    // Cluster 2
085    HBaseTestingUtil htu2 = new HBaseTestingUtil();
086    htu2.getConfiguration().set(HConstants.ZOOKEEPER_ZNODE_PARENT, "/2");
087    htu2.getConfiguration().set(HConstants.ZOOKEEPER_CLIENT_PORT,
088      htu1.getConfiguration().get(HConstants.ZOOKEEPER_CLIENT_PORT, "-1"));
089    htu2.setZkCluster(htu1.getZkCluster());
090
091    // Cluster 3; seed it with the conf from htu1 so we pickup the 'right'
092    // zk cluster config; it is set back into the config. as part of the
093    // start of minizkcluster.
094    HBaseTestingUtil htu3 = new HBaseTestingUtil();
095    htu3.getConfiguration().set(HConstants.ZOOKEEPER_ZNODE_PARENT, "/3");
096    htu3.getConfiguration().set(HConstants.ZOOKEEPER_CLIENT_PORT,
097      htu1.getConfiguration().get(HConstants.ZOOKEEPER_CLIENT_PORT, "-1"));
098    htu3.setZkCluster(htu1.getZkCluster());
099
100    try {
101      htu1.startMiniCluster();
102      htu2.startMiniCluster();
103      htu3.startMiniCluster();
104
105      final TableName tableName = TableName.valueOf(name.getMethodName());
106      final byte[] FAM_NAME = Bytes.toBytes("fam");
107      final byte[] ROW = Bytes.toBytes("row");
108      final byte[] QUAL_NAME = Bytes.toBytes("qual");
109      final byte[] VALUE = Bytes.toBytes("value");
110
111      Table table1 = htu1.createTable(tableName, FAM_NAME);
112      Table table2 = htu2.createTable(tableName, FAM_NAME);
113
114      Put put = new Put(ROW);
115      put.addColumn(FAM_NAME, QUAL_NAME, VALUE);
116      table1.put(put);
117
118      Get get = new Get(ROW);
119      get.addColumn(FAM_NAME, QUAL_NAME);
120      Result res = table1.get(get);
121      assertEquals(1, res.size());
122
123      res = table2.get(get);
124      assertEquals(0, res.size());
125
126      table1.close();
127      table2.close();
128
129    } finally {
130      htu3.shutdownMiniCluster();
131      htu2.shutdownMiniCluster();
132      htu1.shutdownMiniCluster();
133    }
134  }
135
136  @Test
137  public void testMiniCluster() throws Exception {
138    HBaseTestingUtil hbt = new HBaseTestingUtil();
139
140    SingleProcessHBaseCluster cluster = hbt.startMiniCluster();
141    try {
142      assertEquals(1, cluster.getLiveRegionServerThreads().size());
143    } finally {
144      hbt.shutdownMiniCluster();
145    }
146  }
147
148  @Test
149  public void testMiniClusterBindToWildcard() throws Exception {
150    HBaseTestingUtil hbt = new HBaseTestingUtil();
151    hbt.getConfiguration().set("hbase.regionserver.ipc.address", "0.0.0.0");
152    SingleProcessHBaseCluster cluster = hbt.startMiniCluster();
153    try {
154      assertEquals(1, cluster.getLiveRegionServerThreads().size());
155    } finally {
156      hbt.shutdownMiniCluster();
157    }
158  }
159
160  @Test
161  public void testMiniClusterWithSSLOn() throws Exception {
162    final String BASEDIR = System.getProperty("test.build.dir", "target/test-dir") + "/"
163      + TestHBaseTestingUtil.class.getSimpleName();
164    String sslConfDir = KeyStoreTestUtil.getClasspathDir(TestHBaseTestingUtil.class);
165    String keystoresDir = new File(BASEDIR).getAbsolutePath();
166
167    HBaseTestingUtil hbt = new HBaseTestingUtil();
168    File base = new File(BASEDIR);
169    FileUtil.fullyDelete(base);
170    base.mkdirs();
171
172    KeyStoreTestUtil.setupSSLConfig(keystoresDir, sslConfDir, hbt.getConfiguration(), false);
173
174    hbt.getConfiguration().set("hbase.ssl.enabled", "true");
175    hbt.getConfiguration().addResource(hbt.getConfiguration().get(SSLFactory.SSL_CLIENT_CONF_KEY));
176    hbt.getConfiguration().addResource(hbt.getConfiguration().get(SSLFactory.SSL_SERVER_CONF_KEY));
177
178    SingleProcessHBaseCluster cluster = hbt.startMiniCluster();
179    try {
180      assertEquals(1, cluster.getLiveRegionServerThreads().size());
181    } finally {
182      hbt.shutdownMiniCluster();
183    }
184  }
185
186  /**
187   * Test that we can start and stop multiple time a cluster with the same HBaseTestingUtility.
188   */
189  @Test
190  public void testMultipleStartStop() throws Exception {
191    HBaseTestingUtil htu1 = new HBaseTestingUtil();
192    Path foo = new Path("foo");
193
194    htu1.startMiniCluster();
195    htu1.getDFSCluster().getFileSystem().create(foo);
196    assertTrue(htu1.getDFSCluster().getFileSystem().exists(foo));
197    htu1.shutdownMiniCluster();
198
199    htu1.startMiniCluster();
200    assertFalse(htu1.getDFSCluster().getFileSystem().exists(foo));
201    htu1.getDFSCluster().getFileSystem().create(foo);
202    assertTrue(htu1.getDFSCluster().getFileSystem().exists(foo));
203    htu1.shutdownMiniCluster();
204  }
205
206  @Test
207  public void testMiniZooKeeperWithOneServer() throws Exception {
208    HBaseTestingUtil hbt = new HBaseTestingUtil();
209    MiniZooKeeperCluster cluster1 = hbt.startMiniZKCluster();
210    try {
211      assertEquals(0, cluster1.getBackupZooKeeperServerNum());
212      assertTrue((cluster1.killCurrentActiveZooKeeperServer() == -1));
213    } finally {
214      hbt.shutdownMiniZKCluster();
215    }
216  }
217
218  @Test
219  public void testMiniZooKeeperWithMultipleServers() throws Exception {
220    HBaseTestingUtil hbt = new HBaseTestingUtil();
221    // set up zookeeper cluster with 5 zk servers
222    MiniZooKeeperCluster cluster2 = hbt.startMiniZKCluster(5);
223    int defaultClientPort = 21818;
224    cluster2.setDefaultClientPort(defaultClientPort);
225    try {
226      assertEquals(4, cluster2.getBackupZooKeeperServerNum());
227
228      // killing the current active zk server
229      int currentActivePort = cluster2.killCurrentActiveZooKeeperServer();
230      assertTrue(currentActivePort >= defaultClientPort);
231      // Check if the client port is returning a proper value
232      assertTrue(cluster2.getClientPort() == currentActivePort);
233
234      // kill another active zk server
235      currentActivePort = cluster2.killCurrentActiveZooKeeperServer();
236      assertTrue(currentActivePort >= defaultClientPort);
237      assertTrue(cluster2.getClientPort() == currentActivePort);
238      assertEquals(2, cluster2.getBackupZooKeeperServerNum());
239      assertEquals(3, cluster2.getZooKeeperServerNum());
240
241      // killing the backup zk servers
242      cluster2.killOneBackupZooKeeperServer();
243      cluster2.killOneBackupZooKeeperServer();
244      assertEquals(0, cluster2.getBackupZooKeeperServerNum());
245      assertEquals(1, cluster2.getZooKeeperServerNum());
246
247      // killing the last zk server
248      currentActivePort = cluster2.killCurrentActiveZooKeeperServer();
249      assertTrue(currentActivePort == -1);
250      assertTrue(cluster2.getClientPort() == currentActivePort);
251      // this should do nothing.
252      cluster2.killOneBackupZooKeeperServer();
253      assertEquals(-1, cluster2.getBackupZooKeeperServerNum());
254      assertEquals(0, cluster2.getZooKeeperServerNum());
255    } finally {
256      hbt.shutdownMiniZKCluster();
257    }
258  }
259
260  @Test
261  public void testMiniZooKeeperWithMultipleClientPorts() throws Exception {
262    int defaultClientPort = 8888;
263    int i, j;
264    HBaseTestingUtil hbt = new HBaseTestingUtil();
265
266    // Test 1 - set up zookeeper cluster with same number of ZK servers and specified client ports
267    int[] clientPortList1 = { 1111, 1112, 1113 };
268    MiniZooKeeperCluster cluster1 = hbt.startMiniZKCluster(clientPortList1.length, clientPortList1);
269    try {
270      List<Integer> clientPortListInCluster = cluster1.getClientPortList();
271
272      for (i = 0; i < clientPortListInCluster.size(); i++) {
273        // cannot assert the specific port due to the port conflict in which situation
274        // it always chooses a bigger port by +1. The below is the same.
275        assertTrue(clientPortListInCluster.get(i).intValue() >= clientPortList1[i]);
276      }
277    } finally {
278      hbt.shutdownMiniZKCluster();
279    }
280
281    // Test 2 - set up zookeeper cluster with more ZK servers than specified client ports
282    hbt.getConfiguration().setInt("test.hbase.zookeeper.property.clientPort", defaultClientPort);
283    int[] clientPortList2 = { 2222, 2223 };
284    MiniZooKeeperCluster cluster2 =
285      hbt.startMiniZKCluster(clientPortList2.length + 2, clientPortList2);
286
287    try {
288      List<Integer> clientPortListInCluster = cluster2.getClientPortList();
289
290      for (i = 0, j = 0; i < clientPortListInCluster.size(); i++) {
291        if (i < clientPortList2.length) {
292          assertTrue(clientPortListInCluster.get(i).intValue() >= clientPortList2[i]);
293        } else {
294          // servers with no specified client port will use defaultClientPort or some other ports
295          // based on defaultClientPort
296          assertTrue(clientPortListInCluster.get(i).intValue() >= defaultClientPort + j);
297          j++;
298        }
299      }
300    } finally {
301      hbt.shutdownMiniZKCluster();
302    }
303
304    // Test 3 - set up zookeeper cluster with invalid client ports
305    hbt.getConfiguration().setInt("test.hbase.zookeeper.property.clientPort", defaultClientPort);
306    int[] clientPortList3 = { 3333, -3334, 3335, 0 };
307    MiniZooKeeperCluster cluster3 =
308      hbt.startMiniZKCluster(clientPortList3.length + 1, clientPortList3);
309
310    try {
311      List<Integer> clientPortListInCluster = cluster3.getClientPortList();
312
313      for (i = 0, j = 0; i < clientPortListInCluster.size(); i++) {
314        // Servers will only use valid client ports; if ports are not specified or invalid,
315        // the default port or a port based on default port will be used.
316        if (i < clientPortList3.length && clientPortList3[i] > 0) {
317          assertTrue(clientPortListInCluster.get(i).intValue() >= clientPortList3[i]);
318        } else {
319          assertTrue(clientPortListInCluster.get(i).intValue() >= defaultClientPort + j);
320          j++;
321        }
322      }
323    } finally {
324      hbt.shutdownMiniZKCluster();
325    }
326
327    // Test 4 - set up zookeeper cluster with default port and some other ports used
328    // This test tests that the defaultClientPort and defaultClientPort+2 are used, so
329    // the algorithm should choice defaultClientPort+1 and defaultClientPort+3 to fill
330    // out the ports for servers without ports specified.
331    hbt.getConfiguration().setInt("test.hbase.zookeeper.property.clientPort", defaultClientPort);
332    int[] clientPortList4 = { -4444, defaultClientPort + 2, 4446, defaultClientPort };
333    MiniZooKeeperCluster cluster4 =
334      hbt.startMiniZKCluster(clientPortList4.length + 1, clientPortList4);
335
336    try {
337      List<Integer> clientPortListInCluster = cluster4.getClientPortList();
338
339      for (i = 0, j = 1; i < clientPortListInCluster.size(); i++) {
340        // Servers will only use valid client ports; if ports are not specified or invalid,
341        // the default port or a port based on default port will be used.
342        if (i < clientPortList4.length && clientPortList4[i] > 0) {
343          assertTrue(clientPortListInCluster.get(i).intValue() >= clientPortList4[i]);
344        } else {
345          assertTrue(clientPortListInCluster.get(i).intValue() >= defaultClientPort + j);
346          j += 2;
347        }
348      }
349    } finally {
350      hbt.shutdownMiniZKCluster();
351    }
352
353    // Test 5 - set up zookeeper cluster with same ports specified - fail is expected.
354    int[] clientPortList5 = { 5555, 5556, 5556 };
355
356    try {
357      MiniZooKeeperCluster cluster5 =
358        hbt.startMiniZKCluster(clientPortList5.length, clientPortList5);
359      assertTrue(cluster5.getClientPort() == -1); // expected failure
360    } catch (Exception e) {
361      // exception is acceptable
362    } finally {
363      hbt.shutdownMiniZKCluster();
364    }
365  }
366
367  @Test
368  public void testMiniDFSCluster() throws Exception {
369    HBaseTestingUtil hbt = new HBaseTestingUtil();
370    MiniDFSCluster cluster = hbt.startMiniDFSCluster(null);
371    FileSystem dfs = cluster.getFileSystem();
372    Path dir = new Path("dir");
373    Path qualifiedDir = dfs.makeQualified(dir);
374    LOG.info("dir=" + dir + ", qualifiedDir=" + qualifiedDir);
375    assertFalse(dfs.exists(qualifiedDir));
376    assertTrue(dfs.mkdirs(qualifiedDir));
377    assertTrue(dfs.delete(qualifiedDir, true));
378    hbt.shutdownMiniCluster();
379  }
380
381  @Test
382  public void testSetupClusterTestBuildDir() throws Exception {
383    HBaseTestingUtil hbt = new HBaseTestingUtil();
384    Path testdir = hbt.getClusterTestDir();
385    LOG.info("uuid-subdir=" + testdir);
386    FileSystem fs = hbt.getTestFileSystem();
387
388    assertFalse(fs.exists(testdir));
389
390    hbt.startMiniDFSCluster(null);
391    assertTrue(fs.exists(testdir));
392
393    hbt.shutdownMiniCluster();
394    assertFalse(fs.exists(testdir));
395  }
396
397  @Test
398  public void testTestDir() throws Exception {
399    HBaseTestingUtil hbt = new HBaseTestingUtil();
400    Path testdir = hbt.getDataTestDir();
401    LOG.info("testdir=" + testdir);
402    FileSystem fs = hbt.getTestFileSystem();
403    assertTrue(!fs.exists(testdir));
404    assertTrue(fs.mkdirs(testdir));
405    assertTrue(hbt.cleanupTestDir());
406  }
407
408  @Test
409  public void testOverridingOfDefaultPorts() throws Exception {
410    // confirm that default port properties being overridden to random
411    Configuration defaultConfig = HBaseConfiguration.create();
412    defaultConfig.setInt(HConstants.MASTER_INFO_PORT, HConstants.DEFAULT_MASTER_INFOPORT);
413    defaultConfig.setInt(HConstants.REGIONSERVER_INFO_PORT,
414      HConstants.DEFAULT_REGIONSERVER_INFOPORT);
415    HBaseTestingUtil htu = new HBaseTestingUtil(defaultConfig);
416    try {
417      SingleProcessHBaseCluster defaultCluster = htu.startMiniCluster();
418      final String masterHostPort =
419        defaultCluster.getMaster().getServerName().getAddress().toString();
420      assertNotEquals(HConstants.DEFAULT_MASTER_INFOPORT,
421        defaultCluster.getConfiguration().getInt(HConstants.MASTER_INFO_PORT, 0));
422      assertNotEquals(HConstants.DEFAULT_REGIONSERVER_INFOPORT,
423        defaultCluster.getConfiguration().getInt(HConstants.REGIONSERVER_INFO_PORT, 0));
424      assertEquals(masterHostPort,
425        defaultCluster.getConfiguration().get(HConstants.MASTER_ADDRS_KEY));
426    } finally {
427      htu.shutdownMiniCluster();
428    }
429
430    // confirm that nonDefault (custom) port settings are NOT overridden
431    Configuration altConfig = HBaseConfiguration.create();
432    final int nonDefaultMasterInfoPort = 3333;
433    final int nonDefaultRegionServerPort = 4444;
434    altConfig.setInt(HConstants.MASTER_INFO_PORT, nonDefaultMasterInfoPort);
435    altConfig.setInt(HConstants.REGIONSERVER_INFO_PORT, nonDefaultRegionServerPort);
436    htu = new HBaseTestingUtil(altConfig);
437    try {
438      SingleProcessHBaseCluster customCluster = htu.startMiniCluster();
439      final String masterHostPort =
440        customCluster.getMaster().getServerName().getAddress().toString();
441      assertEquals(nonDefaultMasterInfoPort,
442        customCluster.getConfiguration().getInt(HConstants.MASTER_INFO_PORT, 0));
443      assertEquals(nonDefaultRegionServerPort,
444        customCluster.getConfiguration().getInt(HConstants.REGIONSERVER_INFO_PORT, 0));
445      assertEquals(masterHostPort,
446        customCluster.getConfiguration().get(HConstants.MASTER_ADDRS_KEY));
447    } finally {
448      htu.shutdownMiniCluster();
449    }
450  }
451
452  // This test demonstrates how long killHBTU takes vs. shutdownHBTU takes
453  // for realistic results, adjust NUMROWS, NUMTABLES to much larger number.
454  @Test
455  public void testKillMiniHBaseCluster() throws Exception {
456
457    HBaseTestingUtil htu = new HBaseTestingUtil();
458    htu.startMiniZKCluster();
459
460    try {
461      htu.startMiniHBaseCluster();
462
463      TableName tableName;
464      byte[] FAM_NAME;
465
466      for (int i = 0; i < NUMTABLES; i++) {
467        tableName = TableName.valueOf(name.getMethodName() + i);
468        FAM_NAME = Bytes.toBytes("fam" + i);
469
470        try (Table table = htu.createMultiRegionTable(tableName, FAM_NAME, NUMREGIONS)) {
471          htu.loadRandomRows(table, FAM_NAME, 100, NUMROWS);
472        }
473      }
474    } finally {
475      htu.killMiniHBaseCluster();
476      htu.shutdownMiniZKCluster();
477    }
478  }
479}