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.master;
019
020import static org.apache.hadoop.hbase.HConstants.ZOOKEEPER_QUORUM;
021import static org.junit.jupiter.api.Assertions.assertFalse;
022import static org.junit.jupiter.api.Assertions.assertNull;
023
024import java.io.IOException;
025import org.apache.hadoop.conf.Configuration;
026import org.apache.hadoop.hbase.Abortable;
027import org.apache.hadoop.hbase.HBaseTestingUtil;
028import org.apache.hadoop.hbase.HConstants;
029import org.apache.hadoop.hbase.Waiter;
030import org.apache.hadoop.hbase.ZooKeeperConnectionException;
031import org.apache.hadoop.hbase.testclassification.MasterTests;
032import org.apache.hadoop.hbase.testclassification.MediumTests;
033import org.apache.hadoop.hbase.util.CommonFSUtils;
034import org.apache.hadoop.hbase.util.Threads;
035import org.apache.hadoop.hbase.zookeeper.ZKUtil;
036import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
037import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
038import org.apache.zookeeper.KeeperException;
039import org.junit.jupiter.api.AfterAll;
040import org.junit.jupiter.api.AfterEach;
041import org.junit.jupiter.api.BeforeAll;
042import org.junit.jupiter.api.Tag;
043import org.junit.jupiter.api.Test;
044import org.slf4j.Logger;
045import org.slf4j.LoggerFactory;
046
047/**
048 * Standup the master and fake it to test various aspects of master function. Does NOT spin up a
049 * mini hbase nor mini dfs cluster testing master (it does put up a zk cluster but this is usually
050 * pretty fast compared). Also, should be possible to inject faults at points difficult to get at in
051 * cluster context. TODO: Speed up the zk connection by Master. It pauses 5 seconds establishing
052 * session.
053 */
054@Tag(MasterTests.TAG)
055@Tag(MediumTests.TAG)
056public class TestMasterNoCluster {
057
058  private static final Logger LOG = LoggerFactory.getLogger(TestMasterNoCluster.class);
059
060  private static final HBaseTestingUtil TESTUTIL = new HBaseTestingUtil();
061
062  @BeforeAll
063  public static void setUpBeforeClass() throws Exception {
064    Configuration c = TESTUTIL.getConfiguration();
065    // We use local filesystem. Set it so it writes into the testdir.
066    CommonFSUtils.setRootDir(c, TESTUTIL.getDataTestDir());
067    DefaultMetricsSystem.setMiniClusterMode(true);
068    // Startup a mini zk cluster.
069    TESTUTIL.startMiniZKCluster();
070  }
071
072  @AfterAll
073  public static void tearDownAfterClass() throws Exception {
074    TESTUTIL.shutdownMiniZKCluster();
075  }
076
077  @AfterEach
078  public void tearDown() throws KeeperException, ZooKeeperConnectionException, IOException {
079    // Make sure zk is clean before we run the next test.
080    ZKWatcher zkw = new ZKWatcher(TESTUTIL.getConfiguration(), "@BeforeEach", new Abortable() {
081      @Override
082      public void abort(String why, Throwable e) {
083        throw new RuntimeException(why, e);
084      }
085
086      @Override
087      public boolean isAborted() {
088        return false;
089      }
090    });
091    // Before fails sometimes so retry.
092    try {
093      TESTUTIL.waitFor(10000, (Waiter.Predicate<Exception>) () -> {
094        try {
095          ZKUtil.deleteNodeRecursively(zkw, zkw.getZNodePaths().baseZNode);
096          return true;
097        } catch (KeeperException.NotEmptyException e) {
098          LOG.info("Failed delete, retrying", e);
099        }
100        return false;
101      });
102    } catch (Exception e) {
103      LOG.info("Failed zk clear", e);
104    }
105    zkw.close();
106  }
107
108  /**
109   * Test starting master then stopping it before its fully up.
110   */
111  @Test
112  public void testStopDuringStart() throws IOException, KeeperException, InterruptedException {
113    HMaster master = new HMaster(TESTUTIL.getConfiguration());
114    master.start();
115    // Immediately have it stop. We used hang in assigning meta.
116    master.stopMaster();
117    master.join();
118  }
119
120  @Test
121  public void testMasterInitWithSameClientServerZKQuorum() throws Exception {
122    Configuration conf = new Configuration(TESTUTIL.getConfiguration());
123    conf.set(HConstants.CLIENT_ZOOKEEPER_QUORUM, conf.get(ZOOKEEPER_QUORUM));
124    conf.setInt(HConstants.CLIENT_ZOOKEEPER_CLIENT_PORT, TESTUTIL.getZkCluster().getClientPort());
125    HMaster master = new HMaster(conf);
126    master.start();
127    // the master will abort due to IllegalArgumentException so we should finish within 60 seconds
128    master.join();
129  }
130
131  @Test
132  public void testMasterInitWithObserverModeClientZKQuorum() throws Exception {
133    Configuration conf = new Configuration(TESTUTIL.getConfiguration());
134    assertFalse(Boolean.getBoolean(HConstants.CLIENT_ZOOKEEPER_OBSERVER_MODE));
135    // set client ZK to some non-existing address and make sure server won't access client ZK
136    // (server start should not be affected)
137    conf.set(HConstants.CLIENT_ZOOKEEPER_QUORUM, HConstants.LOCALHOST);
138    conf.setInt(HConstants.CLIENT_ZOOKEEPER_CLIENT_PORT,
139      TESTUTIL.getZkCluster().getClientPort() + 1);
140    // need to enable maintenance mode so we will start master and an in process region server
141    conf.setBoolean(HMaster.MAINTENANCE_MODE, true);
142    // settings to allow us not to start additional RS
143    conf.setInt(ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART, 1);
144    // main setting for this test case
145    conf.setBoolean(HConstants.CLIENT_ZOOKEEPER_OBSERVER_MODE, true);
146    HMaster master = new HMaster(conf);
147    master.start();
148    while (!master.isInitialized()) {
149      Threads.sleep(200);
150    }
151    assertNull(master.getMetaLocationSyncer());
152    assertNull(master.masterAddressSyncer);
153    master.stopMaster();
154    master.join();
155  }
156}