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