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.assertNotNull; 022import static org.junit.Assert.assertNull; 023import static org.junit.Assert.assertTrue; 024 025import java.io.IOException; 026import java.util.ArrayList; 027import java.util.Collections; 028import java.util.List; 029import java.util.NavigableMap; 030import org.apache.hadoop.hbase.client.ClusterConnection; 031import org.apache.hadoop.hbase.client.HConnectionTestingUtility; 032import org.apache.hadoop.hbase.client.RegionInfo; 033import org.apache.hadoop.hbase.client.RegionInfoBuilder; 034import org.apache.hadoop.hbase.client.Result; 035import org.apache.hadoop.hbase.client.Table; 036import org.apache.hadoop.hbase.client.coprocessor.Batch; 037import org.apache.hadoop.hbase.ipc.HBaseRpcController; 038import org.apache.hadoop.hbase.testclassification.MiscTests; 039import org.apache.hadoop.hbase.testclassification.SmallTests; 040import org.apache.hadoop.hbase.util.Bytes; 041import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 042import org.apache.hadoop.hbase.zookeeper.ZKWatcher; 043import org.junit.After; 044import org.junit.Before; 045import org.junit.ClassRule; 046import org.junit.Test; 047import org.junit.experimental.categories.Category; 048import org.mockito.Mockito; 049import org.mockito.invocation.InvocationOnMock; 050import org.mockito.stubbing.Answer; 051import org.slf4j.Logger; 052import org.slf4j.LoggerFactory; 053 054import org.apache.hbase.thirdparty.com.google.protobuf.RpcController; 055import org.apache.hbase.thirdparty.com.google.protobuf.ServiceException; 056 057import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos; 058import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.ScanRequest; 059import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.ScanResponse; 060 061/** 062 * Test MetaTableAccessor but without spinning up a cluster. We mock regionserver back and forth (we 063 * do spin up a zk cluster). 064 */ 065@Category({ MiscTests.class, SmallTests.class }) 066public class TestMetaTableAccessorNoCluster { 067 068 @ClassRule 069 public static final HBaseClassTestRule CLASS_RULE = 070 HBaseClassTestRule.forClass(TestMetaTableAccessorNoCluster.class); 071 072 private static final Logger LOG = LoggerFactory.getLogger(TestMetaTableAccessorNoCluster.class); 073 private static final HBaseTestingUtility UTIL = new HBaseTestingUtility(); 074 private static final Abortable ABORTABLE = new Abortable() { 075 boolean aborted = false; 076 077 @Override 078 public void abort(String why, Throwable e) { 079 LOG.info(why, e); 080 this.aborted = true; 081 throw new RuntimeException(e); 082 } 083 084 @Override 085 public boolean isAborted() { 086 return this.aborted; 087 } 088 }; 089 090 @Before 091 public void before() throws Exception { 092 UTIL.startMiniZKCluster(); 093 } 094 095 @After 096 public void after() throws IOException { 097 UTIL.shutdownMiniZKCluster(); 098 } 099 100 /** 101 * Expect a IOE to come out of multiMutate, even if down in the depths we throw a 102 * RuntimeException. See HBASE-23904 103 */ 104 @Test(expected = IOException.class) 105 public void testMultiMutate() throws Throwable { 106 Table table = Mockito.mock(Table.class); 107 Mockito 108 .when(table.coprocessorService(Mockito.any(), Mockito.any(byte[].class), 109 Mockito.any(byte[].class), Mockito.any(Batch.Call.class))) 110 .thenThrow(new RuntimeException("FAIL TEST WITH RuntimeException!")); 111 MetaTableAccessor.multiMutate(table, HConstants.LAST_ROW, Collections.emptyList()); 112 } 113 114 @Test 115 public void testGetHRegionInfo() throws IOException { 116 assertNull(MetaTableAccessor.getRegionInfo(new Result())); 117 118 List<Cell> kvs = new ArrayList<>(); 119 Result r = Result.create(kvs); 120 assertNull(MetaTableAccessor.getRegionInfo(r)); 121 122 byte[] f = HConstants.CATALOG_FAMILY; 123 // Make a key value that doesn't have the expected qualifier. 124 kvs.add(new KeyValue(HConstants.EMPTY_BYTE_ARRAY, f, HConstants.SERVER_QUALIFIER, f)); 125 r = Result.create(kvs); 126 assertNull(MetaTableAccessor.getRegionInfo(r)); 127 // Make a key that does not have a regioninfo value. 128 kvs.add(new KeyValue(HConstants.EMPTY_BYTE_ARRAY, f, HConstants.REGIONINFO_QUALIFIER, f)); 129 RegionInfo hri = MetaTableAccessor.getRegionInfo(Result.create(kvs)); 130 assertTrue(hri == null); 131 // OK, give it what it expects 132 kvs.clear(); 133 kvs.add(new KeyValue(HConstants.EMPTY_BYTE_ARRAY, f, HConstants.REGIONINFO_QUALIFIER, 134 RegionInfo.toByteArray(RegionInfoBuilder.FIRST_META_REGIONINFO))); 135 hri = MetaTableAccessor.getRegionInfo(Result.create(kvs)); 136 assertNotNull(hri); 137 assertTrue(RegionInfo.COMPARATOR.compare(hri, RegionInfoBuilder.FIRST_META_REGIONINFO) == 0); 138 } 139 140 /** 141 * Test that MetaTableAccessor will ride over server throwing "Server not running" IOEs. 142 * @see <a href="https://issues.apache.org/jira/browse/HBASE-3446">HBASE-3446</a> 143 */ 144 @Test 145 public void testRideOverServerNotRunning() 146 throws IOException, InterruptedException, ServiceException { 147 // Need a zk watcher. 148 ZKWatcher zkw = 149 new ZKWatcher(UTIL.getConfiguration(), this.getClass().getSimpleName(), ABORTABLE, true); 150 // This is a servername we use in a few places below. 151 ServerName sn = ServerName.valueOf("example.com", 1234, EnvironmentEdgeManager.currentTime()); 152 ClusterConnection connection = null; 153 try { 154 // Mock an ClientProtocol. Our mock implementation will fail a few 155 // times when we go to open a scanner. 156 final ClientProtos.ClientService.BlockingInterface implementation = 157 Mockito.mock(ClientProtos.ClientService.BlockingInterface.class); 158 // When scan called throw IOE 'Server not running' a few times 159 // before we return a scanner id. Whats WEIRD is that these 160 // exceptions do not show in the log because they are caught and only 161 // printed if we FAIL. We eventually succeed after retry so these don't 162 // show. We will know if they happened or not because we will ask 163 // mockito at the end of this test to verify that scan was indeed 164 // called the wanted number of times. 165 List<Cell> kvs = new ArrayList<>(); 166 final byte[] rowToVerify = Bytes.toBytes("rowToVerify"); 167 kvs.add(new KeyValue(rowToVerify, HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER, 168 RegionInfo.toByteArray(RegionInfoBuilder.FIRST_META_REGIONINFO))); 169 kvs.add(new KeyValue(rowToVerify, HConstants.CATALOG_FAMILY, HConstants.SERVER_QUALIFIER, 170 Bytes.toBytes(sn.getAddress().toString()))); 171 kvs.add(new KeyValue(rowToVerify, HConstants.CATALOG_FAMILY, HConstants.STARTCODE_QUALIFIER, 172 Bytes.toBytes(sn.getStartcode()))); 173 final List<CellScannable> cellScannables = new ArrayList<>(1); 174 cellScannables.add(Result.create(kvs)); 175 final ScanResponse.Builder builder = ScanResponse.newBuilder(); 176 for (CellScannable result : cellScannables) { 177 builder.addCellsPerResult(((Result) result).size()); 178 } 179 Mockito.when(implementation.scan((RpcController) Mockito.any(), (ScanRequest) Mockito.any())) 180 .thenThrow(new ServiceException("Server not running (1 of 3)")) 181 .thenThrow(new ServiceException("Server not running (2 of 3)")) 182 .thenThrow(new ServiceException("Server not running (3 of 3)")) 183 .thenAnswer(new Answer<ScanResponse>() { 184 @Override 185 public ScanResponse answer(InvocationOnMock invocation) throws Throwable { 186 ((HBaseRpcController) invocation.getArgument(0)) 187 .setCellScanner(CellUtil.createCellScanner(cellScannables)); 188 return builder.setScannerId(1234567890L).setMoreResults(false).build(); 189 } 190 }); 191 // Associate a spied-upon Connection with UTIL.getConfiguration. Need 192 // to shove this in here first so it gets picked up all over; e.g. by 193 // HTable. 194 connection = HConnectionTestingUtility.getSpiedConnection(UTIL.getConfiguration()); 195 196 // Fix the location lookup so it 'works' though no network. First 197 // make an 'any location' object. 198 final HRegionLocation anyLocation = 199 new HRegionLocation(RegionInfoBuilder.FIRST_META_REGIONINFO, sn); 200 final RegionLocations rl = new RegionLocations(anyLocation); 201 // Return the RegionLocations object when locateRegion 202 // The ugly format below comes of 'Important gotcha on spying real objects!' from 203 // http://mockito.googlecode.com/svn/branches/1.6/javadoc/org/mockito/Mockito.html 204 Mockito.doReturn(rl).when(connection).locateRegion((TableName) Mockito.any(), 205 (byte[]) Mockito.any(), Mockito.anyBoolean(), Mockito.anyBoolean(), Mockito.anyInt()); 206 207 // Now shove our HRI implementation into the spied-upon connection. 208 Mockito.doReturn(implementation).when(connection).getClient(Mockito.any()); 209 210 // Scan meta for user tables and verify we got back expected answer. 211 NavigableMap<RegionInfo, Result> hris = 212 MetaTableAccessor.getServerUserRegions(connection, sn); 213 assertEquals(1, hris.size()); 214 assertTrue(RegionInfo.COMPARATOR.compare(hris.firstEntry().getKey(), 215 RegionInfoBuilder.FIRST_META_REGIONINFO) == 0); 216 assertTrue(Bytes.equals(rowToVerify, hris.firstEntry().getValue().getRow())); 217 // Finally verify that scan was called four times -- three times 218 // with exception and then on 4th attempt we succeed 219 Mockito.verify(implementation, Mockito.times(4)).scan((RpcController) Mockito.any(), 220 (ScanRequest) Mockito.any()); 221 } finally { 222 if (connection != null && !connection.isClosed()) { 223 connection.close(); 224 } 225 zkw.close(); 226 } 227 } 228}