blob: 8819821fdc54a3c1dbc47ee7864446a5eae8295c [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):
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 = {
184 'binary': TBinaryProtocol.TBinaryProtocolFactory,
185 'accel': TBinaryProtocol.TBinaryProtocolAcceleratedFactory,
186 'compact': TCompactProtocol.TCompactProtocolFactory,
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900187 'accelc': TCompactProtocol.TCompactProtocolAcceleratedFactory,
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900188 'json': TJSONProtocol.TJSONProtocolFactory,
189 }
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
197 except:
198 # 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]
David Reissbcaa2ad2008-06-10 22:55:26 +0000205
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900206 # Set up the handler and processor objects
207 handler = TestHandler()
208 processor = ThriftTest.Processor(handler)
Bryan Duxbury16066592011-03-22 18:06:04 +0000209
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900210 # Handle THttpServer as a special case
211 if server_type == 'THttpServer':
212 server = THttpServer.THttpServer(processor, ('', options.port), pfactory)
213 server.serve()
214 sys.exit(0)
215
216 # set up server transport and transport factory
217
218 abs_key_path = os.path.join(os.path.dirname(SCRIPT_DIR), 'keys', 'server.pem')
219
220 host = None
221 if options.ssl:
222 from thrift.transport import TSSLSocket
223 transport = TSSLSocket.TSSLServerSocket(host, options.port, certfile=abs_key_path)
224 else:
225 transport = TSocket.TServerSocket(host, options.port)
226 tfactory = TTransport.TBufferedTransportFactory()
227 if options.trans == 'buffered':
228 tfactory = TTransport.TBufferedTransportFactory()
229 elif options.trans == 'framed':
230 tfactory = TTransport.TFramedTransportFactory()
231 elif options.trans == '':
232 raise AssertionError('Unknown --transport option: %s' % options.trans)
233 else:
234 tfactory = TTransport.TBufferedTransportFactory()
235 # if --zlib, then wrap server transport, and use a different transport factory
236 if options.zlib:
237 transport = TZlibTransport.TZlibTransport(transport) # wrap with zlib
238 tfactory = TZlibTransport.TZlibTransportFactory()
239
240 # do server-specific setup here:
241 if server_type == "TNonblockingServer":
242 server = TNonblockingServer.TNonblockingServer(processor, transport, inputProtocolFactory=pfactory)
243 elif server_type == "TProcessPoolServer":
244 import signal
245 from thrift.server import TProcessPoolServer
246 server = TProcessPoolServer.TProcessPoolServer(processor, transport, tfactory, pfactory)
247 server.setNumWorkers(5)
248
249 def set_alarm():
250 def clean_shutdown(signum, frame):
251 for worker in server.workers:
252 if options.verbose > 0:
253 logging.info('Terminating worker: %s' % worker)
254 worker.terminate()
255 if options.verbose > 0:
256 logging.info('Requesting server to stop()')
257 try:
258 server.stop()
259 except:
260 pass
261 signal.signal(signal.SIGALRM, clean_shutdown)
262 signal.alarm(4)
263 set_alarm()
264 else:
265 # look up server class dynamically to instantiate server
266 ServerClass = getattr(TServer, server_type)
267 server = ServerClass(processor, transport, tfactory, pfactory)
268 # enter server main loop
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900269 server.serve()
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900270
271if __name__ == '__main__':
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900272 parser = OptionParser()
273 parser.add_option('--libpydir', type='string', dest='libpydir',
274 help='include this directory to sys.path for locating library code')
275 parser.add_option('--genpydir', type='string', dest='genpydir',
276 default='gen-py',
277 help='include this directory to sys.path for locating generated code')
278 parser.add_option("--port", type="int", dest="port",
279 help="port number for server to listen on")
280 parser.add_option("--zlib", action="store_true", dest="zlib",
281 help="use zlib wrapper for compressed transport")
282 parser.add_option("--ssl", action="store_true", dest="ssl",
283 help="use SSL for encrypted transport")
284 parser.add_option('-v', '--verbose', action="store_const",
285 dest="verbose", const=2,
286 help="verbose output")
287 parser.add_option('-q', '--quiet', action="store_const",
288 dest="verbose", const=0,
289 help="minimal output")
290 parser.add_option('--protocol', dest="proto", type="string",
291 help="protocol to use, one of: accel, binary, compact, json")
292 parser.add_option('--transport', dest="trans", type="string",
293 help="transport to use, one of: buffered, framed")
294 parser.add_option('--container-limit', dest='container_limit', type='int', default=None)
295 parser.add_option('--string-limit', dest='string_limit', type='int', default=None)
296 parser.set_defaults(port=9090, verbose=1, proto='binary')
297 options, args = parser.parse_args()
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900298
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900299 # Print TServer log to stdout so that the test-runner can redirect it to log files
300 logging.basicConfig(level=options.verbose)
Nobuaki Sukegawa7b545b52016-01-11 13:46:04 +0900301
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900302 sys.path.insert(0, os.path.join(SCRIPT_DIR, options.genpydir))
303 if options.libpydir:
304 sys.path.insert(0, glob.glob(options.libpydir)[0])
305 else:
306 sys.path.insert(0, glob.glob(DEFAULT_LIBDIR_GLOB)[0])
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900307
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900308 from ThriftTest import ThriftTest
309 from ThriftTest.ttypes import Xtruct, Xception, Xception2, Insanity
310 from thrift.Thrift import TException
311 from thrift.transport import TTransport
312 from thrift.transport import TSocket
313 from thrift.transport import TZlibTransport
314 from thrift.protocol import TBinaryProtocol
315 from thrift.protocol import TCompactProtocol
316 from thrift.protocol import TJSONProtocol
317 from thrift.server import TServer, TNonblockingServer, THttpServer
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900318
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900319 sys.exit(main(options))