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