View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertNotNull;
22  import static org.junit.Assert.assertNull;
23  import static org.junit.Assert.assertTrue;
24  
25  import com.google.protobuf.RpcController;
26  import com.google.protobuf.ServiceException;
27  
28  import java.io.IOException;
29  import java.util.ArrayList;
30  import java.util.List;
31  import java.util.NavigableMap;
32  
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  import org.apache.hadoop.hbase.client.ClusterConnection;
36  import org.apache.hadoop.hbase.client.HConnectionTestingUtility;
37  import org.apache.hadoop.hbase.client.Result;
38  import org.apache.hadoop.hbase.ipc.HBaseRpcController;
39  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
40  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ScanRequest;
41  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ScanResponse;
42  import org.apache.hadoop.hbase.testclassification.MediumTests;
43  import org.apache.hadoop.hbase.util.Bytes;
44  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
45  import org.junit.After;
46  import org.junit.Before;
47  import org.junit.Test;
48  import org.junit.experimental.categories.Category;
49  import org.mockito.Mockito;
50  import org.mockito.invocation.InvocationOnMock;
51  import org.mockito.stubbing.Answer;
52  
53  /**
54   * Test MetaTableAccessor but without spinning up a cluster.
55   * We mock regionserver back and forth (we do spin up a zk cluster).
56   */
57  @Category(MediumTests.class)
58  public class TestMetaTableAccessorNoCluster {
59    private static final Log LOG = LogFactory.getLog(TestMetaTableAccessorNoCluster.class);
60    private static final  HBaseTestingUtility UTIL = new HBaseTestingUtility();
61    private static final Abortable ABORTABLE = new Abortable() {
62      boolean aborted = false;
63      @Override
64      public void abort(String why, Throwable e) {
65        LOG.info(why, e);
66        this.aborted = true;
67        throw new RuntimeException(e);
68      }
69      @Override
70      public boolean isAborted()  {
71        return this.aborted;
72      }
73    };
74  
75    @Before
76    public void before() throws Exception {
77      UTIL.startMiniZKCluster();
78    }
79  
80    @After
81    public void after() throws IOException {
82      UTIL.shutdownMiniZKCluster();
83    }
84  
85    @Test
86    public void testGetHRegionInfo() throws IOException {
87      assertNull(HRegionInfo.getHRegionInfo(new Result()));
88  
89      List<Cell> kvs = new ArrayList<Cell>();
90      Result r = Result.create(kvs);
91      assertNull(HRegionInfo.getHRegionInfo(r));
92  
93      byte [] f = HConstants.CATALOG_FAMILY;
94      // Make a key value that doesn't have the expected qualifier.
95      kvs.add(new KeyValue(HConstants.EMPTY_BYTE_ARRAY, f,
96        HConstants.SERVER_QUALIFIER, f));
97      r = Result.create(kvs);
98      assertNull(HRegionInfo.getHRegionInfo(r));
99      // Make a key that does not have a regioninfo value.
100     kvs.add(new KeyValue(HConstants.EMPTY_BYTE_ARRAY, f,
101       HConstants.REGIONINFO_QUALIFIER, f));
102     HRegionInfo hri = HRegionInfo.getHRegionInfo(Result.create(kvs));
103     assertTrue(hri == null);
104     // OK, give it what it expects
105     kvs.clear();
106     kvs.add(new KeyValue(HConstants.EMPTY_BYTE_ARRAY, f,
107       HConstants.REGIONINFO_QUALIFIER,
108       HRegionInfo.FIRST_META_REGIONINFO.toByteArray()));
109     hri = HRegionInfo.getHRegionInfo(Result.create(kvs));
110     assertNotNull(hri);
111     assertTrue(hri.equals(HRegionInfo.FIRST_META_REGIONINFO));
112   }
113 
114   /**
115    * Test that MetaTableAccessor will ride over server throwing
116    * "Server not running" IOEs.
117    * @see @link {https://issues.apache.org/jira/browse/HBASE-3446}
118    * @throws IOException
119    * @throws InterruptedException
120    */
121   @Test
122   public void testRideOverServerNotRunning()
123       throws IOException, InterruptedException, ServiceException {
124     // Need a zk watcher.
125     ZooKeeperWatcher zkw = new ZooKeeperWatcher(UTIL.getConfiguration(),
126       this.getClass().getSimpleName(), ABORTABLE, true);
127     // This is a servername we use in a few places below.
128     ServerName sn = ServerName.valueOf("example.com", 1234, System.currentTimeMillis());
129 
130     ClusterConnection connection = null;
131     try {
132       // Mock an ClientProtocol. Our mock implementation will fail a few
133       // times when we go to open a scanner.
134       final ClientProtos.ClientService.BlockingInterface implementation =
135         Mockito.mock(ClientProtos.ClientService.BlockingInterface.class);
136       // When scan called throw IOE 'Server not running' a few times
137       // before we return a scanner id.  Whats WEIRD is that these
138       // exceptions do not show in the log because they are caught and only
139       // printed if we FAIL.  We eventually succeed after retry so these don't
140       // show.  We will know if they happened or not because we will ask
141       // mockito at the end of this test to verify that scan was indeed
142       // called the wanted number of times.
143       List<Cell> kvs = new ArrayList<Cell>();
144       final byte [] rowToVerify = Bytes.toBytes("rowToVerify");
145       kvs.add(new KeyValue(rowToVerify,
146         HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER,
147         HRegionInfo.FIRST_META_REGIONINFO.toByteArray()));
148       kvs.add(new KeyValue(rowToVerify,
149         HConstants.CATALOG_FAMILY, HConstants.SERVER_QUALIFIER,
150         Bytes.toBytes(sn.getHostAndPort())));
151       kvs.add(new KeyValue(rowToVerify,
152         HConstants.CATALOG_FAMILY, HConstants.STARTCODE_QUALIFIER,
153         Bytes.toBytes(sn.getStartcode())));
154       final List<CellScannable> cellScannables = new ArrayList<CellScannable>(1);
155       cellScannables.add(Result.create(kvs));
156       final ScanResponse.Builder builder = ScanResponse.newBuilder();
157       for (CellScannable result : cellScannables) {
158         builder.addCellsPerResult(((Result)result).size());
159       }
160       Mockito.when(implementation.scan((RpcController) Mockito.any(), (ScanRequest) Mockito.any()))
161           .thenThrow(new ServiceException("Server not running (1 of 3)"))
162           .thenThrow(new ServiceException("Server not running (2 of 3)"))
163           .thenThrow(new ServiceException("Server not running (3 of 3)"))
164           .thenAnswer(new Answer<ScanResponse>() {
165             public ScanResponse answer(InvocationOnMock invocation) throws Throwable {
166               ((HBaseRpcController) invocation.getArguments()[0]).setCellScanner(CellUtil
167                   .createCellScanner(cellScannables));
168               return builder.setScannerId(1234567890L).setMoreResults(false).build();
169             }
170           });
171       // Associate a spied-upon HConnection with UTIL.getConfiguration.  Need
172       // to shove this in here first so it gets picked up all over; e.g. by
173       // HTable.
174       connection = HConnectionTestingUtility.getSpiedConnection(UTIL.getConfiguration());
175       
176       // Fix the location lookup so it 'works' though no network.  First
177       // make an 'any location' object.
178       final HRegionLocation anyLocation =
179         new HRegionLocation(HRegionInfo.FIRST_META_REGIONINFO, sn);
180       final RegionLocations rl = new RegionLocations(anyLocation);
181       // Return the RegionLocations object when locateRegion
182       // The ugly format below comes of 'Important gotcha on spying real objects!' from
183       // http://mockito.googlecode.com/svn/branches/1.6/javadoc/org/mockito/Mockito.html
184       ClusterConnection cConnection =
185           HConnectionTestingUtility.getSpiedClusterConnection(UTIL.getConfiguration());
186       Mockito.doReturn(rl).when
187       (cConnection).locateRegion((TableName)Mockito.any(), (byte[])Mockito.any(),
188               Mockito.anyBoolean(), Mockito.anyBoolean(), Mockito.anyInt());
189 
190       // Now shove our HRI implementation into the spied-upon connection.
191       Mockito.doReturn(implementation).
192         when(connection).getClient(Mockito.any(ServerName.class));
193 
194       // Scan meta for user tables and verify we got back expected answer.
195       NavigableMap<HRegionInfo, Result> hris =
196         MetaTableAccessor.getServerUserRegions(connection, sn);
197       assertEquals(1, hris.size());
198       assertTrue(hris.firstEntry().getKey().equals(HRegionInfo.FIRST_META_REGIONINFO));
199       assertTrue(Bytes.equals(rowToVerify, hris.firstEntry().getValue().getRow()));
200       // Finally verify that scan was called four times -- three times
201       // with exception and then on 4th attempt we succeed
202       Mockito.verify(implementation, Mockito.times(4)).
203         scan((RpcController)Mockito.any(), (ScanRequest)Mockito.any());
204     } finally {
205       if (connection != null && !connection.isClosed()) connection.close();
206       zkw.close();
207     }
208   }
209 }