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