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