|
from functools import reduce |
|
import gc |
|
import io |
|
import locale |
|
import logging |
|
import operator |
|
import textwrap |
|
import sys |
|
import unittest |
|
import warnings |
|
|
|
from tornado.httpclient import AsyncHTTPClient |
|
from tornado.httpserver import HTTPServer |
|
from tornado.netutil import Resolver |
|
from tornado.options import define, add_parse_callback, options |
|
|
|
|
|
TEST_MODULES = [ |
|
"tornado.httputil.doctests", |
|
"tornado.iostream.doctests", |
|
"tornado.util.doctests", |
|
"tornado.test.asyncio_test", |
|
"tornado.test.auth_test", |
|
"tornado.test.autoreload_test", |
|
"tornado.test.circlerefs_test", |
|
"tornado.test.concurrent_test", |
|
"tornado.test.curl_httpclient_test", |
|
"tornado.test.escape_test", |
|
"tornado.test.gen_test", |
|
"tornado.test.http1connection_test", |
|
"tornado.test.httpclient_test", |
|
"tornado.test.httpserver_test", |
|
"tornado.test.httputil_test", |
|
"tornado.test.import_test", |
|
"tornado.test.ioloop_test", |
|
"tornado.test.iostream_test", |
|
"tornado.test.locale_test", |
|
"tornado.test.locks_test", |
|
"tornado.test.netutil_test", |
|
"tornado.test.log_test", |
|
"tornado.test.options_test", |
|
"tornado.test.process_test", |
|
"tornado.test.queues_test", |
|
"tornado.test.routing_test", |
|
"tornado.test.simple_httpclient_test", |
|
"tornado.test.tcpclient_test", |
|
"tornado.test.tcpserver_test", |
|
"tornado.test.template_test", |
|
"tornado.test.testing_test", |
|
"tornado.test.twisted_test", |
|
"tornado.test.util_test", |
|
"tornado.test.web_test", |
|
"tornado.test.websocket_test", |
|
"tornado.test.wsgi_test", |
|
] |
|
|
|
|
|
def all(): |
|
return unittest.defaultTestLoader.loadTestsFromNames(TEST_MODULES) |
|
|
|
|
|
def test_runner_factory(stderr): |
|
class TornadoTextTestRunner(unittest.TextTestRunner): |
|
def __init__(self, *args, **kwargs): |
|
kwargs["stream"] = stderr |
|
super().__init__(*args, **kwargs) |
|
|
|
def run(self, test): |
|
result = super().run(test) |
|
if result.skipped: |
|
skip_reasons = set(reason for (test, reason) in result.skipped) |
|
self.stream.write( |
|
textwrap.fill( |
|
"Some tests were skipped because: %s" |
|
% ", ".join(sorted(skip_reasons)) |
|
) |
|
) |
|
self.stream.write("\n") |
|
return result |
|
|
|
return TornadoTextTestRunner |
|
|
|
|
|
class LogCounter(logging.Filter): |
|
"""Counts the number of WARNING or higher log records.""" |
|
|
|
def __init__(self, *args, **kwargs): |
|
super().__init__(*args, **kwargs) |
|
self.info_count = self.warning_count = self.error_count = 0 |
|
|
|
def filter(self, record): |
|
if record.levelno >= logging.ERROR: |
|
self.error_count += 1 |
|
elif record.levelno >= logging.WARNING: |
|
self.warning_count += 1 |
|
elif record.levelno >= logging.INFO: |
|
self.info_count += 1 |
|
return True |
|
|
|
|
|
class CountingStderr(io.IOBase): |
|
def __init__(self, real): |
|
self.real = real |
|
self.byte_count = 0 |
|
|
|
def write(self, data): |
|
self.byte_count += len(data) |
|
return self.real.write(data) |
|
|
|
def flush(self): |
|
return self.real.flush() |
|
|
|
|
|
def main(): |
|
|
|
|
|
|
|
|
|
|
|
warnings.filterwarnings("error") |
|
|
|
|
|
warnings.filterwarnings("ignore", category=ImportWarning) |
|
|
|
|
|
warnings.filterwarnings("ignore", category=DeprecationWarning) |
|
warnings.filterwarnings("error", category=DeprecationWarning, module=r"tornado\..*") |
|
warnings.filterwarnings("ignore", category=PendingDeprecationWarning) |
|
warnings.filterwarnings( |
|
"error", category=PendingDeprecationWarning, module=r"tornado\..*" |
|
) |
|
|
|
logging.getLogger("tornado.access").setLevel(logging.CRITICAL) |
|
|
|
define( |
|
"httpclient", |
|
type=str, |
|
default=None, |
|
callback=lambda s: AsyncHTTPClient.configure( |
|
s, defaults=dict(allow_ipv6=False) |
|
), |
|
) |
|
define("httpserver", type=str, default=None, callback=HTTPServer.configure) |
|
define("resolver", type=str, default=None, callback=Resolver.configure) |
|
define( |
|
"debug_gc", |
|
type=str, |
|
multiple=True, |
|
help="A comma-separated list of gc module debug constants, " |
|
"e.g. DEBUG_STATS or DEBUG_COLLECTABLE,DEBUG_OBJECTS", |
|
callback=lambda values: gc.set_debug( |
|
reduce(operator.or_, (getattr(gc, v) for v in values)) |
|
), |
|
) |
|
define( |
|
"fail-if-logs", |
|
default=True, |
|
help="If true, fail the tests if any log output is produced (unless captured by ExpectLog)", |
|
) |
|
|
|
def set_locale(x): |
|
locale.setlocale(locale.LC_ALL, x) |
|
|
|
define("locale", type=str, default=None, callback=set_locale) |
|
|
|
log_counter = LogCounter() |
|
add_parse_callback(lambda: logging.getLogger().handlers[0].addFilter(log_counter)) |
|
|
|
|
|
|
|
|
|
orig_stderr = sys.stderr |
|
counting_stderr = CountingStderr(orig_stderr) |
|
sys.stderr = counting_stderr |
|
|
|
import tornado.testing |
|
|
|
kwargs = {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
kwargs["warnings"] = False |
|
|
|
kwargs["testRunner"] = test_runner_factory(orig_stderr) |
|
try: |
|
tornado.testing.main(**kwargs) |
|
finally: |
|
|
|
|
|
if ( |
|
log_counter.info_count > 0 |
|
or log_counter.warning_count > 0 |
|
or log_counter.error_count > 0 |
|
or counting_stderr.byte_count > 0 |
|
): |
|
logging.error( |
|
"logged %d infos, %d warnings, %d errors, and %d bytes to stderr", |
|
log_counter.info_count, |
|
log_counter.warning_count, |
|
log_counter.error_count, |
|
counting_stderr.byte_count, |
|
) |
|
if options.fail_if_logs: |
|
sys.exit(1) |
|
|
|
|
|
if __name__ == "__main__": |
|
main() |
|
|