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.client; 019 020import static org.junit.Assert.fail; 021import static org.mockito.ArgumentMatchers.any; 022import static org.mockito.Mockito.atLeast; 023import static org.mockito.Mockito.doReturn; 024import static org.mockito.Mockito.mock; 025import static org.mockito.Mockito.spy; 026import static org.mockito.Mockito.verify; 027import static org.mockito.Mockito.when; 028 029import com.google.protobuf.ServiceException; 030import java.io.IOException; 031import java.util.ArrayList; 032import org.apache.hadoop.conf.Configuration; 033import org.apache.hadoop.hbase.HBaseClassTestRule; 034import org.apache.hadoop.hbase.HBaseConfiguration; 035import org.apache.hadoop.hbase.HBaseTestingUtility; 036import org.apache.hadoop.hbase.HConstants; 037import org.apache.hadoop.hbase.HTableDescriptor; 038import org.apache.hadoop.hbase.MasterNotRunningException; 039import org.apache.hadoop.hbase.PleaseHoldException; 040import org.apache.hadoop.hbase.TableName; 041import org.apache.hadoop.hbase.ZooKeeperConnectionException; 042import org.apache.hadoop.hbase.ipc.HBaseRpcController; 043import org.apache.hadoop.hbase.ipc.RpcControllerFactory; 044import org.apache.hadoop.hbase.testclassification.ClientTests; 045import org.apache.hadoop.hbase.testclassification.SmallTests; 046import org.junit.ClassRule; 047import org.junit.Ignore; 048import org.junit.Rule; 049import org.junit.Test; 050import org.junit.experimental.categories.Category; 051import org.junit.rules.TestName; 052import org.mockito.Mockito; 053import org.mockito.invocation.InvocationOnMock; 054import org.mockito.stubbing.Answer; 055import org.slf4j.Logger; 056import org.slf4j.LoggerFactory; 057 058@Category({ SmallTests.class, ClientTests.class }) 059public class TestHBaseAdminNoCluster { 060 061 @ClassRule 062 public static final HBaseClassTestRule CLASS_RULE = 063 HBaseClassTestRule.forClass(TestHBaseAdminNoCluster.class); 064 065 private static final Logger LOG = LoggerFactory.getLogger(TestHBaseAdminNoCluster.class); 066 067 @Rule 068 public TestName name = new TestName(); 069 070 /** 071 * Verify that PleaseHoldException gets retried. HBASE-8764 072 */ 073 // TODO: Clean up, with Procedure V2 and nonce to prevent the same procedure to call mulitple 074 // time, this test is invalid anymore. Just keep the test around for some time before 075 // fully removing it. 076 @Ignore 077 @Test 078 public void testMasterMonitorCallableRetries() 079 throws MasterNotRunningException, ZooKeeperConnectionException, IOException, 080 org.apache.hbase.thirdparty.com.google.protobuf.ServiceException { 081 Configuration configuration = HBaseConfiguration.create(); 082 // Set the pause and retry count way down. 083 configuration.setLong(HConstants.HBASE_CLIENT_PAUSE, 1); 084 final int count = 10; 085 configuration.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, count); 086 // Get mocked connection. Getting the connection will register it so when HBaseAdmin is 087 // constructed with same configuration, it will find this mocked connection. 088 ClusterConnection connection = HConnectionTestingUtility.getMockedConnection(configuration); 089 // Mock so we get back the master interface. Make it so when createTable is called, we throw 090 // the PleaseHoldException. 091 MasterKeepAliveConnection masterAdmin = mock(MasterKeepAliveConnection.class); 092 when(masterAdmin.createTable(any(), any())) 093 .thenThrow(new ServiceException("Test fail").initCause(new PleaseHoldException("test"))); 094 when(connection.getMaster()).thenReturn(masterAdmin); 095 Admin admin = new HBaseAdmin(connection); 096 try { 097 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(name.getMethodName())); 098 // Pass any old htable descriptor; not important 099 try { 100 admin.createTable(htd, HBaseTestingUtility.KEYS_FOR_HBA_CREATE_TABLE); 101 fail(); 102 } catch (RetriesExhaustedException e) { 103 LOG.info("Expected fail", e); 104 } 105 // Assert we were called 'count' times. 106 verify(masterAdmin, atLeast(count)).createTable(any(), any()); 107 } finally { 108 admin.close(); 109 if (connection != null) connection.close(); 110 } 111 } 112 113 @Test 114 public void testMasterOperationsRetries() throws Exception { 115 116 // Admin.listTables() 117 testMasterOperationIsRetried(new MethodCaller() { 118 @Override 119 public void call(Admin admin) throws Exception { 120 admin.listTables(); 121 } 122 123 @Override 124 public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception { 125 Mockito.verify(masterAdmin, atLeast(count)).getTableDescriptors(any(), any()); 126 } 127 }); 128 129 // Admin.listTableNames() 130 testMasterOperationIsRetried(new MethodCaller() { 131 @Override 132 public void call(Admin admin) throws Exception { 133 admin.listTableNames(); 134 } 135 136 @Override 137 public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception { 138 Mockito.verify(masterAdmin, atLeast(count)).getTableNames(any(), any()); 139 } 140 }); 141 142 // Admin.getTableDescriptor() 143 testMasterOperationIsRetried(new MethodCaller() { 144 @Override 145 public void call(Admin admin) throws Exception { 146 admin.getTableDescriptor(TableName.valueOf(name.getMethodName())); 147 } 148 149 @Override 150 public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception { 151 Mockito.verify(masterAdmin, atLeast(count)).getTableDescriptors(any(), any()); 152 } 153 }); 154 155 // Admin.getTableDescriptorsByTableName() 156 testMasterOperationIsRetried(new MethodCaller() { 157 @Override 158 public void call(Admin admin) throws Exception { 159 admin.getTableDescriptorsByTableName(new ArrayList<>()); 160 } 161 162 @Override 163 public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception { 164 Mockito.verify(masterAdmin, atLeast(count)).getTableDescriptors(any(), any()); 165 } 166 }); 167 168 // Admin.move() 169 testMasterOperationIsRetried(new MethodCaller() { 170 @Override 171 public void call(Admin admin) throws Exception { 172 admin.move(new byte[0]); 173 } 174 175 @Override 176 public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception { 177 Mockito.verify(masterAdmin, atLeast(count)).moveRegion(any(), any()); 178 } 179 }); 180 181 // Admin.offline() 182 testMasterOperationIsRetried(new MethodCaller() { 183 @Override 184 public void call(Admin admin) throws Exception { 185 admin.offline(new byte[0]); 186 } 187 188 @Override 189 public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception { 190 Mockito.verify(masterAdmin, atLeast(count)).offlineRegion(any(), any()); 191 } 192 }); 193 194 // Admin.setBalancerRunning() 195 testMasterOperationIsRetried(new MethodCaller() { 196 @Override 197 public void call(Admin admin) throws Exception { 198 admin.setBalancerRunning(true, true); 199 } 200 201 @Override 202 public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception { 203 Mockito.verify(masterAdmin, atLeast(count)).setBalancerRunning(any(), any()); 204 } 205 }); 206 207 // Admin.balancer() 208 testMasterOperationIsRetried(new MethodCaller() { 209 @Override 210 public void call(Admin admin) throws Exception { 211 admin.balancer(); 212 } 213 214 @Override 215 public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception { 216 Mockito.verify(masterAdmin, atLeast(count)).balance(any(), any()); 217 } 218 }); 219 220 // Admin.enabledCatalogJanitor() 221 testMasterOperationIsRetried(new MethodCaller() { 222 @Override 223 public void call(Admin admin) throws Exception { 224 admin.enableCatalogJanitor(true); 225 } 226 227 @Override 228 public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception { 229 Mockito.verify(masterAdmin, atLeast(count)).enableCatalogJanitor(any(), any()); 230 } 231 }); 232 233 // Admin.runCatalogScan() 234 testMasterOperationIsRetried(new MethodCaller() { 235 @Override 236 public void call(Admin admin) throws Exception { 237 admin.runCatalogScan(); 238 } 239 240 @Override 241 public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception { 242 Mockito.verify(masterAdmin, atLeast(count)).runCatalogScan(any(), any()); 243 } 244 }); 245 246 // Admin.isCatalogJanitorEnabled() 247 testMasterOperationIsRetried(new MethodCaller() { 248 @Override 249 public void call(Admin admin) throws Exception { 250 admin.isCatalogJanitorEnabled(); 251 } 252 253 @Override 254 public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception { 255 Mockito.verify(masterAdmin, atLeast(count)).isCatalogJanitorEnabled(any(), any()); 256 } 257 }); 258 } 259 260 private static interface MethodCaller { 261 void call(Admin admin) throws Exception; 262 263 void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception; 264 } 265 266 private void testMasterOperationIsRetried(MethodCaller caller) throws Exception { 267 Configuration configuration = HBaseConfiguration.create(); 268 // Set the pause and retry count way down. 269 configuration.setLong(HConstants.HBASE_CLIENT_PAUSE, 1); 270 final int count = 10; 271 configuration.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, count); 272 273 ClusterConnection connection = mock(ClusterConnection.class); 274 when(connection.getConfiguration()).thenReturn(configuration); 275 ConnectionConfiguration connectionConfig = new ConnectionConfiguration(configuration); 276 when(connection.getConnectionConfiguration()).thenReturn(connectionConfig); 277 MasterKeepAliveConnection masterAdmin = mock(MasterKeepAliveConnection.class, new Answer() { 278 @Override 279 public Object answer(InvocationOnMock invocation) throws Throwable { 280 if (invocation.getMethod().getName().equals("close")) { 281 return null; 282 } 283 throw new MasterNotRunningException(); // all methods will throw an exception 284 } 285 }); 286 when(connection.getMaster()).thenReturn(masterAdmin); 287 RpcControllerFactory rpcControllerFactory = mock(RpcControllerFactory.class); 288 when(connection.getRpcControllerFactory()).thenReturn(rpcControllerFactory); 289 when(rpcControllerFactory.newController()).thenReturn(mock(HBaseRpcController.class)); 290 291 // we need a real retrying caller 292 RpcRetryingCallerFactory callerFactory = 293 new RpcRetryingCallerFactory(configuration, connectionConfig); 294 when(connection.getRpcRetryingCallerFactory()).thenReturn(callerFactory); 295 296 Admin admin = null; 297 try { 298 admin = spy(new HBaseAdmin(connection)); 299 // mock the call to getRegion since in the absence of a cluster (which means the meta 300 // is not assigned), getRegion can't function 301 doReturn(null).when(((HBaseAdmin) admin)).getRegion(any()); 302 try { 303 caller.call(admin); // invoke the HBaseAdmin method 304 fail(); 305 } catch (RetriesExhaustedException e) { 306 LOG.info("Expected fail", e); 307 } 308 // Assert we were called 'count' times. 309 caller.verify(masterAdmin, count); 310 } finally { 311 if (admin != null) { 312 admin.close(); 313 } 314 } 315 } 316}