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.client;
19  
20  import java.io.IOException;
21  
22  import org.apache.hadoop.conf.Configuration;
23  import org.apache.hadoop.hbase.RegionLocations;
24  import org.apache.hadoop.hbase.TableName;
25  import org.apache.hadoop.hbase.HRegionInfo;
26  import org.apache.hadoop.hbase.HRegionLocation;
27  import org.apache.hadoop.hbase.ServerName;
28  import org.apache.hadoop.hbase.ZooKeeperConnectionException;
29  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos;
30  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
31  import org.apache.hadoop.hbase.client.ConnectionManager.HConnectionImplementation;
32  import org.apache.hadoop.hbase.ipc.RpcControllerFactory;
33  import org.mockito.Mockito;
34  import org.mockito.invocation.InvocationOnMock;
35  import org.mockito.stubbing.Answer;
36  
37  /**
38   * {@link ClusterConnection} testing utility.
39   */
40  public class HConnectionTestingUtility {
41    /*
42     * Not part of {@link HBaseTestingUtility} because this class is not
43     * in same package as {@link HConnection}.  Would have to reveal ugly
44     * {@link HConnectionManager} innards to HBaseTestingUtility to give it access.
45     */
46    /**
47     * Get a Mocked {@link HConnection} that goes with the passed <code>conf</code>
48     * configuration instance.  Minimally the mock will return
49     * <code>conf</conf> when {@link ClusterConnection#getConfiguration()} is invoked.
50     * Be sure to shutdown the connection when done by calling
51     * {@link HConnectionManager#deleteConnection(Configuration)} else it
52     * will stick around; this is probably not what you want.
53     * @param conf configuration
54     * @return HConnection object for <code>conf</code>
55     * @throws ZooKeeperConnectionException
56     */
57    public static ClusterConnection getMockedConnection(final Configuration conf)
58    throws ZooKeeperConnectionException {
59      HConnectionKey connectionKey = new HConnectionKey(conf);
60      synchronized (ConnectionManager.CONNECTION_INSTANCES) {
61        HConnectionImplementation connection =
62            ConnectionManager.CONNECTION_INSTANCES.get(connectionKey);
63        if (connection == null) {
64          connection = Mockito.mock(HConnectionImplementation.class);
65          Mockito.when(connection.getConfiguration()).thenReturn(conf);
66          ConnectionManager.CONNECTION_INSTANCES.put(connectionKey, connection);
67        }
68        return connection;
69      }
70    }
71  
72    /**
73     * @param connection
74     */
75    private static void mockRegionLocator(final HConnectionImplementation connection) {
76      try {
77        Mockito.when(connection.getRegionLocator(Mockito.any(TableName.class))).thenAnswer(
78            new Answer<RegionLocator>() {
79              @Override
80              public RegionLocator answer(InvocationOnMock invocation) throws Throwable {
81                TableName tableName = (TableName) invocation.getArguments()[0];
82                return new HRegionLocator(tableName, connection);
83              }
84            });
85      } catch (IOException e) {
86      }
87    }
88  
89    /**
90     * Calls {@link #getMockedConnection(Configuration)} and then mocks a few
91     * more of the popular {@link ClusterConnection} methods so they do 'normal'
92     * operation (see return doc below for list). Be sure to shutdown the
93     * connection when done by calling
94     * {@link HConnectionManager#deleteConnection(Configuration)} else it
95     * will stick around; this is probably not what you want.
96     *
97     * @param conf Configuration to use
98     * @param admin An AdminProtocol; can be null but is usually
99     * itself a mock.
100    * @param client A ClientProtocol; can be null but is usually
101    * itself a mock.
102    * @param sn ServerName to include in the region location returned by this
103    * <code>connection</code>
104    * @param hri HRegionInfo to include in the location returned when
105    * getRegionLocator is called on the mocked connection
106    * @return Mock up a connection that returns a {@link Configuration} when
107    * {@link ClusterConnection#getConfiguration()} is called, a 'location' when
108    * {@link ClusterConnection#getRegionLocation(org.apache.hadoop.hbase.TableName, byte[], boolean)}
109    * is called,
110    * and that returns the passed {@link AdminProtos.AdminService.BlockingInterface} instance when
111    * {@link ClusterConnection#getAdmin(ServerName)} is called, returns the passed
112    * {@link ClientProtos.ClientService.BlockingInterface} instance when
113    * {@link ClusterConnection#getClient(ServerName)} is called (Be sure to call
114    * {@link HConnectionManager#deleteConnection(Configuration)}
115    * when done with this mocked Connection.
116    * @throws IOException
117    */
118   public static ClusterConnection getMockedConnectionAndDecorate(final Configuration conf,
119       final AdminProtos.AdminService.BlockingInterface admin,
120       final ClientProtos.ClientService.BlockingInterface client,
121       final ServerName sn, final HRegionInfo hri)
122   throws IOException {
123     HConnectionImplementation c = Mockito.mock(HConnectionImplementation.class);
124     Mockito.when(c.getConfiguration()).thenReturn(conf);
125     ConnectionManager.CONNECTION_INSTANCES.put(new HConnectionKey(conf), c);
126     Mockito.doNothing().when(c).close();
127     // Make it so we return a particular location when asked.
128     final HRegionLocation loc = new HRegionLocation(hri, sn);
129     mockRegionLocator(c);
130     Mockito.when(c.getRegionLocation((TableName) Mockito.any(),
131         (byte[]) Mockito.any(), Mockito.anyBoolean())).
132       thenReturn(loc);
133     Mockito.when(c.locateRegion((TableName) Mockito.any(), (byte[]) Mockito.any())).
134       thenReturn(loc);
135     Mockito.when(c.locateRegion((TableName) Mockito.any(), (byte[]) Mockito.any(),
136         Mockito.anyBoolean(), Mockito.anyBoolean(),  Mockito.anyInt()))
137         .thenReturn(new RegionLocations(loc));
138     if (admin != null) {
139       // If a call to getAdmin, return this implementation.
140       Mockito.when(c.getAdmin(Mockito.any(ServerName.class))).
141         thenReturn(admin);
142     }
143     if (client != null) {
144       // If a call to getClient, return this client.
145       Mockito.when(c.getClient(Mockito.any(ServerName.class))).
146         thenReturn(client);
147     }
148     NonceGenerator ng = Mockito.mock(NonceGenerator.class);
149     Mockito.when(c.getNonceGenerator()).thenReturn(ng);
150     Mockito.when(c.getAsyncProcess()).thenReturn(
151       new AsyncProcess(c, conf, null, RpcRetryingCallerFactory.instantiate(conf), false,
152           RpcControllerFactory.instantiate(conf)));
153     Mockito.doNothing().when(c).incCount();
154     Mockito.doNothing().when(c).decCount();
155     Mockito.when(c.getNewRpcRetryingCallerFactory(conf)).thenReturn(
156         RpcRetryingCallerFactory.instantiate(conf,
157             RetryingCallerInterceptorFactory.NO_OP_INTERCEPTOR, null));
158     HTableInterface t = Mockito.mock(HTableInterface.class);
159     Mockito.when(c.getTable((TableName)Mockito.any())).thenReturn(t);
160     ResultScanner rs = Mockito.mock(ResultScanner.class);
161     Mockito.when(t.getScanner((Scan)Mockito.any())).thenReturn(rs);
162     return c;
163   }
164 
165   /**
166    * Get a Mockito spied-upon {@link ClusterConnection} that goes with the passed
167    * <code>conf</code> configuration instance.
168    * Be sure to shutdown the connection when done by calling
169    * {@link HConnectionManager#deleteConnection(Configuration)} else it
170    * will stick around; this is probably not what you want.
171    * @param conf configuration
172    * @return HConnection object for <code>conf</code>
173    * @throws ZooKeeperConnectionException
174    * @see @link
175    * {http://mockito.googlecode.com/svn/branches/1.6/javadoc/org/mockito/Mockito.html#spy(T)}
176    */
177   public static ClusterConnection getSpiedConnection(final Configuration conf)
178   throws IOException {
179     HConnectionKey connectionKey = new HConnectionKey(conf);
180     synchronized (ConnectionManager.CONNECTION_INSTANCES) {
181       HConnectionImplementation connection =
182           ConnectionManager.CONNECTION_INSTANCES.get(connectionKey);
183       if (connection == null) {
184         connection = Mockito.spy(new HConnectionImplementation(conf, true));
185         ConnectionManager.CONNECTION_INSTANCES.put(connectionKey, connection);
186       }
187       return connection;
188     }
189   }
190 
191   public static ClusterConnection getSpiedClusterConnection(final Configuration conf)
192   throws IOException {
193     HConnectionKey connectionKey = new HConnectionKey(conf);
194     synchronized (ConnectionManager.CONNECTION_INSTANCES) {
195       HConnectionImplementation connection =
196           ConnectionManager.CONNECTION_INSTANCES.get(connectionKey);
197       if (connection == null) {
198         connection = Mockito.spy(new HConnectionImplementation(conf, true));
199         ConnectionManager.CONNECTION_INSTANCES.put(connectionKey, connection);
200       }
201       return connection;
202     }
203   }
204 
205   /**
206    * @return Count of extant connection instances
207    */
208   public static int getConnectionCount() {
209     synchronized (ConnectionManager.CONNECTION_INSTANCES) {
210       return ConnectionManager.CONNECTION_INSTANCES.size();
211     }
212   }
213 }