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. 081 * HBASE-8764 082 */ 083 //TODO: Clean up, with Procedure V2 and nonce to prevent the same procedure to call mulitple 084 // time, this test is invalid anymore. Just keep the test around for some time before 085 // fully removing it. 086 @Ignore 087 @Test 088 public void testMasterMonitorCallableRetries() 089 throws MasterNotRunningException, ZooKeeperConnectionException, IOException, 090 org.apache.hbase.thirdparty.com.google.protobuf.ServiceException { 091 Configuration configuration = HBaseConfiguration.create(); 092 // Set the pause and retry count way down. 093 configuration.setLong(HConstants.HBASE_CLIENT_PAUSE, 1); 094 final int count = 10; 095 configuration.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, count); 096 // Get mocked connection. Getting the connection will register it so when HBaseAdmin is 097 // constructed with same configuration, it will find this mocked connection. 098 ClusterConnection connection = HConnectionTestingUtility.getMockedConnection(configuration); 099 // Mock so we get back the master interface. Make it so when createTable is called, we throw 100 // the PleaseHoldException. 101 MasterKeepAliveConnection masterAdmin = Mockito.mock(MasterKeepAliveConnection.class); 102 Mockito.when(masterAdmin.createTable((RpcController)Mockito.any(), 103 (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 @Override 135 public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception { 136 Mockito.verify(masterAdmin, Mockito.atLeast(count)) 137 .getTableDescriptors((RpcController)Mockito.any(), 138 (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 @Override 149 public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception { 150 Mockito.verify(masterAdmin, Mockito.atLeast(count)) 151 .getTableNames((RpcController)Mockito.any(), 152 (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 @Override 163 public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception { 164 Mockito.verify(masterAdmin, Mockito.atLeast(count)) 165 .getTableDescriptors((RpcController)Mockito.any(), 166 (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 @Override 177 public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception { 178 Mockito.verify(masterAdmin, Mockito.atLeast(count)) 179 .getTableDescriptors((RpcController)Mockito.any(), 180 (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 @Override 191 public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception { 192 Mockito.verify(masterAdmin, Mockito.atLeast(count)) 193 .moveRegion((RpcController)Mockito.any(), 194 (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 @Override 205 public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception { 206 Mockito.verify(masterAdmin, Mockito.atLeast(count)) 207 .offlineRegion((RpcController)Mockito.any(), 208 (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 @Override 219 public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception { 220 Mockito.verify(masterAdmin, Mockito.atLeast(count)) 221 .setBalancerRunning((RpcController)Mockito.any(), 222 (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 @Override 233 public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception { 234 Mockito.verify(masterAdmin, Mockito.atLeast(count)) 235 .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 @Override 247 public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception { 248 Mockito.verify(masterAdmin, Mockito.atLeast(count)) 249 .enableCatalogJanitor((RpcController)Mockito.any(), 250 (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 @Override 261 public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception { 262 Mockito.verify(masterAdmin, Mockito.atLeast(count)) 263 .runCatalogScan((RpcController)Mockito.any(), 264 (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 @Override 275 public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception { 276 Mockito.verify(masterAdmin, Mockito.atLeast(count)) 277 .isCatalogJanitorEnabled((RpcController)Mockito.any(), 278 (IsCatalogJanitorEnabledRequest)Mockito.any()); 279 } 280 }); 281 } 282 283 private static interface MethodCaller { 284 void call(Admin admin) throws Exception; 285 void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception; 286 } 287 288 private void testMasterOperationIsRetried(MethodCaller caller) throws Exception { 289 Configuration configuration = HBaseConfiguration.create(); 290 // Set the pause and retry count way down. 291 configuration.setLong(HConstants.HBASE_CLIENT_PAUSE, 1); 292 final int count = 10; 293 configuration.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, count); 294 295 ClusterConnection connection = mock(ClusterConnection.class); 296 when(connection.getConfiguration()).thenReturn(configuration); 297 MasterKeepAliveConnection masterAdmin = 298 Mockito.mock(MasterKeepAliveConnection.class, new Answer() { 299 @Override 300 public Object answer(InvocationOnMock invocation) throws Throwable { 301 if (invocation.getMethod().getName().equals("close")) { 302 return null; 303 } 304 throw new MasterNotRunningException(); // all methods will throw an exception 305 } 306 }); 307 Mockito.when(connection.getMaster()).thenReturn(masterAdmin); 308 RpcControllerFactory rpcControllerFactory = Mockito.mock(RpcControllerFactory.class); 309 Mockito.when(connection.getRpcControllerFactory()).thenReturn(rpcControllerFactory); 310 Mockito.when(rpcControllerFactory.newController()).thenReturn( 311 Mockito.mock(HBaseRpcController.class)); 312 313 // we need a real retrying caller 314 RpcRetryingCallerFactory callerFactory = new RpcRetryingCallerFactory(configuration); 315 Mockito.when(connection.getRpcRetryingCallerFactory()).thenReturn(callerFactory); 316 317 Admin admin = null; 318 try { 319 admin = Mockito.spy(new HBaseAdmin(connection)); 320 // mock the call to getRegion since in the absence of a cluster (which means the meta 321 // is not assigned), getRegion can't function 322 Mockito.doReturn(null).when(((HBaseAdmin)admin)).getRegion(Matchers.<byte[]>any()); 323 try { 324 caller.call(admin); // invoke the HBaseAdmin method 325 fail(); 326 } catch (RetriesExhaustedException e) { 327 LOG.info("Expected fail", e); 328 } 329 // Assert we were called 'count' times. 330 caller.verify(masterAdmin, count); 331 } finally { 332 if (admin != null) {admin.close();} 333 } 334 } 335}