blob: 04ad62a955911e5f091d97121885d4834a81638c [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
24import sys
25import time
Bryan Duxbury59d4efd2011-03-21 17:38:22 +000026from optparse import OptionParser
Mark Sleec9676562006-09-05 17:34:52 +000027
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +090028from util import local_libpath
29
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +090030SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
Roger Meierf4eec7a2011-09-11 18:16:21 +000031
Mark Sleec9676562006-09-05 17:34:52 +000032
Jens Geyerd629ea02015-09-23 21:16:50 +020033class TestHandler(object):
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090034 def testVoid(self):
35 if options.verbose > 1:
36 logging.info('testVoid()')
Mark Sleec9676562006-09-05 17:34:52 +000037
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090038 def testString(self, str):
39 if options.verbose > 1:
40 logging.info('testString(%s)' % str)
41 return str
Mark Sleec9676562006-09-05 17:34:52 +000042
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090043 def testBool(self, boolean):
44 if options.verbose > 1:
45 logging.info('testBool(%s)' % str(boolean).lower())
46 return boolean
Nobuaki Sukegawaa649e742015-09-21 13:53:25 +090047
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090048 def testByte(self, byte):
49 if options.verbose > 1:
50 logging.info('testByte(%d)' % byte)
51 return byte
Mark Sleec9676562006-09-05 17:34:52 +000052
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090053 def testI16(self, i16):
54 if options.verbose > 1:
55 logging.info('testI16(%d)' % i16)
56 return i16
Mark Sleec98d0502006-09-06 02:42:25 +000057
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090058 def testI32(self, i32):
59 if options.verbose > 1:
60 logging.info('testI32(%d)' % i32)
61 return i32
Mark Sleec98d0502006-09-06 02:42:25 +000062
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090063 def testI64(self, i64):
64 if options.verbose > 1:
65 logging.info('testI64(%d)' % i64)
66 return i64
Mark Sleec98d0502006-09-06 02:42:25 +000067
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090068 def testDouble(self, dub):
69 if options.verbose > 1:
70 logging.info('testDouble(%f)' % dub)
71 return dub
Mark Sleec98d0502006-09-06 02:42:25 +000072
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090073 def testBinary(self, thing):
74 if options.verbose > 1:
75 logging.info('testBinary()') # TODO: hex output
76 return thing
Jens Geyerd629ea02015-09-23 21:16:50 +020077
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090078 def testStruct(self, thing):
79 if options.verbose > 1:
80 logging.info('testStruct({%s, %s, %s, %s})' % (thing.string_thing, thing.byte_thing, thing.i32_thing, thing.i64_thing))
81 return thing
Mark Sleec98d0502006-09-06 02:42:25 +000082
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090083 def testException(self, arg):
84 # if options.verbose > 1:
85 logging.info('testException(%s)' % arg)
86 if arg == 'Xception':
87 raise Xception(errorCode=1001, message=arg)
88 elif arg == 'TException':
89 raise TException(message='This is a TException')
Roger Meier1f554e12013-01-05 20:38:35 +010090
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090091 def testMultiException(self, arg0, arg1):
92 if options.verbose > 1:
93 logging.info('testMultiException(%s, %s)' % (arg0, arg1))
94 if arg0 == 'Xception':
95 raise Xception(errorCode=1001, message='This is an Xception')
96 elif arg0 == 'Xception2':
97 raise Xception2(
98 errorCode=2002,
99 struct_thing=Xtruct(string_thing='This is an Xception2'))
100 return Xtruct(string_thing=arg1)
Mark Sleec9676562006-09-05 17:34:52 +0000101
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900102 def testOneway(self, seconds):
103 if options.verbose > 1:
104 logging.info('testOneway(%d) => sleeping...' % seconds)
105 time.sleep(seconds / 3) # be quick
106 if options.verbose > 1:
107 logging.info('done sleeping')
David Reissdb893b62008-02-18 02:11:48 +0000108
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900109 def testNest(self, thing):
110 if options.verbose > 1:
111 logging.info('testNest(%s)' % thing)
112 return thing
David Reiss74421272008-11-07 23:09:31 +0000113
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900114 def testMap(self, thing):
115 if options.verbose > 1:
116 logging.info('testMap(%s)' % thing)
117 return thing
Jens Geyerd629ea02015-09-23 21:16:50 +0200118
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900119 def testStringMap(self, thing):
120 if options.verbose > 1:
121 logging.info('testStringMap(%s)' % thing)
122 return thing
David Reiss74421272008-11-07 23:09:31 +0000123
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900124 def testSet(self, thing):
125 if options.verbose > 1:
126 logging.info('testSet(%s)' % thing)
127 return thing
David Reiss74421272008-11-07 23:09:31 +0000128
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900129 def testList(self, thing):
130 if options.verbose > 1:
131 logging.info('testList(%s)' % thing)
132 return thing
David Reiss74421272008-11-07 23:09:31 +0000133
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900134 def testEnum(self, thing):
135 if options.verbose > 1:
136 logging.info('testEnum(%s)' % thing)
137 return thing
David Reiss74421272008-11-07 23:09:31 +0000138
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900139 def testTypedef(self, thing):
140 if options.verbose > 1:
141 logging.info('testTypedef(%s)' % thing)
142 return thing
David Reiss74421272008-11-07 23:09:31 +0000143
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900144 def testMapMap(self, thing):
145 if options.verbose > 1:
146 logging.info('testMapMap(%s)' % thing)
147 return {
148 -4: {
149 -4: -4,
150 -3: -3,
151 -2: -2,
152 -1: -1,
153 },
154 4: {
155 4: 4,
156 3: 3,
157 2: 2,
158 1: 1,
159 },
160 }
Roger Meier1f554e12013-01-05 20:38:35 +0100161
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900162 def testInsanity(self, argument):
163 if options.verbose > 1:
164 logging.info('testInsanity(%s)' % argument)
165 return {
166 1: {
167 2: argument,
168 3: argument,
169 },
170 2: {6: Insanity()},
171 }
Bryan Duxbury59d4efd2011-03-21 17:38:22 +0000172
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900173 def testMulti(self, arg0, arg1, arg2, arg3, arg4, arg5):
174 if options.verbose > 1:
175 logging.info('testMulti(%s)' % [arg0, arg1, arg2, arg3, arg4, arg5])
176 return Xtruct(string_thing='Hello2',
177 byte_thing=arg0, i32_thing=arg1, i64_thing=arg2)
Roger Meier1f554e12013-01-05 20:38:35 +0100178
Bryan Duxbury59d4efd2011-03-21 17:38:22 +0000179
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900180def main(options):
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900181 # set up the protocol factory form the --protocol option
182 prot_factories = {
183 'binary': TBinaryProtocol.TBinaryProtocolFactory,
184 'accel': TBinaryProtocol.TBinaryProtocolAcceleratedFactory,
185 'compact': TCompactProtocol.TCompactProtocolFactory,
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900186 'accelc': TCompactProtocol.TCompactProtocolAcceleratedFactory,
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900187 '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()
193 try:
194 pfactory.string_length_limit = options.string_limit
195 pfactory.container_length_limit = options.container_limit
James E. King, III350fe752017-10-25 09:57:18 -0400196 except Exception:
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900197 # Ignore errors for those protocols that does not support length limit
198 pass
Bryan Duxbury16066592011-03-22 18:06:04 +0000199
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +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 Sukegawa10308cb2016-02-03 01:57:03 +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 Sukegawa10308cb2016-02-03 01:57:03 +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)
214
215 # set up server transport and transport factory
216
217 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)
225 tfactory = TTransport.TBufferedTransportFactory()
226 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()
238
239 # 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)
247
248 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()
254 if options.verbose > 0:
255 logging.info('Requesting server to stop()')
256 try:
257 server.stop()
James E. King, III350fe752017-10-25 09:57:18 -0400258 except Exception:
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900259 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
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900268 server.serve()
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900269
James E. King, III0ad20bd2017-09-30 15:44:16 -0700270
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900271if __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))
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900303 sys.path.insert(0, local_libpath())
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900304
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900305 from ThriftTest import ThriftTest
306 from ThriftTest.ttypes import Xtruct, Xception, Xception2, Insanity
307 from thrift.Thrift import TException
308 from thrift.transport import TTransport
309 from thrift.transport import TSocket
310 from thrift.transport import TZlibTransport
311 from thrift.protocol import TBinaryProtocol
312 from thrift.protocol import TCompactProtocol
313 from thrift.protocol import TJSONProtocol
314 from thrift.server import TServer, TNonblockingServer, THttpServer
Nobuaki Sukegawaa185d7e2015-11-06 21:24:24 +0900315
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900316 sys.exit(main(options))