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