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    public 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.startMiniCluster();
120     //ensure that server time increments every time we do an operation, otherwise
121     //successive puts having the same timestamp will override each other
122     EnvironmentEdgeManagerTestHelper.injectEdge(new IncrementingEnvironmentEdge());
123   }
124 
125   @AfterClass
126   public static void tearDownAfterClass() throws Exception {
127     TEST_UTIL.shutdownMiniCluster();
128     EnvironmentEdgeManager.reset();
129   }
130 
131   private void startCmdLineThread(final String[] args) {
132     LOG.info("Starting HBase Thrift server with command line: " + Joiner.on(" ").join(args));
133 
134     cmdLineException = null;
135     cmdLineThread = new Thread(new Runnable() {
136       @Override
137       public void run() {
138         try {
139           thriftServer.doMain(args);
140         } catch (Exception e) {
141           cmdLineException = e;
142         }
143       }
144     });
145     cmdLineThread.setName(ThriftServer.class.getSimpleName() +
146         "-cmdline");
147     cmdLineThread.start();
148   }
149 
150   @Test(timeout=600000)
151   public void testRunThriftServer() throws Exception {
152     List<String> args = new ArrayList<String>();
153     if (implType != null) {
154       String serverTypeOption = implType.toString();
155       assertTrue(serverTypeOption.startsWith("-"));
156       args.add(serverTypeOption);
157     }
158     port = HBaseTestingUtility.randomFreePort();
159     args.add("-" + ThriftServer.PORT_OPTION);
160     args.add(String.valueOf(port));
161     if (specifyFramed) {
162       args.add("-" + ThriftServer.FRAMED_OPTION);
163     }
164     if (specifyBindIP) {
165       args.add("-" + ThriftServer.BIND_OPTION);
166       args.add(InetAddress.getLocalHost().getHostName());
167     }
168     if (specifyCompact) {
169       args.add("-" + ThriftServer.COMPACT_OPTION);
170     }
171     args.add("start");
172 
173     thriftServer = new ThriftServer(TEST_UTIL.getConfiguration());
174     startCmdLineThread(args.toArray(new String[args.size()]));
175 
176     // wait up to 10s for the server to start
177     for (int i = 0; i < 100
178         && (thriftServer.serverRunner == null || thriftServer.serverRunner.tserver == null); i++) {
179       Thread.sleep(100);
180     }
181 
182     Class<? extends TServer> expectedClass = implType != null ?
183         implType.serverClass : TBoundedThreadPoolServer.class;
184     assertEquals(expectedClass,
185                  thriftServer.serverRunner.tserver.getClass());
186 
187     try {
188       talkToThriftServer();
189     } catch (Exception ex) {
190       clientSideException = ex;
191     } finally {
192       stopCmdLineThread();
193     }
194 
195     if (clientSideException != null) {
196       LOG.error("Thrift client threw an exception. Parameters:" +
197           getParametersString(), clientSideException);
198       throw new Exception(clientSideException);
199     }
200   }
201 
202   private static volatile boolean tableCreated = false;
203 
204   private void talkToThriftServer() throws Exception {
205     TSocket sock = new TSocket(InetAddress.getLocalHost().getHostName(),
206         port);
207     TTransport transport = sock;
208     if (specifyFramed || implType.isAlwaysFramed) {
209       transport = new TFramedTransport(transport);
210     }
211 
212     sock.open();
213     try {
214       TProtocol prot;
215       if (specifyCompact) {
216         prot = new TCompactProtocol(transport);
217       } else {
218         prot = new TBinaryProtocol(transport);
219       }
220       Hbase.Client client = new Hbase.Client(prot);
221       if (!tableCreated){
222         TestThriftServer.createTestTables(client);
223         tableCreated = true;
224       }
225       TestThriftServer.checkTableList(client);
226 
227     } finally {
228       sock.close();
229     }
230   }
231 
232   private void stopCmdLineThread() throws Exception {
233     LOG.debug("Stopping " + implType.simpleClassName() + " Thrift server");
234     thriftServer.stop();
235     cmdLineThread.join();
236     if (cmdLineException != null) {
237       LOG.error("Command-line invocation of HBase Thrift server threw an " +
238           "exception", cmdLineException);
239       throw new Exception(cmdLineException);
240     }
241   }
242 
243 
244 }
245