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