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}