View Javadoc

1   /*
2    * Copyright The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one or more
5    * contributor license agreements. See the NOTICE file distributed with this
6    * work for additional information regarding copyright ownership. The ASF
7    * licenses this file to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   * http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16   * License for the specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.hadoop.hbase.thrift;
20  
21  import static org.junit.Assert.assertEquals;
22  import static org.junit.Assert.assertTrue;
23  
24  import java.net.InetAddress;
25  import java.util.ArrayList;
26  import java.util.Collection;
27  import java.util.List;
28  
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.apache.hadoop.hbase.HBaseTestingUtility;
32  import org.apache.hadoop.hbase.testclassification.LargeTests;
33  import org.apache.hadoop.hbase.thrift.ThriftServerRunner.ImplType;
34  import org.apache.hadoop.hbase.thrift.generated.Hbase;
35  import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
36  import org.apache.hadoop.hbase.util.EnvironmentEdgeManagerTestHelper;
37  import org.apache.hadoop.hbase.util.IncrementingEnvironmentEdge;
38  import org.apache.thrift.protocol.TBinaryProtocol;
39  import org.apache.thrift.protocol.TCompactProtocol;
40  import org.apache.thrift.protocol.TProtocol;
41  import org.apache.thrift.server.TServer;
42  import org.apache.thrift.transport.TFramedTransport;
43  import org.apache.thrift.transport.TSocket;
44  import org.apache.thrift.transport.TTransport;
45  import org.junit.AfterClass;
46  import org.junit.BeforeClass;
47  import org.junit.Test;
48  import org.junit.experimental.categories.Category;
49  import org.junit.runner.RunWith;
50  import org.junit.runners.Parameterized;
51  import org.junit.runners.Parameterized.Parameters;
52  
53  import com.google.common.base.Joiner;
54  
55  /**
56   * Start the HBase Thrift server on a random port through the command-line
57   * interface and talk to it from client side.
58   */
59  @Category(LargeTests.class)
60  @RunWith(Parameterized.class)
61  public class TestThriftServerCmdLine {
62  
63    private static final Log LOG =
64        LogFactory.getLog(TestThriftServerCmdLine.class);
65  
66    private final ImplType implType;
67    private boolean specifyFramed;
68    private boolean specifyBindIP;
69    private boolean specifyCompact;
70  
71    private static final HBaseTestingUtility TEST_UTIL =
72        new HBaseTestingUtility();
73  
74    private Thread cmdLineThread;
75    private volatile Exception cmdLineException;
76  
77    private Exception clientSideException;
78  
79    private ThriftServer thriftServer;
80    private int port;
81  
82    @Parameters
83    public static Collection<Object[]> getParameters() {
84      Collection<Object[]> parameters = new ArrayList<Object[]>();
85      for (ImplType implType : ImplType.values()) {
86        for (boolean specifyFramed : new boolean[] {false, true}) {
87          for (boolean specifyBindIP : new boolean[] {false, true}) {
88            if (specifyBindIP && !implType.canSpecifyBindIP) {
89              continue;
90            }
91            for (boolean specifyCompact : new boolean[] {false, true}) {
92              parameters.add(new Object[]{implType, specifyFramed,
93                  specifyBindIP, specifyCompact});
94            }
95          }
96        }
97      }
98      return parameters;
99    }
100 
101   public TestThriftServerCmdLine(ImplType implType, boolean specifyFramed,
102       boolean specifyBindIP, boolean specifyCompact) {
103     this.implType = implType;
104     this.specifyFramed = specifyFramed;
105     this.specifyBindIP = specifyBindIP;
106     this.specifyCompact = specifyCompact;
107     LOG.debug(getParametersString());
108   }
109 
110   private String getParametersString() {
111     return "implType=" + implType + ", " +
112         "specifyFramed=" + specifyFramed + ", " +
113         "specifyBindIP=" + specifyBindIP + ", " +
114         "specifyCompact=" + specifyCompact;
115   }
116 
117   @BeforeClass
118   public static void setUpBeforeClass() throws Exception {
119     TEST_UTIL.getConfiguration().setBoolean("hbase.table.sanity.checks", false);
120     TEST_UTIL.startMiniCluster();
121     //ensure that server time increments every time we do an operation, otherwise
122     //successive puts having the same timestamp will override each other
123     EnvironmentEdgeManagerTestHelper.injectEdge(new IncrementingEnvironmentEdge());
124   }
125 
126   @AfterClass
127   public static void tearDownAfterClass() throws Exception {
128     TEST_UTIL.shutdownMiniCluster();
129     EnvironmentEdgeManager.reset();
130   }
131 
132   private void startCmdLineThread(final String[] args) {
133     LOG.info("Starting HBase Thrift server with command line: " + Joiner.on(" ").join(args));
134 
135     cmdLineException = null;
136     cmdLineThread = new Thread(new Runnable() {
137       @Override
138       public void run() {
139         try {
140           thriftServer.doMain(args);
141         } catch (Exception e) {
142           cmdLineException = e;
143         }
144       }
145     });
146     cmdLineThread.setName(ThriftServer.class.getSimpleName() +
147         "-cmdline");
148     cmdLineThread.start();
149   }
150 
151   @Test(timeout=600000)
152   public void testRunThriftServer() throws Exception {
153     List<String> args = new ArrayList<String>();
154     if (implType != null) {
155       String serverTypeOption = implType.toString();
156       assertTrue(serverTypeOption.startsWith("-"));
157       args.add(serverTypeOption);
158     }
159     port = HBaseTestingUtility.randomFreePort();
160     args.add("-" + ThriftServer.PORT_OPTION);
161     args.add(String.valueOf(port));
162     if (specifyFramed) {
163       args.add("-" + ThriftServer.FRAMED_OPTION);
164     }
165     if (specifyBindIP) {
166       args.add("-" + ThriftServer.BIND_OPTION);
167       args.add(InetAddress.getLocalHost().getHostName());
168     }
169     if (specifyCompact) {
170       args.add("-" + ThriftServer.COMPACT_OPTION);
171     }
172     args.add("start");
173 
174     thriftServer = new ThriftServer(TEST_UTIL.getConfiguration());
175     startCmdLineThread(args.toArray(new String[args.size()]));
176 
177     // wait up to 10s for the server to start
178     for (int i = 0; i < 100
179         && (thriftServer.serverRunner == null || thriftServer.serverRunner.tserver == null); i++) {
180       Thread.sleep(100);
181     }
182 
183     Class<? extends TServer> expectedClass = implType != null ?
184         implType.serverClass : TBoundedThreadPoolServer.class;
185     assertEquals(expectedClass,
186                  thriftServer.serverRunner.tserver.getClass());
187 
188     try {
189       talkToThriftServer();
190     } catch (Exception ex) {
191       clientSideException = ex;
192     } finally {
193       stopCmdLineThread();
194     }
195 
196     if (clientSideException != null) {
197       LOG.error("Thrift client threw an exception. Parameters:" +
198           getParametersString(), clientSideException);
199       throw new Exception(clientSideException);
200     }
201   }
202 
203   private static volatile boolean tableCreated = false;
204 
205   private void talkToThriftServer() throws Exception {
206     TSocket sock = new TSocket(InetAddress.getLocalHost().getHostName(),
207         port);
208     TTransport transport = sock;
209     if (specifyFramed || implType.isAlwaysFramed) {
210       transport = new TFramedTransport(transport);
211     }
212 
213     sock.open();
214     try {
215       TProtocol prot;
216       if (specifyCompact) {
217         prot = new TCompactProtocol(transport);
218       } else {
219         prot = new TBinaryProtocol(transport);
220       }
221       Hbase.Client client = new Hbase.Client(prot);
222       if (!tableCreated){
223         TestThriftServer.createTestTables(client);
224         tableCreated = true;
225       }
226       TestThriftServer.checkTableList(client);
227 
228     } finally {
229       sock.close();
230     }
231   }
232 
233   private void stopCmdLineThread() throws Exception {
234     LOG.debug("Stopping " + implType.simpleClassName() + " Thrift server");
235     thriftServer.stop();
236     cmdLineThread.join();
237     if (cmdLineException != null) {
238       LOG.error("Command-line invocation of HBase Thrift server threw an " +
239           "exception", cmdLineException);
240       throw new Exception(cmdLineException);
241     }
242   }
243 }
244