THRIFT-4780: finish the server implementation of multi in python server
- Add default processor handling to python multi
diff --git a/test/py/TestClient.py b/test/py/TestClient.py
index a85098e..e7a9a1a 100755
--- a/test/py/TestClient.py
+++ b/test/py/TestClient.py
@@ -27,8 +27,7 @@
from optparse import OptionParser
from util import local_libpath
sys.path.insert(0, local_libpath())
-from thrift.protocol import TProtocolDecorator
-from thrift.protocol import TProtocol
+from thrift.protocol import TProtocol, TProtocolDecorator
SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
@@ -272,7 +271,7 @@
# LAST_SEQID is a global because we have one transport and multiple protocols
-# running on it (when multiplexec)
+# running on it (when multiplexed)
LAST_SEQID = None
@@ -398,6 +397,16 @@
return make_pedantic(factory.getProtocol(transport))
+class MultiplexedHeaderTest(MultiplexedOptionalTest):
+ def get_protocol(self, transport):
+ wrapped_proto = make_pedantic(THeaderProtocol.THeaderProtocolFactory().getProtocol(transport))
+ return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "ThriftTest")
+
+ def get_protocol2(self, transport):
+ wrapped_proto = make_pedantic(THeaderProtocol.THeaderProtocolFactory().getProtocol(transport))
+ return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "SecondService")
+
+
def suite():
suite = unittest.TestSuite()
loader = unittest.TestLoader()
@@ -421,6 +430,8 @@
suite.addTest(loader.loadTestsFromTestCase(MultiplexedAcceleratedCompactTest))
elif options.proto == 'multic':
suite.addTest(loader.loadTestsFromTestCase(MultiplexedCompactTest))
+ elif options.proto == 'multih':
+ suite.addTest(loader.loadTestsFromTestCase(MultiplexedHeaderTest))
elif options.proto == 'multij':
suite.addTest(loader.loadTestsFromTestCase(MultiplexedJSONTest))
else:
@@ -460,7 +471,7 @@
dest="verbose", const=0,
help="minimal output")
parser.add_option('--protocol', dest="proto", type="string",
- help="protocol to use, one of: accel, accelc, binary, compact, header, json, multi, multia, multiac, multic, multij")
+ help="protocol to use, one of: accel, accelc, binary, compact, header, json, multi, multia, multiac, multic, multih, multij")
parser.add_option('--transport', dest="trans", type="string",
help="transport to use, one of: buffered, framed, http")
parser.set_defaults(framed=False, http_path=None, verbose=1, host='localhost', port=9090, proto='binary')
diff --git a/test/py/TestServer.py b/test/py/TestServer.py
index aba0d42..d0a13e5 100755
--- a/test/py/TestServer.py
+++ b/test/py/TestServer.py
@@ -27,6 +27,8 @@
from optparse import OptionParser
from util import local_libpath
+sys.path.insert(0, local_libpath())
+from thrift.protocol import TProtocol, TProtocolDecorator
SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
@@ -178,21 +180,79 @@
byte_thing=arg0, i32_thing=arg1, i64_thing=arg2)
+class SecondHandler(object):
+ def secondtestString(self, argument):
+ return "testString(\"" + argument + "\")"
+
+
+# LAST_SEQID is a global because we have one transport and multiple protocols
+# running on it (when multiplexed)
+LAST_SEQID = None
+
+
+class TPedanticSequenceIdProtocolWrapper(TProtocolDecorator.TProtocolDecorator):
+ """
+ Wraps any protocol with sequence ID checking: looks for outbound
+ uniqueness as well as request/response alignment.
+ """
+ def __init__(self, protocol):
+ # TProtocolDecorator.__new__ does all the heavy lifting
+ pass
+
+ def readMessageBegin(self):
+ global LAST_SEQID
+ (name, type, seqid) =\
+ super(TPedanticSequenceIdProtocolWrapper, self).readMessageBegin()
+ if LAST_SEQID is not None and LAST_SEQID == seqid:
+ raise TProtocol.TProtocolException(
+ TProtocol.TProtocolException.INVALID_DATA,
+ "We received the same seqid {0} twice in a row".format(seqid))
+ LAST_SEQID = seqid
+ return (name, type, seqid)
+
+
+def make_pedantic(proto):
+ """ Wrap a protocol in the pedantic sequence ID wrapper. """
+ # NOTE: this is disabled for now as many clients send seqid
+ # of zero and that is okay, need a way to identify
+ # clients that MUST send seqid unique to function right
+ # or just force all implementations to send unique seqids (preferred)
+ return proto # TPedanticSequenceIdProtocolWrapper(proto)
+
+
+class TPedanticSequenceIdProtocolFactory(TProtocol.TProtocolFactory):
+ def __init__(self, encapsulated):
+ super(TPedanticSequenceIdProtocolFactory, self).__init__()
+ self.encapsulated = encapsulated
+
+ def getProtocol(self, trans):
+ return make_pedantic(self.encapsulated.getProtocol(trans))
+
+
def main(options):
+ # common header allowed client types
+ allowed_client_types = [
+ THeaderTransport.THeaderClientType.HEADERS,
+ THeaderTransport.THeaderClientType.FRAMED_BINARY,
+ THeaderTransport.THeaderClientType.UNFRAMED_BINARY,
+ THeaderTransport.THeaderClientType.FRAMED_COMPACT,
+ THeaderTransport.THeaderClientType.UNFRAMED_COMPACT,
+ ]
+
# set up the protocol factory form the --protocol option
prot_factories = {
'accel': TBinaryProtocol.TBinaryProtocolAcceleratedFactory(),
+ 'multia': TBinaryProtocol.TBinaryProtocolAcceleratedFactory(),
'accelc': TCompactProtocol.TCompactProtocolAcceleratedFactory(),
- 'binary': TBinaryProtocol.TBinaryProtocolFactory(),
+ 'multiac': TCompactProtocol.TCompactProtocolAcceleratedFactory(),
+ 'binary': TPedanticSequenceIdProtocolFactory(TBinaryProtocol.TBinaryProtocolFactory()),
+ 'multi': TPedanticSequenceIdProtocolFactory(TBinaryProtocol.TBinaryProtocolFactory()),
'compact': TCompactProtocol.TCompactProtocolFactory(),
- 'header': THeaderProtocol.THeaderProtocolFactory(allowed_client_types=[
- THeaderTransport.THeaderClientType.HEADERS,
- THeaderTransport.THeaderClientType.FRAMED_BINARY,
- THeaderTransport.THeaderClientType.UNFRAMED_BINARY,
- THeaderTransport.THeaderClientType.FRAMED_COMPACT,
- THeaderTransport.THeaderClientType.UNFRAMED_COMPACT,
- ]),
+ 'multic': TCompactProtocol.TCompactProtocolFactory(),
+ 'header': THeaderProtocol.THeaderProtocolFactory(allowed_client_types),
+ 'multih': THeaderProtocol.THeaderProtocolFactory(allowed_client_types),
'json': TJSONProtocol.TJSONProtocolFactory(),
+ 'multij': TJSONProtocol.TJSONProtocolFactory(),
}
pfactory = prot_factories.get(options.proto, None)
if pfactory is None:
@@ -215,6 +275,16 @@
handler = TestHandler()
processor = ThriftTest.Processor(handler)
+ if options.proto.startswith('multi'):
+ secondHandler = SecondHandler()
+ secondProcessor = SecondService.Processor(secondHandler)
+
+ multiplexedProcessor = TMultiplexedProcessor()
+ multiplexedProcessor.registerDefault(processor)
+ multiplexedProcessor.registerProcessor('ThriftTest', processor)
+ multiplexedProcessor.registerProcessor('SecondService', secondProcessor)
+ processor = multiplexedProcessor
+
global server
# Handle THttpServer as a special case
@@ -312,7 +382,7 @@
dest="verbose", const=0,
help="minimal output")
parser.add_option('--protocol', dest="proto", type="string",
- help="protocol to use, one of: accel, accelc, binary, compact, json")
+ help="protocol to use, one of: accel, accelc, binary, compact, json, multi, multia, multiac, multic, multih, multij")
parser.add_option('--transport', dest="trans", type="string",
help="transport to use, one of: buffered, framed, http")
parser.add_option('--container-limit', dest='container_limit', type='int', default=None)
@@ -324,11 +394,11 @@
logging.basicConfig(level=options.verbose)
sys.path.insert(0, os.path.join(SCRIPT_DIR, options.genpydir))
- sys.path.insert(0, local_libpath())
- from ThriftTest import ThriftTest
+ from ThriftTest import ThriftTest, SecondService
from ThriftTest.ttypes import Xtruct, Xception, Xception2, Insanity
from thrift.Thrift import TException
+ from thrift.TMultiplexedProcessor import TMultiplexedProcessor
from thrift.transport import THeaderTransport
from thrift.transport import TTransport
from thrift.transport import TSocket