blob: f12a9fe76229b81b803275ce71e6bdf0e5e575af [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 glob
23import logging
24import os
25import sys
26import time
Bryan Duxbury59d4efd2011-03-21 17:38:22 +000027from optparse import OptionParser
Mark Sleec9676562006-09-05 17:34:52 +000028
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +090029SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
30ROOT_DIR = os.path.dirname(os.path.dirname(SCRIPT_DIR))
31DEFAULT_LIBDIR_GLOB = os.path.join(ROOT_DIR, 'lib', 'py', 'build', 'lib.*')
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):
Mark Sleec9676562006-09-05 17:34:52 +000035 def testVoid(self):
Bryan Duxbury16066592011-03-22 18:06:04 +000036 if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -070037 logging.info('testVoid()')
Mark Sleec9676562006-09-05 17:34:52 +000038
39 def testString(self, str):
Bryan Duxbury16066592011-03-22 18:06:04 +000040 if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -070041 logging.info('testString(%s)' % str)
Mark Sleec9676562006-09-05 17:34:52 +000042 return str
43
Nobuaki Sukegawaa649e742015-09-21 13:53:25 +090044 def testBool(self, boolean):
45 if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -070046 logging.info('testBool(%s)' % str(boolean).lower())
Nobuaki Sukegawaa649e742015-09-21 13:53:25 +090047 return boolean
48
Mark Sleec9676562006-09-05 17:34:52 +000049 def testByte(self, byte):
Bryan Duxbury16066592011-03-22 18:06:04 +000050 if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -070051 logging.info('testByte(%d)' % byte)
Mark Sleec9676562006-09-05 17:34:52 +000052 return byte
53
Mark Sleec98d0502006-09-06 02:42:25 +000054 def testI16(self, i16):
Bryan Duxbury16066592011-03-22 18:06:04 +000055 if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -070056 logging.info('testI16(%d)' % i16)
Mark Sleec98d0502006-09-06 02:42:25 +000057 return i16
58
59 def testI32(self, i32):
Bryan Duxbury16066592011-03-22 18:06:04 +000060 if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -070061 logging.info('testI32(%d)' % i32)
Mark Sleec98d0502006-09-06 02:42:25 +000062 return i32
63
64 def testI64(self, i64):
Bryan Duxbury16066592011-03-22 18:06:04 +000065 if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -070066 logging.info('testI64(%d)' % i64)
Mark Sleec98d0502006-09-06 02:42:25 +000067 return i64
68
69 def testDouble(self, dub):
Bryan Duxbury16066592011-03-22 18:06:04 +000070 if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -070071 logging.info('testDouble(%f)' % dub)
Mark Sleec98d0502006-09-06 02:42:25 +000072 return dub
73
Jens Geyer8bcfdd92014-12-14 03:14:26 +010074 def testBinary(self, thing):
75 if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -070076 logging.info('testBinary()') # TODO: hex output
Jens Geyerd629ea02015-09-23 21:16:50 +020077 return thing
78
Mark Sleec98d0502006-09-06 02:42:25 +000079 def testStruct(self, thing):
Bryan Duxbury16066592011-03-22 18:06:04 +000080 if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -070081 logging.info('testStruct({%s, %s, %s, %s})' % (thing.string_thing, thing.byte_thing, thing.i32_thing, thing.i64_thing))
Mark Sleec98d0502006-09-06 02:42:25 +000082 return thing
83
Roger Meier1f554e12013-01-05 20:38:35 +010084 def testException(self, arg):
Jens Geyerd629ea02015-09-23 21:16:50 +020085 # if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -070086 logging.info('testException(%s)' % arg)
Roger Meier1f554e12013-01-05 20:38:35 +010087 if arg == 'Xception':
88 raise Xception(errorCode=1001, message=arg)
89 elif arg == 'TException':
90 raise TException(message='This is a TException')
91
92 def testMultiException(self, arg0, arg1):
Bryan Duxbury16066592011-03-22 18:06:04 +000093 if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -070094 logging.info('testMultiException(%s, %s)' % (arg0, arg1))
Roger Meier1f554e12013-01-05 20:38:35 +010095 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
David Reiss6ce401d2009-03-24 20:01:58 +0000103 def testOneway(self, seconds):
Bryan Duxbury16066592011-03-22 18:06:04 +0000104 if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -0700105 logging.info('testOneway(%d) => sleeping...' % seconds)
Jens Geyerd629ea02015-09-23 21:16:50 +0200106 time.sleep(seconds / 3) # be quick
Bryan Duxbury16066592011-03-22 18:06:04 +0000107 if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -0700108 logging.info('done sleeping')
David Reissdb893b62008-02-18 02:11:48 +0000109
David Reiss74421272008-11-07 23:09:31 +0000110 def testNest(self, thing):
Bryan Duxbury16066592011-03-22 18:06:04 +0000111 if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -0700112 logging.info('testNest(%s)' % thing)
David Reiss74421272008-11-07 23:09:31 +0000113 return thing
114
115 def testMap(self, thing):
Bryan Duxbury16066592011-03-22 18:06:04 +0000116 if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -0700117 logging.info('testMap(%s)' % thing)
Jens Geyerd629ea02015-09-23 21:16:50 +0200118 return thing
119
120 def testStringMap(self, thing):
121 if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -0700122 logging.info('testStringMap(%s)' % thing)
David Reiss74421272008-11-07 23:09:31 +0000123 return thing
124
125 def testSet(self, thing):
Bryan Duxbury16066592011-03-22 18:06:04 +0000126 if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -0700127 logging.info('testSet(%s)' % thing)
David Reiss74421272008-11-07 23:09:31 +0000128 return thing
129
130 def testList(self, thing):
Bryan Duxbury16066592011-03-22 18:06:04 +0000131 if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -0700132 logging.info('testList(%s)' % thing)
David Reiss74421272008-11-07 23:09:31 +0000133 return thing
134
135 def testEnum(self, thing):
Bryan Duxbury16066592011-03-22 18:06:04 +0000136 if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -0700137 logging.info('testEnum(%s)' % thing)
David Reiss74421272008-11-07 23:09:31 +0000138 return thing
139
140 def testTypedef(self, thing):
Bryan Duxbury16066592011-03-22 18:06:04 +0000141 if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -0700142 logging.info('testTypedef(%s)' % thing)
David Reiss74421272008-11-07 23:09:31 +0000143 return thing
144
Bryan Duxbury59d4efd2011-03-21 17:38:22 +0000145 def testMapMap(self, thing):
Bryan Duxbury16066592011-03-22 18:06:04 +0000146 if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -0700147 logging.info('testMapMap(%s)' % thing)
Jens Geyerd629ea02015-09-23 21:16:50 +0200148 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
163 def testInsanity(self, argument):
164 if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -0700165 logging.info('testInsanity(%s)' % argument)
Jens Geyerd629ea02015-09-23 21:16:50 +0200166 return {
167 1: {
168 2: argument,
169 3: argument,
170 },
171 2: {6: Insanity()},
172 }
Bryan Duxbury59d4efd2011-03-21 17:38:22 +0000173
174 def testMulti(self, arg0, arg1, arg2, arg3, arg4, arg5):
Bryan Duxbury16066592011-03-22 18:06:04 +0000175 if options.verbose > 1:
Randy Abernethy983bf7d2015-10-09 12:28:57 -0700176 logging.info('testMulti(%s)' % [arg0, arg1, arg2, arg3, arg4, arg5])
Roger Meier1f554e12013-01-05 20:38:35 +0100177 return Xtruct(string_thing='Hello2',
178 byte_thing=arg0, i32_thing=arg1, i64_thing=arg2)
179
Bryan Duxbury59d4efd2011-03-21 17:38:22 +0000180
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900181def main(options):
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900182 # set up the protocol factory form the --protocol option
183 prot_factories = {
184 'binary': TBinaryProtocol.TBinaryProtocolFactory,
185 'accel': TBinaryProtocol.TBinaryProtocolAcceleratedFactory,
186 'compact': TCompactProtocol.TCompactProtocolFactory,
187 'json': TJSONProtocol.TJSONProtocolFactory,
188 }
189 pfactory_cls = prot_factories.get(options.proto, None)
190 if pfactory_cls is None:
191 raise AssertionError('Unknown --protocol option: %s' % options.proto)
192 pfactory = pfactory_cls()
Nobuaki Sukegawa7b545b52016-01-11 13:46:04 +0900193 try:
194 pfactory.string_length_limit = options.string_limit
195 pfactory.container_length_limit = options.container_limit
196 except:
197 # Ignore errors for those protocols that does not support length limit
198 pass
Bryan Duxbury16066592011-03-22 18:06:04 +0000199
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900200 # get the server type (TSimpleServer, TNonblockingServer, etc...)
201 if len(args) > 1:
202 raise AssertionError('Only one server type may be specified, not multiple types.')
203 server_type = args[0]
David Reissbcaa2ad2008-06-10 22:55:26 +0000204
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900205 # Set up the handler and processor objects
206 handler = TestHandler()
207 processor = ThriftTest.Processor(handler)
Bryan Duxbury16066592011-03-22 18:06:04 +0000208
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900209 # Handle THttpServer as a special case
210 if server_type == 'THttpServer':
211 server = THttpServer.THttpServer(processor, ('', options.port), pfactory)
212 server.serve()
213 sys.exit(0)
Roger Meier76150722014-05-31 22:22:07 +0200214
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900215 # set up server transport and transport factory
Roger Meier76150722014-05-31 22:22:07 +0200216
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900217 abs_key_path = os.path.join(os.path.dirname(SCRIPT_DIR), 'keys', 'server.pem')
218
219 host = None
220 if options.ssl:
221 from thrift.transport import TSSLSocket
222 transport = TSSLSocket.TSSLServerSocket(host, options.port, certfile=abs_key_path)
223 else:
224 transport = TSocket.TServerSocket(host, options.port)
Roger Meier76150722014-05-31 22:22:07 +0200225 tfactory = TTransport.TBufferedTransportFactory()
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900226 if options.trans == 'buffered':
227 tfactory = TTransport.TBufferedTransportFactory()
228 elif options.trans == 'framed':
229 tfactory = TTransport.TFramedTransportFactory()
230 elif options.trans == '':
231 raise AssertionError('Unknown --transport option: %s' % options.trans)
232 else:
233 tfactory = TTransport.TBufferedTransportFactory()
234 # if --zlib, then wrap server transport, and use a different transport factory
235 if options.zlib:
236 transport = TZlibTransport.TZlibTransport(transport) # wrap with zlib
237 tfactory = TZlibTransport.TZlibTransportFactory()
Bryan Duxbury16066592011-03-22 18:06:04 +0000238
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900239 # do server-specific setup here:
240 if server_type == "TNonblockingServer":
241 server = TNonblockingServer.TNonblockingServer(processor, transport, inputProtocolFactory=pfactory)
242 elif server_type == "TProcessPoolServer":
243 import signal
244 from thrift.server import TProcessPoolServer
245 server = TProcessPoolServer.TProcessPoolServer(processor, transport, tfactory, pfactory)
246 server.setNumWorkers(5)
Jens Geyerd629ea02015-09-23 21:16:50 +0200247
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900248 def set_alarm():
249 def clean_shutdown(signum, frame):
250 for worker in server.workers:
251 if options.verbose > 0:
252 logging.info('Terminating worker: %s' % worker)
253 worker.terminate()
Bryan Duxbury16066592011-03-22 18:06:04 +0000254 if options.verbose > 0:
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900255 logging.info('Requesting server to stop()')
256 try:
257 server.stop()
258 except:
259 pass
260 signal.signal(signal.SIGALRM, clean_shutdown)
261 signal.alarm(4)
262 set_alarm()
263 else:
264 # look up server class dynamically to instantiate server
265 ServerClass = getattr(TServer, server_type)
266 server = ServerClass(processor, transport, tfactory, pfactory)
267 # enter server main loop
268 server.serve()
269
270if __name__ == '__main__':
271 parser = OptionParser()
272 parser.add_option('--libpydir', type='string', dest='libpydir',
273 help='include this directory to sys.path for locating library code')
274 parser.add_option('--genpydir', type='string', dest='genpydir',
275 default='gen-py',
276 help='include this directory to sys.path for locating generated code')
277 parser.add_option("--port", type="int", dest="port",
278 help="port number for server to listen on")
279 parser.add_option("--zlib", action="store_true", dest="zlib",
280 help="use zlib wrapper for compressed transport")
281 parser.add_option("--ssl", action="store_true", dest="ssl",
282 help="use SSL for encrypted transport")
283 parser.add_option('-v', '--verbose', action="store_const",
284 dest="verbose", const=2,
285 help="verbose output")
286 parser.add_option('-q', '--quiet', action="store_const",
287 dest="verbose", const=0,
288 help="minimal output")
289 parser.add_option('--protocol', dest="proto", type="string",
290 help="protocol to use, one of: accel, binary, compact, json")
291 parser.add_option('--transport', dest="trans", type="string",
292 help="transport to use, one of: buffered, framed")
Nobuaki Sukegawa7b545b52016-01-11 13:46:04 +0900293 parser.add_option('--container-limit', dest='container_limit', type='int', default=None)
294 parser.add_option('--string-limit', dest='string_limit', type='int', default=None)
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900295 parser.set_defaults(port=9090, verbose=1, proto='binary')
296 options, args = parser.parse_args()
297
Nobuaki Sukegawa7b545b52016-01-11 13:46:04 +0900298 # Print TServer log to stdout so that the test-runner can redirect it to log files
299 logging.basicConfig(level=options.verbose)
300
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900301 sys.path.insert(0, os.path.join(SCRIPT_DIR, options.genpydir))
302 if options.libpydir:
303 sys.path.insert(0, glob.glob(options.libpydir)[0])
304 else:
305 sys.path.insert(0, glob.glob(DEFAULT_LIBDIR_GLOB)[0])
306
307 from ThriftTest import ThriftTest
308 from ThriftTest.ttypes import Xtruct, Xception, Xception2, Insanity
309 from thrift.Thrift import TException
310 from thrift.transport import TTransport
311 from thrift.transport import TSocket
312 from thrift.transport import TZlibTransport
313 from thrift.protocol import TBinaryProtocol
314 from thrift.protocol import TCompactProtocol
315 from thrift.protocol import TJSONProtocol
316 from thrift.server import TServer, TNonblockingServer, THttpServer
317
318 sys.exit(main(options))