diff options
author | James E. King III <jking@apache.org> | 2018-03-24 16:32:02 -0400 |
---|---|---|
committer | James E. King III <jking@apache.org> | 2018-04-05 10:25:19 -0400 |
commit | 6f8c99e98170dcd4f311e755b79f7013868c64c5 (patch) | |
tree | 0d8a7a41c707815ed86d624bf81be5317a70185b | |
parent | a0cf38ed312a5342eb05574719485b725fa52eee (diff) | |
download | thrift-6f8c99e98170dcd4f311e755b79f7013868c64c5.tar.gz |
THRIFT-3118: add http (for non-ssl and for ssl) to the python cross tests
-rwxr-xr-x | build/docker/scripts/sca.sh | 6 | ||||
-rw-r--r-- | lib/py/src/server/THttpServer.py | 23 | ||||
-rw-r--r-- | lib/py/src/transport/THttpClient.py | 32 | ||||
-rw-r--r-- | test/crossrunner/run.py | 2 | ||||
-rw-r--r-- | test/known_failures_Linux.json | 172 | ||||
-rwxr-xr-x | test/py/TestClient.py | 21 | ||||
-rwxr-xr-x | test/py/TestServer.py | 32 | ||||
-rwxr-xr-x | test/test.py | 20 | ||||
-rw-r--r-- | test/tests.json | 12 |
9 files changed, 283 insertions, 37 deletions
diff --git a/build/docker/scripts/sca.sh b/build/docker/scripts/sca.sh index f17f7035d..f26ce9556 100755 --- a/build/docker/scripts/sca.sh +++ b/build/docker/scripts/sca.sh @@ -39,10 +39,10 @@ cppcheck --force --quiet --inline-suppr --error-exitcode=1 -j2 lib/cpp/src lib/c cppcheck --force --quiet --inline-suppr --error-exitcode=1 -j2 lib/c_glib/src lib/c_glib/test test/c_glib/src tutorial/c_glib # Python code style -flake8 --ignore=E501 lib/py -flake8 tutorial/py +flake8 --ignore=E501 --exclude=lib/py/build lib/py +flake8 --exclude=tutorial/py/build tutorial/py # THRIFT-4371 : generated files are excluded because they haven't been scrubbed yet -flake8 --ignore=E501 --exclude="*/gen-py*/*" test/py +flake8 --ignore=E501 --exclude="*/gen-py*/*",test/py/build test/py flake8 test/py.twisted flake8 test/py.tornado flake8 --ignore=E501 test/test.py diff --git a/lib/py/src/server/THttpServer.py b/lib/py/src/server/THttpServer.py index 1b501a7aa..85cf4005e 100644 --- a/lib/py/src/server/THttpServer.py +++ b/lib/py/src/server/THttpServer.py @@ -17,6 +17,8 @@ # under the License. # +import ssl + from six.moves import BaseHTTPServer from thrift.server import TServer @@ -47,11 +49,17 @@ class THttpServer(TServer.TServer): server_address, inputProtocolFactory, outputProtocolFactory=None, - server_class=BaseHTTPServer.HTTPServer): - """Set up protocol factories and HTTP server. + server_class=BaseHTTPServer.HTTPServer, + **kwargs): + """Set up protocol factories and HTTP (or HTTPS) server. See BaseHTTPServer for server_address. See TServer for protocol factories. + + To make a secure server, provide the named arguments: + * cafile - to validate clients [optional] + * cert_file - the server cert + * key_file - the server's key """ if outputProtocolFactory is None: outputProtocolFactory = inputProtocolFactory @@ -83,5 +91,16 @@ class THttpServer(TServer.TServer): self.httpd = server_class(server_address, RequestHander) + if (kwargs.get('cafile') or kwargs.get('cert_file') or kwargs.get('key_file')): + context = ssl.create_default_context(cafile=kwargs.get('cafile')) + context.check_hostname = False + context.load_cert_chain(kwargs.get('cert_file'), kwargs.get('key_file')) + context.verify_mode = ssl.CERT_REQUIRED if kwargs.get('cafile') else ssl.CERT_NONE + self.httpd.socket = context.wrap_socket(self.httpd.socket, server_side=True) + def serve(self): self.httpd.serve_forever() + + def shutdown(self): + self.httpd.socket.close() + # self.httpd.shutdown() # hangs forever, python doesn't handle POLLNVAL properly! diff --git a/lib/py/src/transport/THttpClient.py b/lib/py/src/transport/THttpClient.py index fb33421d7..60ff226a9 100644 --- a/lib/py/src/transport/THttpClient.py +++ b/lib/py/src/transport/THttpClient.py @@ -20,6 +20,7 @@ from io import BytesIO import os import socket +import ssl import sys import warnings import base64 @@ -34,17 +35,20 @@ import six class THttpClient(TTransportBase): """Http implementation of TTransport base.""" - def __init__(self, uri_or_host, port=None, path=None): - """THttpClient supports two different types constructor parameters. + def __init__(self, uri_or_host, port=None, path=None, cafile=None, cert_file=None, key_file=None, ssl_context=None): + """THttpClient supports two different types of construction: THttpClient(host, port, path) - deprecated - THttpClient(uri) + THttpClient(uri, [port=<n>, path=<s>, cafile=<filename>, cert_file=<filename>, key_file=<filename>, ssl_context=<context>]) - Only the second supports https. + Only the second supports https. To properly authenticate against the server, + provide the client's identity by specifying cert_file and key_file. To properly + authenticate the server, specify either cafile or ssl_context with a CA defined. + NOTE: if both cafile and ssl_context are defined, ssl_context will override cafile. """ if port is not None: warnings.warn( - "Please use the THttpClient('http://host:port/path') syntax", + "Please use the THttpClient('http{s}://host:port/path') constructor", DeprecationWarning, stacklevel=2) self.host = uri_or_host @@ -60,6 +64,9 @@ class THttpClient(TTransportBase): self.port = parsed.port or http_client.HTTP_PORT elif self.scheme == 'https': self.port = parsed.port or http_client.HTTPS_PORT + self.certfile = cert_file + self.keyfile = key_file + self.context = ssl.create_default_context(cafile=cafile) if (cafile and not ssl_context) else ssl_context self.host = parsed.hostname self.path = parsed.path if parsed.query: @@ -100,12 +107,17 @@ class THttpClient(TTransportBase): def open(self): if self.scheme == 'http': - self.__http = http_client.HTTPConnection(self.host, self.port) + self.__http = http_client.HTTPConnection(self.host, self.port, + timeout=self.__timeout) elif self.scheme == 'https': - self.__http = http_client.HTTPSConnection(self.host, self.port) - if self.using_proxy(): - self.__http.set_tunnel(self.realhost, self.realport, - {"Proxy-Authorization": self.proxy_auth}) + self.__http = http_client.HTTPSConnection(self.host, self.port, + key_file=self.keyfile, + cert_file=self.certfile, + timeout=self.__timeout, + context=self.context) + if self.using_proxy(): + self.__http.set_tunnel(self.realhost, self.realport, + {"Proxy-Authorization": self.proxy_auth}) def close(self): self.__http.close() diff --git a/test/crossrunner/run.py b/test/crossrunner/run.py index 25c58cef3..a7bc939ea 100644 --- a/test/crossrunner/run.py +++ b/test/crossrunner/run.py @@ -235,7 +235,7 @@ def run_test(testdir, logdir, test_dict, max_retry, async=True): logger.warn('[%s]: Detected socket bind failure, retrying...', test.server.name) bind_retry_count += 1 else: - result = RESULT_TIMEOUT if cl.expired else cl.returncode if cl.proc.poll() is not None else RESULT_ERROR + result = RESULT_TIMEOUT if cl.expired else cl.returncode if (cl.proc and cl.proc.poll()) is not None else RESULT_ERROR # For servers that handle a controlled shutdown by signal # if they are killed, or return an error code, that is a diff --git a/test/known_failures_Linux.json b/test/known_failures_Linux.json index f7676498a..16ede2735 100644 --- a/test/known_failures_Linux.json +++ b/test/known_failures_Linux.json @@ -83,6 +83,46 @@ "cpp-nodejs_multij-json_http-domain", "cpp-nodejs_multij-json_http-ip", "cpp-nodejs_multij-json_http-ip-ssl", + "cpp-py3_binary-accel_http-ip", + "cpp-py3_binary-accel_http-ip-ssl", + "cpp-py3_binary_http-ip", + "cpp-py3_binary_http-ip-ssl", + "cpp-py3_compact-accelc_http-ip", + "cpp-py3_compact-accelc_http-ip-ssl", + "cpp-py3_compact_http-ip", + "cpp-py3_compact_http-ip-ssl", + "cpp-py3_json_http-ip", + "cpp-py3_json_http-ip-ssl", + "cpp-py3_multi-accel_http-ip", + "cpp-py3_multi-accel_http-ip-ssl", + "cpp-py3_multi-binary_http-ip", + "cpp-py3_multi-binary_http-ip-ssl", + "cpp-py3_multic-accelc_http-ip", + "cpp-py3_multic-accelc_http-ip-ssl", + "cpp-py3_multic-compact_http-ip", + "cpp-py3_multic-compact_http-ip-ssl", + "cpp-py3_multij-json_http-ip", + "cpp-py3_multij-json_http-ip-ssl", + "cpp-py_binary-accel_http-ip", + "cpp-py_binary-accel_http-ip-ssl", + "cpp-py_binary_http-ip", + "cpp-py_binary_http-ip-ssl", + "cpp-py_compact-accelc_http-ip", + "cpp-py_compact-accelc_http-ip-ssl", + "cpp-py_compact_http-ip", + "cpp-py_compact_http-ip-ssl", + "cpp-py_json_http-ip", + "cpp-py_json_http-ip-ssl", + "cpp-py_multi-accel_http-ip", + "cpp-py_multi-accel_http-ip-ssl", + "cpp-py_multi-binary_http-ip", + "cpp-py_multi-binary_http-ip-ssl", + "cpp-py_multic-accelc_http-ip", + "cpp-py_multic-accelc_http-ip-ssl", + "cpp-py_multic-compact_http-ip", + "cpp-py_multic-compact_http-ip-ssl", + "cpp-py_multij-json_http-ip", + "cpp-py_multij-json_http-ip-ssl", "cpp-rs_multi_buffered-ip", "cpp-rs_multi_framed-ip", "cpp-rs_multic_buffered-ip", @@ -166,42 +206,62 @@ "d-py3_binary-accel_buffered-ip-ssl", "d-py3_binary-accel_framed-ip", "d-py3_binary-accel_framed-ip-ssl", + "d-py3_binary-accel_http-ip", + "d-py3_binary-accel_http-ip-ssl", "d-py3_binary_buffered-ip", "d-py3_binary_buffered-ip-ssl", "d-py3_binary_framed-ip", "d-py3_binary_framed-ip-ssl", + "d-py3_binary_http-ip", + "d-py3_binary_http-ip-ssl", "d-py3_compact-accelc_buffered-ip", "d-py3_compact-accelc_buffered-ip-ssl", "d-py3_compact-accelc_framed-ip", "d-py3_compact-accelc_framed-ip-ssl", + "d-py3_compact-accelc_http-ip", + "d-py3_compact-accelc_http-ip-ssl", "d-py3_compact_buffered-ip", "d-py3_compact_buffered-ip-ssl", "d-py3_compact_framed-ip", "d-py3_compact_framed-ip-ssl", + "d-py3_compact_http-ip", + "d-py3_compact_http-ip-ssl", "d-py3_json_buffered-ip", "d-py3_json_buffered-ip-ssl", "d-py3_json_framed-ip", "d-py3_json_framed-ip-ssl", + "d-py3_json_http-ip", + "d-py3_json_http-ip-ssl", "d-py_binary-accel_buffered-ip", "d-py_binary-accel_buffered-ip-ssl", "d-py_binary-accel_framed-ip", "d-py_binary-accel_framed-ip-ssl", + "d-py_binary-accel_http-ip", + "d-py_binary-accel_http-ip-ssl", "d-py_binary_buffered-ip", "d-py_binary_buffered-ip-ssl", "d-py_binary_framed-ip", "d-py_binary_framed-ip-ssl", + "d-py_binary_http-ip", + "d-py_binary_http-ip-ssl", "d-py_compact-accelc_buffered-ip", "d-py_compact-accelc_buffered-ip-ssl", "d-py_compact-accelc_framed-ip", "d-py_compact-accelc_framed-ip-ssl", + "d-py_compact-accelc_http-ip", + "d-py_compact-accelc_http-ip-ssl", "d-py_compact_buffered-ip", "d-py_compact_buffered-ip-ssl", "d-py_compact_framed-ip", "d-py_compact_framed-ip-ssl", + "d-py_compact_http-ip", + "d-py_compact_http-ip-ssl", "d-py_json_buffered-ip", "d-py_json_buffered-ip-ssl", "d-py_json_framed-ip", "d-py_json_framed-ip-ssl", + "d-py_json_http-ip", + "d-py_json_http-ip-ssl", "erl-cpp_binary_buffered-ip", "erl-cpp_compact_buffered-ip", "erl-csharp_binary_buffered-ip", @@ -302,8 +362,118 @@ "nodejs-netcore_json_buffered-ip-ssl", "nodejs-netcore_json_framed-ip", "nodejs-netcore_json_framed-ip-ssl", + "nodejs-py3_binary-accel_http-ip", + "nodejs-py3_binary-accel_http-ip-ssl", + "nodejs-py3_binary_http-ip", + "nodejs-py3_binary_http-ip-ssl", + "nodejs-py3_compact-accelc_http-ip", + "nodejs-py3_compact-accelc_http-ip-ssl", + "nodejs-py3_compact_http-ip", + "nodejs-py3_compact_http-ip-ssl", + "nodejs-py3_json_http-ip", + "nodejs-py3_json_http-ip-ssl", + "nodejs-py_binary-accel_http-ip", + "nodejs-py_binary-accel_http-ip-ssl", + "nodejs-py_binary_http-ip", + "nodejs-py_binary_http-ip-ssl", + "nodejs-py_compact-accelc_http-ip", + "nodejs-py_compact-accelc_http-ip-ssl", + "nodejs-py_compact_http-ip", + "nodejs-py_compact_http-ip-ssl", + "nodejs-py_json_http-ip", + "nodejs-py_json_http-ip-ssl", "perl-rs_multi_buffered-ip", "perl-rs_multi_framed-ip", + "py-cpp_accel-binary_http-ip", + "py-cpp_accel-binary_http-ip-ssl", + "py-cpp_accelc-compact_http-ip", + "py-cpp_accelc-compact_http-ip-ssl", + "py-cpp_binary_http-ip", + "py-cpp_binary_http-ip-ssl", + "py-cpp_compact_http-ip", + "py-cpp_compact_http-ip-ssl", + "py-cpp_json_http-ip", + "py-cpp_json_http-ip-ssl", + "py-d_accel-binary_http-ip", + "py-d_accel-binary_http-ip-ssl", + "py-d_accelc-compact_http-ip", + "py-d_accelc-compact_http-ip-ssl", + "py-d_binary_http-ip", + "py-d_binary_http-ip-ssl", + "py-d_compact_http-ip", + "py-d_compact_http-ip-ssl", + "py-d_json_http-ip", + "py-d_json_http-ip-ssl", + "py-dart_accel-binary_http-ip", + "py-dart_accelc-compact_http-ip", + "py-dart_binary_http-ip", + "py-dart_compact_http-ip", + "py-dart_json_http-ip", + "py-hs_accel-binary_http-ip", + "py-hs_accelc-compact_http-ip", + "py-hs_binary_http-ip", + "py-hs_compact_http-ip", + "py-hs_json_http-ip", + "py-java_accel-binary_http-ip", + "py-java_accel-binary_http-ip-ssl", + "py-java_accelc-compact_http-ip", + "py-java_accelc-compact_http-ip-ssl", + "py-java_binary_http-ip", + "py-java_binary_http-ip-ssl", + "py-java_compact_http-ip", + "py-java_compact_http-ip-ssl", + "py-java_json_http-ip", + "py-java_json_http-ip-ssl", + "py-lua_accel-binary_http-ip", + "py-lua_accelc-compact_http-ip", + "py-lua_binary_http-ip", + "py-lua_compact_http-ip", + "py-lua_json_http-ip", + "py3-cpp_accel-binary_http-ip", + "py3-cpp_accel-binary_http-ip-ssl", + "py3-cpp_accelc-compact_http-ip", + "py3-cpp_accelc-compact_http-ip-ssl", + "py3-cpp_binary_http-ip", + "py3-cpp_binary_http-ip-ssl", + "py3-cpp_compact_http-ip", + "py3-cpp_compact_http-ip-ssl", + "py3-cpp_json_http-ip", + "py3-cpp_json_http-ip-ssl", + "py3-d_accel-binary_http-ip", + "py3-d_accel-binary_http-ip-ssl", + "py3-d_accelc-compact_http-ip", + "py3-d_accelc-compact_http-ip-ssl", + "py3-d_binary_http-ip", + "py3-d_binary_http-ip-ssl", + "py3-d_compact_http-ip", + "py3-d_compact_http-ip-ssl", + "py3-d_json_http-ip", + "py3-d_json_http-ip-ssl", + "py3-dart_accel-binary_http-ip", + "py3-dart_accelc-compact_http-ip", + "py3-dart_binary_http-ip", + "py3-dart_compact_http-ip", + "py3-dart_json_http-ip", + "py3-hs_accel-binary_http-ip", + "py3-hs_accelc-compact_http-ip", + "py3-hs_binary_http-ip", + "py3-hs_compact_http-ip", + "py3-hs_json_http-ip", + "py3-java_accel-binary_http-ip", + "py3-java_accel-binary_http-ip-ssl", + "py3-java_accelc-compact_http-ip", + "py3-java_accelc-compact_http-ip-ssl", + "py3-java_binary_http-ip", + "py3-java_binary_http-ip-ssl", + "py3-java_compact_http-ip", + "py3-java_compact_http-ip-ssl", + "py3-java_json_http-ip", + "py3-java_json_http-ip-ssl", + "py3-lua_accel-binary_http-ip", + "py3-lua_accelc-compact_http-ip", + "py3-lua_binary_http-ip", + "py3-lua_compact_http-ip", + "py3-lua_json_http-ip", "rb-cpp_json_buffered-domain", "rb-cpp_json_buffered-ip", "rb-cpp_json_buffered-ip-ssl", @@ -322,4 +492,4 @@ "rs-cpp_multic-compact_framed-ip", "rs-cpp_multic_buffered-ip", "rs-cpp_multic_framed-ip" -] +]
\ No newline at end of file diff --git a/test/py/TestClient.py b/test/py/TestClient.py index 1ab8e78ae..edab610b1 100755 --- a/test/py/TestClient.py +++ b/test/py/TestClient.py @@ -32,8 +32,18 @@ SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__)) class AbstractTest(unittest.TestCase): def setUp(self): - if options.http_path: - self.transport = THttpClient.THttpClient(options.host, port=options.port, path=options.http_path) + if options.trans == 'http': + uri = '{0}://{1}:{2}{3}'.format(('https' if options.ssl else 'http'), + options.host, + options.port, + (options.http_path if options.http_path else '/')) + if options.ssl: + __cafile = os.path.join(os.path.dirname(SCRIPT_DIR), "keys", "CA.pem") + __certfile = os.path.join(os.path.dirname(SCRIPT_DIR), "keys", "client.crt") + __keyfile = os.path.join(os.path.dirname(SCRIPT_DIR), "keys", "client.key") + self.transport = THttpClient.THttpClient(uri, cafile=__cafile, cert_file=__certfile, key_file=__keyfile) + else: + self.transport = THttpClient.THttpClient(uri) else: if options.ssl: from thrift.transport import TSSLSocket @@ -325,9 +335,9 @@ if __name__ == "__main__": dest="verbose", const=0, help="minimal output") parser.add_option('--protocol', dest="proto", type="string", - help="protocol to use, one of: accel, binary, compact, json") + help="protocol to use, one of: accel, accelc, binary, compact, json") parser.add_option('--transport', dest="trans", type="string", - help="transport to use, one of: buffered, framed") + 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') options, args = parser.parse_args() @@ -335,6 +345,9 @@ if __name__ == "__main__": sys.path.insert(0, os.path.join(SCRIPT_DIR, options.genpydir)) sys.path.insert(0, local_libpath()) + if options.http_path: + options.trans = 'http' + from ThriftTest import ThriftTest from ThriftTest.ttypes import Xtruct, Xtruct2, Numberz, Xception, Xception2 from thrift.Thrift import TException diff --git a/test/py/TestServer.py b/test/py/TestServer.py index 04ad62a95..4dc4c0744 100755 --- a/test/py/TestServer.py +++ b/test/py/TestServer.py @@ -21,6 +21,7 @@ from __future__ import division import logging import os +import signal import sys import time from optparse import OptionParser @@ -180,11 +181,11 @@ class TestHandler(object): def main(options): # set up the protocol factory form the --protocol option prot_factories = { - 'binary': TBinaryProtocol.TBinaryProtocolFactory, 'accel': TBinaryProtocol.TBinaryProtocolAcceleratedFactory, - 'compact': TCompactProtocol.TCompactProtocolFactory, 'accelc': TCompactProtocol.TCompactProtocolAcceleratedFactory, - 'json': TJSONProtocol.TJSONProtocolFactory, + 'binary': TBinaryProtocol.TBinaryProtocolFactory, + 'compact': TCompactProtocol.TCompactProtocolFactory, + 'json': TJSONProtocol.TJSONProtocolFactory } pfactory_cls = prot_factories.get(options.proto, None) if pfactory_cls is None: @@ -201,14 +202,23 @@ def main(options): if len(args) > 1: raise AssertionError('Only one server type may be specified, not multiple types.') server_type = args[0] + if options.trans == 'http': + server_type = 'THttpServer' # Set up the handler and processor objects handler = TestHandler() processor = ThriftTest.Processor(handler) + global server + # Handle THttpServer as a special case if server_type == 'THttpServer': - server = THttpServer.THttpServer(processor, ('', options.port), pfactory) + if options.ssl: + __certfile = os.path.join(os.path.dirname(SCRIPT_DIR), "keys", "server.crt") + __keyfile = os.path.join(os.path.dirname(SCRIPT_DIR), "keys", "server.key") + server = THttpServer.THttpServer(processor, ('', options.port), pfactory, cert_file=__certfile, key_file=__keyfile) + else: + server = THttpServer.THttpServer(processor, ('', options.port), pfactory) server.serve() sys.exit(0) @@ -268,7 +278,15 @@ def main(options): server.serve() +def exit_gracefully(signum, frame): + print("SIGINT received\n") + server.shutdown() # doesn't work properly, yet + sys.exit(0) + + if __name__ == '__main__': + signal.signal(signal.SIGINT, exit_gracefully) + parser = OptionParser() parser.add_option('--libpydir', type='string', dest='libpydir', help='include this directory to sys.path for locating library code') @@ -288,12 +306,12 @@ if __name__ == '__main__': dest="verbose", const=0, help="minimal output") parser.add_option('--protocol', dest="proto", type="string", - help="protocol to use, one of: accel, binary, compact, json") + help="protocol to use, one of: accel, accelc, binary, compact, json") parser.add_option('--transport', dest="trans", type="string", - help="transport to use, one of: buffered, framed") + help="transport to use, one of: buffered, framed, http") parser.add_option('--container-limit', dest='container_limit', type='int', default=None) parser.add_option('--string-limit', dest='string_limit', type='int', default=None) - parser.set_defaults(port=9090, verbose=1, proto='binary') + parser.set_defaults(port=9090, verbose=1, proto='binary', transport='buffered') options, args = parser.parse_args() # Print TServer log to stdout so that the test-runner can redirect it to log files diff --git a/test/test.py b/test/test.py index 24e7c4e47..f59256a26 100755 --- a/test/test.py +++ b/test/test.py @@ -52,7 +52,7 @@ FEATURE_DIR_RELATIVE = path_join(TEST_DIR_RELATIVE, 'features') CONFIG_FILE = 'tests.json' -def run_cross_tests(server_match, client_match, jobs, skip_known_failures, retry_count, regex): +def run_cross_tests(server_match, client_match, jobs, skip_known_failures, only_known_failures, retry_count, regex): logger = multiprocessing.get_logger() logger.debug('Collecting tests') with open(path_join(TEST_DIR, CONFIG_FILE), 'r') as fp: @@ -63,6 +63,10 @@ def run_cross_tests(server_match, client_match, jobs, skip_known_failures, retry print(' servers: %s' % server_match, file=sys.stderr) print(' clients: %s' % client_match, file=sys.stderr) return False + if only_known_failures: + logger.debug('Only running known failures') + known = crossrunner.load_known_failures(TEST_DIR) + tests = list(filter(lambda t: crossrunner.test_name(**t) in known, tests)) if skip_known_failures: logger.debug('Skipping known failures') known = crossrunner.load_known_failures(TEST_DIR) @@ -81,7 +85,7 @@ def run_cross_tests(server_match, client_match, jobs, skip_known_failures, retry return False -def run_feature_tests(server_match, feature_match, jobs, skip_known_failures, retry_count, regex): +def run_feature_tests(server_match, feature_match, jobs, skip_known_failures, only_known_failures, retry_count, regex): basedir = path_join(ROOT_DIR, FEATURE_DIR_RELATIVE) logger = multiprocessing.get_logger() logger.debug('Collecting tests') @@ -95,6 +99,10 @@ def run_feature_tests(server_match, feature_match, jobs, skip_known_failures, re print(' servers: %s' % server_match, file=sys.stderr) print(' features: %s' % feature_match, file=sys.stderr) return False + if only_known_failures: + logger.debug('Only running known failures') + known = crossrunner.load_known_failures(basedir) + tests = list(filter(lambda t: crossrunner.test_name(**t) in known, tests)) if skip_known_failures: logger.debug('Skipping known failures') known = crossrunner.load_known_failures(basedir) @@ -130,6 +138,8 @@ def main(argv): parser.add_argument('-F', '--features', nargs='*', default=None, help='run server feature tests instead of cross language tests') parser.add_argument('-R', '--regex', help='test name pattern to run') + parser.add_argument('-o', '--only-known_failures', action='store_true', dest='only_known_failures', + help='only execute tests that are known to fail') parser.add_argument('-s', '--skip-known-failures', action='store_true', dest='skip_known_failures', help='do not execute tests that are known to fail') parser.add_argument('-r', '--retry-count', type=int, @@ -169,10 +179,12 @@ def main(argv): elif options.features is not None: features = options.features or ['.*'] res = run_feature_tests(server_match, features, options.jobs, - options.skip_known_failures, options.retry_count, options.regex) + options.skip_known_failures, options.only_known_failures, + options.retry_count, options.regex) else: res = run_cross_tests(server_match, client_match, options.jobs, - options.skip_known_failures, options.retry_count, options.regex) + options.skip_known_failures, options.only_known_failures, + options.retry_count, options.regex) return 0 if res else 1 diff --git a/test/tests.json b/test/tests.json index 4641f223b..ed38fea3b 100644 --- a/test/tests.json +++ b/test/tests.json @@ -64,7 +64,7 @@ "server": { "command": [ "thrift_test_server", - "--trace" + "--trace" ] }, "client": { @@ -254,7 +254,8 @@ }, "transports": [ "buffered", - "framed" + "framed", + "http" ], "sockets": [ "ip", @@ -292,11 +293,12 @@ }, "transports": [ "buffered", - "framed" + "framed", + "http" ], "sockets": [ - "ip-ssl", - "ip" + "ip", + "ip-ssl" ], "protocols": [ "compact", |