blob: 4dc4c0744ea430bea02cab2d1c8b6ce588ff333f [file] [log] [blame]
Mark Slee57cc25e2007-02-28 21:43:54 +00001#!/usr/bin/env python
Mark Sleec9676562006-09-05 17:34:52 +00002
David Reissea2cba82009-03-30 21:35:00 +00003#
4# Licensed to the Apache Software Foundation (ASF) under one
5# or more contributor license agreements. See the NOTICE file
6# distributed with this work for additional information
7# regarding copyright ownership. The ASF licenses this file
8# to you under the Apache License, Version 2.0 (the
9# "License"); you may not use this file except in compliance
10# with the License. You may obtain a copy of the License at
11#
12# http://www.apache.org/licenses/LICENSE-2.0
13#
14# Unless required by applicable law or agreed to in writing,
15# software distributed under the License is distributed on an
16# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17# KIND, either express or implied. See the License for the
18# specific language governing permissions and limitations
19# under the License.
20#
Nobuaki Sukegawa7b545b52016-01-11 13:46:04 +090021from __future__ import division
Jens Geyerd629ea02015-09-23 21:16:50 +020022import logging
23import os
James E. King III6f8c99e2018-03-24 16:32:02 -040024import signal
Jens Geyerd629ea02015-09-23 21:16:50 +020025import sys
26import time
Bryan Duxbury59d4efd2011-03-21 17:38:22 +000027from optparse import OptionParser
Mark Sleec9676562006-09-05 17:34:52 +000028
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +090029from util import local_libpath
30
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +090031SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
Roger Meierf4eec7a2011-09-11 18:16:21 +000032
Mark Sleec9676562006-09-05 17:34:52 +000033
Jens Geyerd629ea02015-09-23 21:16:50 +020034class TestHandler(object):
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090035 def testVoid(self):
36 if options.verbose > 1:
37 logging.info('testVoid()')
Mark Sleec9676562006-09-05 17:34:52 +000038
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090039 def testString(self, str):
40 if options.verbose > 1:
41 logging.info('testString(%s)' % str)
42 return str
Mark Sleec9676562006-09-05 17:34:52 +000043
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090044 def testBool(self, boolean):
45 if options.verbose > 1:
46 logging.info('testBool(%s)' % str(boolean).lower())
47 return boolean
Nobuaki Sukegawaa649e742015-09-21 13:53:25 +090048
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090049 def testByte(self, byte):
50 if options.verbose > 1:
51 logging.info('testByte(%d)' % byte)
52 return byte
Mark Sleec9676562006-09-05 17:34:52 +000053
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090054 def testI16(self, i16):
55 if options.verbose > 1:
56 logging.info('testI16(%d)' % i16)
57 return i16
Mark Sleec98d0502006-09-06 02:42:25 +000058
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090059 def testI32(self, i32):
60 if options.verbose > 1:
61 logging.info('testI32(%d)' % i32)
62 return i32
Mark Sleec98d0502006-09-06 02:42:25 +000063
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090064 def testI64(self, i64):
65 if options.verbose > 1:
66 logging.info('testI64(%d)' % i64)
67 return i64
Mark Sleec98d0502006-09-06 02:42:25 +000068
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090069 def testDouble(self, dub):
70 if options.verbose > 1:
71 logging.info('testDouble(%f)' % dub)
72 return dub
Mark Sleec98d0502006-09-06 02:42:25 +000073
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090074 def testBinary(self, thing):
75 if options.verbose > 1:
76 logging.info('testBinary()') # TODO: hex output
77 return thing
Jens Geyerd629ea02015-09-23 21:16:50 +020078
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090079 def testStruct(self, thing):
80 if options.verbose > 1:
81 logging.info('testStruct({%s, %s, %s, %s})' % (thing.string_thing, thing.byte_thing, thing.i32_thing, thing.i64_thing))
82 return thing
Mark Sleec98d0502006-09-06 02:42:25 +000083
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090084 def testException(self, arg):
85 # if options.verbose > 1:
86 logging.info('testException(%s)' % arg)
87 if arg == 'Xception':
88 raise Xception(errorCode=1001, message=arg)
89 elif arg == 'TException':
90 raise TException(message='This is a TException')
Roger Meier1f554e12013-01-05 20:38:35 +010091
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090092 def testMultiException(self, arg0, arg1):
93 if options.verbose > 1:
94 logging.info('testMultiException(%s, %s)' % (arg0, arg1))
95 if arg0 == 'Xception':
96 raise Xception(errorCode=1001, message='This is an Xception')
97 elif arg0 == 'Xception2':
98 raise Xception2(
99 errorCode=2002,
100 struct_thing=Xtruct(string_thing='This is an Xception2'))
101 return Xtruct(string_thing=arg1)
Mark Sleec9676562006-09-05 17:34:52 +0000102
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900103 def testOneway(self, seconds):
104 if options.verbose > 1:
105 logging.info('testOneway(%d) => sleeping...' % seconds)
106 time.sleep(seconds / 3) # be quick
107 if options.verbose > 1:
108 logging.info('done sleeping')
David Reissdb893b62008-02-18 02:11:48 +0000109
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900110 def testNest(self, thing):
111 if options.verbose > 1:
112 logging.info('testNest(%s)' % thing)
113 return thing
David Reiss74421272008-11-07 23:09:31 +0000114
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900115 def testMap(self, thing):
116 if options.verbose > 1:
117 logging.info('testMap(%s)' % thing)
118 return thing
Jens Geyerd629ea02015-09-23 21:16:50 +0200119
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900120 def testStringMap(self, thing):
121 if options.verbose > 1:
122 logging.info('testStringMap(%s)' % thing)
123 return thing
David Reiss74421272008-11-07 23:09:31 +0000124
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900125 def testSet(self, thing):
126 if options.verbose > 1:
127 logging.info('testSet(%s)' % thing)
128 return thing
David Reiss74421272008-11-07 23:09:31 +0000129
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900130 def testList(self, thing):
131 if options.verbose > 1:
132 logging.info('testList(%s)' % thing)
133 return thing
David Reiss74421272008-11-07 23:09:31 +0000134
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900135 def testEnum(self, thing):
136 if options.verbose > 1:
137 logging.info('testEnum(%s)' % thing)
138 return thing
David Reiss74421272008-11-07 23:09:31 +0000139
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900140 def testTypedef(self, thing):
141 if options.verbose > 1:
142 logging.info('testTypedef(%s)' % thing)
143 return thing
David Reiss74421272008-11-07 23:09:31 +0000144
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900145 def testMapMap(self, thing):
146 if options.verbose > 1:
147 logging.info('testMapMap(%s)' % thing)
148 return {
149 -4: {
150 -4: -4,
151 -3: -3,
152 -2: -2,
153 -1: -1,
154 },
155 4: {
156 4: 4,
157 3: 3,
158 2: 2,
159 1: 1,
160 },
161 }
Roger Meier1f554e12013-01-05 20:38:35 +0100162
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900163 def testInsanity(self, argument):
164 if options.verbose > 1:
165 logging.info('testInsanity(%s)' % argument)
166 return {
167 1: {
168 2: argument,
169 3: argument,
170 },
171 2: {6: Insanity()},
172 }
Bryan Duxbury59d4efd2011-03-21 17:38:22 +0000173
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900174 def testMulti(self, arg0, arg1, arg2, arg3, arg4, arg5):
175 if options.verbose > 1:
176 logging.info('testMulti(%s)' % [arg0, arg1, arg2, arg3, arg4, arg5])
177 return Xtruct(string_thing='Hello2',
178 byte_thing=arg0, i32_thing=arg1, i64_thing=arg2)
Roger Meier1f554e12013-01-05 20:38:35 +0100179
Bryan Duxbury59d4efd2011-03-21 17:38:22 +0000180
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900181def main(options):
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900182 # set up the protocol factory form the --protocol option
183 prot_factories = {
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900184 'accel': TBinaryProtocol.TBinaryProtocolAcceleratedFactory,
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900185 'accelc': TCompactProtocol.TCompactProtocolAcceleratedFactory,
James E. King III6f8c99e2018-03-24 16:32:02 -0400186 'binary': TBinaryProtocol.TBinaryProtocolFactory,
187 'compact': TCompactProtocol.TCompactProtocolFactory,
188 'json': TJSONProtocol.TJSONProtocolFactory
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900189 }
190 pfactory_cls = prot_factories.get(options.proto, None)
191 if pfactory_cls is None:
192 raise AssertionError('Unknown --protocol option: %s' % options.proto)
193 pfactory = pfactory_cls()
194 try:
195 pfactory.string_length_limit = options.string_limit
196 pfactory.container_length_limit = options.container_limit
James E. King, III350fe752017-10-25 09:57:18 -0400197 except Exception:
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900198 # Ignore errors for those protocols that does not support length limit
199 pass
Bryan Duxbury16066592011-03-22 18:06:04 +0000200
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900201 # get the server type (TSimpleServer, TNonblockingServer, etc...)
202 if len(args) > 1:
203 raise AssertionError('Only one server type may be specified, not multiple types.')
204 server_type = args[0]
James E. King III6f8c99e2018-03-24 16:32:02 -0400205 if options.trans == 'http':
206 server_type = 'THttpServer'
David Reissbcaa2ad2008-06-10 22:55:26 +0000207
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900208 # Set up the handler and processor objects
209 handler = TestHandler()
210 processor = ThriftTest.Processor(handler)
Bryan Duxbury16066592011-03-22 18:06:04 +0000211
James E. King III6f8c99e2018-03-24 16:32:02 -0400212 global server
213
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900214 # Handle THttpServer as a special case
215 if server_type == 'THttpServer':
James E. King III6f8c99e2018-03-24 16:32:02 -0400216 if options.ssl:
217 __certfile = os.path.join(os.path.dirname(SCRIPT_DIR), "keys", "server.crt")
218 __keyfile = os.path.join(os.path.dirname(SCRIPT_DIR), "keys", "server.key")
219 server = THttpServer.THttpServer(processor, ('', options.port), pfactory, cert_file=__certfile, key_file=__keyfile)
220 else:
221 server = THttpServer.THttpServer(processor, ('', options.port), pfactory)
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900222 server.serve()
223 sys.exit(0)
224
225 # set up server transport and transport factory
226
227 abs_key_path = os.path.join(os.path.dirname(SCRIPT_DIR), 'keys', 'server.pem')
228
229 host = None
230 if options.ssl:
231 from thrift.transport import TSSLSocket
232 transport = TSSLSocket.TSSLServerSocket(host, options.port, certfile=abs_key_path)
233 else:
234 transport = TSocket.TServerSocket(host, options.port)
235 tfactory = TTransport.TBufferedTransportFactory()
236 if options.trans == 'buffered':
237 tfactory = TTransport.TBufferedTransportFactory()
238 elif options.trans == 'framed':
239 tfactory = TTransport.TFramedTransportFactory()
240 elif options.trans == '':
241 raise AssertionError('Unknown --transport option: %s' % options.trans)
242 else:
243 tfactory = TTransport.TBufferedTransportFactory()
244 # if --zlib, then wrap server transport, and use a different transport factory
245 if options.zlib:
246 transport = TZlibTransport.TZlibTransport(transport) # wrap with zlib
247 tfactory = TZlibTransport.TZlibTransportFactory()
248
249 # do server-specific setup here:
250 if server_type == "TNonblockingServer":
251 server = TNonblockingServer.TNonblockingServer(processor, transport, inputProtocolFactory=pfactory)
252 elif server_type == "TProcessPoolServer":
253 import signal
254 from thrift.server import TProcessPoolServer
255 server = TProcessPoolServer.TProcessPoolServer(processor, transport, tfactory, pfactory)
256 server.setNumWorkers(5)
257
258 def set_alarm():
259 def clean_shutdown(signum, frame):
260 for worker in server.workers:
261 if options.verbose > 0:
262 logging.info('Terminating worker: %s' % worker)
263 worker.terminate()
264 if options.verbose > 0:
265 logging.info('Requesting server to stop()')
266 try:
267 server.stop()
James E. King, III350fe752017-10-25 09:57:18 -0400268 except Exception:
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900269 pass
270 signal.signal(signal.SIGALRM, clean_shutdown)
271 signal.alarm(4)
272 set_alarm()
273 else:
274 # look up server class dynamically to instantiate server
275 ServerClass = getattr(TServer, server_type)
276 server = ServerClass(processor, transport, tfactory, pfactory)
277 # enter server main loop
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900278 server.serve()
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900279
James E. King, III0ad20bd2017-09-30 15:44:16 -0700280
James E. King III6f8c99e2018-03-24 16:32:02 -0400281def exit_gracefully(signum, frame):
282 print("SIGINT received\n")
283 server.shutdown() # doesn't work properly, yet
284 sys.exit(0)
285
286
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900287if __name__ == '__main__':
James E. King III6f8c99e2018-03-24 16:32:02 -0400288 signal.signal(signal.SIGINT, exit_gracefully)
289
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900290 parser = OptionParser()
291 parser.add_option('--libpydir', type='string', dest='libpydir',
292 help='include this directory to sys.path for locating library code')
293 parser.add_option('--genpydir', type='string', dest='genpydir',
294 default='gen-py',
295 help='include this directory to sys.path for locating generated code')
296 parser.add_option("--port", type="int", dest="port",
297 help="port number for server to listen on")
298 parser.add_option("--zlib", action="store_true", dest="zlib",
299 help="use zlib wrapper for compressed transport")
300 parser.add_option("--ssl", action="store_true", dest="ssl",
301 help="use SSL for encrypted transport")
302 parser.add_option('-v', '--verbose', action="store_const",
303 dest="verbose", const=2,
304 help="verbose output")
305 parser.add_option('-q', '--quiet', action="store_const",
306 dest="verbose", const=0,
307 help="minimal output")
308 parser.add_option('--protocol', dest="proto", type="string",
James E. King III6f8c99e2018-03-24 16:32:02 -0400309 help="protocol to use, one of: accel, accelc, binary, compact, json")
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900310 parser.add_option('--transport', dest="trans", type="string",
James E. King III6f8c99e2018-03-24 16:32:02 -0400311 help="transport to use, one of: buffered, framed, http")
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900312 parser.add_option('--container-limit', dest='container_limit', type='int', default=None)
313 parser.add_option('--string-limit', dest='string_limit', type='int', default=None)
James E. King III6f8c99e2018-03-24 16:32:02 -0400314 parser.set_defaults(port=9090, verbose=1, proto='binary', transport='buffered')
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900315 options, args = parser.parse_args()
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900316
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900317 # Print TServer log to stdout so that the test-runner can redirect it to log files
318 logging.basicConfig(level=options.verbose)
Nobuaki Sukegawa7b545b52016-01-11 13:46:04 +0900319
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900320 sys.path.insert(0, os.path.join(SCRIPT_DIR, options.genpydir))
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900321 sys.path.insert(0, local_libpath())
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900322
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900323 from ThriftTest import ThriftTest
324 from ThriftTest.ttypes import Xtruct, Xception, Xception2, Insanity
325 from thrift.Thrift import TException
326 from thrift.transport import TTransport
327 from thrift.transport import TSocket
328 from thrift.transport import TZlibTransport
329 from thrift.protocol import TBinaryProtocol
330 from thrift.protocol import TCompactProtocol
331 from thrift.protocol import TJSONProtocol
332 from thrift.server import TServer, TNonblockingServer, THttpServer
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900333
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900334 sys.exit(main(options))