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.catalog;
19  
20  import static org.junit.Assert.assertTrue;
21  
22  import java.io.IOException;
23  import java.util.ArrayList;
24  import java.util.List;
25  import java.util.NavigableMap;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.hadoop.hbase.*;
30  import org.apache.hadoop.hbase.client.HConnection;
31  import org.apache.hadoop.hbase.client.HConnectionManager;
32  import org.apache.hadoop.hbase.client.HConnectionTestingUtility;
33  import org.apache.hadoop.hbase.client.Result;
34  import org.apache.hadoop.hbase.client.Scan;
35  import org.apache.hadoop.hbase.ipc.HRegionInterface;
36  import org.apache.hadoop.hbase.util.Bytes;
37  import org.apache.hadoop.hbase.util.Writables;
38  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
39  import org.junit.After;
40  import org.junit.Before;
41  import org.junit.Test;
42  import org.junit.experimental.categories.Category;
43  import org.mockito.Mockito;
44  
45  /**
46   * Test MetaReader/Editor but without spinning up a cluster.
47   * We mock regionserver back and forth (we do spin up a zk cluster).
48   */
49  @Category(MediumTests.class)
50  public class TestMetaReaderEditorNoCluster {
51    private static final Log LOG = LogFactory.getLog(TestMetaReaderEditorNoCluster.class);
52    private static final  HBaseTestingUtility UTIL = new HBaseTestingUtility();
53    private static final Abortable ABORTABLE = new Abortable() {
54      boolean aborted = false;
55      @Override
56      public void abort(String why, Throwable e) {
57        LOG.info(why, e);
58        this.aborted = true;
59        throw new RuntimeException(e);
60      }
61      @Override
62      public boolean isAborted()  {
63        return this.aborted;
64      }
65    };
66  
67    @Before
68    public void before() throws Exception {
69      UTIL.startMiniZKCluster();
70    }
71  
72    @After
73    public void after() throws IOException {
74      UTIL.shutdownMiniZKCluster();
75    }
76  
77    /**
78     * Test that MetaReader will ride over server throwing
79     * "Server not running" IOEs.
80     * @see https://issues.apache.org/jira/browse/HBASE-3446
81     * @throws IOException 
82     * @throws InterruptedException 
83     */
84    @Test
85    public void testRideOverServerNotRunning() throws IOException, InterruptedException {
86      // Need a zk watcher.
87      ZooKeeperWatcher zkw = new ZooKeeperWatcher(UTIL.getConfiguration(),
88        this.getClass().getSimpleName(), ABORTABLE, true);
89      // This is a servername we use in a few places below.
90      ServerName sn = new ServerName("example.com", 1234, System.currentTimeMillis());
91  
92      HConnection connection = null;
93      CatalogTracker ct = null;
94      try {
95        // Mock an HRegionInterface. Our mock implementation will fail a few
96        // times when we go to open a scanner.
97        final HRegionInterface implementation = Mockito.mock(HRegionInterface.class);
98        // When openScanner called throw IOE 'Server not running' a few times
99        // before we return a scanner id.  Whats WEIRD is that these
100       // exceptions do not show in the log because they are caught and only
101       // printed if we FAIL.  We eventually succeed after retry so these don't
102       // show.  We will know if they happened or not because we will ask
103       // mockito at the end of this test to verify that openscanner was indeed
104       // called the wanted number of times.
105       final long scannerid = 123L;
106       Mockito.when(implementation.openScanner((byte [])Mockito.any(),
107           (Scan)Mockito.any())).
108         thenThrow(new IOException("Server not running (1 of 3)")).
109         thenThrow(new IOException("Server not running (2 of 3)")).
110         thenThrow(new IOException("Server not running (3 of 3)")).
111         thenReturn(scannerid);
112       // Make it so a verifiable answer comes back when next is called.  Return
113       // the verifiable answer and then a null so we stop scanning.  Our
114       // verifiable answer is something that looks like a row in META with
115       // a server and startcode that is that of the above defined servername.
116       List<KeyValue> kvs = new ArrayList<KeyValue>();
117       final byte [] rowToVerify = Bytes.toBytes("rowToVerify");
118       kvs.add(new KeyValue(rowToVerify,
119         HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER,
120         Writables.getBytes(HRegionInfo.FIRST_META_REGIONINFO)));
121       kvs.add(new KeyValue(rowToVerify,
122         HConstants.CATALOG_FAMILY, HConstants.SERVER_QUALIFIER,
123         Bytes.toBytes(sn.getHostAndPort())));
124       kvs.add(new KeyValue(rowToVerify,
125         HConstants.CATALOG_FAMILY, HConstants.STARTCODE_QUALIFIER,
126         Bytes.toBytes(sn.getStartcode())));
127       final Result [] result = new Result [] {new Result(kvs)};
128       Mockito.when(implementation.next(Mockito.anyLong(), Mockito.anyInt())).
129         thenReturn(result).
130         thenReturn(null);
131 
132       // Associate a spied-upon HConnection with UTIL.getConfiguration.  Need
133       // to shove this in here first so it gets picked up all over; e.g. by
134       // HTable.
135       connection = HConnectionTestingUtility.getSpiedConnection(UTIL.getConfiguration());
136       // Fix the location lookup so it 'works' though no network.  First
137       // make an 'any location' object.
138       final HRegionLocation anyLocation =
139         new HRegionLocation(HRegionInfo.FIRST_META_REGIONINFO, sn.getHostname(),
140           sn.getPort());
141       // Return the any location object when locateRegion is called in HTable
142       // constructor and when its called by ServerCallable (it uses getRegionLocation).
143       // The ugly format below comes of 'Important gotcha on spying real objects!' from
144       // http://mockito.googlecode.com/svn/branches/1.6/javadoc/org/mockito/Mockito.html
145       Mockito.doReturn(anyLocation).
146         when(connection).locateRegion((byte[]) Mockito.any(), (byte[]) Mockito.any());
147       Mockito.doReturn(anyLocation).
148         when(connection).getRegionLocation((byte[]) Mockito.any(),
149           (byte[]) Mockito.any(), Mockito.anyBoolean());
150 
151       // Now shove our HRI implementation into the spied-upon connection.
152       Mockito.doReturn(implementation).
153         when(connection).getHRegionConnection(Mockito.anyString(), Mockito.anyInt());
154 
155       // Now start up the catalogtracker with our doctored Connection.
156       ct = new CatalogTracker(zkw, null, connection, ABORTABLE);
157       ct.start();
158       // Scan meta for user tables and verify we got back expected answer.
159       NavigableMap<HRegionInfo, Result> hris = MetaReader.getServerUserRegions(ct, sn);
160       assertTrue(hris.size() == 1);
161       assertTrue(hris.firstEntry().getKey().equals(HRegionInfo.FIRST_META_REGIONINFO));
162       assertTrue(Bytes.equals(rowToVerify, hris.firstEntry().getValue().getRow()));
163       // Finally verify that openscanner was called four times -- three times
164       // with exception and then on 4th attempt we succeed.
165       Mockito.verify(implementation, Mockito.times(4)).
166         openScanner((byte [])Mockito.any(), (Scan)Mockito.any());
167     } finally {
168       if (ct != null) ct.stop();
169       HConnectionManager.deleteConnection(UTIL.getConfiguration());
170       zkw.close();
171     }
172   }
173 
174   @org.junit.Rule
175   public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
176     new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
177 }
178