001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.thrift; 019 020import static org.apache.hadoop.hbase.thrift.Constants.BIND_OPTION; 021import static org.apache.hadoop.hbase.thrift.Constants.COMPACT_OPTION; 022import static org.apache.hadoop.hbase.thrift.Constants.FRAMED_OPTION; 023import static org.apache.hadoop.hbase.thrift.Constants.INFOPORT_OPTION; 024import static org.apache.hadoop.hbase.thrift.Constants.PORT_OPTION; 025import static org.junit.Assert.assertEquals; 026import static org.junit.Assert.assertTrue; 027 028import java.net.InetAddress; 029import java.util.ArrayList; 030import java.util.Collection; 031import java.util.List; 032import org.apache.hadoop.hbase.HBaseClassTestRule; 033import org.apache.hadoop.hbase.HBaseTestingUtility; 034import org.apache.hadoop.hbase.testclassification.ClientTests; 035import org.apache.hadoop.hbase.testclassification.LargeTests; 036import org.apache.hadoop.hbase.thrift.generated.Hbase; 037import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 038import org.apache.hadoop.hbase.util.EnvironmentEdgeManagerTestHelper; 039import org.apache.hadoop.hbase.util.IncrementingEnvironmentEdge; 040import org.apache.hadoop.hbase.util.TableDescriptorChecker; 041import org.apache.thrift.protocol.TBinaryProtocol; 042import org.apache.thrift.protocol.TCompactProtocol; 043import org.apache.thrift.protocol.TProtocol; 044import org.apache.thrift.server.TServer; 045import org.apache.thrift.transport.TFramedTransport; 046import org.apache.thrift.transport.TSocket; 047import org.apache.thrift.transport.TTransport; 048import org.junit.AfterClass; 049import org.junit.BeforeClass; 050import org.junit.ClassRule; 051import org.junit.Test; 052import org.junit.experimental.categories.Category; 053import org.junit.runner.RunWith; 054import org.junit.runners.Parameterized; 055import org.junit.runners.Parameterized.Parameters; 056import org.slf4j.Logger; 057import org.slf4j.LoggerFactory; 058 059import org.apache.hbase.thirdparty.com.google.common.base.Joiner; 060 061/** 062 * Start the HBase Thrift server on a random port through the command-line 063 * interface and talk to it from client side. 064 */ 065@Category({ClientTests.class, LargeTests.class}) 066@RunWith(Parameterized.class) 067public class TestThriftServerCmdLine { 068 069 @ClassRule 070 public static final HBaseClassTestRule CLASS_RULE = 071 HBaseClassTestRule.forClass(TestThriftServerCmdLine.class); 072 073 private static final Logger LOG = 074 LoggerFactory.getLogger(TestThriftServerCmdLine.class); 075 076 protected final ImplType implType; 077 protected boolean specifyFramed; 078 protected boolean specifyBindIP; 079 protected boolean specifyCompact; 080 081 protected static final HBaseTestingUtility TEST_UTIL = 082 new HBaseTestingUtility(); 083 084 private Thread cmdLineThread; 085 private volatile Exception cmdLineException; 086 087 private Exception clientSideException; 088 089 private volatile ThriftServer thriftServer; 090 protected int port; 091 092 @Parameters 093 public static Collection<Object[]> getParameters() { 094 Collection<Object[]> parameters = new ArrayList<>(); 095 for (ImplType implType : ImplType.values()) { 096 for (boolean specifyFramed : new boolean[] {false, true}) { 097 for (boolean specifyBindIP : new boolean[] {false, true}) { 098 if (specifyBindIP && !implType.canSpecifyBindIP) { 099 continue; 100 } 101 for (boolean specifyCompact : new boolean[] {false, true}) { 102 parameters.add(new Object[]{implType, specifyFramed, 103 specifyBindIP, specifyCompact}); 104 } 105 } 106 } 107 } 108 return parameters; 109 } 110 111 public TestThriftServerCmdLine(ImplType implType, boolean specifyFramed, 112 boolean specifyBindIP, boolean specifyCompact) { 113 this.implType = implType; 114 this.specifyFramed = specifyFramed; 115 this.specifyBindIP = specifyBindIP; 116 this.specifyCompact = specifyCompact; 117 LOG.debug(getParametersString()); 118 } 119 120 private String getParametersString() { 121 return "implType=" + implType + ", " + 122 "specifyFramed=" + specifyFramed + ", " + 123 "specifyBindIP=" + specifyBindIP + ", " + 124 "specifyCompact=" + specifyCompact; 125 } 126 127 @BeforeClass 128 public static void setUpBeforeClass() throws Exception { 129 TEST_UTIL.getConfiguration().setBoolean(TableDescriptorChecker.TABLE_SANITY_CHECKS, false); 130 TEST_UTIL.startMiniCluster(); 131 //ensure that server time increments every time we do an operation, otherwise 132 //successive puts having the same timestamp will override each other 133 EnvironmentEdgeManagerTestHelper.injectEdge(new IncrementingEnvironmentEdge()); 134 } 135 136 @AfterClass 137 public static void tearDownAfterClass() throws Exception { 138 TEST_UTIL.shutdownMiniCluster(); 139 EnvironmentEdgeManager.reset(); 140 } 141 142 private void startCmdLineThread(final String[] args) { 143 LOG.info("Starting HBase Thrift server with command line: " + Joiner.on(" ").join(args)); 144 145 cmdLineException = null; 146 cmdLineThread = new Thread(new Runnable() { 147 @Override 148 public void run() { 149 try { 150 thriftServer.run(args); 151 } catch (Exception e) { 152 LOG.error("Error when start thrift server", e); 153 cmdLineException = e; 154 } 155 } 156 }); 157 cmdLineThread.setName(ThriftServer.class.getSimpleName() + 158 "-cmdline"); 159 cmdLineThread.start(); 160 } 161 162 protected ThriftServer createThriftServer() { 163 return new ThriftServer(TEST_UTIL.getConfiguration()); 164 } 165 166 @Test 167 public void testRunThriftServer() throws Exception { 168 List<String> args = new ArrayList<>(); 169 if (implType != null) { 170 String serverTypeOption = implType.toString(); 171 assertTrue(serverTypeOption.startsWith("-")); 172 args.add(serverTypeOption); 173 } 174 port = HBaseTestingUtility.randomFreePort(); 175 args.add("-" + PORT_OPTION); 176 args.add(String.valueOf(port)); 177 args.add("-" + INFOPORT_OPTION); 178 int infoPort = HBaseTestingUtility.randomFreePort(); 179 args.add(String.valueOf(infoPort)); 180 181 if (specifyFramed) { 182 args.add("-" + FRAMED_OPTION); 183 } 184 if (specifyBindIP) { 185 args.add("-" + BIND_OPTION); 186 args.add(InetAddress.getLocalHost().getHostName()); 187 } 188 if (specifyCompact) { 189 args.add("-" + COMPACT_OPTION); 190 } 191 args.add("start"); 192 193 thriftServer = createThriftServer(); 194 startCmdLineThread(args.toArray(new String[args.size()])); 195 196 // wait up to 10s for the server to start 197 for (int i = 0; i < 100 198 && (thriftServer.tserver == null); i++) { 199 Thread.sleep(100); 200 } 201 202 Class<? extends TServer> expectedClass = implType != null ? 203 implType.serverClass : TBoundedThreadPoolServer.class; 204 assertEquals(expectedClass, 205 thriftServer.tserver.getClass()); 206 207 try { 208 talkToThriftServer(); 209 } catch (Exception ex) { 210 clientSideException = ex; 211 } finally { 212 stopCmdLineThread(); 213 } 214 215 if (clientSideException != null) { 216 LOG.error("Thrift client threw an exception. Parameters:" + 217 getParametersString(), clientSideException); 218 throw new Exception(clientSideException); 219 } 220 } 221 222 protected static volatile boolean tableCreated = false; 223 224 protected void talkToThriftServer() throws Exception { 225 TSocket sock = new TSocket(InetAddress.getLocalHost().getHostName(), 226 port); 227 TTransport transport = sock; 228 if (specifyFramed || implType.isAlwaysFramed) { 229 transport = new TFramedTransport(transport); 230 } 231 232 sock.open(); 233 try { 234 TProtocol prot; 235 if (specifyCompact) { 236 prot = new TCompactProtocol(transport); 237 } else { 238 prot = new TBinaryProtocol(transport); 239 } 240 241 Hbase.Client client = new Hbase.Client(prot); 242 if (!tableCreated){ 243 TestThriftServer.createTestTables(client); 244 tableCreated = true; 245 } 246 TestThriftServer.checkTableList(client); 247 248 } finally { 249 sock.close(); 250 } 251 } 252 253 private void stopCmdLineThread() throws Exception { 254 LOG.debug("Stopping " + implType.simpleClassName() + " Thrift server"); 255 thriftServer.stop(); 256 cmdLineThread.join(); 257 if (cmdLineException != null) { 258 LOG.error("Command-line invocation of HBase Thrift server threw an " + 259 "exception", cmdLineException); 260 throw new Exception(cmdLineException); 261 } 262 } 263} 264