blob: 4fa889460b9b00aefd2059ad72266402a2167f16 [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 Sukegawa760511f2015-11-06 21:24:16 +090021from __future__ import division, print_function
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):
182 # Print TServer log to stdout so that the test-runner can redirect it to log files
183 logging.basicConfig(level=logging.DEBUG)
Bryan Duxbury16066592011-03-22 18:06:04 +0000184
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900185 # set up the protocol factory form the --protocol option
186 prot_factories = {
187 'binary': TBinaryProtocol.TBinaryProtocolFactory,
188 'accel': TBinaryProtocol.TBinaryProtocolAcceleratedFactory,
189 'compact': TCompactProtocol.TCompactProtocolFactory,
190 'json': TJSONProtocol.TJSONProtocolFactory,
191 }
192 pfactory_cls = prot_factories.get(options.proto, None)
193 if pfactory_cls is None:
194 raise AssertionError('Unknown --protocol option: %s' % options.proto)
195 pfactory = pfactory_cls()
Bryan Duxbury16066592011-03-22 18:06:04 +0000196
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900197 # get the server type (TSimpleServer, TNonblockingServer, etc...)
198 if len(args) > 1:
199 raise AssertionError('Only one server type may be specified, not multiple types.')
200 server_type = args[0]
David Reissbcaa2ad2008-06-10 22:55:26 +0000201
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900202 # Set up the handler and processor objects
203 handler = TestHandler()
204 processor = ThriftTest.Processor(handler)
Bryan Duxbury16066592011-03-22 18:06:04 +0000205
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900206 # Handle THttpServer as a special case
207 if server_type == 'THttpServer':
208 server = THttpServer.THttpServer(processor, ('', options.port), pfactory)
209 server.serve()
210 sys.exit(0)
Roger Meier76150722014-05-31 22:22:07 +0200211
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900212 # set up server transport and transport factory
Roger Meier76150722014-05-31 22:22:07 +0200213
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900214 abs_key_path = os.path.join(os.path.dirname(SCRIPT_DIR), 'keys', 'server.pem')
215
216 host = None
217 if options.ssl:
218 from thrift.transport import TSSLSocket
219 transport = TSSLSocket.TSSLServerSocket(host, options.port, certfile=abs_key_path)
220 else:
221 transport = TSocket.TServerSocket(host, options.port)
Roger Meier76150722014-05-31 22:22:07 +0200222 tfactory = TTransport.TBufferedTransportFactory()
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900223 if options.trans == 'buffered':
224 tfactory = TTransport.TBufferedTransportFactory()
225 elif options.trans == 'framed':
226 tfactory = TTransport.TFramedTransportFactory()
227 elif options.trans == '':
228 raise AssertionError('Unknown --transport option: %s' % options.trans)
229 else:
230 tfactory = TTransport.TBufferedTransportFactory()
231 # if --zlib, then wrap server transport, and use a different transport factory
232 if options.zlib:
233 transport = TZlibTransport.TZlibTransport(transport) # wrap with zlib
234 tfactory = TZlibTransport.TZlibTransportFactory()
Bryan Duxbury16066592011-03-22 18:06:04 +0000235
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900236 # do server-specific setup here:
237 if server_type == "TNonblockingServer":
238 server = TNonblockingServer.TNonblockingServer(processor, transport, inputProtocolFactory=pfactory)
239 elif server_type == "TProcessPoolServer":
240 import signal
241 from thrift.server import TProcessPoolServer
242 server = TProcessPoolServer.TProcessPoolServer(processor, transport, tfactory, pfactory)
243 server.setNumWorkers(5)
Jens Geyerd629ea02015-09-23 21:16:50 +0200244
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900245 def set_alarm():
246 def clean_shutdown(signum, frame):
247 for worker in server.workers:
248 if options.verbose > 0:
249 logging.info('Terminating worker: %s' % worker)
250 worker.terminate()
Bryan Duxbury16066592011-03-22 18:06:04 +0000251 if options.verbose > 0:
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900252 logging.info('Requesting server to stop()')
253 try:
254 server.stop()
255 except:
256 pass
257 signal.signal(signal.SIGALRM, clean_shutdown)
258 signal.alarm(4)
259 set_alarm()
260 else:
261 # look up server class dynamically to instantiate server
262 ServerClass = getattr(TServer, server_type)
263 server = ServerClass(processor, transport, tfactory, pfactory)
264 # enter server main loop
265 server.serve()
266
267if __name__ == '__main__':
268 parser = OptionParser()
269 parser.add_option('--libpydir', type='string', dest='libpydir',
270 help='include this directory to sys.path for locating library code')
271 parser.add_option('--genpydir', type='string', dest='genpydir',
272 default='gen-py',
273 help='include this directory to sys.path for locating generated code')
274 parser.add_option("--port", type="int", dest="port",
275 help="port number for server to listen on")
276 parser.add_option("--zlib", action="store_true", dest="zlib",
277 help="use zlib wrapper for compressed transport")
278 parser.add_option("--ssl", action="store_true", dest="ssl",
279 help="use SSL for encrypted transport")
280 parser.add_option('-v', '--verbose', action="store_const",
281 dest="verbose", const=2,
282 help="verbose output")
283 parser.add_option('-q', '--quiet', action="store_const",
284 dest="verbose", const=0,
285 help="minimal output")
286 parser.add_option('--protocol', dest="proto", type="string",
287 help="protocol to use, one of: accel, binary, compact, json")
288 parser.add_option('--transport', dest="trans", type="string",
289 help="transport to use, one of: buffered, framed")
290 parser.set_defaults(port=9090, verbose=1, proto='binary')
291 options, args = parser.parse_args()
292
293 sys.path.insert(0, os.path.join(SCRIPT_DIR, options.genpydir))
294 if options.libpydir:
295 sys.path.insert(0, glob.glob(options.libpydir)[0])
296 else:
297 sys.path.insert(0, glob.glob(DEFAULT_LIBDIR_GLOB)[0])
298
299 from ThriftTest import ThriftTest
300 from ThriftTest.ttypes import Xtruct, Xception, Xception2, Insanity
301 from thrift.Thrift import TException
302 from thrift.transport import TTransport
303 from thrift.transport import TSocket
304 from thrift.transport import TZlibTransport
305 from thrift.protocol import TBinaryProtocol
306 from thrift.protocol import TCompactProtocol
307 from thrift.protocol import TJSONProtocol
308 from thrift.server import TServer, TNonblockingServer, THttpServer
309
310 sys.exit(main(options))