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 */ 018 019package org.apache.hadoop.hbase.client; 020 021import static junit.framework.TestCase.assertTrue; 022import static org.junit.Assert.assertEquals; 023 024import java.io.IOException; 025import java.util.Arrays; 026import java.util.List; 027import java.util.stream.Collectors; 028 029import org.apache.hadoop.hbase.HBaseClassTestRule; 030import org.apache.hadoop.hbase.HBaseTestingUtility; 031import org.apache.hadoop.hbase.ServerName; 032import org.apache.hadoop.hbase.TableName; 033import org.apache.hadoop.hbase.master.RegionState; 034import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv; 035import org.apache.hadoop.hbase.master.procedure.TableProcedureInterface; 036import org.apache.hadoop.hbase.procedure2.Procedure; 037import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; 038import org.apache.hadoop.hbase.procedure2.ProcedureSuspendedException; 039import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility; 040import org.apache.hadoop.hbase.regionserver.HRegionServer; 041import org.apache.hadoop.hbase.testclassification.ClientTests; 042import org.apache.hadoop.hbase.testclassification.LargeTests; 043import org.apache.hadoop.hbase.util.Bytes; 044import org.apache.hadoop.hbase.util.Threads; 045import org.junit.AfterClass; 046import org.junit.BeforeClass; 047import org.junit.ClassRule; 048import org.junit.Rule; 049import org.junit.Test; 050import org.junit.experimental.categories.Category; 051import org.junit.rules.TestName; 052import org.slf4j.Logger; 053import org.slf4j.LoggerFactory; 054 055import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 056 057/** 058 * Class to test HBaseHbck. 059 * Spins up the minicluster once at test start and then takes it down afterward. 060 * Add any testing of HBaseHbck functionality here. 061 */ 062@Category({LargeTests.class, ClientTests.class}) 063public class TestHbck { 064 @ClassRule 065 public static final HBaseClassTestRule CLASS_RULE = 066 HBaseClassTestRule.forClass(TestHbck.class); 067 068 private static final Logger LOG = LoggerFactory.getLogger(TestHbck.class); 069 private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); 070 071 @Rule 072 public TestName name = new TestName(); 073 074 private static final TableName TABLE_NAME = TableName.valueOf(TestHbck.class.getSimpleName()); 075 076 private static ProcedureExecutor<MasterProcedureEnv> procExec; 077 078 @BeforeClass 079 public static void setUpBeforeClass() throws Exception { 080 TEST_UTIL.startMiniCluster(3); 081 TEST_UTIL.createMultiRegionTable(TABLE_NAME, Bytes.toBytes("family1"), 5); 082 procExec = TEST_UTIL.getMiniHBaseCluster().getMaster().getMasterProcedureExecutor(); 083 } 084 085 @AfterClass 086 public static void tearDownAfterClass() throws Exception { 087 TEST_UTIL.shutdownMiniCluster(); 088 } 089 090 public static class SuspendProcedure extends 091 ProcedureTestingUtility.NoopProcedure<MasterProcedureEnv> implements TableProcedureInterface { 092 public SuspendProcedure() { 093 super(); 094 } 095 096 @Override 097 protected Procedure[] execute(final MasterProcedureEnv env) 098 throws ProcedureSuspendedException { 099 // Always suspend the procedure 100 throw new ProcedureSuspendedException(); 101 } 102 103 @Override 104 public TableName getTableName() { 105 return TABLE_NAME; 106 } 107 108 @Override 109 public TableOperationType getTableOperationType() { 110 return TableOperationType.READ; 111 } 112 } 113 114 @Test 115 public void testBypassProcedure() throws Exception { 116 // SuspendProcedure 117 final SuspendProcedure proc = new SuspendProcedure(); 118 long procId = procExec.submitProcedure(proc); 119 Thread.sleep(500); 120 121 //bypass the procedure 122 List<Long> pids = Arrays.<Long>asList(procId); 123 List<Boolean> results = 124 TEST_UTIL.getHbck().bypassProcedure(pids, 30000, false, false); 125 assertTrue("Failed to by pass procedure!", results.get(0)); 126 TEST_UTIL.waitFor(5000, () -> proc.isSuccess() && proc.isBypass()); 127 LOG.info("{} finished", proc); 128 } 129 130 @Test 131 public void testSetTableStateInMeta() throws IOException { 132 Hbck hbck = TEST_UTIL.getHbck(); 133 // set table state to DISABLED 134 hbck.setTableStateInMeta(new TableState(TABLE_NAME, TableState.State.DISABLED)); 135 // Method {@link Hbck#setTableStateInMeta()} returns previous state, which in this case 136 // will be DISABLED 137 TableState prevState = 138 hbck.setTableStateInMeta(new TableState(TABLE_NAME, TableState.State.ENABLED)); 139 assertTrue("Incorrect previous state! expeced=DISABLED, found=" + prevState.getState(), 140 prevState.isDisabled()); 141 } 142 143 @Test 144 public void testAssigns() throws IOException { 145 Hbck hbck = TEST_UTIL.getHbck(); 146 try (Admin admin = TEST_UTIL.getConnection().getAdmin()) { 147 List<RegionInfo> regions = admin.getRegions(TABLE_NAME); 148 for (RegionInfo ri: regions) { 149 RegionState rs = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager(). 150 getRegionStates().getRegionState(ri.getEncodedName()); 151 LOG.info("RS: {}", rs.toString()); 152 } 153 List<Long> pids = hbck.unassigns(regions.stream().map(r -> r.getEncodedName()). 154 collect(Collectors.toList())); 155 waitOnPids(pids); 156 for (RegionInfo ri: regions) { 157 RegionState rs = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager(). 158 getRegionStates().getRegionState(ri.getEncodedName()); 159 LOG.info("RS: {}", rs.toString()); 160 assertTrue(rs.toString(), rs.isClosed()); 161 } 162 pids = hbck.assigns(regions.stream().map(r -> r.getEncodedName()). 163 collect(Collectors.toList())); 164 waitOnPids(pids); 165 for (RegionInfo ri: regions) { 166 RegionState rs = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager(). 167 getRegionStates().getRegionState(ri.getEncodedName()); 168 LOG.info("RS: {}", rs.toString()); 169 assertTrue(rs.toString(), rs.isOpened()); 170 } 171 // What happens if crappy region list passed? 172 pids = hbck.assigns(Arrays.stream(new String [] {"a", "some rubbish name"}). 173 collect(Collectors.toList())); 174 for (long pid: pids) { 175 assertEquals(org.apache.hadoop.hbase.procedure2.Procedure.NO_PROC_ID, pid); 176 } 177 } 178 } 179 180 @Test 181 public void testScheduleSCP() throws Exception { 182 HRegionServer testRs = TEST_UTIL.getRSForFirstRegionInTable(TABLE_NAME); 183 TEST_UTIL.loadTable(TEST_UTIL.getConnection().getTable(TABLE_NAME), Bytes.toBytes("family1"), 184 true); 185 ServerName serverName = testRs.getServerName(); 186 Hbck hbck = TEST_UTIL.getHbck(); 187 List<Long> pids = 188 hbck.scheduleServerCrashProcedure(Arrays.asList(ProtobufUtil.toServerName(serverName))); 189 assertTrue(pids.get(0) > 0); 190 LOG.info("pid is {}", pids.get(0)); 191 192 pids = hbck.scheduleServerCrashProcedure(Arrays.asList(ProtobufUtil.toServerName(serverName))); 193 assertTrue(pids.get(0) == -1); 194 LOG.info("pid is {}", pids.get(0)); 195 } 196 197 private void waitOnPids(List<Long> pids) { 198 for (Long pid: pids) { 199 while (!TEST_UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor(). 200 isFinished(pid)) { 201 Threads.sleep(100); 202 } 203 } 204 } 205}