diff options
Diffstat (limited to 'test')
79 files changed, 7386 insertions, 6350 deletions
diff --git a/test/conftest.py b/test/conftest.py new file mode 100644 index 00000000..b62264ca --- /dev/null +++ b/test/conftest.py @@ -0,0 +1,329 @@ +import fcntl +import os +import platform +import re +import shutil +import signal +import stat +import subprocess +import sys +import tempfile +import time + +import pytest + +from unit.check.go import check_go +from unit.check.node import check_node +from unit.check.tls import check_openssl + + +def pytest_addoption(parser): + parser.addoption( + "--detailed", + default=False, + action="store_true", + help="Detailed output for tests", + ) + parser.addoption( + "--print_log", + default=False, + action="store_true", + help="Print unit.log to stdout in case of errors", + ) + parser.addoption( + "--save_log", + default=False, + action="store_true", + help="Save unit.log after the test execution", + ) + parser.addoption( + "--unsafe", + default=False, + action="store_true", + help="Run unsafe tests", + ) + + +unit_instance = {} +option = None + + +def pytest_configure(config): + global option + option = config.option + + option.generated_tests = {} + option.current_dir = os.path.abspath( + os.path.join(os.path.dirname(__file__), os.pardir) + ) + option.test_dir = option.current_dir + '/test' + option.architecture = platform.architecture()[0] + option.system = platform.system() + + # set stdout to non-blocking + + if option.detailed or option.print_log: + fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, 0) + + +def pytest_generate_tests(metafunc): + cls = metafunc.cls + if not hasattr(cls, 'application_type'): + return + + type = cls.application_type + + def generate_tests(versions): + metafunc.fixturenames.append('tmp_ct') + metafunc.parametrize('tmp_ct', versions) + + for version in versions: + option.generated_tests[ + metafunc.function.__name__ + '[{}]'.format(version) + ] = (type + ' ' + version) + + # take available module from option and generate tests for each version + + for module, prereq_version in cls.prerequisites['modules'].items(): + if module in option.available['modules']: + available_versions = option.available['modules'][module] + + if prereq_version == 'all': + generate_tests(available_versions) + + elif prereq_version == 'any': + option.generated_tests[metafunc.function.__name__] = ( + type + ' ' + available_versions[0] + ) + elif callable(prereq_version): + generate_tests( + list(filter(prereq_version, available_versions)) + ) + + else: + raise ValueError( + """ +Unexpected prerequisite version "%s" for module "%s" in %s. +'all', 'any' or callable expected.""" + % (str(prereq_version), module, str(cls)) + ) + + +def pytest_sessionstart(session): + option.available = {'modules': {}, 'features': {}} + + unit = unit_run() + + # read unit.log + + for i in range(50): + with open(unit['temp_dir'] + '/unit.log', 'r') as f: + log = f.read() + m = re.search('controller started', log) + + if m is None: + time.sleep(0.1) + else: + break + + if m is None: + _print_log() + exit("Unit is writing log too long") + + # discover available modules from unit.log + + for module in re.findall(r'module: ([a-zA-Z]+) (.*) ".*"$', log, re.M): + if module[0] not in option.available['modules']: + option.available['modules'][module[0]] = [module[1]] + else: + option.available['modules'][module[0]].append(module[1]) + + # discover modules from check + + option.available['modules']['openssl'] = check_openssl(unit['unitd']) + option.available['modules']['go'] = check_go( + option.current_dir, unit['temp_dir'], option.test_dir + ) + option.available['modules']['node'] = check_node(option.current_dir) + + # remove None values + + option.available['modules'] = { + k: v for k, v in option.available['modules'].items() if v is not None + } + + unit_stop() + + +def setup_method(self): + option.skip_alerts = [ + r'read signalfd\(4\) failed', + r'sendmsg.+failed', + r'recvmsg.+failed', + ] + option.skip_sanitizer = False + +def unit_run(): + global unit_instance + build_dir = option.current_dir + '/build' + unitd = build_dir + '/unitd' + + if not os.path.isfile(unitd): + exit('Could not find unit') + + temp_dir = tempfile.mkdtemp(prefix='unit-test-') + public_dir(temp_dir) + + if oct(stat.S_IMODE(os.stat(build_dir).st_mode)) != '0o777': + public_dir(build_dir) + + os.mkdir(temp_dir + '/state') + + with open(temp_dir + '/unit.log', 'w') as log: + unit_instance['process'] = subprocess.Popen( + [ + unitd, + '--no-daemon', + '--modules', + build_dir, + '--state', + temp_dir + '/state', + '--pid', + temp_dir + '/unit.pid', + '--log', + temp_dir + '/unit.log', + '--control', + 'unix:' + temp_dir + '/control.unit.sock', + '--tmp', + temp_dir, + ], + stderr=log, + ) + + if not waitforfiles(temp_dir + '/control.unit.sock'): + _print_log() + exit('Could not start unit') + + # dumb (TODO: remove) + option.skip_alerts = [ + r'read signalfd\(4\) failed', + r'sendmsg.+failed', + r'recvmsg.+failed', + ] + option.skip_sanitizer = False + + unit_instance['temp_dir'] = temp_dir + unit_instance['log'] = temp_dir + '/unit.log' + unit_instance['control_sock'] = temp_dir + '/control.unit.sock' + unit_instance['unitd'] = unitd + + return unit_instance + + +def unit_stop(): + p = unit_instance['process'] + + if p.poll() is not None: + return + + p.send_signal(signal.SIGQUIT) + + try: + retcode = p.wait(15) + if retcode: + return 'Child process terminated with code ' + str(retcode) + except: + p.kill() + return 'Could not terminate unit' + + shutil.rmtree(unit_instance['temp_dir']) + +def public_dir(path): + os.chmod(path, 0o777) + + for root, dirs, files in os.walk(path): + for d in dirs: + os.chmod(os.path.join(root, d), 0o777) + for f in files: + os.chmod(os.path.join(root, f), 0o777) + +def waitforfiles(*files): + for i in range(50): + wait = False + ret = False + + for f in files: + if not os.path.exists(f): + wait = True + break + + if wait: + time.sleep(0.1) + + else: + ret = True + break + + return ret + + +def skip_alert(*alerts): + option.skip_alerts.extend(alerts) + + +def _check_alerts(log): + found = False + + alerts = re.findall(r'.+\[alert\].+', log) + + if alerts: + print('All alerts/sanitizer errors found in log:') + [print(alert) for alert in alerts] + found = True + + if option.skip_alerts: + for skip in option.skip_alerts: + alerts = [al for al in alerts if re.search(skip, al) is None] + + if alerts: + _print_log(data=log) + assert not alerts, 'alert(s)' + + if not option.skip_sanitizer: + sanitizer_errors = re.findall('.+Sanitizer.+', log) + + if sanitizer_errors: + _print_log(data=log) + assert not sanitizer_errors, 'sanitizer error(s)' + + if found: + print('skipped.') + + +def _print_log(path=None, data=None): + if path is None: + path = unit_instance['log'] + + print('Path to unit.log:\n' + path + '\n') + + if option.print_log: + os.set_blocking(sys.stdout.fileno(), True) + sys.stdout.flush() + + if data is None: + with open(path, 'r', encoding='utf-8', errors='ignore') as f: + shutil.copyfileobj(f, sys.stdout) + else: + sys.stdout.write(data) + + +@pytest.fixture +def is_unsafe(request): + return request.config.getoption("--unsafe") + +@pytest.fixture +def is_su(request): + return os.geteuid() == 0 + +def pytest_sessionfinish(session): + unit_stop() diff --git a/test/php/get_variables/index.php b/test/php/get_variables/index.php index dd7ef985..d6eb7d6b 100644 --- a/test/php/get_variables/index.php +++ b/test/php/get_variables/index.php @@ -1,7 +1,7 @@ <?php header('Content-Length: 0'); header('X-Var-1: ' . $_GET['var1']); -header('X-Var-2: ' . $_GET['var2'] . isset($_GET['var2'])); -header('X-Var-3: ' . $_GET['var3'] . isset($_GET['var3'])); -header('X-Var-4: ' . $_GET['var4'] . isset($_GET['var4'])); +header('X-Var-2: ' . (isset($_GET['var2']) ? $_GET['var2'] : 'not set')); +header('X-Var-3: ' . (isset($_GET['var3']) ? $_GET['var3'] : 'not set')); +header('X-Var-4: ' . (isset($_GET['var4']) ? $_GET['var4'] : 'not set')); ?> diff --git a/test/php/list-extensions/index.php b/test/php/list-extensions/index.php new file mode 100644 index 00000000..d6eb40d0 --- /dev/null +++ b/test/php/list-extensions/index.php @@ -0,0 +1,11 @@ +<?php + +function quote($str) { + return '"' . $str . '"'; +} + +header('Content-Type: application/json'); + +print "[" . join(",", array_map('quote', get_loaded_extensions())) . "]"; + +?> diff --git a/test/php/list-extensions/php.ini b/test/php/list-extensions/php.ini new file mode 100644 index 00000000..5848a0f2 --- /dev/null +++ b/test/php/list-extensions/php.ini @@ -0,0 +1 @@ +extension=json.so diff --git a/test/php/post_variables/index.php b/test/php/post_variables/index.php index 5ea17324..8981d54d 100644 --- a/test/php/post_variables/index.php +++ b/test/php/post_variables/index.php @@ -1,6 +1,6 @@ <?php header('Content-Length: 0'); header('X-Var-1: ' . $_POST['var1']); -header('X-Var-2: ' . $_POST['var2'] . isset($_POST['var2'])); -header('X-Var-3: ' . $_POST['var3'] . isset($_POST['var3'])); +header('X-Var-2: ' . (isset($_POST['var2']) ? $_POST['var2'] : 'not set')); +header('X-Var-3: ' . (isset($_POST['var3']) ? $_POST['var3'] : 'not set')); ?> diff --git a/test/pytest.ini b/test/pytest.ini new file mode 100644 index 00000000..c672788a --- /dev/null +++ b/test/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +addopts = -rs -vvv +python_functions = test_* diff --git a/test/python/204_no_content/asgi.py b/test/python/204_no_content/asgi.py new file mode 100644 index 00000000..634facc2 --- /dev/null +++ b/test/python/204_no_content/asgi.py @@ -0,0 +1,8 @@ +async def application(scope, receive, send): + assert scope['type'] == 'http' + + await send({ + 'type': 'http.response.start', + 'status': 204, + 'headers': [], + }) diff --git a/test/python/callable/wsgi.py b/test/python/callable/wsgi.py new file mode 100644 index 00000000..365f82fa --- /dev/null +++ b/test/python/callable/wsgi.py @@ -0,0 +1,7 @@ +def application(env, start_response): + start_response('204', [('Content-Length', '0')]) + return [] + +def app(env, start_response): + start_response('200', [('Content-Length', '0')]) + return [] diff --git a/test/python/delayed/asgi.py b/test/python/delayed/asgi.py new file mode 100644 index 00000000..d5cad929 --- /dev/null +++ b/test/python/delayed/asgi.py @@ -0,0 +1,51 @@ +import asyncio + +async def application(scope, receive, send): + assert scope['type'] == 'http' + + body = b'' + while True: + m = await receive() + body += m.get('body', b'') + if not m.get('more_body', False): + break + + headers = scope.get('headers', []) + + def get_header(n, v=None): + for h in headers: + if h[0] == n: + return h[1] + return v + + parts = int(get_header(b'x-parts', 1)) + delay = int(get_header(b'x-delay', 0)) + + loop = asyncio.get_event_loop() + + async def sleep(n): + future = loop.create_future() + loop.call_later(n, future.set_result, None) + await future + + await send({ + 'type': 'http.response.start', + 'status': 200, + 'headers': [ + (b'content-length', str(len(body)).encode()), + ] + }) + + if not body: + await sleep(delay) + return + + step = int(len(body) / parts) + for i in range(0, len(body), step): + await send({ + 'type': 'http.response.body', + 'body': body[i : i + step], + 'more_body': True, + }) + + await sleep(delay) diff --git a/test/python/empty/asgi.py b/test/python/empty/asgi.py new file mode 100644 index 00000000..58b7c1f2 --- /dev/null +++ b/test/python/empty/asgi.py @@ -0,0 +1,10 @@ +async def application(scope, receive, send): + assert scope['type'] == 'http' + + await send({ + 'type': 'http.response.start', + 'status': 200, + 'headers': [ + (b'content-length', b'0'), + ] + }) diff --git a/test/python/lifespan/empty/asgi.py b/test/python/lifespan/empty/asgi.py new file mode 100644 index 00000000..ea43af13 --- /dev/null +++ b/test/python/lifespan/empty/asgi.py @@ -0,0 +1,27 @@ +import os + + +async def application(scope, receive, send): + if scope['type'] == 'lifespan': + with open('version', 'w+') as f: + f.write( + scope['asgi']['version'] + ' ' + scope['asgi']['spec_version'] + ) + while True: + message = await receive() + if message['type'] == 'lifespan.startup': + os.remove('startup') + await send({'type': 'lifespan.startup.complete'}) + elif message['type'] == 'lifespan.shutdown': + os.remove('shutdown') + await send({'type': 'lifespan.shutdown.complete'}) + return + + if scope['type'] == 'http': + await send( + { + 'type': 'http.response.start', + 'status': 204, + 'headers': [(b'content-length', b'0'),], + } + ) diff --git a/test/python/lifespan/error/asgi.py b/test/python/lifespan/error/asgi.py new file mode 100644 index 00000000..509cb3ee --- /dev/null +++ b/test/python/lifespan/error/asgi.py @@ -0,0 +1,3 @@ +async def application(scope, receive, send): + if scope['type'] != 'http': + raise Exception('Exception blah') diff --git a/test/python/lifespan/error_auto/asgi.py b/test/python/lifespan/error_auto/asgi.py new file mode 100644 index 00000000..90d506a1 --- /dev/null +++ b/test/python/lifespan/error_auto/asgi.py @@ -0,0 +1,2 @@ +async def application(scope, receive, send): + assert scope['type'] == 'http' diff --git a/test/python/lifespan/failed/asgi.py b/test/python/lifespan/failed/asgi.py new file mode 100644 index 00000000..8f315f70 --- /dev/null +++ b/test/python/lifespan/failed/asgi.py @@ -0,0 +1,11 @@ +async def application(scope, receive, send): + if scope['type'] == 'lifespan': + while True: + message = await receive() + if message['type'] == 'lifespan.startup': + await send({"type": "lifespan.startup.failed"}) + raise Exception('Exception blah') + + elif message['type'] == 'lifespan.shutdown': + await send({'type': 'lifespan.shutdown.complete'}) + return diff --git a/test/python/mirror/asgi.py b/test/python/mirror/asgi.py new file mode 100644 index 00000000..7088e893 --- /dev/null +++ b/test/python/mirror/asgi.py @@ -0,0 +1,22 @@ +async def application(scope, receive, send): + assert scope['type'] == 'http' + + body = b'' + while True: + m = await receive() + body += m.get('body', b'') + if not m.get('more_body', False): + break + + await send({ + 'type': 'http.response.start', + 'status': 200, + 'headers': [ + (b'content-length', str(len(body)).encode()), + ] + }) + + await send({ + 'type': 'http.response.body', + 'body': body, + }) diff --git a/test/python/query_string/asgi.py b/test/python/query_string/asgi.py new file mode 100644 index 00000000..28f4d107 --- /dev/null +++ b/test/python/query_string/asgi.py @@ -0,0 +1,11 @@ +async def application(scope, receive, send): + assert scope['type'] == 'http' + + await send({ + 'type': 'http.response.start', + 'status': 200, + 'headers': [ + (b'content-length', b'0'), + (b'query-string', scope['query_string']), + ] + }) diff --git a/test/python/server_port/asgi.py b/test/python/server_port/asgi.py new file mode 100644 index 00000000..e79ced00 --- /dev/null +++ b/test/python/server_port/asgi.py @@ -0,0 +1,11 @@ +async def application(scope, receive, send): + assert scope['type'] == 'http' + + await send({ + 'type': 'http.response.start', + 'status': 200, + 'headers': [ + (b'content-length', b'0'), + (b'server-port', str(scope['server'][1]).encode()), + ] + }) diff --git a/test/python/threading/asgi.py b/test/python/threading/asgi.py new file mode 100644 index 00000000..3c978e50 --- /dev/null +++ b/test/python/threading/asgi.py @@ -0,0 +1,42 @@ +import asyncio +import sys +import time +import threading + + +class Foo(threading.Thread): + num = 10 + + def __init__(self, x): + self.__x = x + threading.Thread.__init__(self) + + def log_index(self, index): + sys.stderr.write( + "(" + str(index) + ") Thread: " + str(self.__x) + "\n" + ) + sys.stderr.flush() + + def run(self): + i = 0 + for _ in range(3): + self.log_index(i) + i += 1 + time.sleep(1) + self.log_index(i) + i += 1 + + +async def application(scope, receive, send): + assert scope['type'] == 'http' + + Foo(Foo.num).start() + Foo.num += 10 + + await send({ + 'type': 'http.response.start', + 'status': 200, + 'headers': [ + (b'content-length', b'0'), + ] + }) diff --git a/test/python/variables/asgi.py b/test/python/variables/asgi.py new file mode 100644 index 00000000..dd1cca72 --- /dev/null +++ b/test/python/variables/asgi.py @@ -0,0 +1,40 @@ +async def application(scope, receive, send): + assert scope['type'] == 'http' + + body = b'' + while True: + m = await receive() + body += m.get('body', b'') + if not m.get('more_body', False): + break + + headers = scope.get('headers', []) + + def get_header(n): + res = [] + for h in headers: + if h[0] == n: + res.append(h[1]) + return b', '.join(res) + + await send({ + 'type': 'http.response.start', + 'status': 200, + 'headers': [ + (b'content-type', get_header(b'content-type')), + (b'content-length', str(len(body)).encode()), + (b'request-method', scope['method'].encode()), + (b'request-uri', scope['path'].encode()), + (b'http-host', get_header(b'host')), + (b'http-version', scope['http_version'].encode()), + (b'asgi-version', scope['asgi']['version'].encode()), + (b'asgi-spec-version', scope['asgi']['spec_version'].encode()), + (b'scheme', scope['scheme'].encode()), + (b'custom-header', get_header(b'custom-header')), + ] + }) + + await send({ + 'type': 'http.response.body', + 'body': body, + }) diff --git a/test/python/websockets/mirror/asgi.py b/test/python/websockets/mirror/asgi.py new file mode 100644 index 00000000..0f1d9953 --- /dev/null +++ b/test/python/websockets/mirror/asgi.py @@ -0,0 +1,18 @@ +async def application(scope, receive, send): + if scope['type'] == 'websocket': + while True: + m = await receive() + if m['type'] == 'websocket.connect': + await send({ + 'type': 'websocket.accept', + }) + + if m['type'] == 'websocket.receive': + await send({ + 'type': 'websocket.send', + 'bytes': m.get('bytes', None), + 'text': m.get('text', None), + }) + + if m['type'] == 'websocket.disconnect': + break; diff --git a/test/python/websockets/subprotocol/asgi.py b/test/python/websockets/subprotocol/asgi.py new file mode 100644 index 00000000..92263dd7 --- /dev/null +++ b/test/python/websockets/subprotocol/asgi.py @@ -0,0 +1,25 @@ +async def application(scope, receive, send): + assert scope['type'] == 'websocket' + + while True: + m = await receive() + if m['type'] == 'websocket.connect': + subprotocols = scope['subprotocols'] + + await send({ + 'type': 'websocket.accept', + 'headers': [ + (b'x-subprotocols', str(subprotocols).encode()), + ], + 'subprotocol': subprotocols[0], + }) + + if m['type'] == 'websocket.receive': + await send({ + 'type': 'websocket.send', + 'bytes': m.get('bytes', None), + 'text': m.get('text', None), + }) + + if m['type'] == 'websocket.disconnect': + break; diff --git a/test/run.py b/test/run.py deleted file mode 100755 index 384663f9..00000000 --- a/test/run.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env python3 -import os -import sys -import unittest - -if __name__ == '__main__': - loader = unittest.TestLoader() - suite = unittest.TestSuite() - - this_dir = os.path.dirname(__file__) - tests = loader.discover(start_dir=this_dir) - suite.addTests(tests) - - runner = unittest.TextTestRunner(stream=sys.stdout, verbosity=3) - result = runner.run(suite) - - ret = not (len(result.failures) == len(result.errors) == 0) - - sys.exit(ret) diff --git a/test/test_access_log.py b/test/test_access_log.py index 3ef8f7a0..eaba82ab 100644 --- a/test/test_access_log.py +++ b/test/test_access_log.py @@ -1,5 +1,6 @@ import time -import unittest + +import pytest from unit.applications.lang.python import TestApplicationPython @@ -10,11 +11,9 @@ class TestAccessLog(TestApplicationPython): def load(self, script): super().load(script) - self.assertIn( - 'success', - self.conf('"' + self.testdir + '/access.log"', 'access_log'), - 'access_log configure', - ) + assert 'success' in self.conf( + '"' + self.temp_dir + '/access.log"', 'access_log' + ), 'access_log configure' def wait_for_record(self, pattern, name='access.log'): return super().wait_for_record(pattern, name) @@ -22,7 +21,7 @@ class TestAccessLog(TestApplicationPython): def test_access_log_keepalive(self): self.load('mirror') - self.assertEqual(self.get()['status'], 200, 'init') + assert self.get()['status'] == 200, 'init' (resp, sock) = self.post( headers={ @@ -35,9 +34,9 @@ class TestAccessLog(TestApplicationPython): read_timeout=1, ) - self.assertIsNotNone( - self.wait_for_record(r'"POST / HTTP/1.1" 200 5'), 'keepalive 1' - ) + assert ( + self.wait_for_record(r'"POST / HTTP/1.1" 200 5') is not None + ), 'keepalive 1' resp = self.post( headers={ @@ -51,9 +50,9 @@ class TestAccessLog(TestApplicationPython): self.stop() - self.assertIsNotNone( - self.wait_for_record(r'"POST / HTTP/1.1" 200 10'), 'keepalive 2' - ) + assert ( + self.wait_for_record(r'"POST / HTTP/1.1" 200 10') is not None + ), 'keepalive 2' def test_access_log_pipeline(self): self.load('empty') @@ -79,18 +78,18 @@ Connection: close self.stop() - self.assertIsNotNone( - self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "Referer-1" "-"'), - 'pipeline 1', - ) - self.assertIsNotNone( - self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "Referer-2" "-"'), - 'pipeline 2', - ) - self.assertIsNotNone( - self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "Referer-3" "-"'), - 'pipeline 3', - ) + assert ( + self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "Referer-1" "-"') + is not None + ), 'pipeline 1' + assert ( + self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "Referer-2" "-"') + is not None + ), 'pipeline 2' + assert ( + self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "Referer-3" "-"') + is not None + ), 'pipeline 3' def test_access_log_ipv6(self): self.load('empty') @@ -101,17 +100,17 @@ Connection: close self.stop() - self.assertIsNotNone( + assert ( self.wait_for_record( r'::1 - - \[.+\] "GET / HTTP/1.1" 200 0 "-" "-"' - ), - 'ipv6', - ) + ) + is not None + ), 'ipv6' def test_access_log_unix(self): self.load('empty') - addr = self.testdir + '/sock' + addr = self.temp_dir + '/sock' self.conf( {"unix:" + addr: {"pass": "applications/empty"}}, 'listeners' @@ -121,12 +120,12 @@ Connection: close self.stop() - self.assertIsNotNone( + assert ( self.wait_for_record( r'unix: - - \[.+\] "GET / HTTP/1.1" 200 0 "-" "-"' - ), - 'unix', - ) + ) + is not None + ), 'unix' def test_access_log_referer(self): self.load('empty') @@ -141,12 +140,10 @@ Connection: close self.stop() - self.assertIsNotNone( - self.wait_for_record( - r'"GET / HTTP/1.1" 200 0 "referer-value" "-"' - ), - 'referer', - ) + assert ( + self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "referer-value" "-"') + is not None + ), 'referer' def test_access_log_user_agent(self): self.load('empty') @@ -161,12 +158,12 @@ Connection: close self.stop() - self.assertIsNotNone( + assert ( self.wait_for_record( r'"GET / HTTP/1.1" 200 0 "-" "user-agent-value"' - ), - 'user agent', - ) + ) + is not None + ), 'user agent' def test_access_log_http10(self): self.load('empty') @@ -175,14 +172,14 @@ Connection: close self.stop() - self.assertIsNotNone( - self.wait_for_record(r'"GET / HTTP/1.0" 200 0 "-" "-"'), 'http 1.0' - ) + assert ( + self.wait_for_record(r'"GET / HTTP/1.0" 200 0 "-" "-"') is not None + ), 'http 1.0' def test_access_log_partial(self): self.load('empty') - self.assertEqual(self.post()['status'], 200, 'init') + assert self.post()['status'] == 200, 'init' resp = self.http(b"""GE""", raw=True, read_timeout=1) @@ -190,27 +187,27 @@ Connection: close self.stop() - self.assertIsNotNone( - self.wait_for_record(r'"GE" 400 0 "-" "-"'), 'partial' - ) + assert ( + self.wait_for_record(r'"GE" 400 0 "-" "-"') is not None + ), 'partial' def test_access_log_partial_2(self): self.load('empty') - self.assertEqual(self.post()['status'], 200, 'init') + assert self.post()['status'] == 200, 'init' self.http(b"""GET /\n""", raw=True) self.stop() - self.assertIsNotNone( - self.wait_for_record(r'"GET /" 400 \d+ "-" "-"'), 'partial 2' - ) + assert ( + self.wait_for_record(r'"GET /" 400 \d+ "-" "-"') is not None + ), 'partial 2' def test_access_log_partial_3(self): self.load('empty') - self.assertEqual(self.post()['status'], 200, 'init') + assert self.post()['status'] == 200, 'init' resp = self.http(b"""GET / HTTP/1.1""", raw=True, read_timeout=1) @@ -218,14 +215,14 @@ Connection: close self.stop() - self.assertIsNotNone( - self.wait_for_record(r'"GET /" 400 0 "-" "-"'), 'partial 3' - ) + assert ( + self.wait_for_record(r'"GET /" 400 0 "-" "-"') is not None + ), 'partial 3' def test_access_log_partial_4(self): self.load('empty') - self.assertEqual(self.post()['status'], 200, 'init') + assert self.post()['status'] == 200, 'init' resp = self.http(b"""GET / HTTP/1.1\n""", raw=True, read_timeout=1) @@ -233,25 +230,24 @@ Connection: close self.stop() - self.assertIsNotNone( - self.wait_for_record(r'"GET / HTTP/1.1" 400 0 "-" "-"'), - 'partial 4', - ) + assert ( + self.wait_for_record(r'"GET / HTTP/1.1" 400 0 "-" "-"') is not None + ), 'partial 4' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_access_log_partial_5(self): self.load('empty') - self.assertEqual(self.post()['status'], 200, 'init') + assert self.post()['status'] == 200, 'init' self.get(headers={'Connection': 'close'}) self.stop() - self.assertIsNotNone( - self.wait_for_record(r'"GET / HTTP/1.1" 400 \d+ "-" "-"'), - 'partial 5', - ) + assert ( + self.wait_for_record(r'"GET / HTTP/1.1" 400 \d+ "-" "-"') + is not None + ), 'partial 5' def test_access_log_get_parameters(self): self.load('empty') @@ -260,12 +256,12 @@ Connection: close self.stop() - self.assertIsNotNone( + assert ( self.wait_for_record( r'"GET /\?blah&var=val HTTP/1.1" 200 0 "-" "-"' - ), - 'get parameters', - ) + ) + is not None + ), 'get parameters' def test_access_log_delete(self): self.load('empty') @@ -276,25 +272,20 @@ Connection: close self.stop() - self.assertIsNone( - self.search_in_log(r'/delete', 'access.log'), 'delete' - ) + assert self.search_in_log(r'/delete', 'access.log') is None, 'delete' def test_access_log_change(self): self.load('empty') self.get() - self.conf('"' + self.testdir + '/new.log"', 'access_log') + self.conf('"' + self.temp_dir + '/new.log"', 'access_log') self.get() self.stop() - self.assertIsNotNone( - self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "-" "-"', 'new.log'), - 'change', - ) - -if __name__ == '__main__': - TestAccessLog.main() + assert ( + self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "-" "-"', 'new.log') + is not None + ), 'change' diff --git a/test/test_asgi_application.py b/test/test_asgi_application.py new file mode 100644 index 00000000..948d9823 --- /dev/null +++ b/test/test_asgi_application.py @@ -0,0 +1,402 @@ +import re +import time +from distutils.version import LooseVersion + +import pytest + +from conftest import skip_alert +from unit.applications.lang.python import TestApplicationPython + + +class TestASGIApplication(TestApplicationPython): + prerequisites = {'modules': {'python': + lambda v: LooseVersion(v) >= LooseVersion('3.5')}} + load_module = 'asgi' + + def findall(self, pattern): + with open(self.temp_dir + '/unit.log', 'r', errors='ignore') as f: + return re.findall(pattern, f.read()) + + def test_asgi_application_variables(self): + self.load('variables') + + body = 'Test body string.' + + resp = self.http( + b"""POST / HTTP/1.1 +Host: localhost +Content-Length: %d +Custom-Header: blah +Custom-hEader: Blah +Content-Type: text/html +Connection: close +custom-header: BLAH + +%s""" % (len(body), body.encode()), + raw=True, + ) + + assert resp['status'] == 200, 'status' + headers = resp['headers'] + header_server = headers.pop('Server') + assert re.search(r'Unit/[\d\.]+', header_server), 'server header' + + date = headers.pop('Date') + assert date[-4:] == ' GMT', 'date header timezone' + assert ( + abs(self.date_to_sec_epoch(date) - self.sec_epoch()) < 5 + ), 'date header' + + assert headers == { + 'Connection': 'close', + 'content-length': str(len(body)), + 'content-type': 'text/html', + 'request-method': 'POST', + 'request-uri': '/', + 'http-host': 'localhost', + 'http-version': '1.1', + 'custom-header': 'blah, Blah, BLAH', + 'asgi-version': '3.0', + 'asgi-spec-version': '2.1', + 'scheme': 'http', + }, 'headers' + assert resp['body'] == body, 'body' + + def test_asgi_application_query_string(self): + self.load('query_string') + + resp = self.get(url='/?var1=val1&var2=val2') + + assert ( + resp['headers']['query-string'] == 'var1=val1&var2=val2' + ), 'query-string header' + + def test_asgi_application_query_string_space(self): + self.load('query_string') + + resp = self.get(url='/ ?var1=val1&var2=val2') + assert ( + resp['headers']['query-string'] == 'var1=val1&var2=val2' + ), 'query-string space' + + resp = self.get(url='/ %20?var1=val1&var2=val2') + assert ( + resp['headers']['query-string'] == 'var1=val1&var2=val2' + ), 'query-string space 2' + + resp = self.get(url='/ %20 ?var1=val1&var2=val2') + assert ( + resp['headers']['query-string'] == 'var1=val1&var2=val2' + ), 'query-string space 3' + + resp = self.get(url='/blah %20 blah? var1= val1 & var2=val2') + assert ( + resp['headers']['query-string'] == ' var1= val1 & var2=val2' + ), 'query-string space 4' + + def test_asgi_application_query_string_empty(self): + self.load('query_string') + + resp = self.get(url='/?') + + assert resp['status'] == 200, 'query string empty status' + assert resp['headers']['query-string'] == '', 'query string empty' + + def test_asgi_application_query_string_absent(self): + self.load('query_string') + + resp = self.get() + + assert resp['status'] == 200, 'query string absent status' + assert resp['headers']['query-string'] == '', 'query string absent' + + @pytest.mark.skip('not yet') + def test_asgi_application_server_port(self): + self.load('server_port') + + assert ( + self.get()['headers']['Server-Port'] == '7080' + ), 'Server-Port header' + + @pytest.mark.skip('not yet') + def test_asgi_application_working_directory_invalid(self): + self.load('empty') + + assert 'success' in self.conf( + '"/blah"', 'applications/empty/working_directory' + ), 'configure invalid working_directory' + + assert self.get()['status'] == 500, 'status' + + def test_asgi_application_204_transfer_encoding(self): + self.load('204_no_content') + + assert ( + 'Transfer-Encoding' not in self.get()['headers'] + ), '204 header transfer encoding' + + def test_asgi_application_shm_ack_handle(self): + self.load('mirror') + + # Minimum possible limit + shm_limit = 10 * 1024 * 1024 + + assert ( + 'success' in self.conf('{"shm": ' + str(shm_limit) + '}', + 'applications/mirror/limits') + ) + + # Should exceed shm_limit + max_body_size = 12 * 1024 * 1024 + + assert ( + 'success' in self.conf('{"http":{"max_body_size": ' + + str(max_body_size) + ' }}', + 'settings') + ) + + assert self.get()['status'] == 200, 'init' + + body = '0123456789AB' * 1024 * 1024 # 12 Mb + resp = self.post( + headers={ + 'Host': 'localhost', + 'Connection': 'close', + 'Content-Type': 'text/html', + }, + body=body, + read_buffer_size=1024 * 1024, + ) + + assert resp['body'] == body, 'keep-alive 1' + + def test_asgi_keepalive_body(self): + self.load('mirror') + + assert self.get()['status'] == 200, 'init' + + body = '0123456789' * 500 + (resp, sock) = self.post( + headers={ + 'Host': 'localhost', + 'Connection': 'keep-alive', + 'Content-Type': 'text/html', + }, + start=True, + body=body, + read_timeout=1, + ) + + assert resp['body'] == body, 'keep-alive 1' + + body = '0123456789' + resp = self.post( + headers={ + 'Host': 'localhost', + 'Connection': 'close', + 'Content-Type': 'text/html', + }, + sock=sock, + body=body, + ) + + assert resp['body'] == body, 'keep-alive 2' + + def test_asgi_keepalive_reconfigure(self): + skip_alert( + r'pthread_mutex.+failed', + r'failed to apply', + r'process \d+ exited on signal', + ) + self.load('mirror') + + assert self.get()['status'] == 200, 'init' + + body = '0123456789' + conns = 3 + socks = [] + + for i in range(conns): + (resp, sock) = self.post( + headers={ + 'Host': 'localhost', + 'Connection': 'keep-alive', + 'Content-Type': 'text/html', + }, + start=True, + body=body, + read_timeout=1, + ) + + assert resp['body'] == body, 'keep-alive open' + assert 'success' in self.conf( + str(i + 1), 'applications/mirror/processes' + ), 'reconfigure' + + socks.append(sock) + + for i in range(conns): + (resp, sock) = self.post( + headers={ + 'Host': 'localhost', + 'Connection': 'keep-alive', + 'Content-Type': 'text/html', + }, + start=True, + sock=socks[i], + body=body, + read_timeout=1, + ) + + assert resp['body'] == body, 'keep-alive request' + assert 'success' in self.conf( + str(i + 1), 'applications/mirror/processes' + ), 'reconfigure 2' + + for i in range(conns): + resp = self.post( + headers={ + 'Host': 'localhost', + 'Connection': 'close', + 'Content-Type': 'text/html', + }, + sock=socks[i], + body=body, + ) + + assert resp['body'] == body, 'keep-alive close' + assert 'success' in self.conf( + str(i + 1), 'applications/mirror/processes' + ), 'reconfigure 3' + + def test_asgi_keepalive_reconfigure_2(self): + self.load('mirror') + + assert self.get()['status'] == 200, 'init' + + body = '0123456789' + + (resp, sock) = self.post( + headers={ + 'Host': 'localhost', + 'Connection': 'keep-alive', + 'Content-Type': 'text/html', + }, + start=True, + body=body, + read_timeout=1, + ) + + assert resp['body'] == body, 'reconfigure 2 keep-alive 1' + + self.load('empty') + + assert self.get()['status'] == 200, 'init' + + (resp, sock) = self.post( + headers={ + 'Host': 'localhost', + 'Connection': 'close', + 'Content-Type': 'text/html', + }, + start=True, + sock=sock, + body=body, + ) + + assert resp['status'] == 200, 'reconfigure 2 keep-alive 2' + assert resp['body'] == '', 'reconfigure 2 keep-alive 2 body' + + assert 'success' in self.conf( + {"listeners": {}, "applications": {}} + ), 'reconfigure 2 clear configuration' + + resp = self.get(sock=sock) + + assert resp == {}, 'reconfigure 2 keep-alive 3' + + def test_asgi_keepalive_reconfigure_3(self): + self.load('empty') + + assert self.get()['status'] == 200, 'init' + + (_, sock) = self.http( + b"""GET / HTTP/1.1 +""", + start=True, + raw=True, + no_recv=True, + ) + + assert self.get()['status'] == 200 + + assert 'success' in self.conf( + {"listeners": {}, "applications": {}} + ), 'reconfigure 3 clear configuration' + + resp = self.http( + b"""Host: localhost +Connection: close + +""", + sock=sock, + raw=True, + ) + + assert resp['status'] == 200, 'reconfigure 3' + + def test_asgi_process_switch(self): + self.load('delayed') + + assert 'success' in self.conf( + '2', 'applications/delayed/processes' + ), 'configure 2 processes' + + self.get( + headers={ + 'Host': 'localhost', + 'Content-Length': '0', + 'X-Delay': '5', + 'Connection': 'close', + }, + no_recv=True, + ) + + headers_delay_1 = { + 'Connection': 'close', + 'Host': 'localhost', + 'Content-Length': '0', + 'X-Delay': '1', + } + + self.get(headers=headers_delay_1, no_recv=True) + + time.sleep(0.5) + + for _ in range(10): + self.get(headers=headers_delay_1, no_recv=True) + + self.get(headers=headers_delay_1) + + def test_asgi_application_loading_error(self): + skip_alert(r'Python failed to import module "blah"') + + self.load('empty') + + assert 'success' in self.conf('"blah"', 'applications/empty/module') + + assert self.get()['status'] == 503, 'loading error' + + def test_asgi_application_threading(self): + """wait_for_record() timeouts after 5s while every thread works at + least 3s. So without releasing GIL test should fail. + """ + + self.load('threading') + + for _ in range(10): + self.get(no_recv=True) + + assert ( + self.wait_for_record(r'\(5\) Thread: 100') is not None + ), 'last thread finished' diff --git a/test/test_asgi_lifespan.py b/test/test_asgi_lifespan.py new file mode 100644 index 00000000..c37a1aae --- /dev/null +++ b/test/test_asgi_lifespan.py @@ -0,0 +1,80 @@ +import os +from distutils.version import LooseVersion + +import pytest + +from conftest import option +from conftest import public_dir +from unit.applications.lang.python import TestApplicationPython + + +class TestASGILifespan(TestApplicationPython): + prerequisites = { + 'modules': {'python': lambda v: LooseVersion(v) >= LooseVersion('3.5')} + } + load_module = 'asgi' + + def test_asgi_lifespan(self): + self.load('lifespan/empty') + + startup_path = option.test_dir + '/python/lifespan/empty/startup' + shutdown_path = option.test_dir + '/python/lifespan/empty/shutdown' + version_path = option.test_dir + '/python/lifespan/empty/version' + + os.chmod(option.test_dir + '/python/lifespan/empty', 0o777) + + open(startup_path, 'a').close() + os.chmod(startup_path, 0o777) + + open(shutdown_path, 'a').close() + os.chmod(shutdown_path, 0o777) + + open(version_path, 'a').close() + os.chmod(version_path, 0o777) + + assert self.get()['status'] == 204 + + self.stop() + + is_startup = os.path.isfile(startup_path) + is_shutdown = os.path.isfile(shutdown_path) + + if is_startup: + os.remove(startup_path) + + if is_shutdown: + os.remove(shutdown_path) + + with open(version_path, 'r') as f: + version = f.read() + + os.remove(version_path) + + assert not is_startup, 'startup' + assert not is_shutdown, 'shutdown' + assert version == '3.0 2.0', 'version' + + def test_asgi_lifespan_failed(self): + self.load('lifespan/failed') + + assert self.get()['status'] == 503 + + assert ( + self.wait_for_record(r'\[error\].*Application startup failed') + is not None + ), 'error message' + assert self.wait_for_record(r'Exception blah') is not None, 'exception' + + def test_asgi_lifespan_error(self): + self.load('lifespan/error') + + self.get() + + assert self.wait_for_record(r'Exception blah') is not None, 'exception' + + def test_asgi_lifespan_error_auto(self): + self.load('lifespan/error_auto') + + self.get() + + assert self.wait_for_record(r'AssertionError') is not None, 'assertion' diff --git a/test/test_asgi_websockets.py b/test/test_asgi_websockets.py new file mode 100644 index 00000000..ab49b130 --- /dev/null +++ b/test/test_asgi_websockets.py @@ -0,0 +1,1446 @@ +import struct +import time +from distutils.version import LooseVersion + +import pytest + +from conftest import option +from conftest import skip_alert +from unit.applications.lang.python import TestApplicationPython +from unit.applications.websockets import TestApplicationWebsocket + + +class TestASGIWebsockets(TestApplicationPython): + prerequisites = {'modules': {'python': + lambda v: LooseVersion(v) >= LooseVersion('3.5')}} + load_module = 'asgi' + + ws = TestApplicationWebsocket() + + def setup_method(self): + super().setup_method() + + assert 'success' in self.conf( + {'http': {'websocket': {'keepalive_interval': 0}}}, 'settings' + ), 'clear keepalive_interval' + + skip_alert(r'socket close\(\d+\) failed') + + def close_connection(self, sock): + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc' + + self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close()) + + self.check_close(sock) + + def check_close(self, sock, code=1000, no_close=False): + frame = self.ws.frame_read(sock) + + assert frame['fin'] == True, 'close fin' + assert frame['opcode'] == self.ws.OP_CLOSE, 'close opcode' + assert frame['code'] == code, 'close code' + + if not no_close: + sock.close() + + def check_frame(self, frame, fin, opcode, payload, decode=True): + if opcode == self.ws.OP_BINARY or not decode: + data = frame['data'] + else: + data = frame['data'].decode('utf-8') + + assert frame['fin'] == fin, 'fin' + assert frame['opcode'] == opcode, 'opcode' + assert data == payload, 'payload' + + def test_asgi_websockets_handshake(self): + self.load('websockets/mirror') + + resp, sock, key = self.ws.upgrade() + sock.close() + + assert resp['status'] == 101, 'status' + assert resp['headers']['Upgrade'] == 'websocket', 'upgrade' + assert resp['headers']['Connection'] == 'Upgrade', 'connection' + assert resp['headers']['Sec-WebSocket-Accept'] == self.ws.accept( + key + ), 'key' + + def test_asgi_websockets_subprotocol(self): + self.load('websockets/subprotocol') + + resp, sock, key = self.ws.upgrade() + sock.close() + + assert resp['status'] == 101, 'status' + assert resp['headers']['x-subprotocols'] == "('chat', 'phone', 'video')", 'subprotocols' + assert resp['headers']['sec-websocket-protocol'] == 'chat', 'key' + + def test_asgi_websockets_mirror(self): + self.load('websockets/mirror') + + message = 'blah' + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_TEXT, message) + frame = self.ws.frame_read(sock) + + assert message == frame['data'].decode('utf-8'), 'mirror' + + self.ws.frame_write(sock, self.ws.OP_TEXT, message) + frame = self.ws.frame_read(sock) + + assert message == frame['data'].decode('utf-8'), 'mirror 2' + + sock.close() + + def test_asgi_websockets_no_mask(self): + self.load('websockets/mirror') + + message = 'blah' + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_TEXT, message, mask=False) + + frame = self.ws.frame_read(sock) + + assert frame['opcode'] == self.ws.OP_CLOSE, 'no mask opcode' + assert frame['code'] == 1002, 'no mask close code' + + sock.close() + + def test_asgi_websockets_fragmentation(self): + self.load('websockets/mirror') + + message = 'blah' + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_TEXT, message, fin=False) + self.ws.frame_write(sock, self.ws.OP_CONT, ' ', fin=False) + self.ws.frame_write(sock, self.ws.OP_CONT, message) + + frame = self.ws.frame_read(sock) + + assert message + ' ' + message == frame['data'].decode( + 'utf-8' + ), 'mirror framing' + + sock.close() + + def test_asgi_websockets_length_long(self): + self.load('websockets/mirror') + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False) + self.ws.frame_write( + sock, self.ws.OP_CONT, 'fragment2', length=2**64 - 1 + ) + + self.check_close(sock, 1009) # 1009 - CLOSE_TOO_LARGE + + def test_asgi_websockets_frame_fragmentation_invalid(self): + self.load('websockets/mirror') + + message = 'blah' + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_PING, message, fin=False) + + frame = self.ws.frame_read(sock) + + frame.pop('data') + assert frame == { + 'fin': True, + 'rsv1': False, + 'rsv2': False, + 'rsv3': False, + 'opcode': self.ws.OP_CLOSE, + 'mask': 0, + 'code': 1002, + 'reason': 'Fragmented control frame', + }, 'close frame' + + sock.close() + + def test_asgi_websockets_large(self): + self.load('websockets/mirror') + + message = '0123456789' * 300 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_TEXT, message) + + frame = self.ws.frame_read(sock) + data = frame['data'].decode('utf-8') + + frame = self.ws.frame_read(sock) + data += frame['data'].decode('utf-8') + + assert message == data, 'large' + + sock.close() + + def test_asgi_websockets_two_clients(self): + self.load('websockets/mirror') + + message1 = 'blah1' + message2 = 'blah2' + + _, sock1, _ = self.ws.upgrade() + _, sock2, _ = self.ws.upgrade() + + self.ws.frame_write(sock1, self.ws.OP_TEXT, message1) + self.ws.frame_write(sock2, self.ws.OP_TEXT, message2) + + frame1 = self.ws.frame_read(sock1) + frame2 = self.ws.frame_read(sock2) + + assert message1 == frame1['data'].decode('utf-8'), 'client 1' + assert message2 == frame2['data'].decode('utf-8'), 'client 2' + + sock1.close() + sock2.close() + + @pytest.mark.skip('not yet') + def test_asgi_websockets_handshake_upgrade_absent( + self + ): # FAIL https://tools.ietf.org/html/rfc6455#section-4.2.1 + self.load('websockets/mirror') + + resp = self.get( + headers={ + 'Host': 'localhost', + 'Connection': 'Upgrade', + 'Sec-WebSocket-Key': self.ws.key(), + 'Sec-WebSocket-Protocol': 'chat', + 'Sec-WebSocket-Version': 13, + }, + ) + + assert resp['status'] == 400, 'upgrade absent' + + def test_asgi_websockets_handshake_case_insensitive(self): + self.load('websockets/mirror') + + resp, sock, _ = self.ws.upgrade( + headers={ + 'Host': 'localhost', + 'Upgrade': 'WEBSOCKET', + 'Connection': 'UPGRADE', + 'Sec-WebSocket-Key': self.ws.key(), + 'Sec-WebSocket-Protocol': 'chat', + 'Sec-WebSocket-Version': 13, + } + ) + sock.close() + + assert resp['status'] == 101, 'status' + + @pytest.mark.skip('not yet') + def test_asgi_websockets_handshake_connection_absent(self): # FAIL + self.load('websockets/mirror') + + resp = self.get( + headers={ + 'Host': 'localhost', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Key': self.ws.key(), + 'Sec-WebSocket-Protocol': 'chat', + 'Sec-WebSocket-Version': 13, + }, + ) + + assert resp['status'] == 400, 'status' + + def test_asgi_websockets_handshake_version_absent(self): + self.load('websockets/mirror') + + resp = self.get( + headers={ + 'Host': 'localhost', + 'Upgrade': 'websocket', + 'Connection': 'Upgrade', + 'Sec-WebSocket-Key': self.ws.key(), + 'Sec-WebSocket-Protocol': 'chat', + }, + ) + + assert resp['status'] == 426, 'status' + + @pytest.mark.skip('not yet') + def test_asgi_websockets_handshake_key_invalid(self): + self.load('websockets/mirror') + + resp = self.get( + headers={ + 'Host': 'localhost', + 'Upgrade': 'websocket', + 'Connection': 'Upgrade', + 'Sec-WebSocket-Key': '!', + 'Sec-WebSocket-Protocol': 'chat', + 'Sec-WebSocket-Version': 13, + }, + ) + + assert resp['status'] == 400, 'key length' + + key = self.ws.key() + resp = self.get( + headers={ + 'Host': 'localhost', + 'Upgrade': 'websocket', + 'Connection': 'Upgrade', + 'Sec-WebSocket-Key': [key, key], + 'Sec-WebSocket-Protocol': 'chat', + 'Sec-WebSocket-Version': 13, + }, + ) + + assert resp['status'] == 400, 'key double' # FAIL https://tools.ietf.org/html/rfc6455#section-11.3.1 + + def test_asgi_websockets_handshake_method_invalid(self): + self.load('websockets/mirror') + + resp = self.post( + headers={ + 'Host': 'localhost', + 'Upgrade': 'websocket', + 'Connection': 'Upgrade', + 'Sec-WebSocket-Key': self.ws.key(), + 'Sec-WebSocket-Protocol': 'chat', + 'Sec-WebSocket-Version': 13, + }, + ) + + assert resp['status'] == 400, 'status' + + def test_asgi_websockets_handshake_http_10(self): + self.load('websockets/mirror') + + resp = self.get( + headers={ + 'Host': 'localhost', + 'Upgrade': 'websocket', + 'Connection': 'Upgrade', + 'Sec-WebSocket-Key': self.ws.key(), + 'Sec-WebSocket-Protocol': 'chat', + 'Sec-WebSocket-Version': 13, + }, + http_10=True, + ) + + assert resp['status'] == 400, 'status' + + def test_asgi_websockets_handshake_uri_invalid(self): + self.load('websockets/mirror') + + resp = self.get( + headers={ + 'Host': 'localhost', + 'Upgrade': 'websocket', + 'Connection': 'Upgrade', + 'Sec-WebSocket-Key': self.ws.key(), + 'Sec-WebSocket-Protocol': 'chat', + 'Sec-WebSocket-Version': 13, + }, + url='!', + ) + + assert resp['status'] == 400, 'status' + + def test_asgi_websockets_protocol_absent(self): + self.load('websockets/mirror') + + key = self.ws.key() + resp, sock, _ = self.ws.upgrade( + headers={ + 'Host': 'localhost', + 'Upgrade': 'websocket', + 'Connection': 'Upgrade', + 'Sec-WebSocket-Key': key, + 'Sec-WebSocket-Version': 13, + } + ) + sock.close() + + assert resp['status'] == 101, 'status' + assert resp['headers']['Upgrade'] == 'websocket', 'upgrade' + assert resp['headers']['Connection'] == 'Upgrade', 'connection' + assert resp['headers']['Sec-WebSocket-Accept'] == self.ws.accept( + key + ), 'key' + + # autobahn-testsuite + # + # Some following tests fail because of Unit does not support UTF-8 + # validation for websocket frames. It should be implemented + # by application, if necessary. + + def test_asgi_websockets_1_1_1__1_1_8(self): + self.load('websockets/mirror') + + opcode = self.ws.OP_TEXT + + _, sock, _ = self.ws.upgrade() + + def check_length(length, chopsize=None): + payload = '*' * length + + self.ws.frame_write(sock, opcode, payload, chopsize=chopsize) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, opcode, payload) + + check_length(0) # 1_1_1 + check_length(125) # 1_1_2 + check_length(126) # 1_1_3 + check_length(127) # 1_1_4 + check_length(128) # 1_1_5 + check_length(65535) # 1_1_6 + check_length(65536) # 1_1_7 + check_length(65536, chopsize = 997) # 1_1_8 + + self.close_connection(sock) + + def test_asgi_websockets_1_2_1__1_2_8(self): + self.load('websockets/mirror') + + opcode = self.ws.OP_BINARY + + _, sock, _ = self.ws.upgrade() + + def check_length(length, chopsize=None): + payload = b'\xfe' * length + + self.ws.frame_write(sock, opcode, payload, chopsize=chopsize) + frame = self.ws.frame_read(sock) + + self.check_frame(frame, True, opcode, payload) + + check_length(0) # 1_2_1 + check_length(125) # 1_2_2 + check_length(126) # 1_2_3 + check_length(127) # 1_2_4 + check_length(128) # 1_2_5 + check_length(65535) # 1_2_6 + check_length(65536) # 1_2_7 + check_length(65536, chopsize = 997) # 1_2_8 + + self.close_connection(sock) + + def test_asgi_websockets_2_1__2_6(self): + self.load('websockets/mirror') + + op_ping = self.ws.OP_PING + op_pong = self.ws.OP_PONG + + _, sock, _ = self.ws.upgrade() + + def check_ping(payload, chopsize=None, decode=True): + self.ws.frame_write(sock, op_ping, payload, chopsize=chopsize) + frame = self.ws.frame_read(sock) + + self.check_frame(frame, True, op_pong, payload, decode=decode) + + check_ping('') # 2_1 + check_ping('Hello, world!') # 2_2 + check_ping(b'\x00\xff\xfe\xfd\xfc\xfb\x00\xff', decode=False) # 2_3 + check_ping(b'\xfe' * 125, decode=False) # 2_4 + check_ping(b'\xfe' * 125, chopsize=1, decode=False) # 2_6 + + self.close_connection(sock) + + # 2_5 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_PING, b'\xfe' * 126) + self.check_close(sock, 1002) + + def test_asgi_websockets_2_7__2_9(self): + self.load('websockets/mirror') + + # 2_7 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_PONG, '') + assert self.recvall(sock, read_timeout=0.1) == b'', '2_7' + + # 2_8 + + self.ws.frame_write(sock, self.ws.OP_PONG, 'unsolicited pong payload') + assert self.recvall(sock, read_timeout=0.1) == b'', '2_8' + + # 2_9 + + payload = 'ping payload' + + self.ws.frame_write(sock, self.ws.OP_PONG, 'unsolicited pong payload') + self.ws.frame_write(sock, self.ws.OP_PING, payload) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_PONG, payload) + + self.close_connection(sock) + + def test_asgi_websockets_2_10__2_11(self): + self.load('websockets/mirror') + + # 2_10 + + _, sock, _ = self.ws.upgrade() + + for i in range(0, 10): + self.ws.frame_write(sock, self.ws.OP_PING, 'payload-%d' % i) + + for i in range(0, 10): + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_PONG, 'payload-%d' % i) + + # 2_11 + + for i in range(0, 10): + opcode = self.ws.OP_PING + self.ws.frame_write(sock, opcode, 'payload-%d' % i, chopsize=1) + + for i in range(0, 10): + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_PONG, 'payload-%d' % i) + + self.close_connection(sock) + + @pytest.mark.skip('not yet') + def test_asgi_websockets_3_1__3_7(self): + self.load('websockets/mirror') + + payload = 'Hello, world!' + + # 3_1 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_TEXT, payload, rsv1=True) + self.check_close(sock, 1002) + + # 3_2 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_TEXT, payload) + self.ws.frame_write(sock, self.ws.OP_TEXT, payload, rsv2=True) + self.ws.frame_write(sock, self.ws.OP_PING, '') + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, payload) + + self.check_close(sock, 1002, no_close=True) + + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty 3_2' + sock.close() + + # 3_3 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_TEXT, payload) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, payload) + + self.ws.frame_write( + sock, self.ws.OP_TEXT, payload, rsv1=True, rsv2=True + ) + + self.check_close(sock, 1002, no_close=True) + + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty 3_3' + sock.close() + + # 3_4 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_TEXT, payload, chopsize=1) + self.ws.frame_write( + sock, self.ws.OP_TEXT, payload, rsv3=True, chopsize=1 + ) + self.ws.frame_write(sock, self.ws.OP_PING, '') + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, payload) + + self.check_close(sock, 1002, no_close=True) + + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty 3_4' + sock.close() + + # 3_5 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write( + sock, + self.ws.OP_BINARY, + b'\x00\xff\xfe\xfd\xfc\xfb\x00\xff', + rsv1=True, + rsv3=True, + ) + + self.check_close(sock, 1002) + + # 3_6 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write( + sock, self.ws.OP_PING, payload, rsv2=True, rsv3=True + ) + + self.check_close(sock, 1002) + + # 3_7 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write( + sock, self.ws.OP_CLOSE, payload, rsv1=True, rsv2=True, rsv3=True + ) + + self.check_close(sock, 1002) + + def test_asgi_websockets_4_1_1__4_2_5(self): + self.load('websockets/mirror') + + payload = 'Hello, world!' + + # 4_1_1 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, 0x03, '') + self.check_close(sock, 1002) + + # 4_1_2 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, 0x04, 'reserved opcode payload') + self.check_close(sock, 1002) + + # 4_1_3 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_TEXT, payload) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, payload) + + self.ws.frame_write(sock, 0x05, '') + self.ws.frame_write(sock, self.ws.OP_PING, '') + + self.check_close(sock, 1002) + + # 4_1_4 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_TEXT, payload) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, payload) + + self.ws.frame_write(sock, 0x06, payload) + self.ws.frame_write(sock, self.ws.OP_PING, '') + + self.check_close(sock, 1002) + + # 4_1_5 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_TEXT, payload, chopsize=1) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, payload) + + self.ws.frame_write(sock, 0x07, payload, chopsize=1) + self.ws.frame_write(sock, self.ws.OP_PING, '') + + self.check_close(sock, 1002) + + # 4_2_1 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, 0x0B, '') + self.check_close(sock, 1002) + + # 4_2_2 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, 0x0C, 'reserved opcode payload') + self.check_close(sock, 1002) + + # 4_2_3 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_TEXT, payload) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, payload) + + self.ws.frame_write(sock, 0x0D, '') + self.ws.frame_write(sock, self.ws.OP_PING, '') + + self.check_close(sock, 1002) + + # 4_2_4 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_TEXT, payload) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, payload) + + self.ws.frame_write(sock, 0x0E, payload) + self.ws.frame_write(sock, self.ws.OP_PING, '') + + self.check_close(sock, 1002) + + # 4_2_5 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_TEXT, payload, chopsize=1) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, payload) + + self.ws.frame_write(sock, 0x0F, payload, chopsize=1) + self.ws.frame_write(sock, self.ws.OP_PING, '') + + self.check_close(sock, 1002) + + def test_asgi_websockets_5_1__5_20(self): + self.load('websockets/mirror') + + # 5_1 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_PING, 'fragment1', fin=False) + self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True) + self.check_close(sock, 1002) + + # 5_2 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_PONG, 'fragment1', fin=False) + self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True) + self.check_close(sock, 1002) + + # 5_3 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False) + self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2') + + # 5_4 + + self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False) + assert self.recvall(sock, read_timeout=0.1) == b'', '5_4' + self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2') + + # 5_5 + + self.ws.frame_write( + sock, self.ws.OP_TEXT, 'fragment1', fin=False, chopsize=1 + ) + self.ws.frame_write( + sock, self.ws.OP_CONT, 'fragment2', fin=True, chopsize=1 + ) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2') + + # 5_6 + + ping_payload = 'ping payload' + + self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False) + self.ws.frame_write(sock, self.ws.OP_PING, ping_payload) + self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_PONG, ping_payload) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2') + + # 5_7 + + ping_payload = 'ping payload' + + self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False) + assert self.recvall(sock, read_timeout=0.1) == b'', '5_7' + + self.ws.frame_write(sock, self.ws.OP_PING, ping_payload) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_PONG, ping_payload) + + self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2') + + # 5_8 + + ping_payload = 'ping payload' + + self.ws.frame_write( + sock, self.ws.OP_TEXT, 'fragment1', fin=False, chopsize=1 + ) + self.ws.frame_write(sock, self.ws.OP_PING, ping_payload, chopsize=1) + self.ws.frame_write( + sock, self.ws.OP_CONT, 'fragment2', fin=True, chopsize=1 + ) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_PONG, ping_payload) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2') + + # 5_9 + + self.ws.frame_write( + sock, self.ws.OP_CONT, 'non-continuation payload', fin=True + ) + self.ws.frame_write(sock, self.ws.OP_TEXT, 'Hello, world!', fin=True) + self.check_close(sock, 1002) + + # 5_10 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write( + sock, self.ws.OP_CONT, 'non-continuation payload', fin=True + ) + self.ws.frame_write(sock, self.ws.OP_TEXT, 'Hello, world!', fin=True) + self.check_close(sock, 1002) + + # 5_11 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write( + sock, + self.ws.OP_CONT, + 'non-continuation payload', + fin=True, + chopsize=1, + ) + self.ws.frame_write( + sock, self.ws.OP_TEXT, 'Hello, world!', fin=True, chopsize=1 + ) + self.check_close(sock, 1002) + + # 5_12 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write( + sock, self.ws.OP_CONT, 'non-continuation payload', fin=False + ) + self.ws.frame_write(sock, self.ws.OP_TEXT, 'Hello, world!', fin=True) + self.check_close(sock, 1002) + + # 5_13 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write( + sock, self.ws.OP_CONT, 'non-continuation payload', fin=False + ) + self.ws.frame_write(sock, self.ws.OP_TEXT, 'Hello, world!', fin=True) + self.check_close(sock, 1002) + + # 5_14 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write( + sock, + self.ws.OP_CONT, + 'non-continuation payload', + fin=False, + chopsize=1, + ) + self.ws.frame_write( + sock, self.ws.OP_TEXT, 'Hello, world!', fin=True, chopsize=1 + ) + self.check_close(sock, 1002) + + # 5_15 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False) + self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True) + self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment3', fin=False) + self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment4', fin=True) + self.check_close(sock, 1002) + + # 5_16 + + _, sock, _ = self.ws.upgrade() + + for i in range(0, 2): + self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment1', fin=False) + self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment2', fin=False) + self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment3', fin=True) + self.check_close(sock, 1002) + + # 5_17 + + _, sock, _ = self.ws.upgrade() + + for i in range(0, 2): + self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment1', fin=True) + self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment2', fin=False) + self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment3', fin=True) + self.check_close(sock, 1002) + + # 5_18 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False) + self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment2') + self.check_close(sock, 1002) + + # 5_19 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False) + self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=False) + self.ws.frame_write(sock, self.ws.OP_PING, 'pongme 1!') + + time.sleep(1) + + self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment3', fin=False) + self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment4', fin=False) + self.ws.frame_write(sock, self.ws.OP_PING, 'pongme 2!') + self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment5') + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_PONG, 'pongme 1!') + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_PONG, 'pongme 2!') + + self.check_frame( + self.ws.frame_read(sock), + True, + self.ws.OP_TEXT, + 'fragment1fragment2fragment3fragment4fragment5', + ) + + # 5_20 + + self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False) + self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=False) + self.ws.frame_write(sock, self.ws.OP_PING, 'pongme 1!') + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_PONG, 'pongme 1!') + + time.sleep(1) + + self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment3', fin=False) + self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment4', fin=False) + self.ws.frame_write(sock, self.ws.OP_PING, 'pongme 2!') + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_PONG, 'pongme 2!') + + assert self.recvall(sock, read_timeout=0.1) == b'', '5_20' + self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment5') + + self.check_frame( + self.ws.frame_read(sock), + True, + self.ws.OP_TEXT, + 'fragment1fragment2fragment3fragment4fragment5', + ) + + self.close_connection(sock) + + def test_asgi_websockets_6_1_1__6_4_4(self): + self.load('websockets/mirror') + + # 6_1_1 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_TEXT, '') + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, '') + + # 6_1_2 + + self.ws.frame_write(sock, self.ws.OP_TEXT, '', fin=False) + self.ws.frame_write(sock, self.ws.OP_CONT, '', fin=False) + self.ws.frame_write(sock, self.ws.OP_CONT, '') + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, '') + + # 6_1_3 + + payload = 'middle frame payload' + + self.ws.frame_write(sock, self.ws.OP_TEXT, '', fin=False) + self.ws.frame_write(sock, self.ws.OP_CONT, payload, fin=False) + self.ws.frame_write(sock, self.ws.OP_CONT, '') + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, payload) + + # 6_2_1 + + payload = 'Hello-µ@ßöäüàá-UTF-8!!' + + self.ws.frame_write(sock, self.ws.OP_TEXT, payload) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, payload) + + # 6_2_2 + + self.ws.frame_write(sock, self.ws.OP_TEXT, payload[:12], fin=False) + self.ws.frame_write(sock, self.ws.OP_CONT, payload[12:]) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, payload) + + # 6_2_3 + + self.ws.message(sock, self.ws.OP_TEXT, payload, fragmention_size=1) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, payload) + + # 6_2_4 + + payload = '\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5' + + self.ws.message(sock, self.ws.OP_TEXT, payload, fragmention_size=1) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, payload) + + self.close_connection(sock) + +# Unit does not support UTF-8 validation +# +# # 6_3_1 FAIL +# +# payload_1 = '\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5' +# payload_2 = '\xed\xa0\x80' +# payload_3 = '\x65\x64\x69\x74\x65\x64' +# +# payload = payload_1 + payload_2 + payload_3 +# +# self.ws.message(sock, self.ws.OP_TEXT, payload) +# self.check_close(sock, 1007) +# +# # 6_3_2 FAIL +# +# _, sock, _ = self.ws.upgrade() +# +# self.ws.message(sock, self.ws.OP_TEXT, payload, fragmention_size=1) +# self.check_close(sock, 1007) +# +# # 6_4_1 ... 6_4_4 FAIL + + def test_asgi_websockets_7_1_1__7_5_1(self): + self.load('websockets/mirror') + + # 7_1_1 + + _, sock, _ = self.ws.upgrade() + + payload = "Hello World!" + + self.ws.frame_write(sock, self.ws.OP_TEXT, payload) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, payload) + + self.close_connection(sock) + + # 7_1_2 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close()) + self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close()) + + self.check_close(sock) + + # 7_1_3 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close()) + self.check_close(sock, no_close=True) + + self.ws.frame_write(sock, self.ws.OP_PING, '') + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc' + + sock.close() + + # 7_1_4 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close()) + self.check_close(sock, no_close=True) + + self.ws.frame_write(sock, self.ws.OP_TEXT, payload) + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc' + + sock.close() + + # 7_1_5 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False) + self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close()) + self.check_close(sock, no_close=True) + + self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2') + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc' + + sock.close() + + # 7_1_6 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_TEXT, 'BAsd7&jh23' * 26 * 2 ** 10) + self.ws.frame_write(sock, self.ws.OP_TEXT, payload) + self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close()) + + self.recvall(sock, read_timeout=1) + + self.ws.frame_write(sock, self.ws.OP_PING, '') + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc' + + sock.close() + + # 7_3_1 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_CLOSE, '') + self.check_close(sock) + + # 7_3_2 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_CLOSE, 'a') + self.check_close(sock, 1002) + + # 7_3_3 + + _, sock, _ = self.ws.upgrade() + + self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close()) + self.check_close(sock) + + # 7_3_4 + + _, sock, _ = self.ws.upgrade() + + payload = self.ws.serialize_close(reason='Hello World!') + + self.ws.frame_write(sock, self.ws.OP_CLOSE, payload) + self.check_close(sock) + + # 7_3_5 + + _, sock, _ = self.ws.upgrade() + + payload = self.ws.serialize_close(reason='*' * 123) + + self.ws.frame_write(sock, self.ws.OP_CLOSE, payload) + self.check_close(sock) + + # 7_3_6 + + _, sock, _ = self.ws.upgrade() + + payload = self.ws.serialize_close(reason='*' * 124) + + self.ws.frame_write(sock, self.ws.OP_CLOSE, payload) + self.check_close(sock, 1002) + +# # 7_5_1 FAIL Unit does not support UTF-8 validation +# +# _, sock, _ = self.ws.upgrade() +# +# payload = self.ws.serialize_close(reason = '\xce\xba\xe1\xbd\xb9\xcf' \ +# '\x83\xce\xbc\xce\xb5\xed\xa0\x80\x65\x64\x69\x74\x65\x64') +# +# self.ws.frame_write(sock, self.ws.OP_CLOSE, payload) +# self.check_close(sock, 1007) + + def test_asgi_websockets_7_7_X__7_9_X(self): + self.load('websockets/mirror') + + valid_codes = [ + 1000, + 1001, + 1002, + 1003, + 1007, + 1008, + 1009, + 1010, + 1011, + 3000, + 3999, + 4000, + 4999, + ] + + invalid_codes = [0, 999, 1004, 1005, 1006, 1016, 1100, 2000, 2999] + + for code in valid_codes: + _, sock, _ = self.ws.upgrade() + + payload = self.ws.serialize_close(code=code) + + self.ws.frame_write(sock, self.ws.OP_CLOSE, payload) + self.check_close(sock) + + for code in invalid_codes: + _, sock, _ = self.ws.upgrade() + + payload = self.ws.serialize_close(code=code) + + self.ws.frame_write(sock, self.ws.OP_CLOSE, payload) + self.check_close(sock, 1002) + + def test_asgi_websockets_7_13_1__7_13_2(self): + self.load('websockets/mirror') + + # 7_13_1 + + _, sock, _ = self.ws.upgrade() + + payload = self.ws.serialize_close(code=5000) + + self.ws.frame_write(sock, self.ws.OP_CLOSE, payload) + self.check_close(sock, 1002) + + # 7_13_2 + + _, sock, _ = self.ws.upgrade() + + payload = struct.pack('!I', 65536) + ''.encode('utf-8') + + self.ws.frame_write(sock, self.ws.OP_CLOSE, payload) + self.check_close(sock, 1002) + + def test_asgi_websockets_9_1_1__9_6_6(self, is_unsafe): + if not is_unsafe: + pytest.skip('unsafe, long run') + + self.load('websockets/mirror') + + assert 'success' in self.conf( + { + 'http': { + 'websocket': { + 'max_frame_size': 33554432, + 'keepalive_interval': 0, + } + } + }, + 'settings', + ), 'increase max_frame_size and keepalive_interval' + + _, sock, _ = self.ws.upgrade() + + op_text = self.ws.OP_TEXT + op_binary = self.ws.OP_BINARY + + def check_payload(opcode, length, chopsize=None): + if opcode == self.ws.OP_TEXT: + payload = '*' * length + else: + payload = b'*' * length + + self.ws.frame_write(sock, opcode, payload, chopsize=chopsize) + frame = self.ws.frame_read(sock, read_timeout=5) + self.check_frame(frame, True, opcode, payload) + + def check_message(opcode, f_size): + if opcode == self.ws.OP_TEXT: + payload = '*' * 4 * 2 ** 20 + else: + payload = b'*' * 4 * 2 ** 20 + + self.ws.message(sock, opcode, payload, fragmention_size=f_size) + frame = self.ws.frame_read(sock, read_timeout=5) + self.check_frame(frame, True, opcode, payload) + + check_payload(op_text, 64 * 2 ** 10) # 9_1_1 + check_payload(op_text, 256 * 2 ** 10) # 9_1_2 + check_payload(op_text, 2 ** 20) # 9_1_3 + check_payload(op_text, 4 * 2 ** 20) # 9_1_4 + check_payload(op_text, 8 * 2 ** 20) # 9_1_5 + check_payload(op_text, 16 * 2 ** 20) # 9_1_6 + + check_payload(op_binary, 64 * 2 ** 10) # 9_2_1 + check_payload(op_binary, 256 * 2 ** 10) # 9_2_2 + check_payload(op_binary, 2 ** 20) # 9_2_3 + check_payload(op_binary, 4 * 2 ** 20) # 9_2_4 + check_payload(op_binary, 8 * 2 ** 20) # 9_2_5 + check_payload(op_binary, 16 * 2 ** 20) # 9_2_6 + + if option.system != 'Darwin' and option.system != 'FreeBSD': + check_message(op_text, 64) # 9_3_1 + check_message(op_text, 256) # 9_3_2 + check_message(op_text, 2 ** 10) # 9_3_3 + check_message(op_text, 4 * 2 ** 10) # 9_3_4 + check_message(op_text, 16 * 2 ** 10) # 9_3_5 + check_message(op_text, 64 * 2 ** 10) # 9_3_6 + check_message(op_text, 256 * 2 ** 10) # 9_3_7 + check_message(op_text, 2 ** 20) # 9_3_8 + check_message(op_text, 4 * 2 ** 20) # 9_3_9 + + check_message(op_binary, 64) # 9_4_1 + check_message(op_binary, 256) # 9_4_2 + check_message(op_binary, 2 ** 10) # 9_4_3 + check_message(op_binary, 4 * 2 ** 10) # 9_4_4 + check_message(op_binary, 16 * 2 ** 10) # 9_4_5 + check_message(op_binary, 64 * 2 ** 10) # 9_4_6 + check_message(op_binary, 256 * 2 ** 10) # 9_4_7 + check_message(op_binary, 2 ** 20) # 9_4_8 + check_message(op_binary, 4 * 2 ** 20) # 9_4_9 + + check_payload(op_text, 2 ** 20, chopsize=64) # 9_5_1 + check_payload(op_text, 2 ** 20, chopsize=128) # 9_5_2 + check_payload(op_text, 2 ** 20, chopsize=256) # 9_5_3 + check_payload(op_text, 2 ** 20, chopsize=512) # 9_5_4 + check_payload(op_text, 2 ** 20, chopsize=1024) # 9_5_5 + check_payload(op_text, 2 ** 20, chopsize=2048) # 9_5_6 + + check_payload(op_binary, 2 ** 20, chopsize=64) # 9_6_1 + check_payload(op_binary, 2 ** 20, chopsize=128) # 9_6_2 + check_payload(op_binary, 2 ** 20, chopsize=256) # 9_6_3 + check_payload(op_binary, 2 ** 20, chopsize=512) # 9_6_4 + check_payload(op_binary, 2 ** 20, chopsize=1024) # 9_6_5 + check_payload(op_binary, 2 ** 20, chopsize=2048) # 9_6_6 + + self.close_connection(sock) + + def test_asgi_websockets_10_1_1(self): + self.load('websockets/mirror') + + _, sock, _ = self.ws.upgrade() + + payload = '*' * 65536 + + self.ws.message(sock, self.ws.OP_TEXT, payload, fragmention_size=1300) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_TEXT, payload) + + self.close_connection(sock) + + # settings + + def test_asgi_websockets_max_frame_size(self): + self.load('websockets/mirror') + + assert 'success' in self.conf( + {'http': {'websocket': {'max_frame_size': 100}}}, 'settings' + ), 'configure max_frame_size' + + _, sock, _ = self.ws.upgrade() + + payload = '*' * 94 + opcode = self.ws.OP_TEXT + + self.ws.frame_write(sock, opcode, payload) # frame length is 100 + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, opcode, payload) + + payload = '*' * 95 + + self.ws.frame_write(sock, opcode, payload) # frame length is 101 + self.check_close(sock, 1009) # 1009 - CLOSE_TOO_LARGE + + def test_asgi_websockets_read_timeout(self): + self.load('websockets/mirror') + + assert 'success' in self.conf( + {'http': {'websocket': {'read_timeout': 5}}}, 'settings' + ), 'configure read_timeout' + + _, sock, _ = self.ws.upgrade() + + frame = self.ws.frame_to_send(self.ws.OP_TEXT, 'blah') + sock.sendall(frame[:2]) + + time.sleep(2) + + self.check_close(sock, 1001) # 1001 - CLOSE_GOING_AWAY + + def test_asgi_websockets_keepalive_interval(self): + self.load('websockets/mirror') + + assert 'success' in self.conf( + {'http': {'websocket': {'keepalive_interval': 5}}}, 'settings' + ), 'configure keepalive_interval' + + _, sock, _ = self.ws.upgrade() + + frame = self.ws.frame_to_send(self.ws.OP_TEXT, 'blah') + sock.sendall(frame[:2]) + + time.sleep(2) + + frame = self.ws.frame_read(sock) + self.check_frame(frame, True, self.ws.OP_PING, '') # PING frame + + sock.close() diff --git a/test/test_configuration.py b/test/test_configuration.py index 0b0c9c78..d1e6f000 100644 --- a/test/test_configuration.py +++ b/test/test_configuration.py @@ -1,5 +1,6 @@ -import unittest +import pytest +from conftest import skip_alert from unit.control import TestControl @@ -7,16 +8,14 @@ class TestConfiguration(TestControl): prerequisites = {'modules': {'python': 'any'}} def test_json_empty(self): - self.assertIn('error', self.conf(''), 'empty') + assert 'error' in self.conf(''), 'empty' def test_json_leading_zero(self): - self.assertIn('error', self.conf('00'), 'leading zero') + assert 'error' in self.conf('00'), 'leading zero' def test_json_unicode(self): - self.assertIn( - 'success', - self.conf( - b""" + assert 'success' in self.conf( + u""" { "ap\u0070": { "type": "\u0070ython", @@ -26,50 +25,36 @@ class TestConfiguration(TestControl): } } """, - 'applications', - ), - 'unicode', - ) + 'applications', + ), 'unicode' + + assert self.conf_get('applications') == { + "app": { + "type": "python", + "processes": {"spare": 0}, + "path": "/app", + "module": "wsgi", + } + }, 'unicode get' - self.assertDictEqual( - self.conf_get('applications'), + def test_json_unicode_2(self): + assert 'success' in self.conf( { - "app": { + "приложение": { "type": "python", "processes": {"spare": 0}, "path": "/app", "module": "wsgi", } }, - 'unicode get', - ) + 'applications', + ), 'unicode 2' - def test_json_unicode_2(self): - self.assertIn( - 'success', - self.conf( - { - "приложение": { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - } - }, - 'applications', - ), - 'unicode 2', - ) - - self.assertIn( - 'приложение', self.conf_get('applications'), 'unicode 2 get' - ) + assert 'приложение' in self.conf_get('applications'), 'unicode 2 get' def test_json_unicode_number(self): - self.assertIn( - 'error', - self.conf( - b""" + assert 'success' in self.conf( + u""" { "app": { "type": "python", @@ -79,16 +64,12 @@ class TestConfiguration(TestControl): } } """, - 'applications', - ), - 'unicode number', - ) + 'applications', + ), 'unicode number' def test_json_utf8_bom(self): - self.assertIn( - 'success', - self.conf( - b"""\xEF\xBB\xBF + assert 'success' in self.conf( + b"""\xEF\xBB\xBF { "app": { "type": "python", @@ -98,16 +79,12 @@ class TestConfiguration(TestControl): } } """, - 'applications', - ), - 'UTF-8 BOM', - ) + 'applications', + ), 'UTF-8 BOM' def test_json_comment_single_line(self): - self.assertIn( - 'success', - self.conf( - b""" + assert 'success' in self.conf( + b""" // this is bridge { "//app": { @@ -121,16 +98,12 @@ class TestConfiguration(TestControl): } // end of json \xEF\t """, - 'applications', - ), - 'single line comments', - ) + 'applications', + ), 'single line comments' def test_json_comment_multi_line(self): - self.assertIn( - 'success', - self.conf( - b""" + assert 'success' in self.conf( + b""" /* this is bridge */ { "/*app": { @@ -148,41 +121,31 @@ class TestConfiguration(TestControl): } /* end of json \xEF\t\b */ """, - 'applications', - ), - 'multi line comments', - ) + 'applications', + ), 'multi line comments' def test_json_comment_invalid(self): - self.assertIn('error', self.conf(b'/{}', 'applications'), 'slash') - self.assertIn('error', self.conf(b'//{}', 'applications'), 'comment') - self.assertIn('error', self.conf(b'{} /', 'applications'), 'slash end') - self.assertIn( - 'error', self.conf(b'/*{}', 'applications'), 'slash star' - ) - self.assertIn( - 'error', self.conf(b'{} /*', 'applications'), 'slash star end' - ) + assert 'error' in self.conf(b'/{}', 'applications'), 'slash' + assert 'error' in self.conf(b'//{}', 'applications'), 'comment' + assert 'error' in self.conf(b'{} /', 'applications'), 'slash end' + assert 'error' in self.conf(b'/*{}', 'applications'), 'slash star' + assert 'error' in self.conf(b'{} /*', 'applications'), 'slash star end' def test_applications_open_brace(self): - self.assertIn('error', self.conf('{', 'applications'), 'open brace') + assert 'error' in self.conf('{', 'applications'), 'open brace' def test_applications_string(self): - self.assertIn('error', self.conf('"{}"', 'applications'), 'string') + assert 'error' in self.conf('"{}"', 'applications'), 'string' - @unittest.skip('not yet, unsafe') + @pytest.mark.skip('not yet, unsafe') def test_applications_type_only(self): - self.assertIn( - 'error', - self.conf({"app": {"type": "python"}}, 'applications'), - 'type only', - ) + assert 'error' in self.conf( + {"app": {"type": "python"}}, 'applications' + ), 'type only' def test_applications_miss_quote(self): - self.assertIn( - 'error', - self.conf( - """ + assert 'error' in self.conf( + """ { app": { "type": "python", @@ -192,16 +155,12 @@ class TestConfiguration(TestControl): } } """, - 'applications', - ), - 'miss quote', - ) + 'applications', + ), 'miss quote' def test_applications_miss_colon(self): - self.assertIn( - 'error', - self.conf( - """ + assert 'error' in self.conf( + """ { "app" { "type": "python", @@ -211,16 +170,12 @@ class TestConfiguration(TestControl): } } """, - 'applications', - ), - 'miss colon', - ) + 'applications', + ), 'miss colon' def test_applications_miss_comma(self): - self.assertIn( - 'error', - self.conf( - """ + assert 'error' in self.conf( + """ { "app": { "type": "python" @@ -230,144 +185,117 @@ class TestConfiguration(TestControl): } } """, - 'applications', - ), - 'miss comma', - ) + 'applications', + ), 'miss comma' def test_applications_skip_spaces(self): - self.assertIn( - 'success', self.conf(b'{ \n\r\t}', 'applications'), 'skip spaces' - ) + assert 'success' in self.conf( + b'{ \n\r\t}', 'applications' + ), 'skip spaces' def test_applications_relative_path(self): - self.assertIn( - 'success', - self.conf( - { - "app": { - "type": "python", - "processes": {"spare": 0}, - "path": "../app", - "module": "wsgi", - } - }, - 'applications', - ), - 'relative path', - ) + assert 'success' in self.conf( + { + "app": { + "type": "python", + "processes": {"spare": 0}, + "path": "../app", + "module": "wsgi", + } + }, + 'applications', + ), 'relative path' - @unittest.skip('not yet, unsafe') + @pytest.mark.skip('not yet, unsafe') def test_listeners_empty(self): - self.assertIn( - 'error', self.conf({"*:7080": {}}, 'listeners'), 'listener empty' - ) + assert 'error' in self.conf( + {"*:7080": {}}, 'listeners' + ), 'listener empty' def test_listeners_no_app(self): - self.assertIn( - 'error', - self.conf({"*:7080": {"pass": "applications/app"}}, 'listeners'), - 'listeners no app', - ) + assert 'error' in self.conf( + {"*:7080": {"pass": "applications/app"}}, 'listeners' + ), 'listeners no app' def test_listeners_wildcard(self): - self.assertIn( - 'success', - self.conf( - { - "listeners": {"*:7080": {"pass": "applications/app"}}, - "applications": { - "app": { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - } - }, - } - ), - 'listeners wildcard', - ) + assert 'success' in self.conf( + { + "listeners": {"*:7080": {"pass": "applications/app"}}, + "applications": { + "app": { + "type": "python", + "processes": {"spare": 0}, + "path": "/app", + "module": "wsgi", + } + }, + } + ), 'listeners wildcard' def test_listeners_explicit(self): - self.assertIn( - 'success', - self.conf( - { - "listeners": {"127.0.0.1:7080": {"pass": "applications/app"}}, - "applications": { - "app": { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - } - }, - } - ), - 'explicit', - ) + assert 'success' in self.conf( + { + "listeners": {"127.0.0.1:7080": {"pass": "applications/app"}}, + "applications": { + "app": { + "type": "python", + "processes": {"spare": 0}, + "path": "/app", + "module": "wsgi", + } + }, + } + ), 'explicit' def test_listeners_explicit_ipv6(self): - self.assertIn( - 'success', - self.conf( - { - "listeners": {"[::1]:7080": {"pass": "applications/app"}}, - "applications": { - "app": { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - } - }, - } - ), - 'explicit ipv6', - ) + assert 'success' in self.conf( + { + "listeners": {"[::1]:7080": {"pass": "applications/app"}}, + "applications": { + "app": { + "type": "python", + "processes": {"spare": 0}, + "path": "/app", + "module": "wsgi", + } + }, + } + ), 'explicit ipv6' - @unittest.skip('not yet, unsafe') + @pytest.mark.skip('not yet, unsafe') def test_listeners_no_port(self): - self.assertIn( - 'error', - self.conf( - { - "listeners": {"127.0.0.1": {"pass": "applications/app"}}, - "applications": { - "app": { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - } - }, - } - ), - 'no port', - ) + assert 'error' in self.conf( + { + "listeners": {"127.0.0.1": {"pass": "applications/app"}}, + "applications": { + "app": { + "type": "python", + "processes": {"spare": 0}, + "path": "/app", + "module": "wsgi", + } + }, + } + ), 'no port' def test_json_application_name_large(self): name = "X" * 1024 * 1024 - self.assertIn( - 'success', - self.conf( - { - "listeners": {"*:7080": {"pass": "applications/" + name}}, - "applications": { - name: { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - } - }, - } - ), + assert 'success' in self.conf( + { + "listeners": {"*:7080": {"pass": "applications/" + name}}, + "applications": { + name: { + "type": "python", + "processes": {"spare": 0}, + "path": "/app", + "module": "wsgi", + } + }, + } ) - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_json_application_many(self): apps = 999 @@ -388,7 +316,7 @@ class TestConfiguration(TestControl): }, } - self.assertIn('success', self.conf(conf)) + assert 'success' in self.conf(conf) def test_json_application_many2(self): conf = { @@ -407,35 +335,21 @@ class TestConfiguration(TestControl): "listeners": {"*:7080": {"pass": "applications/app-1"}}, } - self.assertIn('success', self.conf(conf)) - - def test_unprivileged_user_error(self): - self.skip_alerts.extend( - [ - r'cannot set user "root"', - r'failed to apply new conf', - ] - ) - if self.is_su: - print('unprivileged tests, skip this') - raise unittest.SkipTest() - - self.assertIn( - 'error', - self.conf( - { - "app": { - "type": "external", - "processes": 1, - "executable": "/app", - "user": "root", - } - }, - 'applications', - ), - 'setting user', - ) + assert 'success' in self.conf(conf) + def test_unprivileged_user_error(self, is_su): + skip_alert(r'cannot set user "root"', r'failed to apply new conf') + if is_su: + pytest.skip('unprivileged tests') -if __name__ == '__main__': - TestConfiguration.main() + assert 'error' in self.conf( + { + "app": { + "type": "external", + "processes": 1, + "executable": "/app", + "user": "root", + } + }, + 'applications', + ), 'setting user' diff --git a/test/test_go_application.py b/test/test_go_application.py index b9b78e2b..8c77dfc5 100644 --- a/test/test_go_application.py +++ b/test/test_go_application.py @@ -1,3 +1,5 @@ +import re + from unit.applications.lang.go import TestApplicationGo @@ -19,44 +21,38 @@ class TestGoApplication(TestApplicationGo): body=body, ) - self.assertEqual(resp['status'], 200, 'status') + assert resp['status'] == 200, 'status' headers = resp['headers'] header_server = headers.pop('Server') - self.assertRegex(header_server, r'Unit/[\d\.]+', 'server header') + assert re.search(r'Unit/[\d\.]+', header_server), 'server header' date = headers.pop('Date') - self.assertEqual(date[-4:], ' GMT', 'date header timezone') - self.assertLess( - abs(self.date_to_sec_epoch(date) - self.sec_epoch()), - 5, - 'date header', - ) - - self.assertDictEqual( - headers, - { - 'Content-Length': str(len(body)), - 'Content-Type': 'text/html', - 'Request-Method': 'POST', - 'Request-Uri': '/', - 'Http-Host': 'localhost', - 'Server-Protocol': 'HTTP/1.1', - 'Server-Protocol-Major': '1', - 'Server-Protocol-Minor': '1', - 'Custom-Header': 'blah', - 'Connection': 'close', - }, - 'headers', - ) - self.assertEqual(resp['body'], body, 'body') + assert date[-4:] == ' GMT', 'date header timezone' + assert ( + abs(self.date_to_sec_epoch(date) - self.sec_epoch()) < 5 + ), 'date header' + + assert headers == { + 'Content-Length': str(len(body)), + 'Content-Type': 'text/html', + 'Request-Method': 'POST', + 'Request-Uri': '/', + 'Http-Host': 'localhost', + 'Server-Protocol': 'HTTP/1.1', + 'Server-Protocol-Major': '1', + 'Server-Protocol-Minor': '1', + 'Custom-Header': 'blah', + 'Connection': 'close', + }, 'headers' + assert resp['body'] == body, 'body' def test_go_application_get_variables(self): self.load('get_variables') resp = self.get(url='/?var1=val1&var2=&var3') - self.assertEqual(resp['headers']['X-Var-1'], 'val1', 'GET variables') - self.assertEqual(resp['headers']['X-Var-2'], '', 'GET variables 2') - self.assertEqual(resp['headers']['X-Var-3'], '', 'GET variables 3') + assert resp['headers']['X-Var-1'] == 'val1', 'GET variables' + assert resp['headers']['X-Var-2'] == '', 'GET variables 2' + assert resp['headers']['X-Var-3'] == '', 'GET variables 3' def test_go_application_post_variables(self): self.load('post_variables') @@ -70,24 +66,24 @@ class TestGoApplication(TestApplicationGo): body='var1=val1&var2=&var3', ) - self.assertEqual(resp['headers']['X-Var-1'], 'val1', 'POST variables') - self.assertEqual(resp['headers']['X-Var-2'], '', 'POST variables 2') - self.assertEqual(resp['headers']['X-Var-3'], '', 'POST variables 3') + assert resp['headers']['X-Var-1'] == 'val1', 'POST variables' + assert resp['headers']['X-Var-2'] == '', 'POST variables 2' + assert resp['headers']['X-Var-3'] == '', 'POST variables 3' def test_go_application_404(self): self.load('404') resp = self.get() - self.assertEqual(resp['status'], 404, '404 status') - self.assertRegex( - resp['body'], r'<title>404 Not Found</title>', '404 body' - ) + assert resp['status'] == 404, '404 status' + assert re.search( + r'<title>404 Not Found</title>', resp['body'] + ), '404 body' def test_go_keepalive_body(self): self.load('mirror') - self.assertEqual(self.get()['status'], 200, 'init') + assert self.get()['status'] == 200, 'init' body = '0123456789' * 500 (resp, sock) = self.post( @@ -101,7 +97,7 @@ class TestGoApplication(TestApplicationGo): read_timeout=1, ) - self.assertEqual(resp['body'], body, 'keep-alive 1') + assert resp['body'] == body, 'keep-alive 1' body = '0123456789' resp = self.post( @@ -114,7 +110,7 @@ class TestGoApplication(TestApplicationGo): body=body, ) - self.assertEqual(resp['body'], body, 'keep-alive 2') + assert resp['body'] == body, 'keep-alive 2' def test_go_application_cookies(self): self.load('cookies') @@ -127,28 +123,24 @@ class TestGoApplication(TestApplicationGo): } ) - self.assertEqual(resp['headers']['X-Cookie-1'], 'val1', 'cookie 1') - self.assertEqual(resp['headers']['X-Cookie-2'], 'val2', 'cookie 2') + assert resp['headers']['X-Cookie-1'] == 'val1', 'cookie 1' + assert resp['headers']['X-Cookie-2'] == 'val2', 'cookie 2' def test_go_application_command_line_arguments_type(self): self.load('command_line_arguments') - self.assertIn( - 'error', + assert 'error' in \ self.conf( '' "a b c", 'applications/command_line_arguments/arguments' - ), - 'arguments type', - ) + ), \ + 'arguments type' def test_go_application_command_line_arguments_0(self): self.load('command_line_arguments') - self.assertEqual( - self.get()['headers']['X-Arg-0'], - self.conf_get('applications/command_line_arguments/executable'), - 'argument 0', - ) + assert self.get()['headers']['X-Arg-0'] == self.conf_get( + 'applications/command_line_arguments/executable' + ), 'argument 0' def test_go_application_command_line_arguments(self): self.load('command_line_arguments') @@ -162,9 +154,9 @@ class TestGoApplication(TestApplicationGo): 'applications/command_line_arguments/arguments', ) - self.assertEqual( - self.get()['body'], arg1 + ',' + arg2 + ',' + arg3, 'arguments' - ) + assert ( + self.get()['body'] == arg1 + ',' + arg2 + ',' + arg3 + ), 'arguments' def test_go_application_command_line_arguments_change(self): self.load('command_line_arguments') @@ -173,18 +165,14 @@ class TestGoApplication(TestApplicationGo): self.conf('["0", "a", "$", ""]', args_path) - self.assertEqual(self.get()['body'], '0,a,$,', 'arguments') + assert self.get()['body'] == '0,a,$,', 'arguments' self.conf('["-1", "b", "%"]', args_path) - self.assertEqual(self.get()['body'], '-1,b,%', 'arguments change') + assert self.get()['body'] == '-1,b,%', 'arguments change' self.conf('[]', args_path) - self.assertEqual( - self.get()['headers']['Content-Length'], '0', 'arguments empty' - ) - - -if __name__ == '__main__': - TestGoApplication.main() + assert ( + self.get()['headers']['Content-Length'] == '0' + ), 'arguments empty' diff --git a/test/test_go_isolation.py b/test/test_go_isolation.py index 61d39617..1e7243f6 100644 --- a/test/test_go_isolation.py +++ b/test/test_go_isolation.py @@ -1,21 +1,22 @@ import grp +import os import pwd -import unittest + +import pytest from unit.applications.lang.go import TestApplicationGo from unit.feature.isolation import TestFeatureIsolation - class TestGoIsolation(TestApplicationGo): prerequisites = {'modules': {'go': 'any'}, 'features': ['isolation']} isolation = TestFeatureIsolation() @classmethod - def setUpClass(cls, complete_check=True): - unit = super().setUpClass(complete_check=False) + def setup_class(cls, complete_check=True): + unit = super().setup_class(complete_check=False) - TestFeatureIsolation().check(cls.available, unit.testdir) + TestFeatureIsolation().check(cls.available, unit.temp_dir) return unit if not complete_check else unit.complete() @@ -41,24 +42,20 @@ class TestGoIsolation(TestApplicationGo): for ns, ns_value in self.available['features']['isolation'].items(): if ns.upper() in obj['NS']: - self.assertEqual( - obj['NS'][ns.upper()], ns_value, '%s match' % ns - ) + assert obj['NS'][ns.upper()] == ns_value, '%s match' % ns - def test_isolation_unpriv_user(self): + def test_isolation_unpriv_user(self, is_su): if not self.isolation_key('unprivileged_userns_clone'): - print('unprivileged clone is not available') - raise unittest.SkipTest() + pytest.skip('unprivileged clone is not available') - if self.is_su: - print('privileged tests, skip this') - raise unittest.SkipTest() + if is_su: + pytest.skip('privileged tests, skip this') self.load('ns_inspect') obj = self.getjson()['body'] - self.assertEqual(obj['UID'], self.uid, 'uid match') - self.assertEqual(obj['GID'], self.gid, 'gid match') + assert obj['UID'] == os.geteuid(), 'uid match' + assert obj['GID'] == os.getegid(), 'gid match' self.load('ns_inspect', isolation={'namespaces': {'credential': True}}) @@ -67,8 +64,8 @@ class TestGoIsolation(TestApplicationGo): nobody_uid, nogroup_gid, nogroup = self.unpriv_creds() # unprivileged unit map itself to nobody in the container by default - self.assertEqual(obj['UID'], nobody_uid, 'uid of nobody') - self.assertEqual(obj['GID'], nogroup_gid, 'gid of %s' % nogroup) + assert obj['UID'] == nobody_uid, 'uid of nobody' + assert obj['GID'] == nogroup_gid, 'gid of %s' % nogroup self.load( 'ns_inspect', @@ -78,8 +75,8 @@ class TestGoIsolation(TestApplicationGo): obj = self.getjson()['body'] - self.assertEqual(obj['UID'], 0, 'uid match user=root') - self.assertEqual(obj['GID'], 0, 'gid match user=root') + assert obj['UID'] == 0, 'uid match user=root' + assert obj['GID'] == 0, 'gid match user=root' self.load( 'ns_inspect', @@ -90,10 +87,8 @@ class TestGoIsolation(TestApplicationGo): obj = self.getjson()['body'] - self.assertEqual(obj['UID'], 0, 'uid match user=root group=nogroup') - self.assertEqual( - obj['GID'], nogroup_gid, 'gid match user=root group=nogroup' - ) + assert obj['UID'] == 0, 'uid match user=root group=nogroup' + assert obj['GID'] == nogroup_gid, 'gid match user=root group=nogroup' self.load( 'ns_inspect', @@ -101,20 +96,19 @@ class TestGoIsolation(TestApplicationGo): group='root', isolation={ 'namespaces': {'credential': True}, - 'uidmap': [{'container': 0, 'host': self.uid, 'size': 1}], - 'gidmap': [{'container': 0, 'host': self.gid, 'size': 1}], + 'uidmap': [{'container': 0, 'host': os.geteuid(), 'size': 1}], + 'gidmap': [{'container': 0, 'host': os.getegid(), 'size': 1}], }, ) obj = self.getjson()['body'] - self.assertEqual(obj['UID'], 0, 'uid match uidmap') - self.assertEqual(obj['GID'], 0, 'gid match gidmap') + assert obj['UID'] == 0, 'uid match uidmap' + assert obj['GID'] == 0, 'gid match gidmap' - def test_isolation_priv_user(self): - if not self.is_su: - print('unprivileged tests, skip this') - raise unittest.SkipTest() + def test_isolation_priv_user(self, is_su): + if not is_su: + pytest.skip('unprivileged tests, skip this') self.load('ns_inspect') @@ -122,16 +116,16 @@ class TestGoIsolation(TestApplicationGo): obj = self.getjson()['body'] - self.assertEqual(obj['UID'], nobody_uid, 'uid match') - self.assertEqual(obj['GID'], nogroup_gid, 'gid match') + assert obj['UID'] == nobody_uid, 'uid match' + assert obj['GID'] == nogroup_gid, 'gid match' self.load('ns_inspect', isolation={'namespaces': {'credential': True}}) obj = self.getjson()['body'] # privileged unit map app creds in the container by default - self.assertEqual(obj['UID'], nobody_uid, 'uid nobody') - self.assertEqual(obj['GID'], nogroup_gid, 'gid nobody') + assert obj['UID'] == nobody_uid, 'uid nobody' + assert obj['GID'] == nogroup_gid, 'gid nobody' self.load( 'ns_inspect', @@ -141,8 +135,8 @@ class TestGoIsolation(TestApplicationGo): obj = self.getjson()['body'] - self.assertEqual(obj['UID'], 0, 'uid nobody user=root') - self.assertEqual(obj['GID'], 0, 'gid nobody user=root') + assert obj['UID'] == 0, 'uid nobody user=root' + assert obj['GID'] == 0, 'gid nobody user=root' self.load( 'ns_inspect', @@ -153,10 +147,8 @@ class TestGoIsolation(TestApplicationGo): obj = self.getjson()['body'] - self.assertEqual(obj['UID'], 0, 'uid match user=root group=nogroup') - self.assertEqual( - obj['GID'], nogroup_gid, 'gid match user=root group=nogroup' - ) + assert obj['UID'] == 0, 'uid match user=root group=nogroup' + assert obj['GID'] == nogroup_gid, 'gid match user=root group=nogroup' self.load( 'ns_inspect', @@ -171,8 +163,8 @@ class TestGoIsolation(TestApplicationGo): obj = self.getjson()['body'] - self.assertEqual(obj['UID'], 0, 'uid match uidmap user=root') - self.assertEqual(obj['GID'], 0, 'gid match gidmap user=root') + assert obj['UID'] == 0, 'uid match uidmap user=root' + assert obj['GID'] == 0, 'gid match gidmap user=root' # map 65535 uids self.load( @@ -188,21 +180,15 @@ class TestGoIsolation(TestApplicationGo): obj = self.getjson()['body'] - self.assertEqual( - obj['UID'], nobody_uid, 'uid match uidmap user=nobody' - ) - self.assertEqual( - obj['GID'], nogroup_gid, 'gid match uidmap user=nobody' - ) + assert obj['UID'] == nobody_uid, 'uid match uidmap user=nobody' + assert obj['GID'] == nogroup_gid, 'gid match uidmap user=nobody' def test_isolation_mnt(self): if not self.isolation_key('mnt'): - print('mnt namespace is not supported') - raise unittest.SkipTest() + pytest.skip('mnt namespace is not supported') if not self.isolation_key('unprivileged_userns_clone'): - print('unprivileged clone is not available') - raise unittest.SkipTest() + pytest.skip('unprivileged clone is not available') self.load( 'ns_inspect', @@ -218,27 +204,20 @@ class TestGoIsolation(TestApplicationGo): for ns in allns: if ns.upper() in obj['NS']: - self.assertEqual( - obj['NS'][ns.upper()], - self.available['features']['isolation'][ns], - '%s match' % ns, - ) - - self.assertNotEqual( - obj['NS']['MNT'], self.isolation.getns('mnt'), 'mnt set' - ) - self.assertNotEqual( - obj['NS']['USER'], self.isolation.getns('user'), 'user set' - ) + assert ( + obj['NS'][ns.upper()] + == self.available['features']['isolation'][ns] + ), ('%s match' % ns) - def test_isolation_pid(self): + assert obj['NS']['MNT'] != self.isolation.getns('mnt'), 'mnt set' + assert obj['NS']['USER'] != self.isolation.getns('user'), 'user set' + + def test_isolation_pid(self, is_su): if not self.isolation_key('pid'): - print('pid namespace is not supported') - raise unittest.SkipTest() + pytest.skip('pid namespace is not supported') - if not (self.is_su or self.isolation_key('unprivileged_userns_clone')): - print('requires root or unprivileged_userns_clone') - raise unittest.SkipTest() + if not (is_su or self.isolation_key('unprivileged_userns_clone')): + pytest.skip('requires root or unprivileged_userns_clone') self.load( 'ns_inspect', @@ -247,7 +226,7 @@ class TestGoIsolation(TestApplicationGo): obj = self.getjson()['body'] - self.assertEqual(obj['PID'], 1, 'pid of container is 1') + assert obj['PID'] == 1, 'pid of container is 1' def test_isolation_namespace_false(self): self.load('ns_inspect') @@ -275,58 +254,67 @@ class TestGoIsolation(TestApplicationGo): for ns in allns: if ns.upper() in obj['NS']: - self.assertEqual( - obj['NS'][ns.upper()], - self.available['features']['isolation'][ns], - '%s match' % ns, - ) + assert ( + obj['NS'][ns.upper()] + == self.available['features']['isolation'][ns] + ), ('%s match' % ns) def test_go_isolation_rootfs_container(self): if not self.isolation_key('unprivileged_userns_clone'): - print('unprivileged clone is not available') - raise unittest.SkipTest() + pytest.skip('unprivileged clone is not available') if not self.isolation_key('mnt'): - print('mnt namespace is not supported') - raise unittest.SkipTest() + pytest.skip('mnt namespace is not supported') isolation = { 'namespaces': {'mount': True, 'credential': True}, - 'rootfs': self.testdir, + 'rootfs': self.temp_dir, } self.load('ns_inspect', isolation=isolation) obj = self.getjson(url='/?file=/go/app')['body'] - self.assertEqual(obj['FileExists'], True, 'app relative to rootfs') + assert obj['FileExists'] == True, 'app relative to rootfs' obj = self.getjson(url='/?file=/bin/sh')['body'] - self.assertEqual(obj['FileExists'], False, 'file should not exists') + assert obj['FileExists'] == False, 'file should not exists' - def test_go_isolation_rootfs_container_priv(self): - if not self.is_su: - print("requires root") - raise unittest.SkipTest() + def test_go_isolation_rootfs_container_priv(self, is_su): + if not is_su: + pytest.skip('requires root') if not self.isolation_key('mnt'): - print('mnt namespace is not supported') - raise unittest.SkipTest() + pytest.skip('mnt namespace is not supported') isolation = { 'namespaces': {'mount': True}, - 'rootfs': self.testdir, + 'rootfs': self.temp_dir, } self.load('ns_inspect', isolation=isolation) obj = self.getjson(url='/?file=/go/app')['body'] - self.assertEqual(obj['FileExists'], True, 'app relative to rootfs') + assert obj['FileExists'] == True, 'app relative to rootfs' obj = self.getjson(url='/?file=/bin/sh')['body'] - self.assertEqual(obj['FileExists'], False, 'file should not exists') + assert obj['FileExists'] == False, 'file should not exists' + + def test_go_isolation_rootfs_default_tmpfs(self): + if not self.isolation_key('unprivileged_userns_clone'): + pytest.skip('unprivileged clone is not available') + + if not self.isolation_key('mnt'): + pytest.skip('mnt namespace is not supported') + + isolation = { + 'namespaces': {'mount': True, 'credential': True}, + 'rootfs': self.temp_dir, + } + + self.load('ns_inspect', isolation=isolation) + obj = self.getjson(url='/?file=/tmp')['body'] -if __name__ == '__main__': - TestGoIsolation.main() + assert obj['FileExists'] == True, 'app has /tmp' diff --git a/test/test_go_isolation_rootfs.py b/test/test_go_isolation_rootfs.py index 0039ff87..d8e177b1 100644 --- a/test/test_go_isolation_rootfs.py +++ b/test/test_go_isolation_rootfs.py @@ -1,5 +1,6 @@ import os -import unittest + +import pytest from unit.applications.lang.go import TestApplicationGo @@ -7,28 +8,22 @@ from unit.applications.lang.go import TestApplicationGo class TestGoIsolationRootfs(TestApplicationGo): prerequisites = {'modules': {'go': 'all'}} - def test_go_isolation_rootfs_chroot(self): - if not self.is_su: - print("requires root") - raise unittest.SkipTest() + def test_go_isolation_rootfs_chroot(self, is_su): + if not is_su: + pytest.skip('requires root') if os.uname().sysname == 'Darwin': - print('chroot tests not supported on OSX') - raise unittest.SkipTest() + pytest.skip('chroot tests not supported on OSX') isolation = { - 'rootfs': self.testdir, + 'rootfs': self.temp_dir, } self.load('ns_inspect', isolation=isolation) obj = self.getjson(url='/?file=/go/app')['body'] - self.assertEqual(obj['FileExists'], True, 'app relative to rootfs') + assert obj['FileExists'] == True, 'app relative to rootfs' obj = self.getjson(url='/?file=/bin/sh')['body'] - self.assertEqual(obj['FileExists'], False, 'file should not exists') - - -if __name__ == '__main__': - TestGoIsolationRootfs.main() + assert obj['FileExists'] == False, 'file should not exists' diff --git a/test/test_http_header.py b/test/test_http_header.py index ea4520c1..8381a0d9 100644 --- a/test/test_http_header.py +++ b/test/test_http_header.py @@ -1,4 +1,4 @@ -import unittest +import pytest from unit.applications.lang.python import TestApplicationPython @@ -17,12 +17,10 @@ class TestHTTPHeader(TestApplicationPython): } ) - self.assertEqual(resp['status'], 200, 'value leading sp status') - self.assertEqual( - resp['headers']['Custom-Header'], - ',', - 'value leading sp custom header', - ) + assert resp['status'] == 200, 'value leading sp status' + assert ( + resp['headers']['Custom-Header'] == ',' + ), 'value leading sp custom header' def test_http_header_value_leading_htab(self): self.load('custom_header') @@ -35,12 +33,10 @@ class TestHTTPHeader(TestApplicationPython): } ) - self.assertEqual(resp['status'], 200, 'value leading htab status') - self.assertEqual( - resp['headers']['Custom-Header'], - ',', - 'value leading htab custom header', - ) + assert resp['status'] == 200, 'value leading htab status' + assert ( + resp['headers']['Custom-Header'] == ',' + ), 'value leading htab custom header' def test_http_header_value_trailing_sp(self): self.load('custom_header') @@ -53,12 +49,10 @@ class TestHTTPHeader(TestApplicationPython): } ) - self.assertEqual(resp['status'], 200, 'value trailing sp status') - self.assertEqual( - resp['headers']['Custom-Header'], - ',', - 'value trailing sp custom header', - ) + assert resp['status'] == 200, 'value trailing sp status' + assert ( + resp['headers']['Custom-Header'] == ',' + ), 'value trailing sp custom header' def test_http_header_value_trailing_htab(self): self.load('custom_header') @@ -71,12 +65,10 @@ class TestHTTPHeader(TestApplicationPython): } ) - self.assertEqual(resp['status'], 200, 'value trailing htab status') - self.assertEqual( - resp['headers']['Custom-Header'], - ',', - 'value trailing htab custom header', - ) + assert resp['status'] == 200, 'value trailing htab status' + assert ( + resp['headers']['Custom-Header'] == ',' + ), 'value trailing htab custom header' def test_http_header_value_both_sp(self): self.load('custom_header') @@ -89,12 +81,10 @@ class TestHTTPHeader(TestApplicationPython): } ) - self.assertEqual(resp['status'], 200, 'value both sp status') - self.assertEqual( - resp['headers']['Custom-Header'], - ',', - 'value both sp custom header', - ) + assert resp['status'] == 200, 'value both sp status' + assert ( + resp['headers']['Custom-Header'] == ',' + ), 'value both sp custom header' def test_http_header_value_both_htab(self): self.load('custom_header') @@ -107,12 +97,10 @@ class TestHTTPHeader(TestApplicationPython): } ) - self.assertEqual(resp['status'], 200, 'value both htab status') - self.assertEqual( - resp['headers']['Custom-Header'], - ',', - 'value both htab custom header', - ) + assert resp['status'] == 200, 'value both htab status' + assert ( + resp['headers']['Custom-Header'] == ',' + ), 'value both htab custom header' def test_http_header_value_chars(self): self.load('custom_header') @@ -120,17 +108,16 @@ class TestHTTPHeader(TestApplicationPython): resp = self.get( headers={ 'Host': 'localhost', - 'Custom-Header': '(),/:;<=>?@[\]{}\t !#$%&\'*+-.^_`|~', + 'Custom-Header': r'(),/:;<=>?@[\]{}\t !#$%&\'*+-.^_`|~', 'Connection': 'close', } ) - self.assertEqual(resp['status'], 200, 'value chars status') - self.assertEqual( - resp['headers']['Custom-Header'], - '(),/:;<=>?@[\]{}\t !#$%&\'*+-.^_`|~', - 'value chars custom header', - ) + assert resp['status'] == 200, 'value chars status' + assert ( + resp['headers']['Custom-Header'] + == r'(),/:;<=>?@[\]{}\t !#$%&\'*+-.^_`|~' + ), 'value chars custom header' def test_http_header_value_chars_edge(self): self.load('custom_header') @@ -146,10 +133,8 @@ Connection: close encoding='latin1', ) - self.assertEqual(resp['status'], 200, 'value chars edge status') - self.assertEqual( - resp['headers']['Custom-Header'], '\xFF', 'value chars edge' - ) + assert resp['status'] == 200, 'value chars edge status' + assert resp['headers']['Custom-Header'] == '\xFF', 'value chars edge' def test_http_header_value_chars_below(self): self.load('custom_header') @@ -164,7 +149,7 @@ Connection: close raw=True, ) - self.assertEqual(resp['status'], 400, 'value chars below') + assert resp['status'] == 400, 'value chars below' def test_http_header_field_leading_sp(self): self.load('empty') @@ -177,7 +162,7 @@ Connection: close } ) - self.assertEqual(resp['status'], 400, 'field leading sp') + assert resp['status'] == 400, 'field leading sp' def test_http_header_field_leading_htab(self): self.load('empty') @@ -190,7 +175,7 @@ Connection: close } ) - self.assertEqual(resp['status'], 400, 'field leading htab') + assert resp['status'] == 400, 'field leading htab' def test_http_header_field_trailing_sp(self): self.load('empty') @@ -203,7 +188,7 @@ Connection: close } ) - self.assertEqual(resp['status'], 400, 'field trailing sp') + assert resp['status'] == 400, 'field trailing sp' def test_http_header_field_trailing_htab(self): self.load('empty') @@ -216,12 +201,12 @@ Connection: close } ) - self.assertEqual(resp['status'], 400, 'field trailing htab') + assert resp['status'] == 400, 'field trailing htab' def test_http_header_content_length_big(self): self.load('empty') - self.assertEqual( + assert ( self.post( headers={ 'Host': 'localhost', @@ -229,15 +214,14 @@ Connection: close 'Connection': 'close', }, body='X' * 1000, - )['status'], - 400, - 'Content-Length big', - ) + )['status'] + == 400 + ), 'Content-Length big' def test_http_header_content_length_negative(self): self.load('empty') - self.assertEqual( + assert ( self.post( headers={ 'Host': 'localhost', @@ -245,15 +229,14 @@ Connection: close 'Connection': 'close', }, body='X' * 1000, - )['status'], - 400, - 'Content-Length negative', - ) + )['status'] + == 400 + ), 'Content-Length negative' def test_http_header_content_length_text(self): self.load('empty') - self.assertEqual( + assert ( self.post( headers={ 'Host': 'localhost', @@ -261,15 +244,14 @@ Connection: close 'Connection': 'close', }, body='X' * 1000, - )['status'], - 400, - 'Content-Length text', - ) + )['status'] + == 400 + ), 'Content-Length text' def test_http_header_content_length_multiple_values(self): self.load('empty') - self.assertEqual( + assert ( self.post( headers={ 'Host': 'localhost', @@ -277,15 +259,14 @@ Connection: close 'Connection': 'close', }, body='X' * 1000, - )['status'], - 400, - 'Content-Length multiple value', - ) + )['status'] + == 400 + ), 'Content-Length multiple value' def test_http_header_content_length_multiple_fields(self): self.load('empty') - self.assertEqual( + assert ( self.post( headers={ 'Host': 'localhost', @@ -293,39 +274,35 @@ Connection: close 'Connection': 'close', }, body='X' * 1000, - )['status'], - 400, - 'Content-Length multiple fields', - ) + )['status'] + == 400 + ), 'Content-Length multiple fields' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_http_header_host_absent(self): self.load('host') resp = self.get(headers={'Connection': 'close'}) - self.assertEqual(resp['status'], 400, 'Host absent status') + assert resp['status'] == 400, 'Host absent status' def test_http_header_host_empty(self): self.load('host') resp = self.get(headers={'Host': '', 'Connection': 'close'}) - self.assertEqual(resp['status'], 200, 'Host empty status') - self.assertNotEqual( - resp['headers']['X-Server-Name'], '', 'Host empty SERVER_NAME' - ) + assert resp['status'] == 200, 'Host empty status' + assert resp['headers']['X-Server-Name'] != '', 'Host empty SERVER_NAME' def test_http_header_host_big(self): self.load('empty') - self.assertEqual( + assert ( self.get(headers={'Host': 'X' * 10000, 'Connection': 'close'})[ 'status' - ], - 431, - 'Host big', - ) + ] + == 431 + ), 'Host big' def test_http_header_host_port(self): self.load('host') @@ -334,17 +311,13 @@ Connection: close headers={'Host': 'exmaple.com:7080', 'Connection': 'close'} ) - self.assertEqual(resp['status'], 200, 'Host port status') - self.assertEqual( - resp['headers']['X-Server-Name'], - 'exmaple.com', - 'Host port SERVER_NAME', - ) - self.assertEqual( - resp['headers']['X-Http-Host'], - 'exmaple.com:7080', - 'Host port HTTP_HOST', - ) + assert resp['status'] == 200, 'Host port status' + assert ( + resp['headers']['X-Server-Name'] == 'exmaple.com' + ), 'Host port SERVER_NAME' + assert ( + resp['headers']['X-Http-Host'] == 'exmaple.com:7080' + ), 'Host port HTTP_HOST' def test_http_header_host_port_empty(self): self.load('host') @@ -353,63 +326,49 @@ Connection: close headers={'Host': 'exmaple.com:', 'Connection': 'close'} ) - self.assertEqual(resp['status'], 200, 'Host port empty status') - self.assertEqual( - resp['headers']['X-Server-Name'], - 'exmaple.com', - 'Host port empty SERVER_NAME', - ) - self.assertEqual( - resp['headers']['X-Http-Host'], - 'exmaple.com:', - 'Host port empty HTTP_HOST', - ) + assert resp['status'] == 200, 'Host port empty status' + assert ( + resp['headers']['X-Server-Name'] == 'exmaple.com' + ), 'Host port empty SERVER_NAME' + assert ( + resp['headers']['X-Http-Host'] == 'exmaple.com:' + ), 'Host port empty HTTP_HOST' def test_http_header_host_literal(self): self.load('host') resp = self.get(headers={'Host': '127.0.0.1', 'Connection': 'close'}) - self.assertEqual(resp['status'], 200, 'Host literal status') - self.assertEqual( - resp['headers']['X-Server-Name'], - '127.0.0.1', - 'Host literal SERVER_NAME', - ) + assert resp['status'] == 200, 'Host literal status' + assert ( + resp['headers']['X-Server-Name'] == '127.0.0.1' + ), 'Host literal SERVER_NAME' def test_http_header_host_literal_ipv6(self): self.load('host') resp = self.get(headers={'Host': '[::1]:7080', 'Connection': 'close'}) - self.assertEqual(resp['status'], 200, 'Host literal ipv6 status') - self.assertEqual( - resp['headers']['X-Server-Name'], - '[::1]', - 'Host literal ipv6 SERVER_NAME', - ) - self.assertEqual( - resp['headers']['X-Http-Host'], - '[::1]:7080', - 'Host literal ipv6 HTTP_HOST', - ) + assert resp['status'] == 200, 'Host literal ipv6 status' + assert ( + resp['headers']['X-Server-Name'] == '[::1]' + ), 'Host literal ipv6 SERVER_NAME' + assert ( + resp['headers']['X-Http-Host'] == '[::1]:7080' + ), 'Host literal ipv6 HTTP_HOST' def test_http_header_host_trailing_period(self): self.load('host') resp = self.get(headers={'Host': '127.0.0.1.', 'Connection': 'close'}) - self.assertEqual(resp['status'], 200, 'Host trailing period status') - self.assertEqual( - resp['headers']['X-Server-Name'], - '127.0.0.1', - 'Host trailing period SERVER_NAME', - ) - self.assertEqual( - resp['headers']['X-Http-Host'], - '127.0.0.1.', - 'Host trailing period HTTP_HOST', - ) + assert resp['status'] == 200, 'Host trailing period status' + assert ( + resp['headers']['X-Server-Name'] == '127.0.0.1' + ), 'Host trailing period SERVER_NAME' + assert ( + resp['headers']['X-Http-Host'] == '127.0.0.1.' + ), 'Host trailing period HTTP_HOST' def test_http_header_host_trailing_period_2(self): self.load('host') @@ -418,66 +377,53 @@ Connection: close headers={'Host': 'EXAMPLE.COM.', 'Connection': 'close'} ) - self.assertEqual(resp['status'], 200, 'Host trailing period 2 status') - self.assertEqual( - resp['headers']['X-Server-Name'], - 'example.com', - 'Host trailing period 2 SERVER_NAME', - ) - self.assertEqual( - resp['headers']['X-Http-Host'], - 'EXAMPLE.COM.', - 'Host trailing period 2 HTTP_HOST', - ) + assert resp['status'] == 200, 'Host trailing period 2 status' + assert ( + resp['headers']['X-Server-Name'] == 'example.com' + ), 'Host trailing period 2 SERVER_NAME' + assert ( + resp['headers']['X-Http-Host'] == 'EXAMPLE.COM.' + ), 'Host trailing period 2 HTTP_HOST' def test_http_header_host_case_insensitive(self): self.load('host') resp = self.get(headers={'Host': 'EXAMPLE.COM', 'Connection': 'close'}) - self.assertEqual(resp['status'], 200, 'Host case insensitive') - self.assertEqual( - resp['headers']['X-Server-Name'], - 'example.com', - 'Host case insensitive SERVER_NAME', - ) + assert resp['status'] == 200, 'Host case insensitive' + assert ( + resp['headers']['X-Server-Name'] == 'example.com' + ), 'Host case insensitive SERVER_NAME' def test_http_header_host_double_dot(self): self.load('empty') - self.assertEqual( + assert ( self.get(headers={'Host': '127.0.0..1', 'Connection': 'close'})[ 'status' - ], - 400, - 'Host double dot', - ) + ] + == 400 + ), 'Host double dot' def test_http_header_host_slash(self): self.load('empty') - self.assertEqual( + assert ( self.get(headers={'Host': '/localhost', 'Connection': 'close'})[ 'status' - ], - 400, - 'Host slash', - ) + ] + == 400 + ), 'Host slash' def test_http_header_host_multiple_fields(self): self.load('empty') - self.assertEqual( + assert ( self.get( headers={ 'Host': ['localhost', 'example.com'], 'Connection': 'close', } - )['status'], - 400, - 'Host multiple fields', - ) - - -if __name__ == '__main__': - TestHTTPHeader.main() + )['status'] + == 400 + ), 'Host multiple fields' diff --git a/test/test_java_application.py b/test/test_java_application.py index 0cb18c25..afcdf651 100644 --- a/test/test_java_application.py +++ b/test/test_java_application.py @@ -1,54 +1,46 @@ import io import os +import re import time +from conftest import option +from conftest import public_dir +from conftest import skip_alert from unit.applications.lang.java import TestApplicationJava - class TestJavaApplication(TestApplicationJava): prerequisites = {'modules': {'java': 'all'}} def test_java_conf_error(self): - self.skip_alerts.extend( - [ - r'realpath.*failed', - r'failed to apply new conf', - r'application setup failed', - ] - ) - self.assertIn( - 'error', - self.conf( - { - "listeners": {"*:7080": {"pass": "applications/app"}}, - "applications": { - "app": { - "type": "java", - "processes": 1, - "working_directory": self.current_dir - + "/java/empty", - "webapp": self.testdir + "/java", - "unit_jars": self.testdir + "/no_such_dir", - } - }, - } - ), - 'conf error', - ) + skip_alert( + r'realpath.*failed', + r'failed to apply new conf', + r'application setup failed', + ) + assert 'error' in self.conf( + { + "listeners": {"*:7080": {"pass": "applications/app"}}, + "applications": { + "app": { + "type": "java", + "processes": 1, + "working_directory": option.test_dir + "/java/empty", + "webapp": self.temp_dir + "/java", + "unit_jars": self.temp_dir + "/no_such_dir", + } + }, + } + ), 'conf error' def test_java_war(self): self.load('empty_war') - self.assertIn( - 'success', - self.conf( - '"' + self.testdir + '/java/empty.war"', - '/config/applications/empty_war/webapp', - ), - 'configure war', - ) + assert 'success' in self.conf( + '"' + self.temp_dir + '/java/empty.war"', + '/config/applications/empty_war/webapp', + ), 'configure war' - self.assertEqual(self.get()['status'], 200, 'war') + assert self.get()['status'] == 200, 'war' def test_java_application_cookies(self): self.load('cookies') @@ -61,22 +53,20 @@ class TestJavaApplication(TestApplicationJava): } )['headers'] - self.assertEqual(headers['X-Cookie-1'], 'val1', 'cookie 1') - self.assertEqual(headers['X-Cookie-2'], 'val2', 'cookie 2') + assert headers['X-Cookie-1'] == 'val1', 'cookie 1' + assert headers['X-Cookie-2'] == 'val2', 'cookie 2' def test_java_application_filter(self): self.load('filter') headers = self.get()['headers'] - self.assertEqual(headers['X-Filter-Before'], '1', 'filter before') - self.assertEqual(headers['X-Filter-After'], '1', 'filter after') + assert headers['X-Filter-Before'] == '1', 'filter before' + assert headers['X-Filter-After'] == '1', 'filter after' - self.assertEqual( - self.get(url='/test')['headers']['X-Filter-After'], - '0', - 'filter after 2', - ) + assert ( + self.get(url='/test')['headers']['X-Filter-After'] == '0' + ), 'filter after 2' def test_java_application_get_variables(self): self.load('get_params') @@ -85,21 +75,17 @@ class TestJavaApplication(TestApplicationJava): 'headers' ] - self.assertEqual(headers['X-Var-1'], 'val1', 'GET variables') - self.assertEqual(headers['X-Var-2'], 'true', 'GET variables 2') - self.assertEqual(headers['X-Var-3'], 'false', 'GET variables 3') + assert headers['X-Var-1'] == 'val1', 'GET variables' + assert headers['X-Var-2'] == 'true', 'GET variables 2' + assert headers['X-Var-3'] == 'false', 'GET variables 3' - self.assertEqual( - headers['X-Param-Names'], 'var4 var2 var1 ', 'getParameterNames' - ) - self.assertEqual( - headers['X-Param-Values'], 'val4 foo ', 'getParameterValues' - ) - self.assertEqual( - headers['X-Param-Map'], - 'var2= var1=val1 var4=val4,foo ', - 'getParameterMap', - ) + assert ( + headers['X-Param-Names'] == 'var4 var2 var1 ' + ), 'getParameterNames' + assert headers['X-Param-Values'] == 'val4 foo ', 'getParameterValues' + assert ( + headers['X-Param-Map'] == 'var2= var1=val1 var4=val4,foo ' + ), 'getParameterMap' def test_java_application_post_variables(self): self.load('post_params') @@ -113,9 +99,9 @@ class TestJavaApplication(TestApplicationJava): body='var1=val1&var2=', )['headers'] - self.assertEqual(headers['X-Var-1'], 'val1', 'POST variables') - self.assertEqual(headers['X-Var-2'], 'true', 'POST variables 2') - self.assertEqual(headers['X-Var-3'], 'false', 'POST variables 3') + assert headers['X-Var-1'] == 'val1', 'POST variables' + assert headers['X-Var-2'] == 'true', 'POST variables 2' + assert headers['X-Var-3'] == 'false', 'POST variables 3' def test_java_application_session(self): self.load('session') @@ -123,8 +109,8 @@ class TestJavaApplication(TestApplicationJava): headers = self.get(url='/?var1=val1')['headers'] session_id = headers['X-Session-Id'] - self.assertEqual(headers['X-Var-1'], 'null', 'variable empty') - self.assertEqual(headers['X-Session-New'], 'true', 'session create') + assert headers['X-Var-1'] == 'null', 'variable empty' + assert headers['X-Session-New'] == 'true', 'session create' headers = self.get( headers={ @@ -135,36 +121,33 @@ class TestJavaApplication(TestApplicationJava): url='/?var1=val2', )['headers'] - self.assertEqual(headers['X-Var-1'], 'val1', 'variable') - self.assertEqual(headers['X-Session-New'], 'false', 'session resume') - self.assertEqual( - session_id, headers['X-Session-Id'], 'session same id' - ) + assert headers['X-Var-1'] == 'val1', 'variable' + assert headers['X-Session-New'] == 'false', 'session resume' + assert session_id == headers['X-Session-Id'], 'session same id' def test_java_application_session_active(self): self.load('session_inactive') - resp = self.get(headers={ - 'X-Interval': '4', - 'Host': 'localhost', - 'Connection': 'close', - }) + resp = self.get( + headers={ + 'X-Interval': '4', + 'Host': 'localhost', + 'Connection': 'close', + } + ) session_id = resp['headers']['X-Session-Id'] - self.assertEqual(resp['status'], 200, 'session init') - self.assertEqual( - resp['headers']['X-Session-Interval'], '4', 'session interval' - ) - self.assertLess( + assert resp['status'] == 200, 'session init' + assert resp['headers']['X-Session-Interval'] == '4', 'session interval' + assert ( abs( self.date_to_sec_epoch( resp['headers']['X-Session-Last-Access-Time'] ) - self.sec_epoch() - ), - 5, - 'session last access time', - ) + ) + < 5 + ), 'session last access time' time.sleep(1) @@ -176,9 +159,7 @@ class TestJavaApplication(TestApplicationJava): } ) - self.assertEqual( - resp['headers']['X-Session-Id'], session_id, 'session active' - ) + assert resp['headers']['X-Session-Id'] == session_id, 'session active' session_id = resp['headers']['X-Session-Id'] @@ -192,9 +173,9 @@ class TestJavaApplication(TestApplicationJava): } ) - self.assertEqual( - resp['headers']['X-Session-Id'], session_id, 'session active 2' - ) + assert ( + resp['headers']['X-Session-Id'] == session_id + ), 'session active 2' time.sleep(2) @@ -206,18 +187,20 @@ class TestJavaApplication(TestApplicationJava): } ) - self.assertEqual( - resp['headers']['X-Session-Id'], session_id, 'session active 3' - ) + assert ( + resp['headers']['X-Session-Id'] == session_id + ), 'session active 3' def test_java_application_session_inactive(self): self.load('session_inactive') - resp = self.get(headers={ - 'X-Interval': '1', - 'Host': 'localhost', - 'Connection': 'close', - }) + resp = self.get( + headers={ + 'X-Interval': '1', + 'Host': 'localhost', + 'Connection': 'close', + } + ) session_id = resp['headers']['X-Session-Id'] time.sleep(3) @@ -230,9 +213,9 @@ class TestJavaApplication(TestApplicationJava): } ) - self.assertNotEqual( - resp['headers']['X-Session-Id'], session_id, 'session inactive' - ) + assert ( + resp['headers']['X-Session-Id'] != session_id + ), 'session inactive' def test_java_application_session_invalidate(self): self.load('session_invalidate') @@ -248,9 +231,9 @@ class TestJavaApplication(TestApplicationJava): } ) - self.assertNotEqual( - resp['headers']['X-Session-Id'], session_id, 'session invalidate' - ) + assert ( + resp['headers']['X-Session-Id'] != session_id + ), 'session invalidate' def test_java_application_session_listeners(self): self.load('session_listeners') @@ -258,10 +241,8 @@ class TestJavaApplication(TestApplicationJava): headers = self.get(url='/test?var1=val1')['headers'] session_id = headers['X-Session-Id'] - self.assertEqual( - headers['X-Session-Created'], session_id, 'session create' - ) - self.assertEqual(headers['X-Attr-Added'], 'var1=val1', 'attribute add') + assert headers['X-Session-Created'] == session_id, 'session create' + assert headers['X-Attr-Added'] == 'var1=val1', 'attribute add' headers = self.get( headers={ @@ -272,12 +253,8 @@ class TestJavaApplication(TestApplicationJava): url='/?var1=val2', )['headers'] - self.assertEqual( - session_id, headers['X-Session-Id'], 'session same id' - ) - self.assertEqual( - headers['X-Attr-Replaced'], 'var1=val1', 'attribute replace' - ) + assert session_id == headers['X-Session-Id'], 'session same id' + assert headers['X-Attr-Replaced'] == 'var1=val1', 'attribute replace' headers = self.get( headers={ @@ -288,289 +265,219 @@ class TestJavaApplication(TestApplicationJava): url='/', )['headers'] - self.assertEqual( - session_id, headers['X-Session-Id'], 'session same id' - ) - self.assertEqual( - headers['X-Attr-Removed'], 'var1=val2', 'attribute remove' - ) + assert session_id == headers['X-Session-Id'], 'session same id' + assert headers['X-Attr-Removed'] == 'var1=val2', 'attribute remove' def test_java_application_jsp(self): self.load('jsp') headers = self.get(url='/index.jsp')['headers'] - self.assertEqual(headers['X-Unit-JSP'], 'ok', 'JSP Ok header') + assert headers['X-Unit-JSP'] == 'ok', 'JSP Ok header' def test_java_application_url_pattern(self): self.load('url_pattern') headers = self.get(url='/foo/bar/index.html')['headers'] - self.assertEqual(headers['X-Id'], 'servlet1', '#1 Servlet1 request') - self.assertEqual( - headers['X-Request-URI'], '/foo/bar/index.html', '#1 request URI' - ) - self.assertEqual( - headers['X-Servlet-Path'], '/foo/bar', '#1 servlet path' - ) - self.assertEqual(headers['X-Path-Info'], '/index.html', '#1 path info') + assert headers['X-Id'] == 'servlet1', '#1 Servlet1 request' + assert ( + headers['X-Request-URI'] == '/foo/bar/index.html' + ), '#1 request URI' + assert headers['X-Servlet-Path'] == '/foo/bar', '#1 servlet path' + assert headers['X-Path-Info'] == '/index.html', '#1 path info' headers = self.get(url='/foo/bar/index.bop')['headers'] - self.assertEqual(headers['X-Id'], 'servlet1', '#2 Servlet1 request') - self.assertEqual( - headers['X-Request-URI'], '/foo/bar/index.bop', '#2 request URI' - ) - self.assertEqual( - headers['X-Servlet-Path'], '/foo/bar', '#2 servlet path' - ) - self.assertEqual(headers['X-Path-Info'], '/index.bop', '#2 path info') + assert headers['X-Id'] == 'servlet1', '#2 Servlet1 request' + assert ( + headers['X-Request-URI'] == '/foo/bar/index.bop' + ), '#2 request URI' + assert headers['X-Servlet-Path'] == '/foo/bar', '#2 servlet path' + assert headers['X-Path-Info'] == '/index.bop', '#2 path info' headers = self.get(url='/baz')['headers'] - self.assertEqual(headers['X-Id'], 'servlet2', '#3 Servlet2 request') - self.assertEqual(headers['X-Request-URI'], '/baz', '#3 request URI') - self.assertEqual(headers['X-Servlet-Path'], '/baz', '#3 servlet path') - self.assertEqual(headers['X-Path-Info'], 'null', '#3 path info') + assert headers['X-Id'] == 'servlet2', '#3 Servlet2 request' + assert headers['X-Request-URI'] == '/baz', '#3 request URI' + assert headers['X-Servlet-Path'] == '/baz', '#3 servlet path' + assert headers['X-Path-Info'] == 'null', '#3 path info' headers = self.get(url='/baz/index.html')['headers'] - self.assertEqual(headers['X-Id'], 'servlet2', '#4 Servlet2 request') - self.assertEqual( - headers['X-Request-URI'], '/baz/index.html', '#4 request URI' - ) - self.assertEqual(headers['X-Servlet-Path'], '/baz', '#4 servlet path') - self.assertEqual(headers['X-Path-Info'], '/index.html', '#4 path info') + assert headers['X-Id'] == 'servlet2', '#4 Servlet2 request' + assert headers['X-Request-URI'] == '/baz/index.html', '#4 request URI' + assert headers['X-Servlet-Path'] == '/baz', '#4 servlet path' + assert headers['X-Path-Info'] == '/index.html', '#4 path info' headers = self.get(url='/catalog')['headers'] - self.assertEqual(headers['X-Id'], 'servlet3', '#5 Servlet3 request') - self.assertEqual( - headers['X-Request-URI'], '/catalog', '#5 request URI' - ) - self.assertEqual( - headers['X-Servlet-Path'], '/catalog', '#5 servlet path' - ) - self.assertEqual(headers['X-Path-Info'], 'null', '#5 path info') + assert headers['X-Id'] == 'servlet3', '#5 Servlet3 request' + assert headers['X-Request-URI'] == '/catalog', '#5 request URI' + assert headers['X-Servlet-Path'] == '/catalog', '#5 servlet path' + assert headers['X-Path-Info'] == 'null', '#5 path info' headers = self.get(url='/catalog/index.html')['headers'] - self.assertEqual(headers['X-Id'], 'default', '#6 default request') - self.assertEqual( - headers['X-Request-URI'], '/catalog/index.html', '#6 request URI' - ) - self.assertEqual( - headers['X-Servlet-Path'], '/catalog/index.html', '#6 servlet path' - ) - self.assertEqual(headers['X-Path-Info'], 'null', '#6 path info') + assert headers['X-Id'] == 'default', '#6 default request' + assert ( + headers['X-Request-URI'] == '/catalog/index.html' + ), '#6 request URI' + assert ( + headers['X-Servlet-Path'] == '/catalog/index.html' + ), '#6 servlet path' + assert headers['X-Path-Info'] == 'null', '#6 path info' headers = self.get(url='/catalog/racecar.bop')['headers'] - self.assertEqual(headers['X-Id'], 'servlet4', '#7 servlet4 request') - self.assertEqual( - headers['X-Request-URI'], '/catalog/racecar.bop', '#7 request URI' - ) - self.assertEqual( - headers['X-Servlet-Path'], - '/catalog/racecar.bop', - '#7 servlet path', - ) - self.assertEqual(headers['X-Path-Info'], 'null', '#7 path info') + assert headers['X-Id'] == 'servlet4', '#7 servlet4 request' + assert ( + headers['X-Request-URI'] == '/catalog/racecar.bop' + ), '#7 request URI' + assert ( + headers['X-Servlet-Path'] == '/catalog/racecar.bop' + ), '#7 servlet path' + assert headers['X-Path-Info'] == 'null', '#7 path info' headers = self.get(url='/index.bop')['headers'] - self.assertEqual(headers['X-Id'], 'servlet4', '#8 servlet4 request') - self.assertEqual( - headers['X-Request-URI'], '/index.bop', '#8 request URI' - ) - self.assertEqual( - headers['X-Servlet-Path'], '/index.bop', '#8 servlet path' - ) - self.assertEqual(headers['X-Path-Info'], 'null', '#8 path info') + assert headers['X-Id'] == 'servlet4', '#8 servlet4 request' + assert headers['X-Request-URI'] == '/index.bop', '#8 request URI' + assert headers['X-Servlet-Path'] == '/index.bop', '#8 servlet path' + assert headers['X-Path-Info'] == 'null', '#8 path info' headers = self.get(url='/foo/baz')['headers'] - self.assertEqual(headers['X-Id'], 'servlet0', '#9 servlet0 request') - self.assertEqual( - headers['X-Request-URI'], '/foo/baz', '#9 request URI' - ) - self.assertEqual(headers['X-Servlet-Path'], '/foo', '#9 servlet path') - self.assertEqual(headers['X-Path-Info'], '/baz', '#9 path info') + assert headers['X-Id'] == 'servlet0', '#9 servlet0 request' + assert headers['X-Request-URI'] == '/foo/baz', '#9 request URI' + assert headers['X-Servlet-Path'] == '/foo', '#9 servlet path' + assert headers['X-Path-Info'] == '/baz', '#9 path info' headers = self.get()['headers'] - self.assertEqual(headers['X-Id'], 'default', '#10 default request') - self.assertEqual(headers['X-Request-URI'], '/', '#10 request URI') - self.assertEqual(headers['X-Servlet-Path'], '/', '#10 servlet path') - self.assertEqual(headers['X-Path-Info'], 'null', '#10 path info') + assert headers['X-Id'] == 'default', '#10 default request' + assert headers['X-Request-URI'] == '/', '#10 request URI' + assert headers['X-Servlet-Path'] == '/', '#10 servlet path' + assert headers['X-Path-Info'] == 'null', '#10 path info' headers = self.get(url='/index.bop/')['headers'] - self.assertEqual(headers['X-Id'], 'default', '#11 default request') - self.assertEqual( - headers['X-Request-URI'], '/index.bop/', '#11 request URI' - ) - self.assertEqual( - headers['X-Servlet-Path'], '/index.bop/', '#11 servlet path' - ) - self.assertEqual(headers['X-Path-Info'], 'null', '#11 path info') + assert headers['X-Id'] == 'default', '#11 default request' + assert headers['X-Request-URI'] == '/index.bop/', '#11 request URI' + assert headers['X-Servlet-Path'] == '/index.bop/', '#11 servlet path' + assert headers['X-Path-Info'] == 'null', '#11 path info' def test_java_application_header(self): self.load('header') headers = self.get()['headers'] - self.assertEqual( - headers['X-Set-Utf8-Value'], '????', 'set Utf8 header value' - ) - self.assertEqual( - headers['X-Set-Utf8-Name-???'], 'x', 'set Utf8 header name' - ) - self.assertEqual( - headers['X-Add-Utf8-Value'], '????', 'add Utf8 header value' - ) - self.assertEqual( - headers['X-Add-Utf8-Name-???'], 'y', 'add Utf8 header name' - ) - self.assertEqual(headers['X-Add-Test'], 'v1', 'add null header') - self.assertEqual('X-Set-Test1' in headers, False, 'set null header') - self.assertEqual(headers['X-Set-Test2'], '', 'set empty header') + assert headers['X-Set-Utf8-Value'] == '????', 'set Utf8 header value' + assert headers['X-Set-Utf8-Name-???'] == 'x', 'set Utf8 header name' + assert headers['X-Add-Utf8-Value'] == '????', 'add Utf8 header value' + assert headers['X-Add-Utf8-Name-???'] == 'y', 'add Utf8 header name' + assert headers['X-Add-Test'] == 'v1', 'add null header' + assert ('X-Set-Test1' in headers) == False, 'set null header' + assert headers['X-Set-Test2'] == '', 'set empty header' def test_java_application_content_type(self): self.load('content_type') headers = self.get(url='/1')['headers'] - self.assertEqual( - headers['Content-Type'], - 'text/plain;charset=utf-8', - '#1 Content-Type header', - ) - self.assertEqual( - headers['X-Content-Type'], - 'text/plain;charset=utf-8', - '#1 response Content-Type', - ) - self.assertEqual( - headers['X-Character-Encoding'], 'utf-8', '#1 response charset' - ) + assert ( + headers['Content-Type'] == 'text/plain;charset=utf-8' + ), '#1 Content-Type header' + assert ( + headers['X-Content-Type'] == 'text/plain;charset=utf-8' + ), '#1 response Content-Type' + assert ( + headers['X-Character-Encoding'] == 'utf-8' + ), '#1 response charset' headers = self.get(url='/2')['headers'] - self.assertEqual( - headers['Content-Type'], - 'text/plain;charset=iso-8859-1', - '#2 Content-Type header', - ) - self.assertEqual( - headers['X-Content-Type'], - 'text/plain;charset=iso-8859-1', - '#2 response Content-Type', - ) - self.assertEqual( - headers['X-Character-Encoding'], - 'iso-8859-1', - '#2 response charset', - ) + assert ( + headers['Content-Type'] == 'text/plain;charset=iso-8859-1' + ), '#2 Content-Type header' + assert ( + headers['X-Content-Type'] == 'text/plain;charset=iso-8859-1' + ), '#2 response Content-Type' + assert ( + headers['X-Character-Encoding'] == 'iso-8859-1' + ), '#2 response charset' headers = self.get(url='/3')['headers'] - self.assertEqual( - headers['Content-Type'], - 'text/plain;charset=windows-1251', - '#3 Content-Type header', - ) - self.assertEqual( - headers['X-Content-Type'], - 'text/plain;charset=windows-1251', - '#3 response Content-Type', - ) - self.assertEqual( - headers['X-Character-Encoding'], - 'windows-1251', - '#3 response charset', - ) + assert ( + headers['Content-Type'] == 'text/plain;charset=windows-1251' + ), '#3 Content-Type header' + assert ( + headers['X-Content-Type'] == 'text/plain;charset=windows-1251' + ), '#3 response Content-Type' + assert ( + headers['X-Character-Encoding'] == 'windows-1251' + ), '#3 response charset' headers = self.get(url='/4')['headers'] - self.assertEqual( - headers['Content-Type'], - 'text/plain;charset=windows-1251', - '#4 Content-Type header', - ) - self.assertEqual( - headers['X-Content-Type'], - 'text/plain;charset=windows-1251', - '#4 response Content-Type', - ) - self.assertEqual( - headers['X-Character-Encoding'], - 'windows-1251', - '#4 response charset', - ) + assert ( + headers['Content-Type'] == 'text/plain;charset=windows-1251' + ), '#4 Content-Type header' + assert ( + headers['X-Content-Type'] == 'text/plain;charset=windows-1251' + ), '#4 response Content-Type' + assert ( + headers['X-Character-Encoding'] == 'windows-1251' + ), '#4 response charset' headers = self.get(url='/5')['headers'] - self.assertEqual( - headers['Content-Type'], - 'text/plain;charset=iso-8859-1', - '#5 Content-Type header', - ) - self.assertEqual( - headers['X-Content-Type'], - 'text/plain;charset=iso-8859-1', - '#5 response Content-Type', - ) - self.assertEqual( - headers['X-Character-Encoding'], - 'iso-8859-1', - '#5 response charset', - ) + assert ( + headers['Content-Type'] == 'text/plain;charset=iso-8859-1' + ), '#5 Content-Type header' + assert ( + headers['X-Content-Type'] == 'text/plain;charset=iso-8859-1' + ), '#5 response Content-Type' + assert ( + headers['X-Character-Encoding'] == 'iso-8859-1' + ), '#5 response charset' headers = self.get(url='/6')['headers'] - self.assertEqual( - 'Content-Type' in headers, False, '#6 no Content-Type header' - ) - self.assertEqual( - 'X-Content-Type' in headers, False, '#6 no response Content-Type' - ) - self.assertEqual( - headers['X-Character-Encoding'], 'utf-8', '#6 response charset' - ) + assert ( + 'Content-Type' in headers + ) == False, '#6 no Content-Type header' + assert ( + 'X-Content-Type' in headers + ) == False, '#6 no response Content-Type' + assert ( + headers['X-Character-Encoding'] == 'utf-8' + ), '#6 response charset' headers = self.get(url='/7')['headers'] - self.assertEqual( - headers['Content-Type'], - 'text/plain;charset=utf-8', - '#7 Content-Type header', - ) - self.assertEqual( - headers['X-Content-Type'], - 'text/plain;charset=utf-8', - '#7 response Content-Type', - ) - self.assertEqual( - headers['X-Character-Encoding'], 'utf-8', '#7 response charset' - ) + assert ( + headers['Content-Type'] == 'text/plain;charset=utf-8' + ), '#7 Content-Type header' + assert ( + headers['X-Content-Type'] == 'text/plain;charset=utf-8' + ), '#7 response Content-Type' + assert ( + headers['X-Character-Encoding'] == 'utf-8' + ), '#7 response charset' headers = self.get(url='/8')['headers'] - self.assertEqual( - headers['Content-Type'], - 'text/html;charset=utf-8', - '#8 Content-Type header', - ) - self.assertEqual( - headers['X-Content-Type'], - 'text/html;charset=utf-8', - '#8 response Content-Type', - ) - self.assertEqual( - headers['X-Character-Encoding'], 'utf-8', '#8 response charset' - ) + assert ( + headers['Content-Type'] == 'text/html;charset=utf-8' + ), '#8 Content-Type header' + assert ( + headers['X-Content-Type'] == 'text/html;charset=utf-8' + ), '#8 response Content-Type' + assert ( + headers['X-Character-Encoding'] == 'utf-8' + ), '#8 response charset' def test_java_application_welcome_files(self): self.load('welcome_files') @@ -579,126 +486,90 @@ class TestJavaApplication(TestApplicationJava): resp = self.get(url='/dir1') - self.assertEqual(resp['status'], 302, 'dir redirect expected') + assert resp['status'] == 302, 'dir redirect expected' resp = self.get(url='/dir1/') - self.assertEqual( - 'This is index.txt.' in resp['body'], True, 'dir1 index body' - ) - self.assertEqual( - resp['headers']['X-TXT-Filter'], '1', 'TXT Filter header' - ) + assert ( + 'This is index.txt.' in resp['body'] + ) == True, 'dir1 index body' + assert resp['headers']['X-TXT-Filter'] == '1', 'TXT Filter header' headers = self.get(url='/dir2/')['headers'] - self.assertEqual(headers['X-Unit-JSP'], 'ok', 'JSP Ok header') - self.assertEqual(headers['X-JSP-Filter'], '1', 'JSP Filter header') + assert headers['X-Unit-JSP'] == 'ok', 'JSP Ok header' + assert headers['X-JSP-Filter'] == '1', 'JSP Filter header' headers = self.get(url='/dir3/')['headers'] - self.assertEqual( - headers['X-App-Servlet'], '1', 'URL pattern overrides welcome file' - ) + assert ( + headers['X-App-Servlet'] == '1' + ), 'URL pattern overrides welcome file' headers = self.get(url='/dir4/')['headers'] - self.assertEqual( - 'X-App-Servlet' in headers, - False, - 'Static welcome file served first', - ) + assert ( + 'X-App-Servlet' in headers + ) == False, 'Static welcome file served first' headers = self.get(url='/dir5/')['headers'] - self.assertEqual( - headers['X-App-Servlet'], - '1', - 'Servlet for welcome file served when no static file found', - ) + assert ( + headers['X-App-Servlet'] == '1' + ), 'Servlet for welcome file served when no static file found' def test_java_application_request_listeners(self): self.load('request_listeners') headers = self.get(url='/test1')['headers'] - self.assertEqual( - headers['X-Request-Initialized'], - '/test1', - 'request initialized event', - ) - self.assertEqual( - headers['X-Request-Destroyed'], '', 'request destroyed event' - ) - self.assertEqual(headers['X-Attr-Added'], '', 'attribute added event') - self.assertEqual( - headers['X-Attr-Removed'], '', 'attribute removed event' - ) - self.assertEqual( - headers['X-Attr-Replaced'], '', 'attribute replaced event' - ) + assert ( + headers['X-Request-Initialized'] == '/test1' + ), 'request initialized event' + assert headers['X-Request-Destroyed'] == '', 'request destroyed event' + assert headers['X-Attr-Added'] == '', 'attribute added event' + assert headers['X-Attr-Removed'] == '', 'attribute removed event' + assert headers['X-Attr-Replaced'] == '', 'attribute replaced event' headers = self.get(url='/test2?var1=1')['headers'] - self.assertEqual( - headers['X-Request-Initialized'], - '/test2', - 'request initialized event', - ) - self.assertEqual( - headers['X-Request-Destroyed'], '/test1', 'request destroyed event' - ) - self.assertEqual( - headers['X-Attr-Added'], 'var=1;', 'attribute added event' - ) - self.assertEqual( - headers['X-Attr-Removed'], 'var=1;', 'attribute removed event' - ) - self.assertEqual( - headers['X-Attr-Replaced'], '', 'attribute replaced event' - ) + assert ( + headers['X-Request-Initialized'] == '/test2' + ), 'request initialized event' + assert ( + headers['X-Request-Destroyed'] == '/test1' + ), 'request destroyed event' + assert headers['X-Attr-Added'] == 'var=1;', 'attribute added event' + assert headers['X-Attr-Removed'] == 'var=1;', 'attribute removed event' + assert headers['X-Attr-Replaced'] == '', 'attribute replaced event' headers = self.get(url='/test3?var1=1&var2=2')['headers'] - self.assertEqual( - headers['X-Request-Initialized'], - '/test3', - 'request initialized event', - ) - self.assertEqual( - headers['X-Request-Destroyed'], '/test2', 'request destroyed event' - ) - self.assertEqual( - headers['X-Attr-Added'], 'var=1;', 'attribute added event' - ) - self.assertEqual( - headers['X-Attr-Removed'], 'var=2;', 'attribute removed event' - ) - self.assertEqual( - headers['X-Attr-Replaced'], 'var=1;', 'attribute replaced event' - ) + assert ( + headers['X-Request-Initialized'] == '/test3' + ), 'request initialized event' + assert ( + headers['X-Request-Destroyed'] == '/test2' + ), 'request destroyed event' + assert headers['X-Attr-Added'] == 'var=1;', 'attribute added event' + assert headers['X-Attr-Removed'] == 'var=2;', 'attribute removed event' + assert ( + headers['X-Attr-Replaced'] == 'var=1;' + ), 'attribute replaced event' headers = self.get(url='/test4?var1=1&var2=2&var3=3')['headers'] - self.assertEqual( - headers['X-Request-Initialized'], - '/test4', - 'request initialized event', - ) - self.assertEqual( - headers['X-Request-Destroyed'], '/test3', 'request destroyed event' - ) - self.assertEqual( - headers['X-Attr-Added'], 'var=1;', 'attribute added event' - ) - self.assertEqual( - headers['X-Attr-Removed'], '', 'attribute removed event' - ) - self.assertEqual( - headers['X-Attr-Replaced'], - 'var=1;var=2;', - 'attribute replaced event', - ) + assert ( + headers['X-Request-Initialized'] == '/test4' + ), 'request initialized event' + assert ( + headers['X-Request-Destroyed'] == '/test3' + ), 'request destroyed event' + assert headers['X-Attr-Added'] == 'var=1;', 'attribute added event' + assert headers['X-Attr-Removed'] == '', 'attribute removed event' + assert ( + headers['X-Attr-Replaced'] == 'var=1;var=2;' + ), 'attribute replaced event' def test_java_application_request_uri_forward(self): self.load('forward') @@ -708,105 +579,67 @@ class TestJavaApplication(TestApplicationJava): ) headers = resp['headers'] - self.assertEqual( - headers['X-REQUEST-Id'], 'fwd', 'initial request servlet mapping' - ) - self.assertEqual( - headers['X-Forward-To'], - '/data/test?uri=new_uri&a=2&b=3', - 'forwarding triggered', - ) - self.assertEqual( - headers['X-REQUEST-Param-uri'], - '/data/test?uri=new_uri&a=2&b=3', - 'original uri parameter', - ) - self.assertEqual( - headers['X-REQUEST-Param-a'], '1', 'original a parameter' - ) - self.assertEqual( - headers['X-REQUEST-Param-c'], '4', 'original c parameter' - ) - - self.assertEqual( - headers['X-FORWARD-Id'], 'data', 'forward request servlet mapping' - ) - self.assertEqual( - headers['X-FORWARD-Request-URI'], - '/data/test', - 'forward request uri', - ) - self.assertEqual( - headers['X-FORWARD-Servlet-Path'], - '/data', - 'forward request servlet path', - ) - self.assertEqual( - headers['X-FORWARD-Path-Info'], - '/test', - 'forward request path info', - ) - self.assertEqual( - headers['X-FORWARD-Query-String'], - 'uri=new_uri&a=2&b=3', - 'forward request query string', - ) - self.assertEqual( - headers['X-FORWARD-Param-uri'], - 'new_uri,/data/test?uri=new_uri&a=2&b=3', - 'forward uri parameter', - ) - self.assertEqual( - headers['X-FORWARD-Param-a'], '2,1', 'forward a parameter' - ) - self.assertEqual( - headers['X-FORWARD-Param-b'], '3', 'forward b parameter' - ) - self.assertEqual( - headers['X-FORWARD-Param-c'], '4', 'forward c parameter' - ) - - self.assertEqual( - headers['X-javax.servlet.forward.request_uri'], - '/fwd', - 'original request uri', - ) - self.assertEqual( - headers['X-javax.servlet.forward.context_path'], - '', - 'original request context path', - ) - self.assertEqual( - headers['X-javax.servlet.forward.servlet_path'], - '/fwd', - 'original request servlet path', - ) - self.assertEqual( - headers['X-javax.servlet.forward.path_info'], - 'null', - 'original request path info', - ) - self.assertEqual( - headers['X-javax.servlet.forward.query_string'], - 'uri=%2Fdata%2Ftest%3Furi%3Dnew_uri%26a%3D2%26b%3D3&a=1&c=4', - 'original request query', - ) - - self.assertEqual( - 'Before forwarding' in resp['body'], - False, - 'discarded data added before forward() call', - ) - self.assertEqual( - 'X-After-Forwarding' in headers, - False, - 'cannot add headers after forward() call', - ) - self.assertEqual( - 'After forwarding' in resp['body'], - False, - 'cannot add data after forward() call', - ) + assert ( + headers['X-REQUEST-Id'] == 'fwd' + ), 'initial request servlet mapping' + assert ( + headers['X-Forward-To'] == '/data/test?uri=new_uri&a=2&b=3' + ), 'forwarding triggered' + assert ( + headers['X-REQUEST-Param-uri'] == '/data/test?uri=new_uri&a=2&b=3' + ), 'original uri parameter' + assert headers['X-REQUEST-Param-a'] == '1', 'original a parameter' + assert headers['X-REQUEST-Param-c'] == '4', 'original c parameter' + + assert ( + headers['X-FORWARD-Id'] == 'data' + ), 'forward request servlet mapping' + assert ( + headers['X-FORWARD-Request-URI'] == '/data/test' + ), 'forward request uri' + assert ( + headers['X-FORWARD-Servlet-Path'] == '/data' + ), 'forward request servlet path' + assert ( + headers['X-FORWARD-Path-Info'] == '/test' + ), 'forward request path info' + assert ( + headers['X-FORWARD-Query-String'] == 'uri=new_uri&a=2&b=3' + ), 'forward request query string' + assert ( + headers['X-FORWARD-Param-uri'] + == 'new_uri,/data/test?uri=new_uri&a=2&b=3' + ), 'forward uri parameter' + assert headers['X-FORWARD-Param-a'] == '2,1', 'forward a parameter' + assert headers['X-FORWARD-Param-b'] == '3', 'forward b parameter' + assert headers['X-FORWARD-Param-c'] == '4', 'forward c parameter' + + assert ( + headers['X-javax.servlet.forward.request_uri'] == '/fwd' + ), 'original request uri' + assert ( + headers['X-javax.servlet.forward.context_path'] == '' + ), 'original request context path' + assert ( + headers['X-javax.servlet.forward.servlet_path'] == '/fwd' + ), 'original request servlet path' + assert ( + headers['X-javax.servlet.forward.path_info'] == 'null' + ), 'original request path info' + assert ( + headers['X-javax.servlet.forward.query_string'] + == 'uri=%2Fdata%2Ftest%3Furi%3Dnew_uri%26a%3D2%26b%3D3&a=1&c=4' + ), 'original request query' + + assert ( + 'Before forwarding' in resp['body'] + ) == False, 'discarded data added before forward() call' + assert ( + 'X-After-Forwarding' in headers + ) == False, 'cannot add headers after forward() call' + assert ( + 'After forwarding' in resp['body'] + ) == False, 'cannot add data after forward() call' def test_java_application_named_dispatcher_forward(self): self.load('forward') @@ -814,74 +647,52 @@ class TestJavaApplication(TestApplicationJava): resp = self.get(url='/fwd?disp=name&uri=data') headers = resp['headers'] - self.assertEqual( - headers['X-REQUEST-Id'], 'fwd', 'initial request servlet mapping' - ) - self.assertEqual( - headers['X-Forward-To'], 'data', 'forwarding triggered' - ) - - self.assertEqual( - headers['X-FORWARD-Id'], 'data', 'forward request servlet mapping' - ) - self.assertEqual( - headers['X-FORWARD-Request-URI'], '/fwd', 'forward request uri' - ) - self.assertEqual( - headers['X-FORWARD-Servlet-Path'], - '/fwd', - 'forward request servlet path', - ) - self.assertEqual( - headers['X-FORWARD-Path-Info'], 'null', 'forward request path info' - ) - self.assertEqual( - headers['X-FORWARD-Query-String'], - 'disp=name&uri=data', - 'forward request query string', - ) - - self.assertEqual( - headers['X-javax.servlet.forward.request_uri'], - 'null', - 'original request uri', - ) - self.assertEqual( - headers['X-javax.servlet.forward.context_path'], - 'null', - 'original request context path', - ) - self.assertEqual( - headers['X-javax.servlet.forward.servlet_path'], - 'null', - 'original request servlet path', - ) - self.assertEqual( - headers['X-javax.servlet.forward.path_info'], - 'null', - 'original request path info', - ) - self.assertEqual( - headers['X-javax.servlet.forward.query_string'], - 'null', - 'original request query', - ) - - self.assertEqual( - 'Before forwarding' in resp['body'], - False, - 'discarded data added before forward() call', - ) - self.assertEqual( - 'X-After-Forwarding' in headers, - False, - 'cannot add headers after forward() call', - ) - self.assertEqual( - 'After forwarding' in resp['body'], - False, - 'cannot add data after forward() call', - ) + assert ( + headers['X-REQUEST-Id'] == 'fwd' + ), 'initial request servlet mapping' + assert headers['X-Forward-To'] == 'data', 'forwarding triggered' + + assert ( + headers['X-FORWARD-Id'] == 'data' + ), 'forward request servlet mapping' + assert ( + headers['X-FORWARD-Request-URI'] == '/fwd' + ), 'forward request uri' + assert ( + headers['X-FORWARD-Servlet-Path'] == '/fwd' + ), 'forward request servlet path' + assert ( + headers['X-FORWARD-Path-Info'] == 'null' + ), 'forward request path info' + assert ( + headers['X-FORWARD-Query-String'] == 'disp=name&uri=data' + ), 'forward request query string' + + assert ( + headers['X-javax.servlet.forward.request_uri'] == 'null' + ), 'original request uri' + assert ( + headers['X-javax.servlet.forward.context_path'] == 'null' + ), 'original request context path' + assert ( + headers['X-javax.servlet.forward.servlet_path'] == 'null' + ), 'original request servlet path' + assert ( + headers['X-javax.servlet.forward.path_info'] == 'null' + ), 'original request path info' + assert ( + headers['X-javax.servlet.forward.query_string'] == 'null' + ), 'original request query' + + assert ( + 'Before forwarding' in resp['body'] + ) == False, 'discarded data added before forward() call' + assert ( + 'X-After-Forwarding' in headers + ) == False, 'cannot add headers after forward() call' + assert ( + 'After forwarding' in resp['body'] + ) == False, 'cannot add data after forward() call' def test_java_application_request_uri_include(self): self.load('include') @@ -890,55 +701,40 @@ class TestJavaApplication(TestApplicationJava): headers = resp['headers'] body = resp['body'] - self.assertEqual( - headers['X-REQUEST-Id'], 'inc', 'initial request servlet mapping' - ) - self.assertEqual( - headers['X-Include'], '/data/test', 'including triggered' - ) - - self.assertEqual( - 'X-INCLUDE-Id' in headers, - False, - 'unable to add headers in include request', - ) - - self.assertEqual( - 'javax.servlet.include.request_uri: /data/test' in body, - True, - 'include request uri', - ) - # self.assertEqual('javax.servlet.include.context_path: ' in body, - # 'include request context path') - self.assertEqual( - 'javax.servlet.include.servlet_path: /data' in body, - True, - 'include request servlet path', - ) - self.assertEqual( - 'javax.servlet.include.path_info: /test' in body, - True, - 'include request path info', - ) - self.assertEqual( - 'javax.servlet.include.query_string: null' in body, - True, - 'include request query', - ) - - self.assertEqual( - 'Before include' in body, - True, - 'preserve data added before include() call', - ) - self.assertEqual( - headers['X-After-Include'], - 'you-should-see-this', - 'add headers after include() call', - ) - self.assertEqual( - 'After include' in body, True, 'add data after include() call' - ) + assert ( + headers['X-REQUEST-Id'] == 'inc' + ), 'initial request servlet mapping' + assert headers['X-Include'] == '/data/test', 'including triggered' + + assert ( + 'X-INCLUDE-Id' in headers + ) == False, 'unable to add headers in include request' + + assert ( + 'javax.servlet.include.request_uri: /data/test' in body + ) == True, 'include request uri' + #assert ( + # 'javax.servlet.include.context_path: ' in body + #) == True, 'include request context path' + assert ( + 'javax.servlet.include.servlet_path: /data' in body + ) == True, 'include request servlet path' + assert ( + 'javax.servlet.include.path_info: /test' in body + ) == True, 'include request path info' + assert ( + 'javax.servlet.include.query_string: null' in body + ) == True, 'include request query' + + assert ( + 'Before include' in body + ) == True, 'preserve data added before include() call' + assert ( + headers['X-After-Include'] == 'you-should-see-this' + ), 'add headers after include() call' + assert ( + 'After include' in body + ) == True, 'add data after include() call' def test_java_application_named_dispatcher_include(self): self.load('include') @@ -947,144 +743,105 @@ class TestJavaApplication(TestApplicationJava): headers = resp['headers'] body = resp['body'] - self.assertEqual( - headers['X-REQUEST-Id'], 'inc', 'initial request servlet mapping' - ) - self.assertEqual(headers['X-Include'], 'data', 'including triggered') - - self.assertEqual( - 'X-INCLUDE-Id' in headers, - False, - 'unable to add headers in include request', - ) - - self.assertEqual( - 'javax.servlet.include.request_uri: null' in body, - True, - 'include request uri', - ) - # self.assertEqual('javax.servlet.include.context_path: null' in body, - # 'include request context path') - self.assertEqual( - 'javax.servlet.include.servlet_path: null' in body, - True, - 'include request servlet path', - ) - self.assertEqual( - 'javax.servlet.include.path_info: null' in body, - True, - 'include request path info', - ) - self.assertEqual( - 'javax.servlet.include.query_string: null' in body, - True, - 'include request query', - ) - - self.assertEqual( - 'Before include' in body, - True, - 'preserve data added before include() call', - ) - self.assertEqual( - headers['X-After-Include'], - 'you-should-see-this', - 'add headers after include() call', - ) - self.assertEqual( - 'After include' in body, True, 'add data after include() call' - ) + assert ( + headers['X-REQUEST-Id'] == 'inc' + ), 'initial request servlet mapping' + assert headers['X-Include'] == 'data', 'including triggered' + + assert ( + 'X-INCLUDE-Id' in headers + ) == False, 'unable to add headers in include request' + + assert ( + 'javax.servlet.include.request_uri: null' in body + ) == True, 'include request uri' + #assert ( + # 'javax.servlet.include.context_path: null' in body + #) == True, 'include request context path' + assert ( + 'javax.servlet.include.servlet_path: null' in body + ) == True, 'include request servlet path' + assert ( + 'javax.servlet.include.path_info: null' in body + ) == True, 'include request path info' + assert ( + 'javax.servlet.include.query_string: null' in body + ) == True, 'include request query' + + assert ( + 'Before include' in body + ) == True, 'preserve data added before include() call' + assert ( + headers['X-After-Include'] == 'you-should-see-this' + ), 'add headers after include() call' + assert ( + 'After include' in body + ) == True, 'add data after include() call' def test_java_application_path_translation(self): self.load('path_translation') headers = self.get(url='/pt/test?path=/')['headers'] - self.assertEqual( - headers['X-Servlet-Path'], '/pt', 'matched servlet path' - ) - self.assertEqual( - headers['X-Path-Info'], '/test', 'the rest of the path' - ) - self.assertEqual( - headers['X-Path-Translated'], - headers['X-Real-Path'] + headers['X-Path-Info'], - 'translated path is the app root + path info', - ) - self.assertEqual( - headers['X-Resource-Paths'].endswith('/WEB-INF/, /index.html]'), - True, - 'app root directory content', - ) - self.assertEqual( - headers['X-Resource-As-Stream'], - 'null', - 'no resource stream for root path', - ) + assert headers['X-Servlet-Path'] == '/pt', 'matched servlet path' + assert headers['X-Path-Info'] == '/test', 'the rest of the path' + assert ( + headers['X-Path-Translated'] + == headers['X-Real-Path'] + headers['X-Path-Info'] + ), 'translated path is the app root + path info' + assert ( + headers['X-Resource-Paths'].endswith('/WEB-INF/, /index.html]') + == True + ), 'app root directory content' + assert ( + headers['X-Resource-As-Stream'] == 'null' + ), 'no resource stream for root path' headers = self.get(url='/test?path=/none')['headers'] - self.assertEqual( - headers['X-Servlet-Path'], '/test', 'matched whole path' - ) - self.assertEqual( - headers['X-Path-Info'], - 'null', - 'the rest of the path is null, whole path matched', - ) - self.assertEqual( - headers['X-Path-Translated'], - 'null', - 'translated path is null because path info is null', - ) - self.assertEqual( - headers['X-Real-Path'].endswith('/none'), - True, - 'read path is not null', - ) - self.assertEqual( - headers['X-Resource-Paths'], 'null', 'no resource found' - ) - self.assertEqual( - headers['X-Resource-As-Stream'], 'null', 'no resource stream' - ) + assert headers['X-Servlet-Path'] == '/test', 'matched whole path' + assert ( + headers['X-Path-Info'] == 'null' + ), 'the rest of the path is null, whole path matched' + assert ( + headers['X-Path-Translated'] == 'null' + ), 'translated path is null because path info is null' + assert ( + headers['X-Real-Path'].endswith('/none') == True + ), 'read path is not null' + assert headers['X-Resource-Paths'] == 'null', 'no resource found' + assert headers['X-Resource-As-Stream'] == 'null', 'no resource stream' def test_java_application_query_string(self): self.load('query_string') - self.assertEqual( - self.get(url='/?a=b')['headers']['X-Query-String'], - 'a=b', - 'query string', - ) + assert ( + self.get(url='/?a=b')['headers']['X-Query-String'] == 'a=b' + ), 'query string' def test_java_application_query_empty(self): self.load('query_string') - self.assertEqual( - self.get(url='/?')['headers']['X-Query-String'], - '', - 'query string empty', - ) + assert ( + self.get(url='/?')['headers']['X-Query-String'] == '' + ), 'query string empty' def test_java_application_query_absent(self): self.load('query_string') - self.assertEqual( - self.get()['headers']['X-Query-String'], - 'null', - 'query string absent', - ) + assert ( + self.get()['headers']['X-Query-String'] == 'null' + ), 'query string absent' def test_java_application_empty(self): self.load('empty') - self.assertEqual(self.get()['status'], 200, 'empty') + assert self.get()['status'] == 200, 'empty' def test_java_application_keepalive_body(self): self.load('mirror') - self.assertEqual(self.post()['status'], 200, 'init') + assert self.post()['status'] == 200, 'init' body = '0123456789' * 500 (resp, sock) = self.post( @@ -1098,7 +855,7 @@ class TestJavaApplication(TestApplicationJava): read_timeout=1, ) - self.assertEqual(resp['body'], body, 'keep-alive 1') + assert resp['body'] == body, 'keep-alive 1' body = '0123456789' resp = self.post( @@ -1111,22 +868,22 @@ class TestJavaApplication(TestApplicationJava): body=body, ) - self.assertEqual(resp['body'], body, 'keep-alive 2') + assert resp['body'] == body, 'keep-alive 2' def test_java_application_http_10(self): self.load('empty') - self.assertEqual(self.get(http_10=True)['status'], 200, 'HTTP 1.0') + assert self.get(http_10=True)['status'] == 200, 'HTTP 1.0' def test_java_application_no_method(self): self.load('empty') - self.assertEqual(self.post()['status'], 405, 'no method') + assert self.post()['status'] == 405, 'no method' def test_java_application_get_header(self): self.load('get_header') - self.assertEqual( + assert ( self.get( headers={ 'X-Header': 'blah', @@ -1134,15 +891,14 @@ class TestJavaApplication(TestApplicationJava): 'Host': 'localhost', 'Connection': 'close', } - )['headers']['X-Reply'], - 'blah', - 'get header', - ) + )['headers']['X-Reply'] + == 'blah' + ), 'get header' def test_java_application_get_header_empty(self): self.load('get_header') - self.assertNotIn('X-Reply', self.get()['headers'], 'get header empty') + assert 'X-Reply' not in self.get()['headers'], 'get header empty' def test_java_application_get_headers(self): self.load('get_headers') @@ -1156,32 +912,28 @@ class TestJavaApplication(TestApplicationJava): } )['headers'] - self.assertEqual(headers['X-Reply-0'], 'blah', 'get headers') - self.assertEqual(headers['X-Reply-1'], 'blah', 'get headers 2') + assert headers['X-Reply-0'] == 'blah', 'get headers' + assert headers['X-Reply-1'] == 'blah', 'get headers 2' def test_java_application_get_headers_empty(self): self.load('get_headers') - self.assertNotIn( - 'X-Reply-0', self.get()['headers'], 'get headers empty' - ) + assert 'X-Reply-0' not in self.get()['headers'], 'get headers empty' def test_java_application_get_header_names(self): self.load('get_header_names') headers = self.get()['headers'] - self.assertRegex( - headers['X-Reply-0'], r'(?:Host|Connection)', 'get header names' - ) - self.assertRegex( - headers['X-Reply-1'], r'(?:Host|Connection)', 'get header names 2' - ) - self.assertNotEqual( - headers['X-Reply-0'], - headers['X-Reply-1'], - 'get header names not equal', - ) + assert re.search( + r'(?:Host|Connection)', headers['X-Reply-0'] + ), 'get header names' + assert re.search( + r'(?:Host|Connection)', headers['X-Reply-1'] + ), 'get header names 2' + assert ( + headers['X-Reply-0'] != headers['X-Reply-1'] + ), 'get header names not equal' def test_java_application_header_int(self): self.load('header_int') @@ -1195,8 +947,8 @@ class TestJavaApplication(TestApplicationJava): } )['headers'] - self.assertEqual(headers['X-Set-Int'], '1', 'set int header') - self.assertEqual(headers['X-Get-Int'], '2', 'get int header') + assert headers['X-Set-Int'] == '1', 'set int header' + assert headers['X-Get-Int'] == '2', 'get int header' def test_java_application_header_date(self): self.load('header_date') @@ -1212,20 +964,18 @@ class TestJavaApplication(TestApplicationJava): } )['headers'] - self.assertEqual( - headers['X-Set-Date'], - 'Thu, 01 Jan 1970 00:00:01 GMT', - 'set date header', - ) - self.assertEqual(headers['X-Get-Date'], date, 'get date header') + assert ( + headers['X-Set-Date'] == 'Thu, 01 Jan 1970 00:00:01 GMT' + ), 'set date header' + assert headers['X-Get-Date'] == date, 'get date header' def test_java_application_multipart(self): self.load('multipart') reldst = '/uploads' - fulldst = self.testdir + reldst + fulldst = self.temp_dir + reldst os.mkdir(fulldst) - self.public_dir(fulldst) + public_dir(fulldst) fields = { 'file': { @@ -1252,16 +1002,13 @@ class TestJavaApplication(TestApplicationJava): body=body, ) - self.assertEqual(resp['status'], 200, 'multipart status') - self.assertRegex( - resp['body'], r'sample\.txt created', 'multipart body' - ) - self.assertIsNotNone( + assert resp['status'] == 200, 'multipart status' + assert re.search( + r'sample\.txt created', resp['body'] + ), 'multipart body' + assert ( self.search_in_log( r'^Data from sample file$', name=reldst + '/sample.txt' - ), - 'file created', - ) - -if __name__ == '__main__': - TestJavaApplication.main() + ) + is not None + ), 'file created' diff --git a/test/test_java_isolation_rootfs.py b/test/test_java_isolation_rootfs.py index 4d39bdc3..f0f04df1 100644 --- a/test/test_java_isolation_rootfs.py +++ b/test/test_java_isolation_rootfs.py @@ -1,30 +1,32 @@ import os import subprocess -import unittest +import pytest + +from conftest import option from unit.applications.lang.java import TestApplicationJava class TestJavaIsolationRootfs(TestApplicationJava): prerequisites = {'modules': {'java': 'all'}} - def setUp(self): - if not self.is_su: - return + def setup_method(self, is_su): + super().setup_method() - super().setUp() + if not is_su: + return - os.makedirs(self.testdir + '/jars') - os.makedirs(self.testdir + '/tmp') - os.chmod(self.testdir + '/tmp', 0o777) + os.makedirs(self.temp_dir + '/jars') + os.makedirs(self.temp_dir + '/tmp') + os.chmod(self.temp_dir + '/tmp', 0o777) try: process = subprocess.Popen( [ "mount", "--bind", - self.pardir + "/build", - self.testdir + "/jars", + option.current_dir + "/build", + self.temp_dir + "/jars", ], stderr=subprocess.STDOUT, ) @@ -32,54 +34,45 @@ class TestJavaIsolationRootfs(TestApplicationJava): process.communicate() except: - self.fail('Cann\'t run mount process.') + pytest.fail('Cann\'t run mount process.') - def tearDown(self): - if not self.is_su: + def teardown_method(self, is_su): + if not is_su: return try: process = subprocess.Popen( - ["umount", "--lazy", self.testdir + "/jars"], + ["umount", "--lazy", self.temp_dir + "/jars"], stderr=subprocess.STDOUT, ) process.communicate() except: - self.fail('Cann\'t run mount process.') + pytest.fail('Cann\'t run mount process.') # super teardown must happen after unmount to avoid deletion of /build - super().tearDown() + super().teardown_method() - def test_java_isolation_rootfs_chroot_war(self): - if not self.is_su: - print('require root') - raise unittest.SkipTest() + def test_java_isolation_rootfs_chroot_war(self, is_su): + if not is_su: + pytest.skip('require root') isolation = { - 'rootfs': self.testdir, + 'rootfs': self.temp_dir, } self.load('empty_war', isolation=isolation) - self.assertIn( - 'success', - self.conf( - '"/"', '/config/applications/empty_war/working_directory', - ), + assert 'success' in self.conf( + '"/"', '/config/applications/empty_war/working_directory', ) - self.assertIn( - 'success', self.conf('"/jars"', 'applications/empty_war/unit_jars') + assert 'success' in self.conf( + '"/jars"', 'applications/empty_war/unit_jars' ) - self.assertIn( - 'success', - self.conf('"/java/empty.war"', 'applications/empty_war/webapp'), + assert 'success' in self.conf( + '"/java/empty.war"', 'applications/empty_war/webapp' ) - self.assertEqual(self.get()['status'], 200, 'war') - - -if __name__ == '__main__': - TestJavaIsolationRootfs.main() + assert self.get()['status'] == 200, 'war' diff --git a/test/test_java_websockets.py b/test/test_java_websockets.py index d78f7263..7e6d82e8 100644 --- a/test/test_java_websockets.py +++ b/test/test_java_websockets.py @@ -1,7 +1,10 @@ import struct import time -import unittest +import pytest + +from conftest import option +from conftest import skip_alert from unit.applications.lang.java import TestApplicationJava from unit.applications.websockets import TestApplicationWebsocket @@ -11,23 +14,17 @@ class TestJavaWebsockets(TestApplicationJava): ws = TestApplicationWebsocket() - def setUp(self): - super().setUp() + def setup_method(self): + super().setup_method() - self.assertIn( - 'success', - self.conf( - {'http': {'websocket': {'keepalive_interval': 0}}}, 'settings' - ), - 'clear keepalive_interval', - ) + assert 'success' in self.conf( + {'http': {'websocket': {'keepalive_interval': 0}}}, 'settings' + ), 'clear keepalive_interval' - self.skip_alerts.extend( - [r'socket close\(\d+\) failed'] - ) + skip_alert(r'socket close\(\d+\) failed') def close_connection(self, sock): - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc') + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc' self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close()) @@ -36,9 +33,9 @@ class TestJavaWebsockets(TestApplicationJava): def check_close(self, sock, code=1000, no_close=False): frame = self.ws.frame_read(sock) - self.assertEqual(frame['fin'], True, 'close fin') - self.assertEqual(frame['opcode'], self.ws.OP_CLOSE, 'close opcode') - self.assertEqual(frame['code'], code, 'close code') + assert frame['fin'] == True, 'close fin' + assert frame['opcode'] == self.ws.OP_CLOSE, 'close opcode' + assert frame['code'] == code, 'close code' if not no_close: sock.close() @@ -49,9 +46,9 @@ class TestJavaWebsockets(TestApplicationJava): else: data = frame['data'].decode('utf-8') - self.assertEqual(frame['fin'], fin, 'fin') - self.assertEqual(frame['opcode'], opcode, 'opcode') - self.assertEqual(data, payload, 'payload') + assert frame['fin'] == fin, 'fin' + assert frame['opcode'] == opcode, 'opcode' + assert data == payload, 'payload' def test_java_websockets_handshake(self): self.load('websockets_mirror') @@ -59,14 +56,12 @@ class TestJavaWebsockets(TestApplicationJava): resp, sock, key = self.ws.upgrade() sock.close() - self.assertEqual(resp['status'], 101, 'status') - self.assertEqual(resp['headers']['Upgrade'], 'websocket', 'upgrade') - self.assertEqual( - resp['headers']['Connection'], 'Upgrade', 'connection' - ) - self.assertEqual( - resp['headers']['Sec-WebSocket-Accept'], self.ws.accept(key), 'key' - ) + assert resp['status'] == 101, 'status' + assert resp['headers']['Upgrade'] == 'websocket', 'upgrade' + assert resp['headers']['Connection'] == 'Upgrade', 'connection' + assert resp['headers']['Sec-WebSocket-Accept'] == self.ws.accept( + key + ), 'key' def test_java_websockets_mirror(self): self.load('websockets_mirror') @@ -78,12 +73,12 @@ class TestJavaWebsockets(TestApplicationJava): self.ws.frame_write(sock, self.ws.OP_TEXT, message) frame = self.ws.frame_read(sock) - self.assertEqual(message, frame['data'].decode('utf-8'), 'mirror') + assert message == frame['data'].decode('utf-8'), 'mirror' self.ws.frame_write(sock, self.ws.OP_TEXT, message) frame = self.ws.frame_read(sock) - self.assertEqual(message, frame['data'].decode('utf-8'), 'mirror 2') + assert message == frame['data'].decode('utf-8'), 'mirror 2' sock.close() @@ -98,8 +93,8 @@ class TestJavaWebsockets(TestApplicationJava): frame = self.ws.frame_read(sock) - self.assertEqual(frame['opcode'], self.ws.OP_CLOSE, 'no mask opcode') - self.assertEqual(frame['code'], 1002, 'no mask close code') + assert frame['opcode'] == self.ws.OP_CLOSE, 'no mask opcode' + assert frame['code'] == 1002, 'no mask close code' sock.close() @@ -116,11 +111,9 @@ class TestJavaWebsockets(TestApplicationJava): frame = self.ws.frame_read(sock) - self.assertEqual( - message + ' ' + message, - frame['data'].decode('utf-8'), - 'mirror framing', - ) + assert message + ' ' + message == frame['data'].decode( + 'utf-8' + ), 'mirror framing' sock.close() @@ -136,20 +129,16 @@ class TestJavaWebsockets(TestApplicationJava): frame = self.ws.frame_read(sock) frame.pop('data') - self.assertDictEqual( - frame, - { - 'fin': True, - 'rsv1': False, - 'rsv2': False, - 'rsv3': False, - 'opcode': self.ws.OP_CLOSE, - 'mask': 0, - 'code': 1002, - 'reason': 'Fragmented control frame', - }, - 'close frame', - ) + assert frame == { + 'fin': True, + 'rsv1': False, + 'rsv2': False, + 'rsv3': False, + 'opcode': self.ws.OP_CLOSE, + 'mask': 0, + 'code': 1002, + 'reason': 'Fragmented control frame', + }, 'close frame' sock.close() @@ -168,13 +157,13 @@ class TestJavaWebsockets(TestApplicationJava): frame1 = self.ws.frame_read(sock1) frame2 = self.ws.frame_read(sock2) - self.assertEqual(message1, frame1['data'].decode('utf-8'), 'client 1') - self.assertEqual(message2, frame2['data'].decode('utf-8'), 'client 2') + assert message1 == frame1['data'].decode('utf-8'), 'client 1' + assert message2 == frame2['data'].decode('utf-8'), 'client 2' sock1.close() sock2.close() - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_java_websockets_handshake_upgrade_absent( self ): # FAIL https://tools.ietf.org/html/rfc6455#section-4.2.1 @@ -190,7 +179,7 @@ class TestJavaWebsockets(TestApplicationJava): }, ) - self.assertEqual(resp['status'], 400, 'upgrade absent') + assert resp['status'] == 400, 'upgrade absent' def test_java_websockets_handshake_case_insensitive(self): self.load('websockets_mirror') @@ -207,9 +196,9 @@ class TestJavaWebsockets(TestApplicationJava): ) sock.close() - self.assertEqual(resp['status'], 101, 'status') + assert resp['status'] == 101, 'status' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_java_websockets_handshake_connection_absent(self): # FAIL self.load('websockets_mirror') @@ -223,7 +212,7 @@ class TestJavaWebsockets(TestApplicationJava): }, ) - self.assertEqual(resp['status'], 400, 'status') + assert resp['status'] == 400, 'status' def test_java_websockets_handshake_version_absent(self): self.load('websockets_mirror') @@ -238,9 +227,9 @@ class TestJavaWebsockets(TestApplicationJava): }, ) - self.assertEqual(resp['status'], 426, 'status') + assert resp['status'] == 426, 'status' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_java_websockets_handshake_key_invalid(self): self.load('websockets_mirror') @@ -255,7 +244,7 @@ class TestJavaWebsockets(TestApplicationJava): }, ) - self.assertEqual(resp['status'], 400, 'key length') + assert resp['status'] == 400, 'key length' key = self.ws.key() resp = self.get( @@ -269,9 +258,7 @@ class TestJavaWebsockets(TestApplicationJava): }, ) - self.assertEqual( - resp['status'], 400, 'key double' - ) # FAIL https://tools.ietf.org/html/rfc6455#section-11.3.1 + assert resp['status'] == 400, 'key double' # FAIL https://tools.ietf.org/html/rfc6455#section-11.3.1 def test_java_websockets_handshake_method_invalid(self): self.load('websockets_mirror') @@ -287,7 +274,7 @@ class TestJavaWebsockets(TestApplicationJava): }, ) - self.assertEqual(resp['status'], 400, 'status') + assert resp['status'] == 400, 'status' def test_java_websockets_handshake_http_10(self): self.load('websockets_mirror') @@ -304,7 +291,7 @@ class TestJavaWebsockets(TestApplicationJava): http_10=True, ) - self.assertEqual(resp['status'], 400, 'status') + assert resp['status'] == 400, 'status' def test_java_websockets_handshake_uri_invalid(self): self.load('websockets_mirror') @@ -321,7 +308,7 @@ class TestJavaWebsockets(TestApplicationJava): url='!', ) - self.assertEqual(resp['status'], 400, 'status') + assert resp['status'] == 400, 'status' def test_java_websockets_protocol_absent(self): self.load('websockets_mirror') @@ -338,14 +325,12 @@ class TestJavaWebsockets(TestApplicationJava): ) sock.close() - self.assertEqual(resp['status'], 101, 'status') - self.assertEqual(resp['headers']['Upgrade'], 'websocket', 'upgrade') - self.assertEqual( - resp['headers']['Connection'], 'Upgrade', 'connection' - ) - self.assertEqual( - resp['headers']['Sec-WebSocket-Accept'], self.ws.accept(key), 'key' - ) + assert resp['status'] == 101, 'status' + assert resp['headers']['Upgrade'] == 'websocket', 'upgrade' + assert resp['headers']['Connection'] == 'Upgrade', 'connection' + assert resp['headers']['Sec-WebSocket-Accept'] == self.ws.accept( + key + ), 'key' # autobahn-testsuite # @@ -442,12 +427,12 @@ class TestJavaWebsockets(TestApplicationJava): _, sock, _ = self.ws.upgrade() self.ws.frame_write(sock, self.ws.OP_PONG, '') - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '2_7') + assert self.recvall(sock, read_timeout=0.1) == b'', '2_7' # 2_8 self.ws.frame_write(sock, self.ws.OP_PONG, 'unsolicited pong payload') - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '2_8') + assert self.recvall(sock, read_timeout=0.1) == b'', '2_8' # 2_9 @@ -487,7 +472,7 @@ class TestJavaWebsockets(TestApplicationJava): self.close_connection(sock) - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_java_websockets_3_1__3_7(self): self.load('websockets_mirror') @@ -513,7 +498,7 @@ class TestJavaWebsockets(TestApplicationJava): self.check_close(sock, 1002, no_close=True) - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_2') + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty 3_2' sock.close() # 3_3 @@ -531,7 +516,7 @@ class TestJavaWebsockets(TestApplicationJava): self.check_close(sock, 1002, no_close=True) - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_3') + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty 3_3' sock.close() # 3_4 @@ -549,7 +534,7 @@ class TestJavaWebsockets(TestApplicationJava): self.check_close(sock, 1002, no_close=True) - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_4') + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty 3_4' sock.close() # 3_5 @@ -735,7 +720,7 @@ class TestJavaWebsockets(TestApplicationJava): # 5_4 self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False) - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_4') + assert self.recvall(sock, read_timeout=0.1) == b'', '5_4' self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True) frame = self.ws.frame_read(sock) @@ -772,7 +757,7 @@ class TestJavaWebsockets(TestApplicationJava): ping_payload = 'ping payload' self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False) - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_7') + assert self.recvall(sock, read_timeout=0.1) == b'', '5_7' self.ws.frame_write(sock, self.ws.OP_PING, ping_payload) @@ -956,7 +941,7 @@ class TestJavaWebsockets(TestApplicationJava): frame = self.ws.frame_read(sock) self.check_frame(frame, True, self.ws.OP_PONG, 'pongme 2!') - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_20') + assert self.recvall(sock, read_timeout=0.1) == b'', '5_20' self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment5') self.check_frame( @@ -1089,7 +1074,7 @@ class TestJavaWebsockets(TestApplicationJava): self.check_close(sock, no_close=True) self.ws.frame_write(sock, self.ws.OP_PING, '') - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc') + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc' sock.close() @@ -1101,7 +1086,7 @@ class TestJavaWebsockets(TestApplicationJava): self.check_close(sock, no_close=True) self.ws.frame_write(sock, self.ws.OP_TEXT, payload) - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc') + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc' sock.close() @@ -1114,7 +1099,7 @@ class TestJavaWebsockets(TestApplicationJava): self.check_close(sock, no_close=True) self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2') - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc') + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc' sock.close() @@ -1129,7 +1114,7 @@ class TestJavaWebsockets(TestApplicationJava): self.recvall(sock, read_timeout=1) self.ws.frame_write(sock, self.ws.OP_PING, '') - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc') + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc' sock.close() @@ -1249,27 +1234,23 @@ class TestJavaWebsockets(TestApplicationJava): self.ws.frame_write(sock, self.ws.OP_CLOSE, payload) self.check_close(sock, 1002) - def test_java_websockets_9_1_1__9_6_6(self): - if not self.unsafe: - self.skipTest("unsafe, long run") + def test_java_websockets_9_1_1__9_6_6(self, is_unsafe): + if not is_unsafe: + pytest.skip('unsafe, long run') self.load('websockets_mirror') - self.assertIn( - 'success', - self.conf( - { - 'http': { - 'websocket': { - 'max_frame_size': 33554432, - 'keepalive_interval': 0, - } + assert 'success' in self.conf( + { + 'http': { + 'websocket': { + 'max_frame_size': 33554432, + 'keepalive_interval': 0, } - }, - 'settings', - ), - 'increase max_frame_size and keepalive_interval', - ) + } + }, + 'settings', + ), 'increase max_frame_size and keepalive_interval' _, sock, _ = self.ws.upgrade() @@ -1310,7 +1291,7 @@ class TestJavaWebsockets(TestApplicationJava): check_payload(op_binary, 8 * 2 ** 20) # 9_2_5 check_payload(op_binary, 16 * 2 ** 20) # 9_2_6 - if self.system != 'Darwin' and self.system != 'FreeBSD': + if option.system != 'Darwin' and option.system != 'FreeBSD': check_message(op_text, 64) # 9_3_1 check_message(op_text, 256) # 9_3_2 check_message(op_text, 2 ** 10) # 9_3_3 @@ -1366,13 +1347,9 @@ class TestJavaWebsockets(TestApplicationJava): def test_java_websockets_max_frame_size(self): self.load('websockets_mirror') - self.assertIn( - 'success', - self.conf( - {'http': {'websocket': {'max_frame_size': 100}}}, 'settings' - ), - 'configure max_frame_size', - ) + assert 'success' in self.conf( + {'http': {'websocket': {'max_frame_size': 100}}}, 'settings' + ), 'configure max_frame_size' _, sock, _ = self.ws.upgrade() @@ -1392,13 +1369,9 @@ class TestJavaWebsockets(TestApplicationJava): def test_java_websockets_read_timeout(self): self.load('websockets_mirror') - self.assertIn( - 'success', - self.conf( - {'http': {'websocket': {'read_timeout': 5}}}, 'settings' - ), - 'configure read_timeout', - ) + assert 'success' in self.conf( + {'http': {'websocket': {'read_timeout': 5}}}, 'settings' + ), 'configure read_timeout' _, sock, _ = self.ws.upgrade() @@ -1412,13 +1385,9 @@ class TestJavaWebsockets(TestApplicationJava): def test_java_websockets_keepalive_interval(self): self.load('websockets_mirror') - self.assertIn( - 'success', - self.conf( - {'http': {'websocket': {'keepalive_interval': 5}}}, 'settings' - ), - 'configure keepalive_interval', - ) + assert 'success' in self.conf( + {'http': {'websocket': {'keepalive_interval': 5}}}, 'settings' + ), 'configure keepalive_interval' _, sock, _ = self.ws.upgrade() @@ -1431,7 +1400,3 @@ class TestJavaWebsockets(TestApplicationJava): self.check_frame(frame, True, self.ws.OP_PING, '') # PING frame sock.close() - - -if __name__ == '__main__': - TestJavaWebsockets.main() diff --git a/test/test_node_application.py b/test/test_node_application.py index e46cc6a1..a0b882f3 100644 --- a/test/test_node_application.py +++ b/test/test_node_application.py @@ -1,5 +1,8 @@ -import unittest +import re +import pytest + +from conftest import waitforfiles from unit.applications.lang.node import TestApplicationNode @@ -10,16 +13,14 @@ class TestNodeApplication(TestApplicationNode): self.load('basic') resp = self.get() - self.assertEqual( - resp['headers']['Content-Type'], 'text/plain', 'basic header' - ) - self.assertEqual(resp['body'], 'Hello World\n', 'basic body') + assert resp['headers']['Content-Type'] == 'text/plain', 'basic header' + assert resp['body'] == 'Hello World\n', 'basic body' def test_node_application_seq(self): self.load('basic') - self.assertEqual(self.get()['status'], 200, 'seq') - self.assertEqual(self.get()['status'], 200, 'seq 2') + assert self.get()['status'] == 200, 'seq' + assert self.get()['status'] == 200, 'seq 2' def test_node_application_variables(self): self.load('variables') @@ -36,51 +37,44 @@ class TestNodeApplication(TestApplicationNode): body=body, ) - self.assertEqual(resp['status'], 200, 'status') + assert resp['status'] == 200, 'status' headers = resp['headers'] header_server = headers.pop('Server') - self.assertRegex(header_server, r'Unit/[\d\.]+', 'server header') + assert re.search(r'Unit/[\d\.]+', header_server), 'server header' date = headers.pop('Date') - self.assertEqual(date[-4:], ' GMT', 'date header timezone') - self.assertLess( - abs(self.date_to_sec_epoch(date) - self.sec_epoch()), - 5, - 'date header', - ) + assert date[-4:] == ' GMT', 'date header timezone' + assert ( + abs(self.date_to_sec_epoch(date) - self.sec_epoch()) < 5 + ), 'date header' raw_headers = headers.pop('Request-Raw-Headers') - self.assertRegex( - raw_headers, + assert re.search( r'^(?:Host|localhost|Content-Type|' - 'text\/html|Custom-Header|blah|Content-Length|17|Connection|' - 'close|,)+$', - 'raw headers', - ) - - self.assertDictEqual( - headers, - { - 'Connection': 'close', - 'Content-Length': str(len(body)), - 'Content-Type': 'text/html', - 'Request-Method': 'POST', - 'Request-Uri': '/', - 'Http-Host': 'localhost', - 'Server-Protocol': 'HTTP/1.1', - 'Custom-Header': 'blah', - }, - 'headers', - ) - self.assertEqual(resp['body'], body, 'body') + r'text\/html|Custom-Header|blah|Content-Length|17|Connection|' + r'close|,)+$', + raw_headers, + ), 'raw headers' + + assert headers == { + 'Connection': 'close', + 'Content-Length': str(len(body)), + 'Content-Type': 'text/html', + 'Request-Method': 'POST', + 'Request-Uri': '/', + 'Http-Host': 'localhost', + 'Server-Protocol': 'HTTP/1.1', + 'Custom-Header': 'blah', + }, 'headers' + assert resp['body'] == body, 'body' def test_node_application_get_variables(self): self.load('get_variables') resp = self.get(url='/?var1=val1&var2=&var3') - self.assertEqual(resp['headers']['X-Var-1'], 'val1', 'GET variables') - self.assertEqual(resp['headers']['X-Var-2'], '', 'GET variables 2') - self.assertEqual(resp['headers']['X-Var-3'], '', 'GET variables 3') + assert resp['headers']['X-Var-1'] == 'val1', 'GET variables' + assert resp['headers']['X-Var-2'] == '', 'GET variables 2' + assert resp['headers']['X-Var-3'] == '', 'GET variables 3' def test_node_application_post_variables(self): self.load('post_variables') @@ -94,24 +88,24 @@ class TestNodeApplication(TestApplicationNode): body='var1=val1&var2=&var3', ) - self.assertEqual(resp['headers']['X-Var-1'], 'val1', 'POST variables') - self.assertEqual(resp['headers']['X-Var-2'], '', 'POST variables 2') - self.assertEqual(resp['headers']['X-Var-3'], '', 'POST variables 3') + assert resp['headers']['X-Var-1'] == 'val1', 'POST variables' + assert resp['headers']['X-Var-2'] == '', 'POST variables 2' + assert resp['headers']['X-Var-3'] == '', 'POST variables 3' def test_node_application_404(self): self.load('404') resp = self.get() - self.assertEqual(resp['status'], 404, '404 status') - self.assertRegex( - resp['body'], r'<title>404 Not Found</title>', '404 body' - ) + assert resp['status'] == 404, '404 status' + assert re.search( + r'<title>404 Not Found</title>', resp['body'] + ), '404 body' def test_node_keepalive_body(self): self.load('mirror') - self.assertEqual(self.get()['status'], 200, 'init') + assert self.get()['status'] == 200, 'init' body = '0123456789' * 500 (resp, sock) = self.post( @@ -125,7 +119,7 @@ class TestNodeApplication(TestApplicationNode): read_timeout=1, ) - self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1') + assert resp['body'] == '0123456789' * 500, 'keep-alive 1' body = '0123456789' resp = self.post( @@ -138,47 +132,34 @@ class TestNodeApplication(TestApplicationNode): body=body, ) - self.assertEqual(resp['body'], body, 'keep-alive 2') + assert resp['body'] == body, 'keep-alive 2' def test_node_application_write_buffer(self): self.load('write_buffer') - self.assertEqual( - self.get()['body'], 'buffer', 'write buffer' - ) + assert self.get()['body'] == 'buffer', 'write buffer' def test_node_application_write_callback(self): self.load('write_callback') - self.assertEqual( - self.get()['body'], - 'helloworld', - 'write callback order', - ) - self.assertTrue( - self.waitforfiles(self.testdir + '/node/callback'), - 'write callback', - ) + assert self.get()['body'] == 'helloworld', 'write callback order' + assert waitforfiles(self.temp_dir + '/node/callback'), 'write callback' def test_node_application_write_before_write_head(self): self.load('write_before_write_head') - self.assertEqual(self.get()['status'], 200, 'write before writeHead') + assert self.get()['status'] == 200, 'write before writeHead' def test_node_application_double_end(self): self.load('double_end') - self.assertEqual(self.get()['status'], 200, 'double end') - self.assertEqual(self.get()['status'], 200, 'double end 2') + assert self.get()['status'] == 200, 'double end' + assert self.get()['status'] == 200, 'double end 2' def test_node_application_write_return(self): self.load('write_return') - self.assertEqual( - self.get()['body'], - 'bodytrue', - 'write return', - ) + assert self.get()['body'] == 'bodytrue', 'write return' def test_node_application_remove_header(self): self.load('remove_header') @@ -190,69 +171,61 @@ class TestNodeApplication(TestApplicationNode): 'Connection': 'close', } ) - self.assertEqual(resp['headers']['Was-Header'], 'true', 'was header') - self.assertEqual(resp['headers']['Has-Header'], 'false', 'has header') - self.assertFalse('X-Header' in resp['headers'], 'remove header') + assert resp['headers']['Was-Header'] == 'true', 'was header' + assert resp['headers']['Has-Header'] == 'false', 'has header' + assert not ('X-Header' in resp['headers']), 'remove header' def test_node_application_remove_header_nonexisting(self): self.load('remove_header') - self.assertEqual( + assert ( self.get( headers={ 'Host': 'localhost', 'X-Remove': 'blah', 'Connection': 'close', } - )['headers']['Has-Header'], - 'true', - 'remove header nonexisting', - ) + )['headers']['Has-Header'] + == 'true' + ), 'remove header nonexisting' def test_node_application_update_header(self): self.load('update_header') - self.assertEqual( - self.get()['headers']['X-Header'], 'new', 'update header' - ) + assert self.get()['headers']['X-Header'] == 'new', 'update header' def test_node_application_set_header_array(self): self.load('set_header_array') - self.assertListEqual( - self.get()['headers']['Set-Cookie'], - ['tc=one,two,three', 'tc=four,five,six'], - 'set header array', - ) + assert self.get()['headers']['Set-Cookie'] == [ + 'tc=one,two,three', + 'tc=four,five,six', + ], 'set header array' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_node_application_status_message(self): self.load('status_message') - self.assertRegex( - self.get(raw_resp=True), r'200 blah', 'status message' - ) + assert re.search(r'200 blah', self.get(raw_resp=True)), 'status message' def test_node_application_get_header_type(self): self.load('get_header_type') - self.assertEqual( - self.get()['headers']['X-Type'], 'number', 'get header type' - ) + assert self.get()['headers']['X-Type'] == 'number', 'get header type' def test_node_application_header_name_case(self): self.load('header_name_case') headers = self.get()['headers'] - self.assertEqual(headers['X-HEADER'], '3', 'header value') - self.assertNotIn('X-Header', headers, 'insensitive') - self.assertNotIn('X-header', headers, 'insensitive 2') + assert headers['X-HEADER'] == '3', 'header value' + assert 'X-Header' not in headers, 'insensitive' + assert 'X-header' not in headers, 'insensitive 2' def test_node_application_promise_handler(self): self.load('promise_handler') - self.assertEqual( + assert ( self.post( headers={ 'Host': 'localhost', @@ -260,19 +233,15 @@ class TestNodeApplication(TestApplicationNode): 'Connection': 'close', }, body='callback', - )['status'], - 200, - 'promise handler request', - ) - self.assertTrue( - self.waitforfiles(self.testdir + '/node/callback'), - 'promise handler', - ) + )['status'] + == 200 + ), 'promise handler request' + assert waitforfiles(self.temp_dir + '/node/callback'), 'promise handler' def test_node_application_promise_handler_write_after_end(self): self.load('promise_handler') - self.assertEqual( + assert ( self.post( headers={ 'Host': 'localhost', @@ -281,15 +250,14 @@ class TestNodeApplication(TestApplicationNode): 'Connection': 'close', }, body='callback', - )['status'], - 200, - 'promise handler request write after end', - ) + )['status'] + == 200 + ), 'promise handler request write after end' def test_node_application_promise_end(self): self.load('promise_end') - self.assertEqual( + assert ( self.post( headers={ 'Host': 'localhost', @@ -297,13 +265,10 @@ class TestNodeApplication(TestApplicationNode): 'Connection': 'close', }, body='end', - )['status'], - 200, - 'promise end request', - ) - self.assertTrue( - self.waitforfiles(self.testdir + '/node/callback'), 'promise end' - ) + )['status'] + == 200 + ), 'promise end request' + assert waitforfiles(self.temp_dir + '/node/callback'), 'promise end' def test_node_application_promise_multiple_calls(self): self.load('promise_handler') @@ -317,10 +282,9 @@ class TestNodeApplication(TestApplicationNode): body='callback1', ) - self.assertTrue( - self.waitforfiles(self.testdir + '/node/callback1'), - 'promise first call', - ) + assert waitforfiles( + self.temp_dir + '/node/callback1' + ), 'promise first call' self.post( headers={ @@ -331,65 +295,55 @@ class TestNodeApplication(TestApplicationNode): body='callback2', ) - self.assertTrue( - self.waitforfiles(self.testdir + '/node/callback2'), - 'promise second call', - ) + assert waitforfiles( + self.temp_dir + '/node/callback2' + ), 'promise second call' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_node_application_header_name_valid(self): self.load('header_name_valid') - self.assertNotIn('status', self.get(), 'header name valid') + assert 'status' not in self.get(), 'header name valid' def test_node_application_header_value_object(self): self.load('header_value_object') - self.assertIn('X-Header', self.get()['headers'], 'header value object') + assert 'X-Header' in self.get()['headers'], 'header value object' def test_node_application_get_header_names(self): self.load('get_header_names') - self.assertListEqual( - self.get()['headers']['X-Names'], - ['date', 'x-header'], - 'get header names', - ) + assert self.get()['headers']['X-Names'] == [ + 'date', + 'x-header', + ], 'get header names' def test_node_application_has_header(self): self.load('has_header') - self.assertEqual( + assert ( self.get( headers={ 'Host': 'localhost', 'X-Header': 'length', 'Connection': 'close', } - )['headers']['X-Has-Header'], - 'false', - 'has header length', - ) + )['headers']['X-Has-Header'] + == 'false' + ), 'has header length' - self.assertEqual( + assert ( self.get( headers={ 'Host': 'localhost', 'X-Header': 'Date', 'Connection': 'close', } - )['headers']['X-Has-Header'], - 'false', - 'has header date', - ) + )['headers']['X-Has-Header'] + == 'false' + ), 'has header date' def test_node_application_write_multiple(self): self.load('write_multiple') - self.assertEqual( - self.get()['body'], 'writewrite2end', 'write multiple' - ) - - -if __name__ == '__main__': - TestNodeApplication.main() + assert self.get()['body'] == 'writewrite2end', 'write multiple' diff --git a/test/test_node_websockets.py b/test/test_node_websockets.py index 1928d8c9..6a6b7f2d 100644 --- a/test/test_node_websockets.py +++ b/test/test_node_websockets.py @@ -1,7 +1,10 @@ import struct import time -import unittest +import pytest + +from conftest import option +from conftest import skip_alert from unit.applications.lang.node import TestApplicationNode from unit.applications.websockets import TestApplicationWebsocket @@ -11,23 +14,17 @@ class TestNodeWebsockets(TestApplicationNode): ws = TestApplicationWebsocket() - def setUp(self): - super().setUp() + def setup_method(self): + super().setup_method() - self.assertIn( - 'success', - self.conf( - {'http': {'websocket': {'keepalive_interval': 0}}}, 'settings' - ), - 'clear keepalive_interval', - ) + assert 'success' in self.conf( + {'http': {'websocket': {'keepalive_interval': 0}}}, 'settings' + ), 'clear keepalive_interval' - self.skip_alerts.extend( - [r'socket close\(\d+\) failed'] - ) + skip_alert(r'socket close\(\d+\) failed') def close_connection(self, sock): - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc') + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc' self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close()) @@ -36,9 +33,9 @@ class TestNodeWebsockets(TestApplicationNode): def check_close(self, sock, code=1000, no_close=False): frame = self.ws.frame_read(sock) - self.assertEqual(frame['fin'], True, 'close fin') - self.assertEqual(frame['opcode'], self.ws.OP_CLOSE, 'close opcode') - self.assertEqual(frame['code'], code, 'close code') + assert frame['fin'] == True, 'close fin' + assert frame['opcode'] == self.ws.OP_CLOSE, 'close opcode' + assert frame['code'] == code, 'close code' if not no_close: sock.close() @@ -49,9 +46,9 @@ class TestNodeWebsockets(TestApplicationNode): else: data = frame['data'].decode('utf-8') - self.assertEqual(frame['fin'], fin, 'fin') - self.assertEqual(frame['opcode'], opcode, 'opcode') - self.assertEqual(data, payload, 'payload') + assert frame['fin'] == fin, 'fin' + assert frame['opcode'] == opcode, 'opcode' + assert data == payload, 'payload' def test_node_websockets_handshake(self): self.load('websockets/mirror') @@ -59,14 +56,12 @@ class TestNodeWebsockets(TestApplicationNode): resp, sock, key = self.ws.upgrade() sock.close() - self.assertEqual(resp['status'], 101, 'status') - self.assertEqual(resp['headers']['Upgrade'], 'websocket', 'upgrade') - self.assertEqual( - resp['headers']['Connection'], 'Upgrade', 'connection' - ) - self.assertEqual( - resp['headers']['Sec-WebSocket-Accept'], self.ws.accept(key), 'key' - ) + assert resp['status'] == 101, 'status' + assert resp['headers']['Upgrade'] == 'websocket', 'upgrade' + assert resp['headers']['Connection'] == 'Upgrade', 'connection' + assert resp['headers']['Sec-WebSocket-Accept'] == self.ws.accept( + key + ), 'key' def test_node_websockets_mirror(self): self.load('websockets/mirror') @@ -78,12 +73,12 @@ class TestNodeWebsockets(TestApplicationNode): self.ws.frame_write(sock, self.ws.OP_TEXT, message) frame = self.ws.frame_read(sock) - self.assertEqual(message, frame['data'].decode('utf-8'), 'mirror') + assert message == frame['data'].decode('utf-8'), 'mirror' self.ws.frame_write(sock, self.ws.OP_TEXT, message) frame = self.ws.frame_read(sock) - self.assertEqual(message, frame['data'].decode('utf-8'), 'mirror 2') + assert message == frame['data'].decode('utf-8'), 'mirror 2' sock.close() @@ -98,8 +93,8 @@ class TestNodeWebsockets(TestApplicationNode): frame = self.ws.frame_read(sock) - self.assertEqual(frame['opcode'], self.ws.OP_CLOSE, 'no mask opcode') - self.assertEqual(frame['code'], 1002, 'no mask close code') + assert frame['opcode'] == self.ws.OP_CLOSE, 'no mask opcode' + assert frame['code'] == 1002, 'no mask close code' sock.close() @@ -116,11 +111,9 @@ class TestNodeWebsockets(TestApplicationNode): frame = self.ws.frame_read(sock) - self.assertEqual( - message + ' ' + message, - frame['data'].decode('utf-8'), - 'mirror framing', - ) + assert message + ' ' + message == frame['data'].decode( + 'utf-8' + ), 'mirror framing' sock.close() @@ -136,20 +129,16 @@ class TestNodeWebsockets(TestApplicationNode): frame = self.ws.frame_read(sock) frame.pop('data') - self.assertDictEqual( - frame, - { - 'fin': True, - 'rsv1': False, - 'rsv2': False, - 'rsv3': False, - 'opcode': self.ws.OP_CLOSE, - 'mask': 0, - 'code': 1002, - 'reason': 'Fragmented control frame', - }, - 'close frame', - ) + assert frame == { + 'fin': True, + 'rsv1': False, + 'rsv2': False, + 'rsv3': False, + 'opcode': self.ws.OP_CLOSE, + 'mask': 0, + 'code': 1002, + 'reason': 'Fragmented control frame', + }, 'close frame' sock.close() @@ -168,7 +157,7 @@ class TestNodeWebsockets(TestApplicationNode): frame = self.ws.frame_read(sock) data += frame['data'].decode('utf-8') - self.assertEqual(message, data, 'large') + assert message == data, 'large' sock.close() @@ -187,13 +176,13 @@ class TestNodeWebsockets(TestApplicationNode): frame1 = self.ws.frame_read(sock1) frame2 = self.ws.frame_read(sock2) - self.assertEqual(message1, frame1['data'].decode('utf-8'), 'client 1') - self.assertEqual(message2, frame2['data'].decode('utf-8'), 'client 2') + assert message1 == frame1['data'].decode('utf-8'), 'client 1' + assert message2 == frame2['data'].decode('utf-8'), 'client 2' sock1.close() sock2.close() - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_node_websockets_handshake_upgrade_absent( self ): # FAIL https://tools.ietf.org/html/rfc6455#section-4.2.1 @@ -209,7 +198,7 @@ class TestNodeWebsockets(TestApplicationNode): }, ) - self.assertEqual(resp['status'], 400, 'upgrade absent') + assert resp['status'] == 400, 'upgrade absent' def test_node_websockets_handshake_case_insensitive(self): self.load('websockets/mirror') @@ -226,9 +215,9 @@ class TestNodeWebsockets(TestApplicationNode): ) sock.close() - self.assertEqual(resp['status'], 101, 'status') + assert resp['status'] == 101, 'status' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_node_websockets_handshake_connection_absent(self): # FAIL self.load('websockets/mirror') @@ -242,7 +231,7 @@ class TestNodeWebsockets(TestApplicationNode): }, ) - self.assertEqual(resp['status'], 400, 'status') + assert resp['status'] == 400, 'status' def test_node_websockets_handshake_version_absent(self): self.load('websockets/mirror') @@ -257,9 +246,9 @@ class TestNodeWebsockets(TestApplicationNode): }, ) - self.assertEqual(resp['status'], 426, 'status') + assert resp['status'] == 426, 'status' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_node_websockets_handshake_key_invalid(self): self.load('websockets/mirror') @@ -274,7 +263,7 @@ class TestNodeWebsockets(TestApplicationNode): }, ) - self.assertEqual(resp['status'], 400, 'key length') + assert resp['status'] == 400, 'key length' key = self.ws.key() resp = self.get( @@ -288,9 +277,7 @@ class TestNodeWebsockets(TestApplicationNode): }, ) - self.assertEqual( - resp['status'], 400, 'key double' - ) # FAIL https://tools.ietf.org/html/rfc6455#section-11.3.1 + assert resp['status'] == 400, 'key double' # FAIL https://tools.ietf.org/html/rfc6455#section-11.3.1 def test_node_websockets_handshake_method_invalid(self): self.load('websockets/mirror') @@ -306,7 +293,7 @@ class TestNodeWebsockets(TestApplicationNode): }, ) - self.assertEqual(resp['status'], 400, 'status') + assert resp['status'] == 400, 'status' def test_node_websockets_handshake_http_10(self): self.load('websockets/mirror') @@ -323,7 +310,7 @@ class TestNodeWebsockets(TestApplicationNode): http_10=True, ) - self.assertEqual(resp['status'], 400, 'status') + assert resp['status'] == 400, 'status' def test_node_websockets_handshake_uri_invalid(self): self.load('websockets/mirror') @@ -340,7 +327,7 @@ class TestNodeWebsockets(TestApplicationNode): url='!', ) - self.assertEqual(resp['status'], 400, 'status') + assert resp['status'] == 400, 'status' def test_node_websockets_protocol_absent(self): self.load('websockets/mirror') @@ -357,14 +344,12 @@ class TestNodeWebsockets(TestApplicationNode): ) sock.close() - self.assertEqual(resp['status'], 101, 'status') - self.assertEqual(resp['headers']['Upgrade'], 'websocket', 'upgrade') - self.assertEqual( - resp['headers']['Connection'], 'Upgrade', 'connection' - ) - self.assertEqual( - resp['headers']['Sec-WebSocket-Accept'], self.ws.accept(key), 'key' - ) + assert resp['status'] == 101, 'status' + assert resp['headers']['Upgrade'] == 'websocket', 'upgrade' + assert resp['headers']['Connection'] == 'Upgrade', 'connection' + assert resp['headers']['Sec-WebSocket-Accept'] == self.ws.accept( + key + ), 'key' # autobahn-testsuite # @@ -461,12 +446,12 @@ class TestNodeWebsockets(TestApplicationNode): _, sock, _ = self.ws.upgrade() self.ws.frame_write(sock, self.ws.OP_PONG, '') - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '2_7') + assert self.recvall(sock, read_timeout=0.1) == b'', '2_7' # 2_8 self.ws.frame_write(sock, self.ws.OP_PONG, 'unsolicited pong payload') - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '2_8') + assert self.recvall(sock, read_timeout=0.1) == b'', '2_8' # 2_9 @@ -506,7 +491,7 @@ class TestNodeWebsockets(TestApplicationNode): self.close_connection(sock) - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_node_websockets_3_1__3_7(self): self.load('websockets/mirror') @@ -532,7 +517,7 @@ class TestNodeWebsockets(TestApplicationNode): self.check_close(sock, 1002, no_close=True) - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_2') + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty 3_2' sock.close() # 3_3 @@ -550,7 +535,7 @@ class TestNodeWebsockets(TestApplicationNode): self.check_close(sock, 1002, no_close=True) - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_3') + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty 3_3' sock.close() # 3_4 @@ -568,7 +553,7 @@ class TestNodeWebsockets(TestApplicationNode): self.check_close(sock, 1002, no_close=True) - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_4') + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty 3_4' sock.close() # 3_5 @@ -754,7 +739,7 @@ class TestNodeWebsockets(TestApplicationNode): # 5_4 self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False) - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_4') + assert self.recvall(sock, read_timeout=0.1) == b'', '5_4' self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True) frame = self.ws.frame_read(sock) @@ -791,7 +776,7 @@ class TestNodeWebsockets(TestApplicationNode): ping_payload = 'ping payload' self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False) - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_7') + assert self.recvall(sock, read_timeout=0.1) == b'', '5_7' self.ws.frame_write(sock, self.ws.OP_PING, ping_payload) @@ -975,7 +960,7 @@ class TestNodeWebsockets(TestApplicationNode): frame = self.ws.frame_read(sock) self.check_frame(frame, True, self.ws.OP_PONG, 'pongme 2!') - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_20') + assert self.recvall(sock, read_timeout=0.1) == b'', '5_20' self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment5') self.check_frame( @@ -1108,7 +1093,7 @@ class TestNodeWebsockets(TestApplicationNode): self.check_close(sock, no_close=True) self.ws.frame_write(sock, self.ws.OP_PING, '') - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc') + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc' sock.close() @@ -1120,7 +1105,7 @@ class TestNodeWebsockets(TestApplicationNode): self.check_close(sock, no_close=True) self.ws.frame_write(sock, self.ws.OP_TEXT, payload) - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc') + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc' sock.close() @@ -1133,7 +1118,7 @@ class TestNodeWebsockets(TestApplicationNode): self.check_close(sock, no_close=True) self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2') - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc') + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc' sock.close() @@ -1148,7 +1133,7 @@ class TestNodeWebsockets(TestApplicationNode): self.recvall(sock, read_timeout=1) self.ws.frame_write(sock, self.ws.OP_PING, '') - self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc') + assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc' sock.close() @@ -1268,27 +1253,23 @@ class TestNodeWebsockets(TestApplicationNode): self.ws.frame_write(sock, self.ws.OP_CLOSE, payload) self.check_close(sock, 1002) - def test_node_websockets_9_1_1__9_6_6(self): - if not self.unsafe: - self.skipTest("unsafe, long run") + def test_node_websockets_9_1_1__9_6_6(self, is_unsafe): + if not is_unsafe: + pytest.skip('unsafe, long run') self.load('websockets/mirror') - self.assertIn( - 'success', - self.conf( - { - 'http': { - 'websocket': { - 'max_frame_size': 33554432, - 'keepalive_interval': 0, - } + assert 'success' in self.conf( + { + 'http': { + 'websocket': { + 'max_frame_size': 33554432, + 'keepalive_interval': 0, } - }, - 'settings', - ), - 'increase max_frame_size and keepalive_interval', - ) + } + }, + 'settings', + ), 'increase max_frame_size and keepalive_interval' _, sock, _ = self.ws.upgrade() @@ -1329,7 +1310,7 @@ class TestNodeWebsockets(TestApplicationNode): check_payload(op_binary, 8 * 2 ** 20) # 9_2_5 check_payload(op_binary, 16 * 2 ** 20) # 9_2_6 - if self.system != 'Darwin' and self.system != 'FreeBSD': + if option.system != 'Darwin' and option.system != 'FreeBSD': check_message(op_text, 64) # 9_3_1 check_message(op_text, 256) # 9_3_2 check_message(op_text, 2 ** 10) # 9_3_3 @@ -1385,13 +1366,9 @@ class TestNodeWebsockets(TestApplicationNode): def test_node_websockets_max_frame_size(self): self.load('websockets/mirror') - self.assertIn( - 'success', - self.conf( - {'http': {'websocket': {'max_frame_size': 100}}}, 'settings' - ), - 'configure max_frame_size', - ) + assert 'success' in self.conf( + {'http': {'websocket': {'max_frame_size': 100}}}, 'settings' + ), 'configure max_frame_size' _, sock, _ = self.ws.upgrade() @@ -1411,13 +1388,9 @@ class TestNodeWebsockets(TestApplicationNode): def test_node_websockets_read_timeout(self): self.load('websockets/mirror') - self.assertIn( - 'success', - self.conf( - {'http': {'websocket': {'read_timeout': 5}}}, 'settings' - ), - 'configure read_timeout', - ) + assert 'success' in self.conf( + {'http': {'websocket': {'read_timeout': 5}}}, 'settings' + ), 'configure read_timeout' _, sock, _ = self.ws.upgrade() @@ -1431,13 +1404,9 @@ class TestNodeWebsockets(TestApplicationNode): def test_node_websockets_keepalive_interval(self): self.load('websockets/mirror') - self.assertIn( - 'success', - self.conf( - {'http': {'websocket': {'keepalive_interval': 5}}}, 'settings' - ), - 'configure keepalive_interval', - ) + assert 'success' in self.conf( + {'http': {'websocket': {'keepalive_interval': 5}}}, 'settings' + ), 'configure keepalive_interval' _, sock, _ = self.ws.upgrade() @@ -1450,7 +1419,3 @@ class TestNodeWebsockets(TestApplicationNode): self.check_frame(frame, True, self.ws.OP_PING, '') # PING frame sock.close() - - -if __name__ == '__main__': - TestNodeWebsockets.main() diff --git a/test/test_perl_application.py b/test/test_perl_application.py index dbf6abf7..78e32a43 100644 --- a/test/test_perl_application.py +++ b/test/test_perl_application.py @@ -1,5 +1,8 @@ -import unittest +import re +import pytest + +from conftest import skip_alert from unit.applications.lang.perl import TestApplicationPerl @@ -21,149 +24,130 @@ class TestPerlApplication(TestApplicationPerl): body=body, ) - self.assertEqual(resp['status'], 200, 'status') + assert resp['status'] == 200, 'status' headers = resp['headers'] header_server = headers.pop('Server') - self.assertRegex(header_server, r'Unit/[\d\.]+', 'server header') - self.assertEqual( - headers.pop('Server-Software'), - header_server, - 'server software header', - ) + assert re.search(r'Unit/[\d\.]+', header_server), 'server header' + assert ( + headers.pop('Server-Software') == header_server + ), 'server software header' date = headers.pop('Date') - self.assertEqual(date[-4:], ' GMT', 'date header timezone') - self.assertLess( - abs(self.date_to_sec_epoch(date) - self.sec_epoch()), - 5, - 'date header', - ) - - self.assertDictEqual( - headers, - { - 'Connection': 'close', - 'Content-Length': str(len(body)), - 'Content-Type': 'text/html', - 'Request-Method': 'POST', - 'Request-Uri': '/', - 'Http-Host': 'localhost', - 'Server-Protocol': 'HTTP/1.1', - 'Custom-Header': 'blah', - 'Psgi-Version': '11', - 'Psgi-Url-Scheme': 'http', - 'Psgi-Multithread': '', - 'Psgi-Multiprocess': '1', - 'Psgi-Run-Once': '', - 'Psgi-Nonblocking': '', - 'Psgi-Streaming': '1', - }, - 'headers', - ) - self.assertEqual(resp['body'], body, 'body') + assert date[-4:] == ' GMT', 'date header timezone' + assert ( + abs(self.date_to_sec_epoch(date) - self.sec_epoch()) < 5 + ), 'date header' + + assert headers == { + 'Connection': 'close', + 'Content-Length': str(len(body)), + 'Content-Type': 'text/html', + 'Request-Method': 'POST', + 'Request-Uri': '/', + 'Http-Host': 'localhost', + 'Server-Protocol': 'HTTP/1.1', + 'Custom-Header': 'blah', + 'Psgi-Version': '11', + 'Psgi-Url-Scheme': 'http', + 'Psgi-Multithread': '', + 'Psgi-Multiprocess': '1', + 'Psgi-Run-Once': '', + 'Psgi-Nonblocking': '', + 'Psgi-Streaming': '1', + }, 'headers' + assert resp['body'] == body, 'body' def test_perl_application_query_string(self): self.load('query_string') resp = self.get(url='/?var1=val1&var2=val2') - self.assertEqual( - resp['headers']['Query-String'], - 'var1=val1&var2=val2', - 'Query-String header', - ) + assert ( + resp['headers']['Query-String'] == 'var1=val1&var2=val2' + ), 'Query-String header' def test_perl_application_query_string_empty(self): self.load('query_string') resp = self.get(url='/?') - self.assertEqual(resp['status'], 200, 'query string empty status') - self.assertEqual( - resp['headers']['Query-String'], '', 'query string empty' - ) + assert resp['status'] == 200, 'query string empty status' + assert resp['headers']['Query-String'] == '', 'query string empty' def test_perl_application_query_string_absent(self): self.load('query_string') resp = self.get() - self.assertEqual(resp['status'], 200, 'query string absent status') - self.assertEqual( - resp['headers']['Query-String'], '', 'query string absent' - ) + assert resp['status'] == 200, 'query string absent status' + assert resp['headers']['Query-String'] == '', 'query string absent' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_perl_application_server_port(self): self.load('server_port') - self.assertEqual( - self.get()['headers']['Server-Port'], '7080', 'Server-Port header' - ) + assert ( + self.get()['headers']['Server-Port'] == '7080' + ), 'Server-Port header' def test_perl_application_input_read_empty(self): self.load('input_read_empty') - self.assertEqual(self.get()['body'], '', 'read empty') + assert self.get()['body'] == '', 'read empty' def test_perl_application_input_read_parts(self): self.load('input_read_parts') - self.assertEqual( - self.post(body='0123456789')['body'], - '0123456789', - 'input read parts', - ) + assert ( + self.post(body='0123456789')['body'] == '0123456789' + ), 'input read parts' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_perl_application_input_read_offset(self): self.load('input_read_offset') - self.assertEqual( - self.post(body='0123456789')['body'], '4567', 'read offset' - ) + assert self.post(body='0123456789')['body'] == '4567', 'read offset' def test_perl_application_input_copy(self): self.load('input_copy') body = '0123456789' - self.assertEqual(self.post(body=body)['body'], body, 'input copy') + assert self.post(body=body)['body'] == body, 'input copy' def test_perl_application_errors_print(self): self.load('errors_print') - self.assertEqual(self.get()['body'], '1', 'errors result') + assert self.get()['body'] == '1', 'errors result' self.stop() - self.assertIsNotNone( - self.wait_for_record(r'\[error\].+Error in application'), - 'errors print', - ) + assert ( + self.wait_for_record(r'\[error\].+Error in application') + is not None + ), 'errors print' def test_perl_application_header_equal_names(self): self.load('header_equal_names') - self.assertListEqual( - self.get()['headers']['Set-Cookie'], - ['tc=one,two,three', 'tc=four,five,six'], - 'header equal names', - ) + assert self.get()['headers']['Set-Cookie'] == [ + 'tc=one,two,three', + 'tc=four,five,six', + ], 'header equal names' def test_perl_application_header_pairs(self): self.load('header_pairs') - self.assertEqual(self.get()['headers']['blah'], 'blah', 'header pairs') + assert self.get()['headers']['blah'] == 'blah', 'header pairs' def test_perl_application_body_empty(self): self.load('body_empty') - self.assertEqual(self.get()['body'], '', 'body empty') + assert self.get()['body'] == '', 'body empty' def test_perl_application_body_array(self): self.load('body_array') - self.assertEqual(self.get()['body'], '0123456789', 'body array') + assert self.get()['body'] == '0123456789', 'body array' def test_perl_application_body_large(self): self.load('variables') @@ -172,31 +156,29 @@ class TestPerlApplication(TestApplicationPerl): resp = self.post(body=body)['body'] - self.assertEqual(resp, body, 'body large') + assert resp == body, 'body large' def test_perl_application_body_io_empty(self): self.load('body_io_empty') - self.assertEqual(self.get()['status'], 200, 'body io empty') + assert self.get()['status'] == 200, 'body io empty' def test_perl_application_body_io_file(self): self.load('body_io_file') - self.assertEqual(self.get()['body'], 'body\n', 'body io file') + assert self.get()['body'] == 'body\n', 'body io file' - @unittest.skip('not yet, unsafe') + @pytest.mark.skip('not yet') def test_perl_application_syntax_error(self): - self.skip_alerts.extend( - [r'PSGI: Failed to parse script'] - ) + skip_alert(r'PSGI: Failed to parse script') self.load('syntax_error') - self.assertEqual(self.get()['status'], 500, 'syntax error') + assert self.get()['status'] == 500, 'syntax error' def test_perl_keepalive_body(self): self.load('variables') - self.assertEqual(self.get()['status'], 200, 'init') + assert self.get()['status'] == 200, 'init' body = '0123456789' * 500 (resp, sock) = self.post( @@ -210,7 +192,7 @@ class TestPerlApplication(TestApplicationPerl): read_timeout=1, ) - self.assertEqual(resp['body'], body, 'keep-alive 1') + assert resp['body'] == body, 'keep-alive 1' body = '0123456789' resp = self.post( @@ -223,39 +205,35 @@ class TestPerlApplication(TestApplicationPerl): body=body, ) - self.assertEqual(resp['body'], body, 'keep-alive 2') + assert resp['body'] == body, 'keep-alive 2' def test_perl_body_io_fake(self): self.load('body_io_fake') - self.assertEqual(self.get()['body'], '21', 'body io fake') + assert self.get()['body'] == '21', 'body io fake' - self.assertIsNotNone( - self.wait_for_record(r'\[error\].+IOFake getline\(\) \$\/ is \d+'), - 'body io fake $/ value', - ) + assert ( + self.wait_for_record(r'\[error\].+IOFake getline\(\) \$\/ is \d+') + is not None + ), 'body io fake $/ value' - self.assertIsNotNone( - self.wait_for_record(r'\[error\].+IOFake close\(\) called'), - 'body io fake close', - ) + assert ( + self.wait_for_record(r'\[error\].+IOFake close\(\) called') + is not None + ), 'body io fake close' def test_perl_delayed_response(self): self.load('delayed_response') resp = self.get() - self.assertEqual(resp['status'], 200, 'status') - self.assertEqual(resp['body'], 'Hello World!', 'body') + assert resp['status'] == 200, 'status' + assert resp['body'] == 'Hello World!', 'body' def test_perl_streaming_body(self): self.load('streaming_body') resp = self.get() - self.assertEqual(resp['status'], 200, 'status') - self.assertEqual(resp['body'], 'Hello World!', 'body') - - -if __name__ == '__main__': - TestPerlApplication.main() + assert resp['status'] == 200, 'status' + assert resp['body'] == 'Hello World!', 'body' diff --git a/test/test_php_application.py b/test/test_php_application.py index d8bfade2..063d3e0c 100644 --- a/test/test_php_application.py +++ b/test/test_php_application.py @@ -2,8 +2,10 @@ import os import re import shutil import time -import unittest +import pytest + +from conftest import option from unit.applications.lang.php import TestApplicationPHP class TestPHPApplication(TestApplicationPHP): @@ -12,30 +14,21 @@ class TestPHPApplication(TestApplicationPHP): def before_disable_functions(self): body = self.get()['body'] - self.assertRegex(body, r'time: \d+', 'disable_functions before time') - self.assertRegex(body, r'exec: \/\w+', 'disable_functions before exec') + assert re.search(r'time: \d+', body), 'disable_functions before time' + assert re.search(r'exec: \/\w+', body), 'disable_functions before exec' def set_opcache(self, app, val): - self.assertIn( - 'success', - self.conf( - { - "admin": { - "opcache.enable": val, - "opcache.enable_cli": val, - }, - }, - 'applications/' + app + '/options', - ), + assert 'success' in self.conf( + {"admin": {"opcache.enable": val, "opcache.enable_cli": val,},}, + 'applications/' + app + '/options', ) opcache = self.get()['headers']['X-OPcache'] if not opcache or opcache == '-1': - print('opcache is not supported') - raise unittest.SkipTest() + pytest.skip('opcache is not supported') - self.assertEqual(opcache, val, 'opcache value') + assert opcache == val, 'opcache value' def test_php_application_variables(self): self.load('variables') @@ -50,140 +43,122 @@ class TestPHPApplication(TestApplicationPHP): 'Connection': 'close', }, body=body, - url='/index.php/blah?var=val' + url='/index.php/blah?var=val', ) - self.assertEqual(resp['status'], 200, 'status') + assert resp['status'] == 200, 'status' headers = resp['headers'] header_server = headers.pop('Server') - self.assertRegex(header_server, r'Unit/[\d\.]+', 'server header') - self.assertEqual( - headers.pop('Server-Software'), - header_server, - 'server software header', - ) + assert re.search(r'Unit/[\d\.]+', header_server), 'server header' + assert ( + headers.pop('Server-Software') == header_server + ), 'server software header' date = headers.pop('Date') - self.assertEqual(date[-4:], ' GMT', 'date header timezone') - self.assertLess( - abs(self.date_to_sec_epoch(date) - self.sec_epoch()), - 5, - 'date header', - ) + assert date[-4:] == ' GMT', 'date header timezone' + assert ( + abs(self.date_to_sec_epoch(date) - self.sec_epoch()) < 5 + ), 'date header' if 'X-Powered-By' in headers: headers.pop('X-Powered-By') headers.pop('Content-type') - self.assertDictEqual( - headers, - { - 'Connection': 'close', - 'Content-Length': str(len(body)), - 'Request-Method': 'POST', - 'Path-Info': '/blah', - 'Request-Uri': '/index.php/blah?var=val', - 'Http-Host': 'localhost', - 'Server-Protocol': 'HTTP/1.1', - 'Custom-Header': 'blah', - }, - 'headers', - ) - self.assertEqual(resp['body'], body, 'body') + assert headers == { + 'Connection': 'close', + 'Content-Length': str(len(body)), + 'Request-Method': 'POST', + 'Path-Info': '/blah', + 'Request-Uri': '/index.php/blah?var=val', + 'Http-Host': 'localhost', + 'Server-Protocol': 'HTTP/1.1', + 'Custom-Header': 'blah', + }, 'headers' + assert resp['body'] == body, 'body' def test_php_application_query_string(self): self.load('query_string') resp = self.get(url='/?var1=val1&var2=val2') - self.assertEqual( - resp['headers']['Query-String'], - 'var1=val1&var2=val2', - 'query string', - ) + assert ( + resp['headers']['Query-String'] == 'var1=val1&var2=val2' + ), 'query string' def test_php_application_query_string_empty(self): self.load('query_string') resp = self.get(url='/?') - self.assertEqual(resp['status'], 200, 'query string empty status') - self.assertEqual( - resp['headers']['Query-String'], '', 'query string empty' - ) + assert resp['status'] == 200, 'query string empty status' + assert resp['headers']['Query-String'] == '', 'query string empty' def test_php_application_query_string_absent(self): self.load('query_string') resp = self.get() - self.assertEqual(resp['status'], 200, 'query string absent status') - self.assertEqual( - resp['headers']['Query-String'], '', 'query string absent' - ) + assert resp['status'] == 200, 'query string absent status' + assert resp['headers']['Query-String'] == '', 'query string absent' def test_php_application_phpinfo(self): self.load('phpinfo') resp = self.get() - self.assertEqual(resp['status'], 200, 'status') - self.assertNotEqual(resp['body'], '', 'body not empty') + assert resp['status'] == 200, 'status' + assert resp['body'] != '', 'body not empty' def test_php_application_header_status(self): self.load('header') - self.assertEqual( + assert ( self.get( headers={ 'Host': 'localhost', 'Connection': 'close', 'X-Header': 'HTTP/1.1 404 Not Found', } - )['status'], - 404, - 'status', - ) + )['status'] + == 404 + ), 'status' - self.assertEqual( + assert ( self.get( headers={ 'Host': 'localhost', 'Connection': 'close', 'X-Header': 'http/1.1 404 Not Found', } - )['status'], - 404, - 'status case insensitive', - ) + )['status'] + == 404 + ), 'status case insensitive' - self.assertEqual( + assert ( self.get( headers={ 'Host': 'localhost', 'Connection': 'close', 'X-Header': 'HTTP/ 404 Not Found', } - )['status'], - 404, - 'status version empty', - ) - + )['status'] + == 404 + ), 'status version empty' def test_php_application_404(self): self.load('404') resp = self.get() - self.assertEqual(resp['status'], 404, '404 status') - self.assertRegex( - resp['body'], r'<title>404 Not Found</title>', '404 body' - ) + assert resp['status'] == 404, '404 status' + assert re.search( + r'<title>404 Not Found</title>', resp['body'] + ), '404 body' def test_php_application_keepalive_body(self): self.load('mirror') - self.assertEqual(self.get()['status'], 200, 'init') + assert self.get()['status'] == 200, 'init' body = '0123456789' * 500 (resp, sock) = self.post( @@ -197,7 +172,7 @@ class TestPHPApplication(TestApplicationPHP): read_timeout=1, ) - self.assertEqual(resp['body'], body, 'keep-alive 1') + assert resp['body'] == body, 'keep-alive 1' body = '0123456789' resp = self.post( @@ -210,22 +185,22 @@ class TestPHPApplication(TestApplicationPHP): body=body, ) - self.assertEqual(resp['body'], body, 'keep-alive 2') + assert resp['body'] == body, 'keep-alive 2' def test_php_application_conditional(self): self.load('conditional') - self.assertRegex(self.get()['body'], r'True', 'conditional true') - self.assertRegex(self.post()['body'], r'False', 'conditional false') + assert re.search(r'True', self.get()['body']), 'conditional true' + assert re.search(r'False', self.post()['body']), 'conditional false' def test_php_application_get_variables(self): self.load('get_variables') resp = self.get(url='/?var1=val1&var2=&var3') - self.assertEqual(resp['headers']['X-Var-1'], 'val1', 'GET variables') - self.assertEqual(resp['headers']['X-Var-2'], '1', 'GET variables 2') - self.assertEqual(resp['headers']['X-Var-3'], '1', 'GET variables 3') - self.assertEqual(resp['headers']['X-Var-4'], '', 'GET variables 4') + assert resp['headers']['X-Var-1'] == 'val1', 'GET variables' + assert resp['headers']['X-Var-2'] == '', 'GET variables 2' + assert resp['headers']['X-Var-3'] == '', 'GET variables 3' + assert resp['headers']['X-Var-4'] == 'not set', 'GET variables 4' def test_php_application_post_variables(self): self.load('post_variables') @@ -238,9 +213,9 @@ class TestPHPApplication(TestApplicationPHP): }, body='var1=val1&var2=', ) - self.assertEqual(resp['headers']['X-Var-1'], 'val1', 'POST variables') - self.assertEqual(resp['headers']['X-Var-2'], '1', 'POST variables 2') - self.assertEqual(resp['headers']['X-Var-3'], '', 'POST variables 3') + assert resp['headers']['X-Var-1'] == 'val1', 'POST variables' + assert resp['headers']['X-Var-2'] == '', 'POST variables 2' + assert resp['headers']['X-Var-3'] == 'not set', 'POST variables 3' def test_php_application_cookies(self): self.load('cookies') @@ -253,41 +228,32 @@ class TestPHPApplication(TestApplicationPHP): } ) - self.assertEqual(resp['headers']['X-Cookie-1'], 'val', 'cookie') - self.assertEqual(resp['headers']['X-Cookie-2'], 'val2', 'cookie') + assert resp['headers']['X-Cookie-1'] == 'val', 'cookie' + assert resp['headers']['X-Cookie-2'] == 'val2', 'cookie' def test_php_application_ini_precision(self): self.load('ini_precision') - self.assertNotEqual( - self.get()['headers']['X-Precision'], '4', 'ini value default' - ) + assert self.get()['headers']['X-Precision'] != '4', 'ini value default' self.conf( {"file": "ini/php.ini"}, 'applications/ini_precision/options' ) - self.assertEqual( - self.get()['headers']['X-File'], - self.current_dir + '/php/ini_precision/ini/php.ini', - 'ini file', - ) - self.assertEqual( - self.get()['headers']['X-Precision'], '4', 'ini value' - ) + assert ( + self.get()['headers']['X-File'] + == option.test_dir + '/php/ini_precision/ini/php.ini' + ), 'ini file' + assert self.get()['headers']['X-Precision'] == '4', 'ini value' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_php_application_ini_admin_user(self): self.load('ini_precision') - self.assertIn( - 'error', - self.conf( - {"user": {"precision": "4"}, "admin": {"precision": "5"}}, - 'applications/ini_precision/options', - ), - 'ini admin user', - ) + assert 'error' in self.conf( + {"user": {"precision": "4"}, "admin": {"precision": "5"}}, + 'applications/ini_precision/options', + ), 'ini admin user' def test_php_application_ini_admin(self): self.load('ini_precision') @@ -297,9 +263,7 @@ class TestPHPApplication(TestApplicationPHP): 'applications/ini_precision/options', ) - self.assertEqual( - self.get()['headers']['X-Precision'], '5', 'ini value admin' - ) + assert self.get()['headers']['X-Precision'] == '5', 'ini value admin' def test_php_application_ini_user(self): self.load('ini_precision') @@ -309,9 +273,7 @@ class TestPHPApplication(TestApplicationPHP): 'applications/ini_precision/options', ) - self.assertEqual( - self.get()['headers']['X-Precision'], '5', 'ini value user' - ) + assert self.get()['headers']['X-Precision'] == '5', 'ini value user' def test_php_application_ini_user_2(self): self.load('ini_precision') @@ -320,17 +282,13 @@ class TestPHPApplication(TestApplicationPHP): {"file": "ini/php.ini"}, 'applications/ini_precision/options' ) - self.assertEqual( - self.get()['headers']['X-Precision'], '4', 'ini user file' - ) + assert self.get()['headers']['X-Precision'] == '4', 'ini user file' self.conf( {"precision": "5"}, 'applications/ini_precision/options/user' ) - self.assertEqual( - self.get()['headers']['X-Precision'], '5', 'ini value user' - ) + assert self.get()['headers']['X-Precision'] == '5', 'ini value user' def test_php_application_ini_set_admin(self): self.load('ini_precision') @@ -339,11 +297,9 @@ class TestPHPApplication(TestApplicationPHP): {"admin": {"precision": "5"}}, 'applications/ini_precision/options' ) - self.assertEqual( - self.get(url='/?precision=6')['headers']['X-Precision'], - '5', - 'ini set admin', - ) + assert ( + self.get(url='/?precision=6')['headers']['X-Precision'] == '5' + ), 'ini set admin' def test_php_application_ini_set_user(self): self.load('ini_precision') @@ -352,11 +308,9 @@ class TestPHPApplication(TestApplicationPHP): {"user": {"precision": "5"}}, 'applications/ini_precision/options' ) - self.assertEqual( - self.get(url='/?precision=6')['headers']['X-Precision'], - '6', - 'ini set user', - ) + assert ( + self.get(url='/?precision=6')['headers']['X-Precision'] == '6' + ), 'ini set user' def test_php_application_ini_repeat(self): self.load('ini_precision') @@ -365,13 +319,9 @@ class TestPHPApplication(TestApplicationPHP): {"user": {"precision": "5"}}, 'applications/ini_precision/options' ) - self.assertEqual( - self.get()['headers']['X-Precision'], '5', 'ini value' - ) + assert self.get()['headers']['X-Precision'] == '5', 'ini value' - self.assertEqual( - self.get()['headers']['X-Precision'], '5', 'ini value repeat' - ) + assert self.get()['headers']['X-Precision'] == '5', 'ini value repeat' def test_php_application_disable_functions_exec(self): self.load('time_exec') @@ -385,8 +335,8 @@ class TestPHPApplication(TestApplicationPHP): body = self.get()['body'] - self.assertRegex(body, r'time: \d+', 'disable_functions time') - self.assertNotRegex(body, r'exec: \/\w+', 'disable_functions exec') + assert re.search(r'time: \d+', body), 'disable_functions time' + assert not re.search(r'exec: \/\w+', body), 'disable_functions exec' def test_php_application_disable_functions_comma(self): self.load('time_exec') @@ -400,10 +350,12 @@ class TestPHPApplication(TestApplicationPHP): body = self.get()['body'] - self.assertNotRegex(body, r'time: \d+', 'disable_functions comma time') - self.assertNotRegex( - body, r'exec: \/\w+', 'disable_functions comma exec' - ) + assert not re.search( + r'time: \d+', body + ), 'disable_functions comma time' + assert not re.search( + r'exec: \/\w+', body + ), 'disable_functions comma exec' def test_php_application_disable_functions_space(self): self.load('time_exec') @@ -417,10 +369,12 @@ class TestPHPApplication(TestApplicationPHP): body = self.get()['body'] - self.assertNotRegex(body, r'time: \d+', 'disable_functions space time') - self.assertNotRegex( - body, r'exec: \/\w+', 'disable_functions space exec' - ) + assert not re.search( + r'time: \d+', body + ), 'disable_functions space time' + assert not re.search( + r'exec: \/\w+', body + ), 'disable_functions space exec' def test_php_application_disable_functions_user(self): self.load('time_exec') @@ -434,10 +388,10 @@ class TestPHPApplication(TestApplicationPHP): body = self.get()['body'] - self.assertRegex(body, r'time: \d+', 'disable_functions user time') - self.assertNotRegex( - body, r'exec: \/\w+', 'disable_functions user exec' - ) + assert re.search(r'time: \d+', body), 'disable_functions user time' + assert not re.search( + r'exec: \/\w+', body + ), 'disable_functions user exec' def test_php_application_disable_functions_nonexistent(self): self.load('time_exec') @@ -451,187 +405,165 @@ class TestPHPApplication(TestApplicationPHP): body = self.get()['body'] - self.assertRegex( - body, r'time: \d+', 'disable_functions nonexistent time' - ) - self.assertRegex( - body, r'exec: \/\w+', 'disable_functions nonexistent exec' - ) + assert re.search( + r'time: \d+', body + ), 'disable_functions nonexistent time' + assert re.search( + r'exec: \/\w+', body + ), 'disable_functions nonexistent exec' def test_php_application_disable_classes(self): self.load('date_time') - self.assertRegex( - self.get()['body'], r'012345', 'disable_classes before' - ) + assert re.search( + r'012345', self.get()['body'] + ), 'disable_classes before' self.conf( {"admin": {"disable_classes": "DateTime"}}, 'applications/date_time/options', ) - self.assertNotRegex( - self.get()['body'], r'012345', 'disable_classes before' - ) + assert not re.search( + r'012345', self.get()['body'] + ), 'disable_classes before' def test_php_application_disable_classes_user(self): self.load('date_time') - self.assertRegex( - self.get()['body'], r'012345', 'disable_classes before' - ) + assert re.search( + r'012345', self.get()['body'] + ), 'disable_classes before' self.conf( {"user": {"disable_classes": "DateTime"}}, 'applications/date_time/options', ) - self.assertNotRegex( - self.get()['body'], r'012345', 'disable_classes before' - ) + assert not re.search( + r'012345', self.get()['body'] + ), 'disable_classes before' def test_php_application_error_log(self): self.load('error_log') - self.assertEqual(self.get()['status'], 200, 'status') + assert self.get()['status'] == 200, 'status' time.sleep(1) - self.assertEqual(self.get()['status'], 200, 'status 2') + assert self.get()['status'] == 200, 'status 2' self.stop() pattern = r'\d{4}\/\d\d\/\d\d\s\d\d:.+\[notice\].+Error in application' - self.assertIsNotNone(self.wait_for_record(pattern), 'errors print') + assert self.wait_for_record(pattern) is not None, 'errors print' - with open(self.testdir + '/unit.log', 'r', errors='ignore') as f: + with open(self.temp_dir + '/unit.log', 'r', errors='ignore') as f: errs = re.findall(pattern, f.read()) - self.assertEqual(len(errs), 2, 'error_log count') + assert len(errs) == 2, 'error_log count' date = errs[0].split('[')[0] date2 = errs[1].split('[')[0] - self.assertNotEqual(date, date2, 'date diff') + assert date != date2, 'date diff' def test_php_application_script(self): - self.assertIn( - 'success', - self.conf( - { - "listeners": {"*:7080": {"pass": "applications/script"}}, - "applications": { - "script": { - "type": "php", - "processes": {"spare": 0}, - "root": self.current_dir + "/php/script", - "script": "phpinfo.php", - } - }, - } - ), - 'configure script', - ) + assert 'success' in self.conf( + { + "listeners": {"*:7080": {"pass": "applications/script"}}, + "applications": { + "script": { + "type": "php", + "processes": {"spare": 0}, + "root": option.test_dir + "/php/script", + "script": "phpinfo.php", + } + }, + } + ), 'configure script' resp = self.get() - self.assertEqual(resp['status'], 200, 'status') - self.assertNotEqual(resp['body'], '', 'body not empty') + assert resp['status'] == 200, 'status' + assert resp['body'] != '', 'body not empty' def test_php_application_index_default(self): - self.assertIn( - 'success', - self.conf( - { - "listeners": {"*:7080": {"pass": "applications/phpinfo"}}, - "applications": { - "phpinfo": { - "type": "php", - "processes": {"spare": 0}, - "root": self.current_dir + "/php/phpinfo", - } - }, - } - ), - 'configure index default', - ) + assert 'success' in self.conf( + { + "listeners": {"*:7080": {"pass": "applications/phpinfo"}}, + "applications": { + "phpinfo": { + "type": "php", + "processes": {"spare": 0}, + "root": option.test_dir + "/php/phpinfo", + } + }, + } + ), 'configure index default' resp = self.get() - self.assertEqual(resp['status'], 200, 'status') - self.assertNotEqual(resp['body'], '', 'body not empty') + assert resp['status'] == 200, 'status' + assert resp['body'] != '', 'body not empty' def test_php_application_extension_check(self): self.load('phpinfo') - self.assertNotEqual( - self.get(url='/index.wrong')['status'], 200, 'status' - ) + assert self.get(url='/index.wrong')['status'] != 200, 'status' - new_root = self.testdir + "/php" + new_root = self.temp_dir + "/php" os.mkdir(new_root) - shutil.copy(self.current_dir + '/php/phpinfo/index.wrong', new_root) - - self.assertIn( - 'success', - self.conf( - { - "listeners": {"*:7080": {"pass": "applications/phpinfo"}}, - "applications": { - "phpinfo": { - "type": "php", - "processes": {"spare": 0}, - "root": new_root, - "working_directory": new_root, - } - }, - } - ), - 'configure new root', - ) + shutil.copy(option.test_dir + '/php/phpinfo/index.wrong', new_root) + + assert 'success' in self.conf( + { + "listeners": {"*:7080": {"pass": "applications/phpinfo"}}, + "applications": { + "phpinfo": { + "type": "php", + "processes": {"spare": 0}, + "root": new_root, + "working_directory": new_root, + } + }, + } + ), 'configure new root' resp = self.get() - self.assertNotEqual( - str(resp['status']) + resp['body'], '200', 'status new root' - ) + assert str(resp['status']) + resp['body'] != '200', 'status new root' def run_php_application_cwd_root_tests(self): - self.assertIn( - 'success', self.conf_delete('applications/cwd/working_directory') + assert 'success' in self.conf_delete( + 'applications/cwd/working_directory' ) - script_cwd = self.current_dir + '/php/cwd' + script_cwd = option.test_dir + '/php/cwd' resp = self.get() - self.assertEqual(resp['status'], 200, 'status ok') - self.assertEqual(resp['body'], script_cwd, 'default cwd') - - self.assertIn( - 'success', - self.conf( - '"' + self.current_dir + '"', - 'applications/cwd/working_directory', - ), + assert resp['status'] == 200, 'status ok' + assert resp['body'] == script_cwd, 'default cwd' + + assert 'success' in self.conf( + '"' + option.test_dir + '"', 'applications/cwd/working_directory', ) resp = self.get() - self.assertEqual(resp['status'], 200, 'status ok') - self.assertEqual(resp['body'], script_cwd, 'wdir cwd') + assert resp['status'] == 200, 'status ok' + assert resp['body'] == script_cwd, 'wdir cwd' resp = self.get(url='/?chdir=/') - self.assertEqual(resp['status'], 200, 'status ok') - self.assertEqual(resp['body'], '/', 'cwd after chdir') + assert resp['status'] == 200, 'status ok' + assert resp['body'] == '/', 'cwd after chdir' # cwd must be restored resp = self.get() - self.assertEqual(resp['status'], 200, 'status ok') - self.assertEqual(resp['body'], script_cwd, 'cwd restored') + assert resp['status'] == 200, 'status ok' + assert resp['body'] == script_cwd, 'cwd restored' resp = self.get(url='/subdir/') - self.assertEqual( - resp['body'], script_cwd + '/subdir', 'cwd subdir', - ) + assert resp['body'] == script_cwd + '/subdir', 'cwd subdir' def test_php_application_cwd_root(self): self.load('cwd') @@ -650,26 +582,20 @@ class TestPHPApplication(TestApplicationPHP): def run_php_application_cwd_script_tests(self): self.load('cwd') - script_cwd = self.current_dir + '/php/cwd' + script_cwd = option.test_dir + '/php/cwd' - self.assertIn( - 'success', self.conf_delete('applications/cwd/working_directory') + assert 'success' in self.conf_delete( + 'applications/cwd/working_directory' ) - self.assertIn( - 'success', self.conf('"index.php"', 'applications/cwd/script') - ) + assert 'success' in self.conf('"index.php"', 'applications/cwd/script') - self.assertEqual( - self.get()['body'], script_cwd, 'default cwd', - ) + assert self.get()['body'] == script_cwd, 'default cwd' - self.assertEqual( - self.get(url='/?chdir=/')['body'], '/', 'cwd after chdir', - ) + assert self.get(url='/?chdir=/')['body'] == '/', 'cwd after chdir' # cwd must be restored - self.assertEqual(self.get()['body'], script_cwd, 'cwd restored') + assert self.get()['body'] == script_cwd, 'cwd restored' def test_php_application_cwd_script(self): self.load('cwd') @@ -688,14 +614,10 @@ class TestPHPApplication(TestApplicationPHP): def test_php_application_path_relative(self): self.load('open') - self.assertEqual(self.get()['body'], 'test', 'relative path') - - self.assertNotEqual( - self.get(url='/?chdir=/')['body'], 'test', 'relative path w/ chdir' - ) - - self.assertEqual(self.get()['body'], 'test', 'relative path 2') + assert self.get()['body'] == 'test', 'relative path' + assert ( + self.get(url='/?chdir=/')['body'] != 'test' + ), 'relative path w/ chdir' -if __name__ == '__main__': - TestPHPApplication.main() + assert self.get()['body'] == 'test', 'relative path 2' diff --git a/test/test_php_basic.py b/test/test_php_basic.py index 16483c4a..1420ec21 100644 --- a/test/test_php_basic.py +++ b/test/test_php_basic.py @@ -23,133 +23,97 @@ class TestPHPBasic(TestControl): conf = self.conf_get() - self.assertEqual(conf['listeners'], {}, 'listeners') - self.assertEqual( - conf['applications'], - { - "app": { - "type": "php", - "processes": {"spare": 0}, - "root": "/app", - "index": "index.php", - } - }, - 'applications', - ) - - self.assertEqual( - self.conf_get('applications'), - { - "app": { - "type": "php", - "processes": {"spare": 0}, - "root": "/app", - "index": "index.php", - } - }, - 'applications prefix', - ) - - self.assertEqual( - self.conf_get('applications/app'), - { + assert conf['listeners'] == {}, 'listeners' + assert conf['applications'] == { + "app": { "type": "php", "processes": {"spare": 0}, "root": "/app", "index": "index.php", - }, - 'applications prefix 2', - ) + } + }, 'applications' - self.assertEqual(self.conf_get('applications/app/type'), 'php', 'type') - self.assertEqual( - self.conf_get('applications/app/processes/spare'), - 0, - 'spare processes', - ) + assert self.conf_get('applications') == { + "app": { + "type": "php", + "processes": {"spare": 0}, + "root": "/app", + "index": "index.php", + } + }, 'applications prefix' + + assert self.conf_get('applications/app') == { + "type": "php", + "processes": {"spare": 0}, + "root": "/app", + "index": "index.php", + }, 'applications prefix 2' + + assert self.conf_get('applications/app/type') == 'php', 'type' + assert ( + self.conf_get('applications/app/processes/spare') == 0 + ), 'spare processes' def test_php_get_listeners(self): self.conf(self.conf_basic) - self.assertEqual( - self.conf_get()['listeners'], - {"*:7080": {"pass": "applications/app"}}, - 'listeners', - ) + assert self.conf_get()['listeners'] == { + "*:7080": {"pass": "applications/app"} + }, 'listeners' - self.assertEqual( - self.conf_get('listeners'), - {"*:7080": {"pass": "applications/app"}}, - 'listeners prefix', - ) + assert self.conf_get('listeners') == { + "*:7080": {"pass": "applications/app"} + }, 'listeners prefix' - self.assertEqual( - self.conf_get('listeners/*:7080'), - {"pass": "applications/app"}, - 'listeners prefix 2', - ) + assert self.conf_get('listeners/*:7080') == { + "pass": "applications/app" + }, 'listeners prefix 2' def test_php_change_listener(self): self.conf(self.conf_basic) self.conf({"*:7081": {"pass": "applications/app"}}, 'listeners') - self.assertEqual( - self.conf_get('listeners'), - {"*:7081": {"pass": "applications/app"}}, - 'change listener', - ) + assert self.conf_get('listeners') == { + "*:7081": {"pass": "applications/app"} + }, 'change listener' def test_php_add_listener(self): self.conf(self.conf_basic) self.conf({"pass": "applications/app"}, 'listeners/*:7082') - self.assertEqual( - self.conf_get('listeners'), - { - "*:7080": {"pass": "applications/app"}, - "*:7082": {"pass": "applications/app"}, - }, - 'add listener', - ) + assert self.conf_get('listeners') == { + "*:7080": {"pass": "applications/app"}, + "*:7082": {"pass": "applications/app"}, + }, 'add listener' def test_php_change_application(self): self.conf(self.conf_basic) self.conf('30', 'applications/app/processes/max') - self.assertEqual( - self.conf_get('applications/app/processes/max'), - 30, - 'change application max', - ) + assert ( + self.conf_get('applications/app/processes/max') == 30 + ), 'change application max' self.conf('"/www"', 'applications/app/root') - self.assertEqual( - self.conf_get('applications/app/root'), - '/www', - 'change application root', - ) + assert ( + self.conf_get('applications/app/root') == '/www' + ), 'change application root' def test_php_delete(self): self.conf(self.conf_basic) - self.assertIn('error', self.conf_delete('applications/app')) - self.assertIn('success', self.conf_delete('listeners/*:7080')) - self.assertIn('success', self.conf_delete('applications/app')) - self.assertIn('error', self.conf_delete('applications/app')) + assert 'error' in self.conf_delete('applications/app') + assert 'success' in self.conf_delete('listeners/*:7080') + assert 'success' in self.conf_delete('applications/app') + assert 'error' in self.conf_delete('applications/app') def test_php_delete_blocks(self): self.conf(self.conf_basic) - self.assertIn('success', self.conf_delete('listeners')) - self.assertIn('success', self.conf_delete('applications')) - - self.assertIn('success', self.conf(self.conf_app, 'applications')) - self.assertIn( - 'success', - self.conf({"*:7081": {"pass": "applications/app"}}, 'listeners'), - 'applications restore', - ) - + assert 'success' in self.conf_delete('listeners') + assert 'success' in self.conf_delete('applications') -if __name__ == '__main__': - TestPHPBasic.main() + assert 'success' in self.conf(self.conf_app, 'applications') + assert 'success' in self.conf( + {"*:7081": {"pass": "applications/app"}}, 'listeners' + ), 'applications restore' diff --git a/test/test_php_isolation.py b/test/test_php_isolation.py index 1b70ef02..8ab3419a 100644 --- a/test/test_php_isolation.py +++ b/test/test_php_isolation.py @@ -1,5 +1,6 @@ -import unittest +import pytest +from conftest import option from unit.applications.lang.php import TestApplicationPHP from unit.feature.isolation import TestFeatureIsolation @@ -10,48 +11,77 @@ class TestPHPIsolation(TestApplicationPHP): isolation = TestFeatureIsolation() @classmethod - def setUpClass(cls, complete_check=True): - unit = super().setUpClass(complete_check=False) + def setup_class(cls, complete_check=True): + unit = super().setup_class(complete_check=False) - TestFeatureIsolation().check(cls.available, unit.testdir) + TestFeatureIsolation().check(cls.available, unit.temp_dir) return unit if not complete_check else unit.complete() - def test_php_isolation_rootfs(self): + def test_php_isolation_rootfs(self, is_su): isolation_features = self.available['features']['isolation'].keys() if 'mnt' not in isolation_features: - print('requires mnt ns') - raise unittest.SkipTest() + pytest.skip('requires mnt ns') - if not self.is_su: + if not is_su: if 'user' not in isolation_features: - print('requires unprivileged userns or root') - raise unittest.SkipTest() + pytest.skip('requires unprivileged userns or root') if not 'unprivileged_userns_clone' in isolation_features: - print('requires unprivileged userns or root') - raise unittest.SkipTest() + pytest.skip('requires unprivileged userns or root') isolation = { - 'namespaces': {'credential': not self.is_su, 'mount': True}, - 'rootfs': self.current_dir, + 'namespaces': {'credential': not is_su, 'mount': True}, + 'rootfs': option.test_dir, } self.load('phpinfo', isolation=isolation) - self.assertIn( - 'success', self.conf('"/php/phpinfo"', 'applications/phpinfo/root') + assert 'success' in self.conf( + '"/php/phpinfo"', 'applications/phpinfo/root' ) - self.assertIn( - 'success', - self.conf( - '"/php/phpinfo"', 'applications/phpinfo/working_directory' - ), + assert 'success' in self.conf( + '"/php/phpinfo"', 'applications/phpinfo/working_directory' ) - self.assertEqual(self.get()['status'], 200, 'empty rootfs') + assert self.get()['status'] == 200, 'empty rootfs' + def test_php_isolation_rootfs_extensions(self, is_su): + isolation_features = self.available['features']['isolation'].keys() + + if not is_su: + if 'user' not in isolation_features: + pytest.skip('requires unprivileged userns or root') + + if not 'unprivileged_userns_clone' in isolation_features: + pytest.skip('requires unprivileged userns or root') + + if 'mnt' not in isolation_features: + pytest.skip('requires mnt ns') + + isolation = { + 'rootfs': option.test_dir, + 'namespaces': {'credential': not is_su, 'mount': not is_su}, + } + + self.load('list-extensions', isolation=isolation) + + assert 'success' in self.conf( + '"/php/list-extensions"', 'applications/list-extensions/root' + ) + + assert 'success' in self.conf( + {'file': '/php/list-extensions/php.ini'}, + 'applications/list-extensions/options', + ) + + assert 'success' in self.conf( + '"/php/list-extensions"', + 'applications/list-extensions/working_directory', + ) + + extensions = self.getjson()['body'] -if __name__ == '__main__': - TestPHPIsolation.main() + assert 'json' in extensions, 'json in extensions list' + assert 'unit' in extensions, 'unit in extensions list' diff --git a/test/test_php_targets.py b/test/test_php_targets.py index 0657554a..e64cd6b6 100644 --- a/test/test_php_targets.py +++ b/test/test_php_targets.py @@ -1,128 +1,98 @@ +from conftest import option from unit.applications.lang.php import TestApplicationPHP + class TestPHPTargets(TestApplicationPHP): prerequisites = {'modules': {'php': 'any'}} def test_php_application_targets(self): - self.assertIn( - 'success', - self.conf( - { - "listeners": {"*:7080": {"pass": "routes"}}, - "routes": [ - { - "match": {"uri": "/1"}, - "action": {"pass": "applications/targets/1"}, - }, - { - "match": {"uri": "/2"}, - "action": {"pass": "applications/targets/2"}, - }, - {"action": {"pass": "applications/targets/default"}}, - ], - "applications": { + assert 'success' in self.conf( + { + "listeners": {"*:7080": {"pass": "routes"}}, + "routes": [ + { + "match": {"uri": "/1"}, + "action": {"pass": "applications/targets/1"}, + }, + { + "match": {"uri": "/2"}, + "action": {"pass": "applications/targets/2"}, + }, + {"action": {"pass": "applications/targets/default"}}, + ], + "applications": { + "targets": { + "type": "php", + "processes": {"spare": 0}, "targets": { - "type": "php", - "processes": {"spare": 0}, - "targets": { - "1": { - "script": "1.php", - "root": self.current_dir + "/php/targets", - }, - "2": { - "script": "2.php", - "root": self.current_dir - + "/php/targets/2", - }, - "default": { - "index": "index.php", - "root": self.current_dir + "/php/targets", - }, + "1": { + "script": "1.php", + "root": option.test_dir + "/php/targets", }, - } - }, - } - ), + "2": { + "script": "2.php", + "root": option.test_dir + "/php/targets/2", + }, + "default": { + "index": "index.php", + "root": option.test_dir + "/php/targets", + }, + }, + } + }, + } ) - self.assertEqual(self.get(url='/1')['body'], '1') - self.assertEqual(self.get(url='/2')['body'], '2') - self.assertEqual(self.get(url='/blah')['status'], 503) # TODO 404 - self.assertEqual(self.get(url='/')['body'], 'index') + assert self.get(url='/1')['body'] == '1' + assert self.get(url='/2')['body'] == '2' + assert self.get(url='/blah')['status'] == 503 # TODO 404 + assert self.get(url='/')['body'] == 'index' - self.assertIn( - 'success', - self.conf( - "\"1.php\"", 'applications/targets/targets/default/index' - ), - 'change targets index', - ) - self.assertEqual(self.get(url='/')['body'], '1') + assert 'success' in self.conf( + "\"1.php\"", 'applications/targets/targets/default/index' + ), 'change targets index' + assert self.get(url='/')['body'] == '1' - self.assertIn( - 'success', - self.conf_delete('applications/targets/targets/default/index'), - 'remove targets index', - ) - self.assertEqual(self.get(url='/')['body'], 'index') + assert 'success' in self.conf_delete( + 'applications/targets/targets/default/index' + ), 'remove targets index' + assert self.get(url='/')['body'] == 'index' def test_php_application_targets_error(self): - self.assertIn( - 'success', - self.conf( - { - "listeners": { - "*:7080": {"pass": "applications/targets/default"} - }, - "applications": { + assert 'success' in self.conf( + { + "listeners": { + "*:7080": {"pass": "applications/targets/default"} + }, + "applications": { + "targets": { + "type": "php", + "processes": {"spare": 0}, "targets": { - "type": "php", - "processes": {"spare": 0}, - "targets": { - "default": { - "index": "index.php", - "root": self.current_dir + "/php/targets", - }, + "default": { + "index": "index.php", + "root": option.test_dir + "/php/targets", }, - } - }, - } - ), - 'initial configuration', - ) - self.assertEqual(self.get()['status'], 200) - - self.assertIn( - 'error', - self.conf( - {"pass": "applications/targets/blah"}, 'listeners/*:7080' - ), - 'invalid targets pass', - ) - self.assertIn( - 'error', - self.conf( - '"' + self.current_dir + '/php/targets\"', - 'applications/targets/root', - ), - 'invalid root', - ) - self.assertIn( - 'error', - self.conf('"index.php"', 'applications/targets/index'), - 'invalid index', - ) - self.assertIn( - 'error', - self.conf('"index.php"', 'applications/targets/script'), - 'invalid script', - ) - self.assertIn( - 'error', - self.conf_delete('applications/targets/default/root'), - 'root remove', - ) - + }, + } + }, + } + ), 'initial configuration' + assert self.get()['status'] == 200 -if __name__ == '__main__': - TestPHPTargets.main() + assert 'error' in self.conf( + {"pass": "applications/targets/blah"}, 'listeners/*:7080' + ), 'invalid targets pass' + assert 'error' in self.conf( + '"' + option.test_dir + '/php/targets\"', + 'applications/targets/root', + ), 'invalid root' + assert 'error' in self.conf( + '"index.php"', 'applications/targets/index' + ), 'invalid index' + assert 'error' in self.conf( + '"index.php"', 'applications/targets/script' + ), 'invalid script' + assert 'error' in self.conf_delete( + 'applications/targets/default/root' + ), 'root remove' diff --git a/test/test_proxy.py b/test/test_proxy.py index feec1ac4..d02c96a7 100644 --- a/test/test_proxy.py +++ b/test/test_proxy.py @@ -1,8 +1,11 @@ import re import socket import time -import unittest +import pytest + +from conftest import option +from conftest import skip_alert from unit.applications.lang.python import TestApplicationPython @@ -42,7 +45,7 @@ Content-Length: 10 to_send = req - m = re.search('X-Len: (\d+)', data) + m = re.search(r'X-Len: (\d+)', data) if m: to_send += b'X' * int(m.group(1)) @@ -56,145 +59,127 @@ Content-Length: 10 def post_http10(self, *args, **kwargs): return self.post(*args, http_10=True, **kwargs) - def setUp(self): - super().setUp() + def setup_method(self): + super().setup_method() self.run_process(self.run_server, self.SERVER_PORT) self.waitforsocket(self.SERVER_PORT) - self.assertIn( - 'success', - self.conf( - { - "listeners": { - "*:7080": {"pass": "routes"}, - "*:7081": {"pass": "applications/mirror"}, + assert 'success' in self.conf( + { + "listeners": { + "*:7080": {"pass": "routes"}, + "*:7081": {"pass": "applications/mirror"}, + }, + "routes": [{"action": {"proxy": "http://127.0.0.1:7081"}}], + "applications": { + "mirror": { + "type": "python", + "processes": {"spare": 0}, + "path": option.test_dir + "/python/mirror", + "working_directory": option.test_dir + + "/python/mirror", + "module": "wsgi", }, - "routes": [{"action": {"proxy": "http://127.0.0.1:7081"}}], - "applications": { - "mirror": { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir + "/python/mirror", - "working_directory": self.current_dir - + "/python/mirror", - "module": "wsgi", - }, - "custom_header": { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir + "/python/custom_header", - "working_directory": self.current_dir - + "/python/custom_header", - "module": "wsgi", - }, - "delayed": { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir + "/python/delayed", - "working_directory": self.current_dir - + "/python/delayed", - "module": "wsgi", - }, + "custom_header": { + "type": "python", + "processes": {"spare": 0}, + "path": option.test_dir + "/python/custom_header", + "working_directory": option.test_dir + + "/python/custom_header", + "module": "wsgi", }, - } - ), - 'proxy initial configuration', - ) + "delayed": { + "type": "python", + "processes": {"spare": 0}, + "path": option.test_dir + "/python/delayed", + "working_directory": option.test_dir + + "/python/delayed", + "module": "wsgi", + }, + }, + } + ), 'proxy initial configuration' def test_proxy_http10(self): for _ in range(10): - self.assertEqual(self.get_http10()['status'], 200, 'status') + assert self.get_http10()['status'] == 200, 'status' def test_proxy_chain(self): - self.assertIn( - 'success', - self.conf( - { - "listeners": { - "*:7080": {"pass": "routes/first"}, - "*:7081": {"pass": "routes/second"}, - "*:7082": {"pass": "routes/third"}, - "*:7083": {"pass": "routes/fourth"}, - "*:7084": {"pass": "routes/fifth"}, - "*:7085": {"pass": "applications/mirror"}, - }, - "routes": { - "first": [ - {"action": {"proxy": "http://127.0.0.1:7081"}} - ], - "second": [ - {"action": {"proxy": "http://127.0.0.1:7082"}} - ], - "third": [ - {"action": {"proxy": "http://127.0.0.1:7083"}} - ], - "fourth": [ - {"action": {"proxy": "http://127.0.0.1:7084"}} - ], - "fifth": [ - {"action": {"proxy": "http://127.0.0.1:7085"}} - ], - }, - "applications": { - "mirror": { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir + "/python/mirror", - "working_directory": self.current_dir - + "/python/mirror", - "module": "wsgi", - } - }, - } - ), - 'proxy chain configuration', - ) + assert 'success' in self.conf( + { + "listeners": { + "*:7080": {"pass": "routes/first"}, + "*:7081": {"pass": "routes/second"}, + "*:7082": {"pass": "routes/third"}, + "*:7083": {"pass": "routes/fourth"}, + "*:7084": {"pass": "routes/fifth"}, + "*:7085": {"pass": "applications/mirror"}, + }, + "routes": { + "first": [{"action": {"proxy": "http://127.0.0.1:7081"}}], + "second": [{"action": {"proxy": "http://127.0.0.1:7082"}}], + "third": [{"action": {"proxy": "http://127.0.0.1:7083"}}], + "fourth": [{"action": {"proxy": "http://127.0.0.1:7084"}}], + "fifth": [{"action": {"proxy": "http://127.0.0.1:7085"}}], + }, + "applications": { + "mirror": { + "type": "python", + "processes": {"spare": 0}, + "path": option.test_dir + "/python/mirror", + "working_directory": option.test_dir + + "/python/mirror", + "module": "wsgi", + } + }, + } + ), 'proxy chain configuration' - self.assertEqual(self.get_http10()['status'], 200, 'status') + assert self.get_http10()['status'] == 200, 'status' def test_proxy_body(self): payload = '0123456789' for _ in range(10): resp = self.post_http10(body=payload) - self.assertEqual(resp['status'], 200, 'status') - self.assertEqual(resp['body'], payload, 'body') + assert resp['status'] == 200, 'status' + assert resp['body'] == payload, 'body' payload = 'X' * 4096 for _ in range(10): resp = self.post_http10(body=payload) - self.assertEqual(resp['status'], 200, 'status') - self.assertEqual(resp['body'], payload, 'body') + assert resp['status'] == 200, 'status' + assert resp['body'] == payload, 'body' payload = 'X' * 4097 for _ in range(10): resp = self.post_http10(body=payload) - self.assertEqual(resp['status'], 200, 'status') - self.assertEqual(resp['body'], payload, 'body') + assert resp['status'] == 200, 'status' + assert resp['body'] == payload, 'body' payload = 'X' * 4096 * 256 for _ in range(10): resp = self.post_http10(body=payload, read_buffer_size=4096 * 128) - self.assertEqual(resp['status'], 200, 'status') - self.assertEqual(resp['body'], payload, 'body') + assert resp['status'] == 200, 'status' + assert resp['body'] == payload, 'body' payload = 'X' * 4096 * 257 for _ in range(10): resp = self.post_http10(body=payload, read_buffer_size=4096 * 128) - self.assertEqual(resp['status'], 200, 'status') - self.assertEqual(resp['body'], payload, 'body') + assert resp['status'] == 200, 'status' + assert resp['body'] == payload, 'body' self.conf({'http': {'max_body_size': 32 * 1024 * 1024}}, 'settings') payload = '0123456789abcdef' * 32 * 64 * 1024 resp = self.post_http10(body=payload, read_buffer_size=1024 * 1024) - self.assertEqual(resp['status'], 200, 'status') - self.assertEqual(resp['body'], payload, 'body') + assert resp['status'] == 200, 'status' + assert resp['body'] == payload, 'body' def test_proxy_parallel(self): payload = 'X' * 4096 * 257 @@ -216,62 +201,53 @@ Content-Length: 10 resp = self._resp_to_dict(resp) - self.assertEqual(resp['status'], 200, 'status') - self.assertEqual(resp['body'], payload + str(i), 'body') + assert resp['status'] == 200, 'status' + assert resp['body'] == payload + str(i), 'body' def test_proxy_header(self): - self.assertIn( - 'success', - self.conf( - {"pass": "applications/custom_header"}, 'listeners/*:7081' - ), - 'custom_header configure', - ) + assert 'success' in self.conf( + {"pass": "applications/custom_header"}, 'listeners/*:7081' + ), 'custom_header configure' header_value = 'blah' - self.assertEqual( + assert ( self.get_http10( headers={'Host': 'localhost', 'Custom-Header': header_value} - )['headers']['Custom-Header'], - header_value, - 'custom header', - ) + )['headers']['Custom-Header'] + == header_value + ), 'custom header' - header_value = '(),/:;<=>?@[\]{}\t !#$%&\'*+-.^_`|~' - self.assertEqual( + header_value = r'(),/:;<=>?@[\]{}\t !#$%&\'*+-.^_`|~' + assert ( self.get_http10( headers={'Host': 'localhost', 'Custom-Header': header_value} - )['headers']['Custom-Header'], - header_value, - 'custom header 2', - ) + )['headers']['Custom-Header'] + == header_value + ), 'custom header 2' header_value = 'X' * 4096 - self.assertEqual( + assert ( self.get_http10( headers={'Host': 'localhost', 'Custom-Header': header_value} - )['headers']['Custom-Header'], - header_value, - 'custom header 3', - ) + )['headers']['Custom-Header'] + == header_value + ), 'custom header 3' header_value = 'X' * 8191 - self.assertEqual( + assert ( self.get_http10( headers={'Host': 'localhost', 'Custom-Header': header_value} - )['headers']['Custom-Header'], - header_value, - 'custom header 4', - ) + )['headers']['Custom-Header'] + == header_value + ), 'custom header 4' header_value = 'X' * 8192 - self.assertEqual( + assert ( self.get_http10( headers={'Host': 'localhost', 'Custom-Header': header_value} - )['status'], - 431, - 'custom header 5', - ) + )['status'] + == 431 + ), 'custom header 5' def test_proxy_fragmented(self): _, sock = self.http( @@ -286,9 +262,9 @@ Content-Length: 10 sock.sendall("t\r\n\r\n".encode()) - self.assertRegex( - self.recvall(sock).decode(), '200 OK', 'fragmented send' - ) + assert re.search( + '200 OK', self.recvall(sock).decode() + ), 'fragmented send' sock.close() def test_proxy_fragmented_close(self): @@ -328,8 +304,8 @@ Content-Length: 10 resp = self._resp_to_dict(self.recvall(sock).decode()) sock.close() - self.assertEqual(resp['status'], 200, 'status') - self.assertEqual(resp['body'], "X" * 30000, 'body') + assert resp['status'] == 200, 'status' + assert resp['body'] == "X" * 30000, 'body' def test_proxy_fragmented_body_close(self): _, sock = self.http( @@ -349,70 +325,48 @@ Content-Length: 10 sock.close() def test_proxy_nowhere(self): - self.assertIn( - 'success', - self.conf( - [{"action": {"proxy": "http://127.0.0.1:7082"}}], 'routes' - ), - 'proxy path changed', - ) + assert 'success' in self.conf( + [{"action": {"proxy": "http://127.0.0.1:7082"}}], 'routes' + ), 'proxy path changed' - self.assertEqual(self.get_http10()['status'], 502, 'status') + assert self.get_http10()['status'] == 502, 'status' def test_proxy_ipv6(self): - self.assertIn( - 'success', - self.conf( - { - "*:7080": {"pass": "routes"}, - "[::1]:7081": {'application': 'mirror'}, - }, - 'listeners', - ), - 'add ipv6 listener configure', - ) + assert 'success' in self.conf( + { + "*:7080": {"pass": "routes"}, + "[::1]:7081": {'application': 'mirror'}, + }, + 'listeners', + ), 'add ipv6 listener configure' - self.assertIn( - 'success', - self.conf([{"action": {"proxy": "http://[::1]:7081"}}], 'routes'), - 'proxy ipv6 configure', - ) + assert 'success' in self.conf( + [{"action": {"proxy": "http://[::1]:7081"}}], 'routes' + ), 'proxy ipv6 configure' - self.assertEqual(self.get_http10()['status'], 200, 'status') + assert self.get_http10()['status'] == 200, 'status' def test_proxy_unix(self): - addr = self.testdir + '/sock' + addr = self.temp_dir + '/sock' - self.assertIn( - 'success', - self.conf( - { - "*:7080": {"pass": "routes"}, - "unix:" + addr: {'application': 'mirror'}, - }, - 'listeners', - ), - 'add unix listener configure', - ) + assert 'success' in self.conf( + { + "*:7080": {"pass": "routes"}, + "unix:" + addr: {'application': 'mirror'}, + }, + 'listeners', + ), 'add unix listener configure' - self.assertIn( - 'success', - self.conf( - [{"action": {"proxy": 'http://unix:' + addr}}], 'routes' - ), - 'proxy unix configure', - ) + assert 'success' in self.conf( + [{"action": {"proxy": 'http://unix:' + addr}}], 'routes' + ), 'proxy unix configure' - self.assertEqual(self.get_http10()['status'], 200, 'status') + assert self.get_http10()['status'] == 200, 'status' def test_proxy_delayed(self): - self.assertIn( - 'success', - self.conf( - {"pass": "applications/delayed"}, 'listeners/*:7081' - ), - 'delayed configure', - ) + assert 'success' in self.conf( + {"pass": "applications/delayed"}, 'listeners/*:7081' + ), 'delayed configure' body = '0123456789' * 1000 resp = self.post_http10( @@ -426,8 +380,8 @@ Content-Length: 10 body=body, ) - self.assertEqual(resp['status'], 200, 'status') - self.assertEqual(resp['body'], body, 'body') + assert resp['status'] == 200, 'status' + assert resp['body'] == body, 'body' resp = self.post_http10( headers={ @@ -440,17 +394,13 @@ Content-Length: 10 body=body, ) - self.assertEqual(resp['status'], 200, 'status') - self.assertEqual(resp['body'], body, 'body') + assert resp['status'] == 200, 'status' + assert resp['body'] == body, 'body' def test_proxy_delayed_close(self): - self.assertIn( - 'success', - self.conf( - {"pass": "applications/delayed"}, 'listeners/*:7081' - ), - 'delayed configure', - ) + assert 'success' in self.conf( + {"pass": "applications/delayed"}, 'listeners/*:7081' + ), 'delayed configure' _, sock = self.post_http10( headers={ @@ -465,9 +415,7 @@ Content-Length: 10 no_recv=True, ) - self.assertRegex( - sock.recv(100).decode(), '200 OK', 'first' - ) + assert re.search('200 OK', sock.recv(100).decode()), 'first' sock.close() _, sock = self.post_http10( @@ -483,51 +431,42 @@ Content-Length: 10 no_recv=True, ) - self.assertRegex( - sock.recv(100).decode(), '200 OK', 'second' - ) + assert re.search('200 OK', sock.recv(100).decode()), 'second' sock.close() - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_proxy_content_length(self): - self.assertIn( - 'success', - self.conf( - [ - { - "action": { - "proxy": "http://127.0.0.1:" - + str(self.SERVER_PORT) - } + assert 'success' in self.conf( + [ + { + "action": { + "proxy": "http://127.0.0.1:" + str(self.SERVER_PORT) } - ], - 'routes', - ), - 'proxy backend configure', - ) + } + ], + 'routes', + ), 'proxy backend configure' resp = self.get_http10() - self.assertEqual(len(resp['body']), 0, 'body lt Content-Length 0') + assert len(resp['body']) == 0, 'body lt Content-Length 0' resp = self.get_http10(headers={'Host': 'localhost', 'X-Len': '5'}) - self.assertEqual(len(resp['body']), 5, 'body lt Content-Length 5') + assert len(resp['body']) == 5, 'body lt Content-Length 5' resp = self.get_http10(headers={'Host': 'localhost', 'X-Len': '9'}) - self.assertEqual(len(resp['body']), 9, 'body lt Content-Length 9') + assert len(resp['body']) == 9, 'body lt Content-Length 9' resp = self.get_http10(headers={'Host': 'localhost', 'X-Len': '11'}) - self.assertEqual(len(resp['body']), 10, 'body gt Content-Length 11') + assert len(resp['body']) == 10, 'body gt Content-Length 11' resp = self.get_http10(headers={'Host': 'localhost', 'X-Len': '15'}) - self.assertEqual(len(resp['body']), 10, 'body gt Content-Length 15') + assert len(resp['body']) == 10, 'body gt Content-Length 15' def test_proxy_invalid(self): def check_proxy(proxy): - self.assertIn( - 'error', - self.conf([{"action": {"proxy": proxy}}], 'routes'), - 'proxy invalid', - ) + assert 'error' in \ + self.conf([{"action": {"proxy": proxy}}], 'routes'), \ + 'proxy invalid' check_proxy('blah') check_proxy('/blah') @@ -544,12 +483,10 @@ Content-Length: 10 check_proxy('http://[::7080') def test_proxy_loop(self): - self.skip_alerts.extend( - [ - r'socket.*failed', - r'accept.*failed', - r'new connections are not accepted', - ] + skip_alert( + r'socket.*failed', + r'accept.*failed', + r'new connections are not accepted', ) self.conf( { @@ -563,9 +500,8 @@ Content-Length: 10 "mirror": { "type": "python", "processes": {"spare": 0}, - "path": self.current_dir + "/python/mirror", - "working_directory": self.current_dir - + "/python/mirror", + "path": option.test_dir + "/python/mirror", + "working_directory": option.test_dir + "/python/mirror", "module": "wsgi", }, }, @@ -574,6 +510,3 @@ Content-Length: 10 self.get_http10(no_recv=True) self.get_http10(read_timeout=1) - -if __name__ == '__main__': - TestProxy.main() diff --git a/test/test_proxy_chunked.py b/test/test_proxy_chunked.py index f344b69a..26023617 100644 --- a/test/test_proxy_chunked.py +++ b/test/test_proxy_chunked.py @@ -12,7 +12,7 @@ class TestProxyChunked(TestApplicationPython): SERVER_PORT = 7999 @staticmethod - def run_server(server_port, testdir): + def run_server(server_port, temp_dir): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) @@ -51,7 +51,7 @@ class TestProxyChunked(TestApplicationPython): for line in re.split('\r\n', body): add = '' - m1 = re.search('(.*)\sX\s(\d+)', line) + m1 = re.search(r'(.*)\sX\s(\d+)', line) if m1 is not None: add = m1.group(1) * int(m1.group(2)) @@ -81,68 +81,62 @@ class TestProxyChunked(TestApplicationPython): def get_http10(self, *args, **kwargs): return self.get(*args, http_10=True, **kwargs) - def setUp(self): - super().setUp() + def setup_method(self): + super().setup_method() - self.run_process(self.run_server, self.SERVER_PORT, self.testdir) + self.run_process(self.run_server, self.SERVER_PORT, self.temp_dir) self.waitforsocket(self.SERVER_PORT) - self.assertIn( - 'success', - self.conf( - { - "listeners": {"*:7080": {"pass": "routes"},}, - "routes": [ - { - "action": { - "proxy": "http://127.0.0.1:" - + str(self.SERVER_PORT) - } + assert 'success' in self.conf( + { + "listeners": {"*:7080": {"pass": "routes"},}, + "routes": [ + { + "action": { + "proxy": "http://127.0.0.1:" + + str(self.SERVER_PORT) } - ], - } - ), - 'proxy initial configuration', - ) + } + ], + } + ), 'proxy initial configuration' def test_proxy_chunked(self): for _ in range(10): - self.assertEqual( - self.get_http10(body='\r\n\r\n0\r\n\r\n')['status'], 200 - ) + assert self.get_http10(body='\r\n\r\n0\r\n\r\n')['status'] == 200 def test_proxy_chunked_body(self): part = '0123456789abcdef' - self.assertEqual( + assert ( self.get_http10(body=self.chunks([('1000', part + ' X 256')]))[ 'body' - ], - part * 256, + ] + == part * 256 ) - self.assertEqual( + assert ( self.get_http10(body=self.chunks([('100000', part + ' X 65536')]))[ 'body' - ], - part * 65536, + ] + == part * 65536 ) - self.assertEqual( + assert ( self.get_http10( body=self.chunks([('1000000', part + ' X 1048576')]), read_buffer_size=4096 * 4096, - )['body'], - part * 1048576, + )['body'] + == part * 1048576 ) - self.assertEqual( + assert ( self.get_http10( body=self.chunks( [('1000', part + ' X 256'), ('1000', part + ' X 256')] ) - )['body'], - part * 256 * 2, + )['body'] + == part * 256 * 2 ) - self.assertEqual( + assert ( self.get_http10( body=self.chunks( [ @@ -150,10 +144,10 @@ class TestProxyChunked(TestApplicationPython): ('100000', part + ' X 65536'), ] ) - )['body'], - part * 65536 * 2, + )['body'] + == part * 65536 * 2 ) - self.assertEqual( + assert ( self.get_http10( body=self.chunks( [ @@ -162,42 +156,40 @@ class TestProxyChunked(TestApplicationPython): ] ), read_buffer_size=4096 * 4096, - )['body'], - part * 1048576 * 2, + )['body'] + == part * 1048576 * 2 ) def test_proxy_chunked_fragmented(self): part = '0123456789abcdef' - self.assertEqual( + assert ( self.get_http10( body=self.chunks( [('1', hex(i % 16)[2:]) for i in range(4096)] ), - )['body'], - part * 256, + )['body'] + == part * 256 ) def test_proxy_chunked_send(self): - self.assertEqual( - self.get_http10(body='\r\n\r\n@0@\r\n\r\n')['status'], 200 - ) - self.assertEqual( + assert self.get_http10(body='\r\n\r\n@0@\r\n\r\n')['status'] == 200 + assert ( self.get_http10( body='\r@\n\r\n2\r@\na@b\r\n2\r\ncd@\r\n0\r@\n\r\n' - )['body'], - 'abcd', + )['body'] + == 'abcd' ) - self.assertEqual( + assert ( self.get_http10( body='\r\n\r\n2\r#\na#b\r\n##2\r\n#cd\r\n0\r\n#\r#\n' - )['body'], - 'abcd', + )['body'] + == 'abcd' ) def test_proxy_chunked_invalid(self): def check_invalid(body): - self.assertNotEqual(self.get_http10(body=body)['status'], 200) + assert self.get_http10(body=body)['status'] != 200 check_invalid('\r\n\r0') check_invalid('\r\n\r\n\r0') @@ -209,41 +201,38 @@ class TestProxyChunked(TestApplicationPython): check_invalid('\r\n\r\n0\r\nX') resp = self.get_http10(body='\r\n\r\n65#\r\nA X 100') - self.assertEqual(resp['status'], 200, 'incomplete chunk status') - self.assertNotEqual(resp['body'][-5:], '0\r\n\r\n', 'incomplete chunk') + assert resp['status'] == 200, 'incomplete chunk status' + assert resp['body'][-5:] != '0\r\n\r\n', 'incomplete chunk' resp = self.get_http10(body='\r\n\r\n64#\r\nA X 100') - self.assertEqual(resp['status'], 200, 'no zero chunk status') - self.assertNotEqual(resp['body'][-5:], '0\r\n\r\n', 'no zero chunk') + assert resp['status'] == 200, 'no zero chunk status' + assert resp['body'][-5:] != '0\r\n\r\n', 'no zero chunk' - self.assertEqual( - self.get_http10(body='\r\n\r\n80000000\r\nA X 100')['status'], 200, + assert ( + self.get_http10(body='\r\n\r\n80000000\r\nA X 100')['status'] + == 200 ) - self.assertEqual( + assert ( self.get_http10(body='\r\n\r\n10000000000000000\r\nA X 100')[ 'status' - ], - 502, + ] + == 502 ) - self.assertGreaterEqual( + assert ( len( self.get_http10( body='\r\n\r\n1000000\r\nA X 1048576\r\n1000000\r\nA X 100', read_buffer_size=4096 * 4096, )['body'] - ), - 1048576, + ) + >= 1048576 ) - self.assertGreaterEqual( + assert ( len( self.get_http10( body='\r\n\r\n1000000\r\nA X 1048576\r\nXXX\r\nA X 100', read_buffer_size=4096 * 4096, )['body'] - ), - 1048576, + ) + >= 1048576 ) - - -if __name__ == '__main__': - TestProxyChunked.main() diff --git a/test/test_python_application.py b/test/test_python_application.py index 4b8983ff..3e27a24c 100644 --- a/test/test_python_application.py +++ b/test/test_python_application.py @@ -2,8 +2,10 @@ import grp import pwd import re import time -import unittest +import pytest + +from conftest import skip_alert from unit.applications.lang.python import TestApplicationPython @@ -11,7 +13,7 @@ class TestPythonApplication(TestApplicationPython): prerequisites = {'modules': {'python': 'all'}} def findall(self, pattern): - with open(self.testdir + '/unit.log', 'r', errors='ignore') as f: + with open(self.temp_dir + '/unit.log', 'r', errors='ignore') as f: return re.findall(pattern, f.read()) def test_python_application_variables(self): @@ -19,145 +21,123 @@ class TestPythonApplication(TestApplicationPython): body = 'Test body string.' - resp = self.post( - headers={ - 'Host': 'localhost', - 'Content-Type': 'text/html', - 'Custom-Header': 'blah', - 'Connection': 'close', - }, - body=body, + resp = self.http( + b"""POST / HTTP/1.1 +Host: localhost +Content-Length: %d +Custom-Header: blah +Custom-hEader: Blah +Content-Type: text/html +Connection: close +custom-header: BLAH + +%s""" % (len(body), body.encode()), + raw=True, ) - self.assertEqual(resp['status'], 200, 'status') + assert resp['status'] == 200, 'status' headers = resp['headers'] header_server = headers.pop('Server') - self.assertRegex(header_server, r'Unit/[\d\.]+', 'server header') - self.assertEqual( - headers.pop('Server-Software'), - header_server, - 'server software header', - ) + assert re.search(r'Unit/[\d\.]+', header_server), 'server header' + assert ( + headers.pop('Server-Software') == header_server + ), 'server software header' date = headers.pop('Date') - self.assertEqual(date[-4:], ' GMT', 'date header timezone') - self.assertLess( - abs(self.date_to_sec_epoch(date) - self.sec_epoch()), - 5, - 'date header', - ) + assert date[-4:] == ' GMT', 'date header timezone' + assert ( + abs(self.date_to_sec_epoch(date) - self.sec_epoch()) < 5 + ), 'date header' - self.assertDictEqual( - headers, - { - 'Connection': 'close', - 'Content-Length': str(len(body)), - 'Content-Type': 'text/html', - 'Request-Method': 'POST', - 'Request-Uri': '/', - 'Http-Host': 'localhost', - 'Server-Protocol': 'HTTP/1.1', - 'Custom-Header': 'blah', - 'Wsgi-Version': '(1, 0)', - 'Wsgi-Url-Scheme': 'http', - 'Wsgi-Multithread': 'False', - 'Wsgi-Multiprocess': 'True', - 'Wsgi-Run-Once': 'False', - }, - 'headers', - ) - self.assertEqual(resp['body'], body, 'body') + assert headers == { + 'Connection': 'close', + 'Content-Length': str(len(body)), + 'Content-Type': 'text/html', + 'Request-Method': 'POST', + 'Request-Uri': '/', + 'Http-Host': 'localhost', + 'Server-Protocol': 'HTTP/1.1', + 'Custom-Header': 'blah, Blah, BLAH', + 'Wsgi-Version': '(1, 0)', + 'Wsgi-Url-Scheme': 'http', + 'Wsgi-Multithread': 'False', + 'Wsgi-Multiprocess': 'True', + 'Wsgi-Run-Once': 'False', + }, 'headers' + assert resp['body'] == body, 'body' def test_python_application_query_string(self): self.load('query_string') resp = self.get(url='/?var1=val1&var2=val2') - self.assertEqual( - resp['headers']['Query-String'], - 'var1=val1&var2=val2', - 'Query-String header', - ) + assert ( + resp['headers']['Query-String'] == 'var1=val1&var2=val2' + ), 'Query-String header' def test_python_application_query_string_space(self): self.load('query_string') resp = self.get(url='/ ?var1=val1&var2=val2') - self.assertEqual( - resp['headers']['Query-String'], - 'var1=val1&var2=val2', - 'Query-String space', - ) + assert ( + resp['headers']['Query-String'] == 'var1=val1&var2=val2' + ), 'Query-String space' resp = self.get(url='/ %20?var1=val1&var2=val2') - self.assertEqual( - resp['headers']['Query-String'], - 'var1=val1&var2=val2', - 'Query-String space 2', - ) + assert ( + resp['headers']['Query-String'] == 'var1=val1&var2=val2' + ), 'Query-String space 2' resp = self.get(url='/ %20 ?var1=val1&var2=val2') - self.assertEqual( - resp['headers']['Query-String'], - 'var1=val1&var2=val2', - 'Query-String space 3', - ) + assert ( + resp['headers']['Query-String'] == 'var1=val1&var2=val2' + ), 'Query-String space 3' resp = self.get(url='/blah %20 blah? var1= val1 & var2=val2') - self.assertEqual( - resp['headers']['Query-String'], - ' var1= val1 & var2=val2', - 'Query-String space 4', - ) + assert ( + resp['headers']['Query-String'] == ' var1= val1 & var2=val2' + ), 'Query-String space 4' def test_python_application_query_string_empty(self): self.load('query_string') resp = self.get(url='/?') - self.assertEqual(resp['status'], 200, 'query string empty status') - self.assertEqual( - resp['headers']['Query-String'], '', 'query string empty' - ) + assert resp['status'] == 200, 'query string empty status' + assert resp['headers']['Query-String'] == '', 'query string empty' def test_python_application_query_string_absent(self): self.load('query_string') resp = self.get() - self.assertEqual(resp['status'], 200, 'query string absent status') - self.assertEqual( - resp['headers']['Query-String'], '', 'query string absent' - ) + assert resp['status'] == 200, 'query string absent status' + assert resp['headers']['Query-String'] == '', 'query string absent' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_python_application_server_port(self): self.load('server_port') - self.assertEqual( - self.get()['headers']['Server-Port'], '7080', 'Server-Port header' - ) + assert ( + self.get()['headers']['Server-Port'] == '7080' + ), 'Server-Port header' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_python_application_working_directory_invalid(self): self.load('empty') - self.assertIn( - 'success', - self.conf('"/blah"', 'applications/empty/working_directory'), - 'configure invalid working_directory', - ) + assert 'success' in self.conf( + '"/blah"', 'applications/empty/working_directory' + ), 'configure invalid working_directory' - self.assertEqual(self.get()['status'], 500, 'status') + assert self.get()['status'] == 500, 'status' def test_python_application_204_transfer_encoding(self): self.load('204_no_content') - self.assertNotIn( - 'Transfer-Encoding', - self.get()['headers'], - '204 header transfer encoding', - ) + assert ( + 'Transfer-Encoding' not in self.get()['headers'] + ), '204 header transfer encoding' def test_python_application_ctx_iter_atexit(self): self.load('ctx_iter_atexit') @@ -171,21 +151,21 @@ class TestPythonApplication(TestApplicationPython): body='0123456789', ) - self.assertEqual(resp['status'], 200, 'ctx iter status') - self.assertEqual(resp['body'], '0123456789', 'ctx iter body') + assert resp['status'] == 200, 'ctx iter status' + assert resp['body'] == '0123456789', 'ctx iter body' self.conf({"listeners": {}, "applications": {}}) self.stop() - self.assertIsNotNone( - self.wait_for_record(r'RuntimeError'), 'ctx iter atexit' - ) + assert ( + self.wait_for_record(r'RuntimeError') is not None + ), 'ctx iter atexit' def test_python_keepalive_body(self): self.load('mirror') - self.assertEqual(self.get()['status'], 200, 'init') + assert self.get()['status'] == 200, 'init' body = '0123456789' * 500 (resp, sock) = self.post( @@ -199,7 +179,7 @@ class TestPythonApplication(TestApplicationPython): read_timeout=1, ) - self.assertEqual(resp['body'], body, 'keep-alive 1') + assert resp['body'] == body, 'keep-alive 1' body = '0123456789' resp = self.post( @@ -212,19 +192,17 @@ class TestPythonApplication(TestApplicationPython): body=body, ) - self.assertEqual(resp['body'], body, 'keep-alive 2') + assert resp['body'] == body, 'keep-alive 2' def test_python_keepalive_reconfigure(self): - self.skip_alerts.extend( - [ - r'pthread_mutex.+failed', - r'failed to apply', - r'process \d+ exited on signal', - ] + skip_alert( + r'pthread_mutex.+failed', + r'failed to apply', + r'process \d+ exited on signal', ) self.load('mirror') - self.assertEqual(self.get()['status'], 200, 'init') + assert self.get()['status'] == 200, 'init' body = '0123456789' conns = 3 @@ -242,12 +220,10 @@ class TestPythonApplication(TestApplicationPython): read_timeout=1, ) - self.assertEqual(resp['body'], body, 'keep-alive open') - self.assertIn( - 'success', - self.conf(str(i + 1), 'applications/mirror/processes'), - 'reconfigure', - ) + assert resp['body'] == body, 'keep-alive open' + assert 'success' in self.conf( + str(i + 1), 'applications/mirror/processes' + ), 'reconfigure' socks.append(sock) @@ -264,12 +240,10 @@ class TestPythonApplication(TestApplicationPython): read_timeout=1, ) - self.assertEqual(resp['body'], body, 'keep-alive request') - self.assertIn( - 'success', - self.conf(str(i + 1), 'applications/mirror/processes'), - 'reconfigure 2', - ) + assert resp['body'] == body, 'keep-alive request' + assert 'success' in self.conf( + str(i + 1), 'applications/mirror/processes' + ), 'reconfigure 2' for i in range(conns): resp = self.post( @@ -282,17 +256,15 @@ class TestPythonApplication(TestApplicationPython): body=body, ) - self.assertEqual(resp['body'], body, 'keep-alive close') - self.assertIn( - 'success', - self.conf(str(i + 1), 'applications/mirror/processes'), - 'reconfigure 3', - ) + assert resp['body'] == body, 'keep-alive close' + assert 'success' in self.conf( + str(i + 1), 'applications/mirror/processes' + ), 'reconfigure 3' def test_python_keepalive_reconfigure_2(self): self.load('mirror') - self.assertEqual(self.get()['status'], 200, 'init') + assert self.get()['status'] == 200, 'init' body = '0123456789' @@ -307,11 +279,11 @@ class TestPythonApplication(TestApplicationPython): read_timeout=1, ) - self.assertEqual(resp['body'], body, 'reconfigure 2 keep-alive 1') + assert resp['body'] == body, 'reconfigure 2 keep-alive 1' self.load('empty') - self.assertEqual(self.get()['status'], 200, 'init') + assert self.get()['status'] == 200, 'init' (resp, sock) = self.post( headers={ @@ -324,23 +296,21 @@ class TestPythonApplication(TestApplicationPython): body=body, ) - self.assertEqual(resp['status'], 200, 'reconfigure 2 keep-alive 2') - self.assertEqual(resp['body'], '', 'reconfigure 2 keep-alive 2 body') + assert resp['status'] == 200, 'reconfigure 2 keep-alive 2' + assert resp['body'] == '', 'reconfigure 2 keep-alive 2 body' - self.assertIn( - 'success', - self.conf({"listeners": {}, "applications": {}}), - 'reconfigure 2 clear configuration', - ) + assert 'success' in self.conf( + {"listeners": {}, "applications": {}} + ), 'reconfigure 2 clear configuration' resp = self.get(sock=sock) - self.assertEqual(resp, {}, 'reconfigure 2 keep-alive 3') + assert resp == {}, 'reconfigure 2 keep-alive 3' def test_python_keepalive_reconfigure_3(self): self.load('empty') - self.assertEqual(self.get()['status'], 200, 'init') + assert self.get()['status'] == 200, 'init' (_, sock) = self.http( b"""GET / HTTP/1.1 @@ -350,13 +320,11 @@ class TestPythonApplication(TestApplicationPython): no_recv=True, ) - self.assertEqual(self.get()['status'], 200) + assert self.get()['status'] == 200 - self.assertIn( - 'success', - self.conf({"listeners": {}, "applications": {}}), - 'reconfigure 3 clear configuration', - ) + assert 'success' in self.conf( + {"listeners": {}, "applications": {}} + ), 'reconfigure 3 clear configuration' resp = self.http( b"""Host: localhost @@ -367,7 +335,7 @@ Connection: close raw=True, ) - self.assertEqual(resp['status'], 200, 'reconfigure 3') + assert resp['status'] == 200, 'reconfigure 3' def test_python_atexit(self): self.load('atexit') @@ -378,25 +346,24 @@ Connection: close self.stop() - self.assertIsNotNone( - self.wait_for_record(r'At exit called\.'), 'atexit' - ) + assert self.wait_for_record(r'At exit called\.') is not None, 'atexit' def test_python_process_switch(self): self.load('delayed') - self.assertIn( - 'success', - self.conf('2', 'applications/delayed/processes'), - 'configure 2 processes', - ) + assert 'success' in self.conf( + '2', 'applications/delayed/processes' + ), 'configure 2 processes' - self.get(headers={ - 'Host': 'localhost', - 'Content-Length': '0', - 'X-Delay': '5', - 'Connection': 'close', - }, no_recv=True) + self.get( + headers={ + 'Host': 'localhost', + 'Content-Length': '0', + 'X-Delay': '5', + 'Connection': 'close', + }, + no_recv=True, + ) headers_delay_1 = { 'Connection': 'close', @@ -414,11 +381,11 @@ Connection: close self.get(headers=headers_delay_1) - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_python_application_start_response_exit(self): self.load('start_response_exit') - self.assertEqual(self.get()['status'], 500, 'start response exit') + assert self.get()['status'] == 500, 'start response exit' def test_python_application_input_iter(self): self.load('input_iter') @@ -429,10 +396,8 @@ next line last line''' resp = self.post(body=body) - self.assertEqual(resp['body'], body, 'input iter') - self.assertEqual( - resp['headers']['X-Lines-Count'], '4', 'input iter lines' - ) + assert resp['body'] == body, 'input iter' + assert resp['headers']['X-Lines-Count'] == '4', 'input iter lines' def test_python_application_input_readline(self): self.load('input_readline') @@ -443,10 +408,8 @@ next line last line''' resp = self.post(body=body) - self.assertEqual(resp['body'], body, 'input readline') - self.assertEqual( - resp['headers']['X-Lines-Count'], '4', 'input readline lines' - ) + assert resp['body'] == body, 'input readline' + assert resp['headers']['X-Lines-Count'] == '4', 'input readline lines' def test_python_application_input_readline_size(self): self.load('input_readline_size') @@ -456,12 +419,10 @@ next line last line''' - self.assertEqual( - self.post(body=body)['body'], body, 'input readline size' - ) - self.assertEqual( - self.post(body='0123')['body'], '0123', 'input readline size less' - ) + assert self.post(body=body)['body'] == body, 'input readline size' + assert ( + self.post(body='0123')['body'] == '0123' + ), 'input readline size less' def test_python_application_input_readlines(self): self.load('input_readlines') @@ -472,10 +433,8 @@ next line last line''' resp = self.post(body=body) - self.assertEqual(resp['body'], body, 'input readlines') - self.assertEqual( - resp['headers']['X-Lines-Count'], '4', 'input readlines lines' - ) + assert resp['body'] == body, 'input readlines' + assert resp['headers']['X-Lines-Count'] == '4', 'input readlines lines' def test_python_application_input_readlines_huge(self): self.load('input_readlines') @@ -489,11 +448,9 @@ last line: 987654321 * 512 ) - self.assertEqual( - self.post(body=body, read_buffer_size=16384)['body'], - body, - 'input readlines huge', - ) + assert ( + self.post(body=body, read_buffer_size=16384)['body'] == body + ), 'input readlines huge' def test_python_application_input_read_length(self): self.load('input_read_length') @@ -509,7 +466,7 @@ last line: 987654321 body=body, ) - self.assertEqual(resp['body'], body[:5], 'input read length lt body') + assert resp['body'] == body[:5], 'input read length lt body' resp = self.post( headers={ @@ -520,7 +477,7 @@ last line: 987654321 body=body, ) - self.assertEqual(resp['body'], body, 'input read length gt body') + assert resp['body'] == body, 'input read length gt body' resp = self.post( headers={ @@ -531,7 +488,7 @@ last line: 987654321 body=body, ) - self.assertEqual(resp['body'], '', 'input read length zero') + assert resp['body'] == '', 'input read length zero' resp = self.post( headers={ @@ -542,9 +499,9 @@ last line: 987654321 body=body, ) - self.assertEqual(resp['body'], body, 'input read length negative') + assert resp['body'] == body, 'input read length negative' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_python_application_errors_write(self): self.load('errors_write') @@ -552,43 +509,41 @@ last line: 987654321 self.stop() - self.assertIsNotNone( - self.wait_for_record(r'\[error\].+Error in application\.'), - 'errors write', - ) + assert ( + self.wait_for_record(r'\[error\].+Error in application\.') + is not None + ), 'errors write' def test_python_application_body_array(self): self.load('body_array') - self.assertEqual(self.get()['body'], '0123456789', 'body array') + assert self.get()['body'] == '0123456789', 'body array' def test_python_application_body_io(self): self.load('body_io') - self.assertEqual(self.get()['body'], '0123456789', 'body io') + assert self.get()['body'] == '0123456789', 'body io' def test_python_application_body_io_file(self): self.load('body_io_file') - self.assertEqual(self.get()['body'], 'body\n', 'body io file') + assert self.get()['body'] == 'body\n', 'body io file' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_python_application_syntax_error(self): - self.skip_alerts.append(r'Python failed to import module "wsgi"') + skip_alert(r'Python failed to import module "wsgi"') self.load('syntax_error') - self.assertEqual(self.get()['status'], 500, 'syntax error') + assert self.get()['status'] == 500, 'syntax error' def test_python_application_loading_error(self): - self.skip_alerts.append(r'Python failed to import module "blah"') + skip_alert(r'Python failed to import module "blah"') self.load('empty') - self.assertIn( - 'success', self.conf('"blah"', 'applications/empty/module'), - ) + assert 'success' in self.conf('"blah"', 'applications/empty/module') - self.assertEqual(self.get()['status'], 503, 'loading error') + assert self.get()['status'] == 503, 'loading error' def test_python_application_close(self): self.load('close') @@ -597,7 +552,7 @@ last line: 987654321 self.stop() - self.assertIsNotNone(self.wait_for_record(r'Close called\.'), 'close') + assert self.wait_for_record(r'Close called\.') is not None, 'close' def test_python_application_close_error(self): self.load('close_error') @@ -606,9 +561,9 @@ last line: 987654321 self.stop() - self.assertIsNotNone( - self.wait_for_record(r'Close called\.'), 'close error' - ) + assert ( + self.wait_for_record(r'Close called\.') is not None + ), 'close error' def test_python_application_not_iterable(self): self.load('not_iterable') @@ -617,17 +572,17 @@ last line: 987654321 self.stop() - self.assertIsNotNone( + assert ( self.wait_for_record( r'\[error\].+the application returned not an iterable object' - ), - 'not iterable', - ) + ) + is not None + ), 'not iterable' def test_python_application_write(self): self.load('write') - self.assertEqual(self.get()['body'], '0123456789', 'write') + assert self.get()['body'] == '0123456789', 'write' def test_python_application_threading(self): """wait_for_record() timeouts after 5s while every thread works at @@ -639,9 +594,9 @@ last line: 987654321 for _ in range(10): self.get(no_recv=True) - self.assertIsNotNone( - self.wait_for_record(r'\(5\) Thread: 100'), 'last thread finished' - ) + assert ( + self.wait_for_record(r'\(5\) Thread: 100') is not None + ), 'last thread finished' def test_python_application_iter_exception(self): self.load('iter_exception') @@ -656,43 +611,38 @@ last line: 987654321 'Connection': 'close', } ) - self.assertEqual(resp['status'], 200, 'status') - self.assertEqual(resp['body'], 'XXXXXXX', 'body') + assert resp['status'] == 200, 'status' + assert resp['body'] == 'XXXXXXX', 'body' # Exception before start_response(). - self.assertEqual(self.get()['status'], 503, 'error') + assert self.get()['status'] == 503, 'error' - self.assertIsNotNone(self.wait_for_record(r'Traceback'), 'traceback') - self.assertIsNotNone( - self.wait_for_record(r'raise Exception\(\'first exception\'\)'), - 'first exception raise', - ) - self.assertEqual( - len(self.findall(r'Traceback')), 1, 'traceback count 1' - ) + assert self.wait_for_record(r'Traceback') is not None, 'traceback' + assert ( + self.wait_for_record(r'raise Exception\(\'first exception\'\)') + is not None + ), 'first exception raise' + assert len(self.findall(r'Traceback')) == 1, 'traceback count 1' # Exception after start_response(), before first write(). - self.assertEqual( + assert ( self.get( headers={ 'Host': 'localhost', 'X-Skip': '1', 'Connection': 'close', } - )['status'], - 503, - 'error 2', - ) + )['status'] + == 503 + ), 'error 2' - self.assertIsNotNone( - self.wait_for_record(r'raise Exception\(\'second exception\'\)'), - 'exception raise second', - ) - self.assertEqual( - len(self.findall(r'Traceback')), 2, 'traceback count 2' - ) + assert ( + self.wait_for_record(r'raise Exception\(\'second exception\'\)') + is not None + ), 'exception raise second' + assert len(self.findall(r'Traceback')) == 2, 'traceback count 2' # Exception after first write(), before first __next__(). @@ -705,15 +655,13 @@ last line: 987654321 start=True, ) - self.assertIsNotNone( - self.wait_for_record(r'raise Exception\(\'third exception\'\)'), - 'exception raise third', - ) - self.assertEqual( - len(self.findall(r'Traceback')), 3, 'traceback count 3' - ) + assert ( + self.wait_for_record(r'raise Exception\(\'third exception\'\)') + is not None + ), 'exception raise third' + assert len(self.findall(r'Traceback')) == 3, 'traceback count 3' - self.assertDictEqual(self.get(sock=sock), {}, 'closed connection') + assert self.get(sock=sock) == {}, 'closed connection' # Exception after first write(), before first __next__(), # chunked (incomplete body). @@ -725,13 +673,11 @@ last line: 987654321 'X-Chunked': '1', 'Connection': 'close', }, - raw_resp=True + raw_resp=True, ) if resp: - self.assertNotEqual(resp[-5:], '0\r\n\r\n', 'incomplete body') - self.assertEqual( - len(self.findall(r'Traceback')), 4, 'traceback count 4' - ) + assert resp[-5:] != '0\r\n\r\n', 'incomplete body' + assert len(self.findall(r'Traceback')) == 4, 'traceback count 4' # Exception in __next__(). @@ -744,15 +690,13 @@ last line: 987654321 start=True, ) - self.assertIsNotNone( - self.wait_for_record(r'raise Exception\(\'next exception\'\)'), - 'exception raise next', - ) - self.assertEqual( - len(self.findall(r'Traceback')), 5, 'traceback count 5' - ) + assert ( + self.wait_for_record(r'raise Exception\(\'next exception\'\)') + is not None + ), 'exception raise next' + assert len(self.findall(r'Traceback')) == 5, 'traceback count 5' - self.assertDictEqual(self.get(sock=sock), {}, 'closed connection 2') + assert self.get(sock=sock) == {}, 'closed connection 2' # Exception in __next__(), chunked (incomplete body). @@ -763,40 +707,34 @@ last line: 987654321 'X-Chunked': '1', 'Connection': 'close', }, - raw_resp=True + raw_resp=True, ) if resp: - self.assertNotEqual(resp[-5:], '0\r\n\r\n', 'incomplete body 2') - self.assertEqual( - len(self.findall(r'Traceback')), 6, 'traceback count 6' - ) + assert resp[-5:] != '0\r\n\r\n', 'incomplete body 2' + assert len(self.findall(r'Traceback')) == 6, 'traceback count 6' # Exception before start_response() and in close(). - self.assertEqual( + assert ( self.get( headers={ 'Host': 'localhost', 'X-Not-Skip-Close': '1', 'Connection': 'close', } - )['status'], - 503, - 'error', - ) + )['status'] + == 503 + ), 'error' - self.assertIsNotNone( - self.wait_for_record(r'raise Exception\(\'close exception\'\)'), - 'exception raise close', - ) - self.assertEqual( - len(self.findall(r'Traceback')), 8, 'traceback count 8' - ) + assert ( + self.wait_for_record(r'raise Exception\(\'close exception\'\)') + is not None + ), 'exception raise close' + assert len(self.findall(r'Traceback')) == 8, 'traceback count 8' - def test_python_user_group(self): - if not self.is_su: - print("requires root") - raise unittest.SkipTest() + def test_python_user_group(self, is_su): + if not is_su: + pytest.skip('requires root') nobody_uid = pwd.getpwnam('nobody').pw_uid @@ -811,40 +749,38 @@ last line: 987654321 self.load('user_group') obj = self.getjson()['body'] - self.assertEqual(obj['UID'], nobody_uid, 'nobody uid') - self.assertEqual(obj['GID'], group_id, 'nobody gid') + assert obj['UID'] == nobody_uid, 'nobody uid' + assert obj['GID'] == group_id, 'nobody gid' self.load('user_group', user='nobody') obj = self.getjson()['body'] - self.assertEqual(obj['UID'], nobody_uid, 'nobody uid user=nobody') - self.assertEqual(obj['GID'], group_id, 'nobody gid user=nobody') + assert obj['UID'] == nobody_uid, 'nobody uid user=nobody' + assert obj['GID'] == group_id, 'nobody gid user=nobody' self.load('user_group', user='nobody', group=group) obj = self.getjson()['body'] - self.assertEqual( - obj['UID'], nobody_uid, 'nobody uid user=nobody group=%s' % group + assert obj['UID'] == nobody_uid, ( + 'nobody uid user=nobody group=%s' % group ) - self.assertEqual( - obj['GID'], group_id, 'nobody gid user=nobody group=%s' % group + assert obj['GID'] == group_id, ( + 'nobody gid user=nobody group=%s' % group ) self.load('user_group', group=group) obj = self.getjson()['body'] - self.assertEqual( - obj['UID'], nobody_uid, 'nobody uid group=%s' % group - ) + assert obj['UID'] == nobody_uid, 'nobody uid group=%s' % group - self.assertEqual(obj['GID'], group_id, 'nobody gid group=%s' % group) + assert obj['GID'] == group_id, 'nobody gid group=%s' % group self.load('user_group', user='root') obj = self.getjson()['body'] - self.assertEqual(obj['UID'], 0, 'root uid user=root') - self.assertEqual(obj['GID'], 0, 'root gid user=root') + assert obj['UID'] == 0, 'root uid user=root' + assert obj['GID'] == 0, 'root gid user=root' group = 'root' @@ -858,14 +794,39 @@ last line: 987654321 self.load('user_group', user='root', group='root') obj = self.getjson()['body'] - self.assertEqual(obj['UID'], 0, 'root uid user=root group=root') - self.assertEqual(obj['GID'], 0, 'root gid user=root group=root') + assert obj['UID'] == 0, 'root uid user=root group=root' + assert obj['GID'] == 0, 'root gid user=root group=root' self.load('user_group', group='root') obj = self.getjson()['body'] - self.assertEqual(obj['UID'], nobody_uid, 'root uid group=root') - self.assertEqual(obj['GID'], 0, 'root gid group=root') + assert obj['UID'] == nobody_uid, 'root uid group=root' + assert obj['GID'] == 0, 'root gid group=root' + + def test_python_application_callable(self): + skip_alert(r'Python failed to get "blah" from module') + self.load('callable') + + assert self.get()['status'] == 204, 'default application response' + + assert 'success' in self.conf( + '"app"', 'applications/callable/callable' + ) + + assert self.get()['status'] == 200, 'callable response' + + assert 'success' in self.conf( + '"blah"', 'applications/callable/callable' + ) + + assert self.get()['status'] not in [200, 204], 'callable response inv' + + assert 'success' in self.conf( + '"app"', 'applications/callable/callable' + ) + + assert self.get()['status'] == 200, 'callable response 2' + + assert 'success' in self.conf_delete('applications/callable/callable') -if __name__ == '__main__': - TestPythonApplication.main() + assert self.get()['status'] == 204, 'default response 2' diff --git a/test/test_python_basic.py b/test/test_python_basic.py index d6445ac2..0cc70e51 100644 --- a/test/test_python_basic.py +++ b/test/test_python_basic.py @@ -19,142 +19,104 @@ class TestPythonBasic(TestControl): } def test_python_get_empty(self): - self.assertEqual(self.conf_get(), {'listeners': {}, 'applications': {}}) - self.assertEqual(self.conf_get('listeners'), {}) - self.assertEqual(self.conf_get('applications'), {}) + assert self.conf_get() == {'listeners': {}, 'applications': {}} + assert self.conf_get('listeners') == {} + assert self.conf_get('applications') == {} def test_python_get_applications(self): self.conf(self.conf_app, 'applications') conf = self.conf_get() - self.assertEqual(conf['listeners'], {}, 'listeners') - self.assertEqual( - conf['applications'], - { - "app": { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - } - }, - 'applications', - ) - - self.assertEqual( - self.conf_get('applications'), - { - "app": { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - } - }, - 'applications prefix', - ) - - self.assertEqual( - self.conf_get('applications/app'), - { + assert conf['listeners'] == {}, 'listeners' + assert conf['applications'] == { + "app": { "type": "python", "processes": {"spare": 0}, "path": "/app", "module": "wsgi", - }, - 'applications prefix 2', - ) + } + }, 'applications' - self.assertEqual( - self.conf_get('applications/app/type'), 'python', 'type' - ) - self.assertEqual( - self.conf_get('applications/app/processes/spare'), 0, 'spare' - ) + assert self.conf_get('applications') == { + "app": { + "type": "python", + "processes": {"spare": 0}, + "path": "/app", + "module": "wsgi", + } + }, 'applications prefix' + + assert self.conf_get('applications/app') == { + "type": "python", + "processes": {"spare": 0}, + "path": "/app", + "module": "wsgi", + }, 'applications prefix 2' + + assert self.conf_get('applications/app/type') == 'python', 'type' + assert self.conf_get('applications/app/processes/spare') == 0, 'spare' def test_python_get_listeners(self): self.conf(self.conf_basic) - self.assertEqual( - self.conf_get()['listeners'], - {"*:7080": {"pass": "applications/app"}}, - 'listeners', - ) + assert self.conf_get()['listeners'] == { + "*:7080": {"pass": "applications/app"} + }, 'listeners' - self.assertEqual( - self.conf_get('listeners'), - {"*:7080": {"pass": "applications/app"}}, - 'listeners prefix', - ) + assert self.conf_get('listeners') == { + "*:7080": {"pass": "applications/app"} + }, 'listeners prefix' - self.assertEqual( - self.conf_get('listeners/*:7080'), - {"pass": "applications/app"}, - 'listeners prefix 2', - ) + assert self.conf_get('listeners/*:7080') == { + "pass": "applications/app" + }, 'listeners prefix 2' def test_python_change_listener(self): self.conf(self.conf_basic) self.conf({"*:7081": {"pass": "applications/app"}}, 'listeners') - self.assertEqual( - self.conf_get('listeners'), - {"*:7081": {"pass": "applications/app"}}, - 'change listener', - ) + assert self.conf_get('listeners') == { + "*:7081": {"pass": "applications/app"} + }, 'change listener' def test_python_add_listener(self): self.conf(self.conf_basic) self.conf({"pass": "applications/app"}, 'listeners/*:7082') - self.assertEqual( - self.conf_get('listeners'), - { - "*:7080": {"pass": "applications/app"}, - "*:7082": {"pass": "applications/app"}, - }, - 'add listener', - ) + assert self.conf_get('listeners') == { + "*:7080": {"pass": "applications/app"}, + "*:7082": {"pass": "applications/app"}, + }, 'add listener' def test_python_change_application(self): self.conf(self.conf_basic) self.conf('30', 'applications/app/processes/max') - self.assertEqual( - self.conf_get('applications/app/processes/max'), - 30, - 'change application max', - ) + assert ( + self.conf_get('applications/app/processes/max') == 30 + ), 'change application max' self.conf('"/www"', 'applications/app/path') - self.assertEqual( - self.conf_get('applications/app/path'), - '/www', - 'change application path', - ) + assert ( + self.conf_get('applications/app/path') == '/www' + ), 'change application path' def test_python_delete(self): self.conf(self.conf_basic) - self.assertIn('error', self.conf_delete('applications/app')) - self.assertIn('success', self.conf_delete('listeners/*:7080')) - self.assertIn('success', self.conf_delete('applications/app')) - self.assertIn('error', self.conf_delete('applications/app')) + assert 'error' in self.conf_delete('applications/app') + assert 'success' in self.conf_delete('listeners/*:7080') + assert 'success' in self.conf_delete('applications/app') + assert 'error' in self.conf_delete('applications/app') def test_python_delete_blocks(self): self.conf(self.conf_basic) - self.assertIn('success', self.conf_delete('listeners')) - self.assertIn('success', self.conf_delete('applications')) - - self.assertIn('success', self.conf(self.conf_app, 'applications')) - self.assertIn( - 'success', - self.conf({"*:7081": {"pass": "applications/app"}}, 'listeners'), - 'applications restore', - ) - + assert 'success' in self.conf_delete('listeners') + assert 'success' in self.conf_delete('applications') -if __name__ == '__main__': - TestPythonBasic.main() + assert 'success' in self.conf(self.conf_app, 'applications') + assert 'success' in self.conf( + {"*:7081": {"pass": "applications/app"}}, 'listeners' + ), 'applications restore' diff --git a/test/test_python_environment.py b/test/test_python_environment.py index a03b96e6..2d7d1595 100644 --- a/test/test_python_environment.py +++ b/test/test_python_environment.py @@ -7,97 +7,81 @@ class TestPythonEnvironment(TestApplicationPython): def test_python_environment_name_null(self): self.load('environment') - self.assertIn( - 'error', - self.conf( - {"va\0r": "val1"}, 'applications/environment/environment' - ), - 'name null', - ) + assert 'error' in self.conf( + {"va\0r": "val1"}, 'applications/environment/environment' + ), 'name null' def test_python_environment_name_equals(self): self.load('environment') - self.assertIn( - 'error', - self.conf( - {"var=": "val1"}, 'applications/environment/environment' - ), - 'name equals', - ) + assert 'error' in self.conf( + {"var=": "val1"}, 'applications/environment/environment' + ), 'name equals' def test_python_environment_value_null(self): self.load('environment') - self.assertIn( - 'error', - self.conf( - {"var": "\0val"}, 'applications/environment/environment' - ), - 'value null', - ) + assert 'error' in self.conf( + {"var": "\0val"}, 'applications/environment/environment' + ), 'value null' def test_python_environment_update(self): self.load('environment') self.conf({"var": "val1"}, 'applications/environment/environment') - self.assertEqual( + assert ( self.get( headers={ 'Host': 'localhost', 'X-Variables': 'var', 'Connection': 'close', } - )['body'], - 'val1,', - 'set', - ) + )['body'] + == 'val1,' + ), 'set' self.conf({"var": "val2"}, 'applications/environment/environment') - self.assertEqual( + assert ( self.get( headers={ 'Host': 'localhost', 'X-Variables': 'var', 'Connection': 'close', } - )['body'], - 'val2,', - 'update', - ) + )['body'] + == 'val2,' + ), 'update' def test_python_environment_replace(self): self.load('environment') self.conf({"var1": "val1"}, 'applications/environment/environment') - self.assertEqual( + assert ( self.get( headers={ 'Host': 'localhost', 'X-Variables': 'var1', 'Connection': 'close', } - )['body'], - 'val1,', - 'set', - ) + )['body'] + == 'val1,' + ), 'set' self.conf({"var2": "val2"}, 'applications/environment/environment') - self.assertEqual( + assert ( self.get( headers={ 'Host': 'localhost', 'X-Variables': 'var1,var2', 'Connection': 'close', } - )['body'], - 'val2,', - 'replace', - ) + )['body'] + == 'val2,' + ), 'replace' def test_python_environment_clear(self): self.load('environment') @@ -107,31 +91,29 @@ class TestPythonEnvironment(TestApplicationPython): 'applications/environment/environment', ) - self.assertEqual( + assert ( self.get( headers={ 'Host': 'localhost', 'X-Variables': 'var1,var2', 'Connection': 'close', } - )['body'], - 'val1,val2,', - 'set', - ) + )['body'] + == 'val1,val2,' + ), 'set' self.conf({}, 'applications/environment/environment') - self.assertEqual( + assert ( self.get( headers={ 'Host': 'localhost', 'X-Variables': 'var1,var2', 'Connection': 'close', } - )['body'], - '', - 'clear', - ) + )['body'] + == '' + ), 'clear' def test_python_environment_replace_default(self): self.load('environment') @@ -144,36 +126,30 @@ class TestPythonEnvironment(TestApplicationPython): } )['body'] - self.assertGreater(len(home_default), 1, 'get default') + assert len(home_default) > 1, 'get default' self.conf({"HOME": "/"}, 'applications/environment/environment') - self.assertEqual( + assert ( self.get( headers={ 'Host': 'localhost', 'X-Variables': 'HOME', 'Connection': 'close', } - )['body'], - '/,', - 'replace default', - ) + )['body'] + == '/,' + ), 'replace default' self.conf({}, 'applications/environment/environment') - self.assertEqual( + assert ( self.get( headers={ 'Host': 'localhost', 'X-Variables': 'HOME', 'Connection': 'close', } - )['body'], - home_default, - 'restore default', - ) - - -if __name__ == '__main__': - TestPythonEnvironment.main() + )['body'] + == home_default + ), 'restore default' diff --git a/test/test_python_isolation.py b/test/test_python_isolation.py index 1bed64ba..ac678103 100644 --- a/test/test_python_isolation.py +++ b/test/test_python_isolation.py @@ -1,4 +1,4 @@ -import unittest +import pytest from unit.applications.lang.python import TestApplicationPython from unit.feature.isolation import TestFeatureIsolation @@ -10,70 +10,87 @@ class TestPythonIsolation(TestApplicationPython): isolation = TestFeatureIsolation() @classmethod - def setUpClass(cls, complete_check=True): - unit = super().setUpClass(complete_check=False) + def setup_class(cls, complete_check=True): + unit = super().setup_class(complete_check=False) - TestFeatureIsolation().check(cls.available, unit.testdir) + TestFeatureIsolation().check(cls.available, unit.temp_dir) return unit if not complete_check else unit.complete() - def test_python_isolation_rootfs(self): + def test_python_isolation_rootfs(self, is_su): isolation_features = self.available['features']['isolation'].keys() if 'mnt' not in isolation_features: - print('requires mnt ns') - raise unittest.SkipTest() + pytest.skip('requires mnt ns') - if not self.is_su: + if not is_su: if 'user' not in isolation_features: - print('requires unprivileged userns or root') - raise unittest.SkipTest() + pytest.skip('requires unprivileged userns or root') if not 'unprivileged_userns_clone' in isolation_features: - print('requires unprivileged userns or root') - raise unittest.SkipTest() + pytest.skip('requires unprivileged userns or root') isolation = { - 'namespaces': {'credential': not self.is_su, 'mount': True}, - 'rootfs': self.testdir, + 'namespaces': {'credential': not is_su, 'mount': True}, + 'rootfs': self.temp_dir, } self.load('empty', isolation=isolation) - self.assertEqual(self.get()['status'], 200, 'python rootfs') + assert self.get()['status'] == 200, 'python rootfs' self.load('ns_inspect', isolation=isolation) - self.assertEqual( - self.getjson(url='/?path=' + self.testdir)['body']['FileExists'], - False, - 'testdir does not exists in rootfs', - ) - - self.assertEqual( - self.getjson(url='/?path=/proc/self')['body']['FileExists'], - False, - 'no /proc/self', - ) - - self.assertEqual( - self.getjson(url='/?path=/dev/pts')['body']['FileExists'], - False, - 'no /dev/pts', - ) - - self.assertEqual( - self.getjson(url='/?path=/sys/kernel')['body']['FileExists'], - False, - 'no /sys/kernel', - ) + assert ( + self.getjson(url='/?path=' + self.temp_dir)['body']['FileExists'] + == False + ), 'temp_dir does not exists in rootfs' + + assert ( + self.getjson(url='/?path=/proc/self')['body']['FileExists'] + == False + ), 'no /proc/self' + + assert ( + self.getjson(url='/?path=/dev/pts')['body']['FileExists'] == False + ), 'no /dev/pts' + + assert ( + self.getjson(url='/?path=/sys/kernel')['body']['FileExists'] + == False + ), 'no /sys/kernel' ret = self.getjson(url='/?path=/app/python/ns_inspect') - self.assertEqual( - ret['body']['FileExists'], True, 'application exists in rootfs', - ) + assert ( + ret['body']['FileExists'] == True + ), 'application exists in rootfs' + + def test_python_isolation_rootfs_no_language_deps(self, is_su): + isolation_features = self.available['features']['isolation'].keys() + + if 'mnt' not in isolation_features: + pytest.skip('requires mnt ns') + if not is_su: + if 'user' not in isolation_features: + pytest.skip('requires unprivileged userns or root') + + if not 'unprivileged_userns_clone' in isolation_features: + pytest.skip('requires unprivileged userns or root') + + isolation = { + 'namespaces': {'credential': not is_su, 'mount': True}, + 'rootfs': self.temp_dir, + 'automount': {'language_deps': False} + } + + self.load('empty', isolation=isolation) + + assert (self.get()['status'] != 200), 'disabled language_deps' + + isolation['automount']['language_deps'] = True + + self.load('empty', isolation=isolation) -if __name__ == '__main__': - TestPythonIsolation.main() + assert (self.get()['status'] == 200), 'enabled language_deps' diff --git a/test/test_python_isolation_chroot.py b/test/test_python_isolation_chroot.py index 7761128e..315fee9f 100644 --- a/test/test_python_isolation_chroot.py +++ b/test/test_python_isolation_chroot.py @@ -1,4 +1,4 @@ -import unittest +import pytest from unit.applications.lang.python import TestApplicationPython from unit.feature.isolation import TestFeatureIsolation @@ -7,51 +7,41 @@ from unit.feature.isolation import TestFeatureIsolation class TestPythonIsolation(TestApplicationPython): prerequisites = {'modules': {'python': 'any'}} - def test_python_isolation_chroot(self): - if not self.is_su: - print('requires root') - raise unittest.SkipTest() + def test_python_isolation_chroot(self, is_su): + if not is_su: + pytest.skip('requires root') isolation = { - 'rootfs': self.testdir, + 'rootfs': self.temp_dir, } self.load('empty', isolation=isolation) - self.assertEqual(self.get()['status'], 200, 'python chroot') + assert self.get()['status'] == 200, 'python chroot' self.load('ns_inspect', isolation=isolation) - self.assertEqual( - self.getjson(url='/?path=' + self.testdir)['body']['FileExists'], - False, - 'testdir does not exists in rootfs', - ) - - self.assertEqual( - self.getjson(url='/?path=/proc/self')['body']['FileExists'], - False, - 'no /proc/self', - ) - - self.assertEqual( - self.getjson(url='/?path=/dev/pts')['body']['FileExists'], - False, - 'no /dev/pts', - ) - - self.assertEqual( - self.getjson(url='/?path=/sys/kernel')['body']['FileExists'], - False, - 'no /sys/kernel', - ) + assert ( + self.getjson(url='/?path=' + self.temp_dir)['body']['FileExists'] + == False + ), 'temp_dir does not exists in rootfs' - ret = self.getjson(url='/?path=/app/python/ns_inspect') + assert ( + self.getjson(url='/?path=/proc/self')['body']['FileExists'] + == False + ), 'no /proc/self' + + assert ( + self.getjson(url='/?path=/dev/pts')['body']['FileExists'] == False + ), 'no /dev/pts' - self.assertEqual( - ret['body']['FileExists'], True, 'application exists in rootfs', - ) + assert ( + self.getjson(url='/?path=/sys/kernel')['body']['FileExists'] + == False + ), 'no /sys/kernel' + ret = self.getjson(url='/?path=/app/python/ns_inspect') -if __name__ == '__main__': - TestPythonIsolation.main() + assert ( + ret['body']['FileExists'] == True + ), 'application exists in rootfs' diff --git a/test/test_python_procman.py b/test/test_python_procman.py index c327ab14..8eccae3e 100644 --- a/test/test_python_procman.py +++ b/test/test_python_procman.py @@ -1,7 +1,8 @@ import re import subprocess import time -import unittest + +import pytest from unit.applications.lang.python import TestApplicationPython @@ -9,10 +10,10 @@ from unit.applications.lang.python import TestApplicationPython class TestPythonProcman(TestApplicationPython): prerequisites = {'modules': {'python': 'any'}} - def setUp(self): - super().setUp() + def setup_method(self): + super().setup_method() - self.app_name = "app-" + self.testdir.split('/')[-1] + self.app_name = "app-" + self.temp_dir.split('/')[-1] self.app_proc = 'applications/' + self.app_name + '/processes' self.load('empty', self.app_name) @@ -23,7 +24,7 @@ class TestPythonProcman(TestApplicationPython): pids = set() for m in re.findall('.*' + self.app_name, output.decode()): - pids.add(re.search('^\s*(\d+)', m).group(1)) + pids.add(re.search(r'^\s*(\d+)', m).group(1)) return pids @@ -31,35 +32,35 @@ class TestPythonProcman(TestApplicationPython): if path is None: path = self.app_proc - self.assertIn('success', self.conf(conf, path), 'configure processes') + assert 'success' in self.conf(conf, path), 'configure processes' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_python_processes_idle_timeout_zero(self): self.conf_proc({"spare": 0, "max": 2, "idle_timeout": 0}) self.get() - self.assertEqual(len(self.pids_for_process()), 0, 'idle timeout 0') + assert len(self.pids_for_process()) == 0, 'idle timeout 0' def test_python_prefork(self): self.conf_proc('2') pids = self.pids_for_process() - self.assertEqual(len(pids), 2, 'prefork 2') + assert len(pids) == 2, 'prefork 2' self.get() - self.assertSetEqual(self.pids_for_process(), pids, 'prefork still 2') + assert self.pids_for_process() == pids, 'prefork still 2' self.conf_proc('4') pids = self.pids_for_process() - self.assertEqual(len(pids), 4, 'prefork 4') + assert len(pids) == 4, 'prefork 4' self.get() - self.assertSetEqual(self.pids_for_process(), pids, 'prefork still 4') + assert self.pids_for_process() == pids, 'prefork still 4' self.stop_all() - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_python_prefork_same_processes(self): self.conf_proc('2') pids = self.pids_for_process() @@ -67,25 +68,23 @@ class TestPythonProcman(TestApplicationPython): self.conf_proc('4') pids_new = self.pids_for_process() - self.assertTrue(pids.issubset(pids_new), 'prefork same processes') + assert pids.issubset(pids_new), 'prefork same processes' def test_python_ondemand(self): self.conf_proc({"spare": 0, "max": 8, "idle_timeout": 1}) - self.assertEqual(len(self.pids_for_process()), 0, 'on-demand 0') + assert len(self.pids_for_process()) == 0, 'on-demand 0' self.get() pids = self.pids_for_process() - self.assertEqual(len(pids), 1, 'on-demand 1') + assert len(pids) == 1, 'on-demand 1' self.get() - self.assertSetEqual(self.pids_for_process(), pids, 'on-demand still 1') + assert self.pids_for_process() == pids, 'on-demand still 1' time.sleep(1) - self.assertEqual( - len(self.pids_for_process()), 0, 'on-demand stop idle' - ) + assert len(self.pids_for_process()) == 0, 'on-demand stop idle' self.stop_all() @@ -93,27 +92,25 @@ class TestPythonProcman(TestApplicationPython): self.conf_proc({"spare": 2, "max": 8, "idle_timeout": 1}) pids = self.pids_for_process() - self.assertEqual(len(pids), 2, 'updown 2') + assert len(pids) == 2, 'updown 2' self.get() pids_new = self.pids_for_process() - self.assertEqual(len(pids_new), 3, 'updown 3') - self.assertTrue(pids.issubset(pids_new), 'updown 3 only 1 new') + assert len(pids_new) == 3, 'updown 3' + assert pids.issubset(pids_new), 'updown 3 only 1 new' self.get() - self.assertSetEqual( - self.pids_for_process(), pids_new, 'updown still 3' - ) + assert self.pids_for_process() == pids_new, 'updown still 3' time.sleep(1) pids = self.pids_for_process() - self.assertEqual(len(pids), 2, 'updown stop idle') + assert len(pids) == 2, 'updown stop idle' self.get() pids_new = self.pids_for_process() - self.assertEqual(len(pids_new), 3, 'updown again 3') - self.assertTrue(pids.issubset(pids_new), 'updown again 3 only 1 new') + assert len(pids_new) == 3, 'updown again 3' + assert pids.issubset(pids_new), 'updown again 3 only 1 new' self.stop_all() @@ -121,20 +118,20 @@ class TestPythonProcman(TestApplicationPython): self.conf_proc({"spare": 2, "max": 6, "idle_timeout": 1}) pids = self.pids_for_process() - self.assertEqual(len(pids), 2, 'reconf 2') + assert len(pids) == 2, 'reconf 2' self.get() pids_new = self.pids_for_process() - self.assertEqual(len(pids_new), 3, 'reconf 3') - self.assertTrue(pids.issubset(pids_new), 'reconf 3 only 1 new') + assert len(pids_new) == 3, 'reconf 3' + assert pids.issubset(pids_new), 'reconf 3 only 1 new' self.conf_proc('6', self.app_proc + '/spare') pids = self.pids_for_process() - self.assertEqual(len(pids), 6, 'reconf 6') + assert len(pids) == 6, 'reconf 6' self.get() - self.assertSetEqual(self.pids_for_process(), pids, 'reconf still 6') + assert self.pids_for_process() == pids, 'reconf still 6' self.stop_all() @@ -143,7 +140,7 @@ class TestPythonProcman(TestApplicationPython): self.get() pids = self.pids_for_process() - self.assertEqual(len(pids), 1, 'idle timeout 1') + assert len(pids) == 1, 'idle timeout 1' time.sleep(1) @@ -152,14 +149,12 @@ class TestPythonProcman(TestApplicationPython): time.sleep(1) pids_new = self.pids_for_process() - self.assertEqual(len(pids_new), 1, 'idle timeout still 1') - self.assertSetEqual( - self.pids_for_process(), pids, 'idle timeout still 1 same pid' - ) + assert len(pids_new) == 1, 'idle timeout still 1' + assert self.pids_for_process() == pids, 'idle timeout still 1 same pid' time.sleep(1) - self.assertEqual(len(self.pids_for_process()), 0, 'idle timed out') + assert len(self.pids_for_process()) == 0, 'idle timed out' def test_python_processes_connection_keepalive(self): self.conf_proc({"spare": 0, "max": 6, "idle_timeout": 2}) @@ -169,15 +164,11 @@ class TestPythonProcman(TestApplicationPython): start=True, read_timeout=1, ) - self.assertEqual( - len(self.pids_for_process()), 1, 'keepalive connection 1' - ) + assert len(self.pids_for_process()) == 1, 'keepalive connection 1' time.sleep(2) - self.assertEqual( - len(self.pids_for_process()), 0, 'keepalive connection 0' - ) + assert len(self.pids_for_process()) == 0, 'keepalive connection 0' sock.close() @@ -185,43 +176,29 @@ class TestPythonProcman(TestApplicationPython): self.conf_proc('1') path = '/' + self.app_proc - self.assertIn('error', self.conf_get(path + '/max')) - self.assertIn('error', self.conf_get(path + '/spare')) - self.assertIn('error', self.conf_get(path + '/idle_timeout')) + assert 'error' in self.conf_get(path + '/max') + assert 'error' in self.conf_get(path + '/spare') + assert 'error' in self.conf_get(path + '/idle_timeout') def test_python_processes_invalid(self): - self.assertIn( - 'error', self.conf({"spare": -1}, self.app_proc), 'negative spare', - ) - self.assertIn( - 'error', self.conf({"max": -1}, self.app_proc), 'negative max', - ) - self.assertIn( - 'error', - self.conf({"idle_timeout": -1}, self.app_proc), - 'negative idle_timeout', - ) - self.assertIn( - 'error', - self.conf({"spare": 2}, self.app_proc), - 'spare gt max default', - ) - self.assertIn( - 'error', - self.conf({"spare": 2, "max": 1}, self.app_proc), - 'spare gt max', - ) - self.assertIn( - 'error', - self.conf({"spare": 0, "max": 0}, self.app_proc), - 'max zero', - ) + assert 'error' in self.conf( + {"spare": -1}, self.app_proc + ), 'negative spare' + assert 'error' in self.conf({"max": -1}, self.app_proc), 'negative max' + assert 'error' in self.conf( + {"idle_timeout": -1}, self.app_proc + ), 'negative idle_timeout' + assert 'error' in self.conf( + {"spare": 2}, self.app_proc + ), 'spare gt max default' + assert 'error' in self.conf( + {"spare": 2, "max": 1}, self.app_proc + ), 'spare gt max' + assert 'error' in self.conf( + {"spare": 0, "max": 0}, self.app_proc + ), 'max zero' def stop_all(self): self.conf({"listeners": {}, "applications": {}}) - self.assertEqual(len(self.pids_for_process()), 0, 'stop all') - - -if __name__ == '__main__': - TestPythonProcman.main() + assert len(self.pids_for_process()) == 0, 'stop all' diff --git a/test/test_respawn.py b/test/test_respawn.py index f1c71a20..18b9d535 100644 --- a/test/test_respawn.py +++ b/test/test_respawn.py @@ -2,6 +2,7 @@ import re import subprocess import time +from conftest import skip_alert from unit.applications.lang.python import TestApplicationPython @@ -11,21 +12,20 @@ class TestRespawn(TestApplicationPython): PATTERN_ROUTER = 'unit: router' PATTERN_CONTROLLER = 'unit: controller' - def setUp(self): - super().setUp() + def setup_method(self): + super().setup_method() - self.app_name = "app-" + self.testdir.split('/')[-1] + self.app_name = "app-" + self.temp_dir.split('/')[-1] self.load('empty', self.app_name) - self.assertIn( - 'success', - self.conf('1', 'applications/' + self.app_name + '/processes') + assert 'success' in self.conf( + '1', 'applications/' + self.app_name + '/processes' ) def pid_by_name(self, name): output = subprocess.check_output(['ps', 'ax']).decode() - m = re.search('\s*(\d+).*' + name, output) + m = re.search(r'\s*(\d+).*' + name, output) return m if m is None else m.group(1) def kill_pids(self, *pids): @@ -44,27 +44,26 @@ class TestRespawn(TestApplicationPython): def smoke_test(self): for _ in range(5): - self.assertIn( - 'success', - self.conf('1', 'applications/' + self.app_name + '/processes') + assert 'success' in self.conf( + '1', 'applications/' + self.app_name + '/processes' ) - self.assertEqual(self.get()['status'], 200) + assert self.get()['status'] == 200 # Check if the only one router, controller, # and application processes running. output = subprocess.check_output(['ps', 'ax']).decode() - self.assertEqual(len(re.findall(self.PATTERN_ROUTER, output)), 1) - self.assertEqual(len(re.findall(self.PATTERN_CONTROLLER, output)), 1) - self.assertEqual(len(re.findall(self.app_name, output)), 1) + assert len(re.findall(self.PATTERN_ROUTER, output)) == 1 + assert len(re.findall(self.PATTERN_CONTROLLER, output)) == 1 + assert len(re.findall(self.app_name, output)) == 1 def test_respawn_router(self): pid = self.pid_by_name(self.PATTERN_ROUTER) self.kill_pids(pid) - self.skip_alerts.append(r'process %s exited on signal 9' % pid) + skip_alert(r'process %s exited on signal 9' % pid) - self.assertIsNotNone(self.wait_for_process(self.PATTERN_ROUTER)) + assert self.wait_for_process(self.PATTERN_ROUTER) is not None self.smoke_test() @@ -72,11 +71,11 @@ class TestRespawn(TestApplicationPython): pid = self.pid_by_name(self.PATTERN_CONTROLLER) self.kill_pids(pid) - self.skip_alerts.append(r'process %s exited on signal 9' % pid) + skip_alert(r'process %s exited on signal 9' % pid) - self.assertIsNotNone(self.wait_for_process(self.PATTERN_CONTROLLER)) + assert self.wait_for_process(self.PATTERN_CONTROLLER) is not None - self.assertEqual(self.get()['status'], 200) + assert self.get()['status'] == 200 self.smoke_test() @@ -84,12 +83,8 @@ class TestRespawn(TestApplicationPython): pid = self.pid_by_name(self.app_name) self.kill_pids(pid) - self.skip_alerts.append(r'process %s exited on signal 9' % pid) + skip_alert(r'process %s exited on signal 9' % pid) - self.assertIsNotNone(self.wait_for_process(self.app_name)) + assert self.wait_for_process(self.app_name) is not None self.smoke_test() - - -if __name__ == '__main__': - TestRespawn.main() diff --git a/test/test_return.py b/test/test_return.py index a89d97e6..64050022 100644 --- a/test/test_return.py +++ b/test/test_return.py @@ -6,8 +6,8 @@ from unit.applications.proto import TestApplicationProto class TestReturn(TestApplicationProto): prerequisites = {} - def setUp(self): - super().setUp() + def setup_method(self): + super().setup_method() self._load_conf( { @@ -35,59 +35,61 @@ Connection: close def test_return(self): resp = self.get() - self.assertEqual(resp['status'], 200) - self.assertIn('Server', resp['headers']) - self.assertIn('Date', resp['headers']) - self.assertEqual(resp['headers']['Content-Length'], '0') - self.assertEqual(resp['headers']['Connection'], 'close') - self.assertEqual(resp['body'], '', 'body') + assert resp['status'] == 200 + assert 'Server' in resp['headers'] + assert 'Date' in resp['headers'] + assert resp['headers']['Content-Length'] == '0' + assert resp['headers']['Connection'] == 'close' + assert resp['body'] == '', 'body' resp = self.post(body='blah') - self.assertEqual(resp['status'], 200) - self.assertEqual(resp['body'], '', 'body') + assert resp['status'] == 200 + assert resp['body'] == '', 'body' resp = self.get_resps_sc() - self.assertEqual(len(re.findall('200 OK', resp)), 10) - self.assertEqual(len(re.findall('Connection:', resp)), 1) - self.assertEqual(len(re.findall('Connection: close', resp)), 1) + assert len(re.findall('200 OK', resp)) == 10 + assert len(re.findall('Connection:', resp)) == 1 + assert len(re.findall('Connection: close', resp)) == 1 resp = self.get(http_10=True) - self.assertEqual(resp['status'], 200) - self.assertIn('Server', resp['headers']) - self.assertIn('Date', resp['headers']) - self.assertEqual(resp['headers']['Content-Length'], '0') - self.assertNotIn('Connection', resp['headers']) - self.assertEqual(resp['body'], '', 'body') + assert resp['status'] == 200 + assert 'Server' in resp['headers'] + assert 'Date' in resp['headers'] + assert resp['headers']['Content-Length'] == '0' + assert 'Connection' not in resp['headers'] + assert resp['body'] == '', 'body' def test_return_update(self): - self.assertIn('success', self.conf('0', 'routes/0/action/return')) + assert 'success' in self.conf('0', 'routes/0/action/return') resp = self.get() - self.assertEqual(resp['status'], 0) - self.assertEqual(resp['body'], '') + assert resp['status'] == 0 + assert resp['body'] == '' - self.assertIn('success', self.conf('404', 'routes/0/action/return')) + assert 'success' in self.conf('404', 'routes/0/action/return') resp = self.get() - self.assertEqual(resp['status'], 404) - self.assertNotEqual(resp['body'], '') + assert resp['status'] == 404 + assert resp['body'] != '' - self.assertIn('success', self.conf('598', 'routes/0/action/return')) + assert 'success' in self.conf('598', 'routes/0/action/return') resp = self.get() - self.assertEqual(resp['status'], 598) - self.assertNotEqual(resp['body'], '') + assert resp['status'] == 598 + assert resp['body'] != '' - self.assertIn('success', self.conf('999', 'routes/0/action/return')) + assert 'success' in self.conf('999', 'routes/0/action/return') resp = self.get() - self.assertEqual(resp['status'], 999) - self.assertEqual(resp['body'], '') + assert resp['status'] == 999 + assert resp['body'] == '' def test_return_location(self): reserved = ":/?#[]@!$&'()*+,;=" - unreserved = ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" - "0123456789-._~") + unreserved = ( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789-._~" + ) unsafe = " \"%<>\\^`{|}" unsafe_enc = "%20%22%25%3C%3E%5C%5E%60%7B%7C%7D" @@ -95,15 +97,11 @@ Connection: close if expect is None: expect = location - self.assertIn( - 'success', - self.conf( - {"return": 301, "location": location}, 'routes/0/action' - ), - 'configure location' - ) + assert 'success' in self.conf( + {"return": 301, "location": location}, 'routes/0/action' + ), 'configure location' - self.assertEqual(self.get()['headers']['Location'], expect) + assert self.get()['headers']['Location'] == expect # FAIL: can't specify empty header value. # check_location("") @@ -145,39 +143,29 @@ Connection: close check_location("/%20?%20#%20 ", "/%2520?%2520#%2520%20") def test_return_location_edit(self): - self.assertIn( - 'success', - self.conf( - {"return": 302, "location": "blah"}, 'routes/0/action' - ), - 'configure init location' - ) - self.assertEqual(self.get()['headers']['Location'], 'blah') - - self.assertIn( - 'success', - self.conf_delete('routes/0/action/location'), - 'location delete' - ) - self.assertNotIn('Location', self.get()['headers']) - - self.assertIn( - 'success', - self.conf('"blah"', 'routes/0/action/location'), - 'location restore' - ) - self.assertEqual(self.get()['headers']['Location'], 'blah') - - self.assertIn( - 'error', - self.conf_post('"blah"', 'routes/0/action/location'), - 'location method not allowed' - ) - self.assertEqual(self.get()['headers']['Location'], 'blah') + assert 'success' in self.conf( + {"return": 302, "location": "blah"}, 'routes/0/action' + ), 'configure init location' + assert self.get()['headers']['Location'] == 'blah' + + assert 'success' in self.conf_delete( + 'routes/0/action/location' + ), 'location delete' + assert 'Location' not in self.get()['headers'] + + assert 'success' in self.conf( + '"blah"', 'routes/0/action/location' + ), 'location restore' + assert self.get()['headers']['Location'] == 'blah' + + assert 'error' in self.conf_post( + '"blah"', 'routes/0/action/location' + ), 'location method not allowed' + assert self.get()['headers']['Location'] == 'blah' def test_return_invalid(self): def check_error(conf): - self.assertIn('error', self.conf(conf, 'routes/0/action')) + assert 'error' in self.conf(conf, 'routes/0/action') check_error({"return": "200"}) check_error({"return": []}) @@ -186,13 +174,9 @@ Connection: close check_error({"return": -1}) check_error({"return": 200, "share": "/blah"}) - self.assertIn( - 'error', self.conf('001', 'routes/0/action/return'), 'leading zero' - ) + assert 'error' in self.conf( + '001', 'routes/0/action/return' + ), 'leading zero' check_error({"return": 301, "location": 0}) check_error({"return": 301, "location": []}) - - -if __name__ == '__main__': - TestReturn.main() diff --git a/test/test_routing.py b/test/test_routing.py index 269e8efc..2b528435 100644 --- a/test/test_routing.py +++ b/test/test_routing.py @@ -1,117 +1,104 @@ # -*- coding: utf-8 -*- -import unittest +import pytest +from conftest import option +from conftest import skip_alert from unit.applications.proto import TestApplicationProto class TestRouting(TestApplicationProto): prerequisites = {'modules': {'python': 'any'}} - def setUp(self): - super().setUp() + def setup_method(self): + super().setup_method() - self.assertIn( - 'success', - self.conf( - { - "listeners": {"*:7080": {"pass": "routes"}}, - "routes": [ - { - "match": {"method": "GET"}, - "action": {"return": 200}, - } - ], - "applications": {}, - } - ), - 'routing configure', - ) + assert 'success' in self.conf( + { + "listeners": {"*:7080": {"pass": "routes"}}, + "routes": [ + {"match": {"method": "GET"}, "action": {"return": 200},} + ], + "applications": {}, + } + ), 'routing configure' def route(self, route): return self.conf([route], 'routes') def route_match(self, match): - self.assertIn( - 'success', - self.route({"match": match, "action": {"return": 200}}), - 'route match configure', - ) + assert 'success' in self.route( + {"match": match, "action": {"return": 200}} + ), 'route match configure' def route_match_invalid(self, match): - self.assertIn( - 'error', - self.route({"match": match, "action": {"return": 200}}), - 'route match configure invalid', - ) + assert 'error' in self.route( + {"match": match, "action": {"return": 200}} + ), 'route match configure invalid' def host(self, host, status): - self.assertEqual( - self.get(headers={'Host': host, 'Connection': 'close'})[ - 'status' - ], - status, - 'match host', - ) + assert ( + self.get(headers={'Host': host, 'Connection': 'close'})['status'] + == status + ), 'match host' def cookie(self, cookie, status): - self.assertEqual( + assert ( self.get( headers={ 'Host': 'localhost', 'Cookie': cookie, 'Connection': 'close', }, - )['status'], - status, - 'match cookie', - ) + )['status'] + == status + ), 'match cookie' def test_routes_match_method_positive(self): - self.assertEqual(self.get()['status'], 200, 'GET') - self.assertEqual(self.post()['status'], 404, 'POST') + assert self.get()['status'] == 200, 'GET' + assert self.post()['status'] == 404, 'POST' def test_routes_match_method_positive_many(self): self.route_match({"method": ["GET", "POST"]}) - self.assertEqual(self.get()['status'], 200, 'GET') - self.assertEqual(self.post()['status'], 200, 'POST') - self.assertEqual(self.delete()['status'], 404, 'DELETE') + assert self.get()['status'] == 200, 'GET' + assert self.post()['status'] == 200, 'POST' + assert self.delete()['status'] == 404, 'DELETE' def test_routes_match_method_negative(self): self.route_match({"method": "!GET"}) - self.assertEqual(self.get()['status'], 404, 'GET') - self.assertEqual(self.post()['status'], 200, 'POST') + assert self.get()['status'] == 404, 'GET' + assert self.post()['status'] == 200, 'POST' def test_routes_match_method_negative_many(self): self.route_match({"method": ["!GET", "!POST"]}) - self.assertEqual(self.get()['status'], 404, 'GET') - self.assertEqual(self.post()['status'], 404, 'POST') - self.assertEqual(self.delete()['status'], 200, 'DELETE') + assert self.get()['status'] == 404, 'GET' + assert self.post()['status'] == 404, 'POST' + assert self.delete()['status'] == 200, 'DELETE' def test_routes_match_method_wildcard_left(self): self.route_match({"method": "*ET"}) - self.assertEqual(self.get()['status'], 200, 'GET') - self.assertEqual(self.post()['status'], 404, 'POST') + assert self.get()['status'] == 200, 'GET' + assert self.post()['status'] == 404, 'POST' def test_routes_match_method_wildcard_right(self): self.route_match({"method": "GE*"}) - self.assertEqual(self.get()['status'], 200, 'GET') - self.assertEqual(self.post()['status'], 404, 'POST') + assert self.get()['status'] == 200, 'GET' + assert self.post()['status'] == 404, 'POST' def test_routes_match_method_wildcard_left_right(self): self.route_match({"method": "*GET*"}) - self.assertEqual(self.get()['status'], 200, 'GET') - self.assertEqual(self.post()['status'], 404, 'POST') + assert self.get()['status'] == 200, 'GET' + assert self.post()['status'] == 404, 'POST' def test_routes_match_method_wildcard(self): self.route_match({"method": "*"}) - self.assertEqual(self.get()['status'], 200, 'GET') + assert self.get()['status'] == 200, 'GET' def test_routes_match_invalid(self): self.route_match_invalid({"method": "**"}) @@ -124,32 +111,35 @@ class TestRouting(TestApplicationProto): def test_routes_match_empty_exact(self): self.route_match({"uri": ""}) - self.assertEqual(self.get()['status'], 404) + assert self.get()['status'] == 404 self.route_match({"uri": "/"}) - self.assertEqual(self.get()['status'], 200) - self.assertEqual(self.get(url='/blah')['status'], 404) + assert self.get()['status'] == 200 + assert self.get(url='/blah')['status'] == 404 def test_routes_match_negative(self): self.route_match({"uri": "!"}) - self.assertEqual(self.get()['status'], 404) + assert self.get()['status'] == 200 + + self.route_match({"uri": "!*"}) + assert self.get()['status'] == 404 self.route_match({"uri": "!/"}) - self.assertEqual(self.get()['status'], 404) - self.assertEqual(self.get(url='/blah')['status'], 200) + assert self.get()['status'] == 404 + assert self.get(url='/blah')['status'] == 200 self.route_match({"uri": "!*blah"}) - self.assertEqual(self.get()['status'], 200) - self.assertEqual(self.get(url='/bla')['status'], 200) - self.assertEqual(self.get(url='/blah')['status'], 404) - self.assertEqual(self.get(url='/blah1')['status'], 200) + assert self.get()['status'] == 200 + assert self.get(url='/bla')['status'] == 200 + assert self.get(url='/blah')['status'] == 404 + assert self.get(url='/blah1')['status'] == 200 self.route_match({"uri": "!/blah*1*"}) - self.assertEqual(self.get()['status'], 200) - self.assertEqual(self.get(url='/blah')['status'], 200) - self.assertEqual(self.get(url='/blah1')['status'], 404) - self.assertEqual(self.get(url='/blah12')['status'], 404) - self.assertEqual(self.get(url='/blah2')['status'], 200) + assert self.get()['status'] == 200 + assert self.get(url='/blah')['status'] == 200 + assert self.get(url='/blah1')['status'] == 404 + assert self.get(url='/blah12')['status'] == 404 + assert self.get(url='/blah2')['status'] == 200 def test_routes_match_wildcard_middle(self): self.route_match({"host": "ex*le"}) @@ -162,110 +152,105 @@ class TestRouting(TestApplicationProto): def test_routes_match_method_case_insensitive(self): self.route_match({"method": "get"}) - self.assertEqual(self.get()['status'], 200, 'GET') + assert self.get()['status'] == 200, 'GET' def test_routes_match_wildcard_left_case_insensitive(self): self.route_match({"method": "*get"}) - self.assertEqual(self.get()['status'], 200, 'GET') + assert self.get()['status'] == 200, 'GET' self.route_match({"method": "*et"}) - self.assertEqual(self.get()['status'], 200, 'GET') + assert self.get()['status'] == 200, 'GET' def test_routes_match_wildcard_middle_case_insensitive(self): self.route_match({"method": "g*t"}) - self.assertEqual(self.get()['status'], 200, 'GET') + assert self.get()['status'] == 200, 'GET' def test_routes_match_wildcard_right_case_insensitive(self): self.route_match({"method": "get*"}) - self.assertEqual(self.get()['status'], 200, 'GET') + assert self.get()['status'] == 200, 'GET' self.route_match({"method": "ge*"}) - self.assertEqual(self.get()['status'], 200, 'GET') + assert self.get()['status'] == 200, 'GET' def test_routes_match_wildcard_substring_case_insensitive(self): self.route_match({"method": "*et*"}) - self.assertEqual(self.get()['status'], 200, 'GET') + assert self.get()['status'] == 200, 'GET' def test_routes_match_wildcard_left_case_sensitive(self): self.route_match({"uri": "*blah"}) - self.assertEqual(self.get(url='/blah')['status'], 200, '/blah') - self.assertEqual(self.get(url='/BLAH')['status'], 404, '/BLAH') + assert self.get(url='/blah')['status'] == 200, '/blah' + assert self.get(url='/BLAH')['status'] == 404, '/BLAH' def test_routes_match_wildcard_middle_case_sensitive(self): self.route_match({"uri": "/b*h"}) - self.assertEqual(self.get(url='/blah')['status'], 200, '/blah') - self.assertEqual(self.get(url='/BLAH')['status'], 404, '/BLAH') + assert self.get(url='/blah')['status'] == 200, '/blah' + assert self.get(url='/BLAH')['status'] == 404, '/BLAH' def test_route_match_wildcards_ordered(self): self.route_match({"uri": "/a*x*y*"}) - self.assertEqual(self.get(url='/axy')['status'], 200, '/axy') - self.assertEqual(self.get(url='/ayx')['status'], 404, '/ayx') + assert self.get(url='/axy')['status'] == 200, '/axy' + assert self.get(url='/ayx')['status'] == 404, '/ayx' def test_route_match_wildcards_adjust_start(self): self.route_match({"uri": "/bla*bla*"}) - self.assertEqual(self.get(url='/bla_foo')['status'], 404, '/bla_foo') + assert self.get(url='/bla_foo')['status'] == 404, '/bla_foo' def test_route_match_wildcards_adjust_start_substr(self): self.route_match({"uri": "*bla*bla*"}) - self.assertEqual(self.get(url='/bla_foo')['status'], 404, '/bla_foo') + assert self.get(url='/bla_foo')['status'] == 404, '/bla_foo' def test_route_match_wildcards_adjust_end(self): self.route_match({"uri": "/bla*bla"}) - self.assertEqual(self.get(url='/foo_bla')['status'], 404, '/foo_bla') + assert self.get(url='/foo_bla')['status'] == 404, '/foo_bla' def test_routes_match_wildcard_right_case_sensitive(self): self.route_match({"uri": "/bla*"}) - self.assertEqual(self.get(url='/blah')['status'], 200, '/blah') - self.assertEqual(self.get(url='/BLAH')['status'], 404, '/BLAH') + assert self.get(url='/blah')['status'] == 200, '/blah' + assert self.get(url='/BLAH')['status'] == 404, '/BLAH' def test_routes_match_wildcard_substring_case_sensitive(self): self.route_match({"uri": "*bla*"}) - self.assertEqual(self.get(url='/blah')['status'], 200, '/blah') - self.assertEqual(self.get(url='/BLAH')['status'], 404, '/BLAH') + assert self.get(url='/blah')['status'] == 200, '/blah' + assert self.get(url='/BLAH')['status'] == 404, '/BLAH' def test_routes_match_many_wildcard_substrings_case_sensitive(self): self.route_match({"uri": "*a*B*c*"}) - self.assertEqual(self.get(url='/blah-a-B-c-blah')['status'], 200) - self.assertEqual(self.get(url='/a-B-c')['status'], 200) - self.assertEqual(self.get(url='/aBc')['status'], 200) - self.assertEqual(self.get(url='/aBCaBbc')['status'], 200) - self.assertEqual(self.get(url='/ABc')['status'], 404) + assert self.get(url='/blah-a-B-c-blah')['status'] == 200 + assert self.get(url='/a-B-c')['status'] == 200 + assert self.get(url='/aBc')['status'] == 200 + assert self.get(url='/aBCaBbc')['status'] == 200 + assert self.get(url='/ABc')['status'] == 404 def test_routes_pass_encode(self): def check_pass(path, name): - self.assertIn( - 'success', - self.conf( - { - "listeners": { - "*:7080": {"pass": "applications/" + path} - }, - "applications": { - name: { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir + '/python/empty', - "working_directory": self.current_dir - + '/python/empty', - "module": "wsgi", - } - }, - } - ), + assert 'success' in self.conf( + { + "listeners": {"*:7080": {"pass": "applications/" + path}}, + "applications": { + name: { + "type": "python", + "processes": {"spare": 0}, + "path": option.test_dir + '/python/empty', + "working_directory": option.test_dir + + '/python/empty', + "module": "wsgi", + } + }, + } ) - self.assertEqual(self.get()['status'], 200) + assert self.get()['status'] == 200 check_pass("%25", "%") check_pass("blah%2Fblah", "blah/blah") @@ -273,25 +258,20 @@ class TestRouting(TestApplicationProto): check_pass("%20blah%252Fblah%7E", " blah%2Fblah~") def check_pass_error(path, name): - self.assertIn( - 'error', - self.conf( - { - "listeners": { - "*:7080": {"pass": "applications/" + path} - }, - "applications": { - name: { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir + '/python/empty', - "working_directory": self.current_dir - + '/python/empty', - "module": "wsgi", - } - }, - } - ), + assert 'error' in self.conf( + { + "listeners": {"*:7080": {"pass": "applications/" + path}}, + "applications": { + name: { + "type": "python", + "processes": {"spare": 0}, + "path": option.test_dir + '/python/empty', + "working_directory": option.test_dir + + '/python/empty', + "module": "wsgi", + } + }, + } ) check_pass_error("%", "%") @@ -305,8 +285,8 @@ class TestRouting(TestApplicationProto): "empty": { "type": "python", "processes": {"spare": 0}, - "path": self.current_dir + '/python/empty', - "working_directory": self.current_dir + "path": option.test_dir + '/python/empty', + "working_directory": option.test_dir + '/python/empty', "module": "wsgi", } @@ -314,179 +294,214 @@ class TestRouting(TestApplicationProto): } ) - self.assertEqual(self.get(port=7081)['status'], 200, 'routes absent') + assert self.get(port=7081)['status'] == 200, 'routes absent' def test_routes_pass_invalid(self): - self.assertIn( - 'error', - self.conf({"pass": "routes/blah"}, 'listeners/*:7080'), - 'routes invalid', - ) + assert 'error' in self.conf( + {"pass": "routes/blah"}, 'listeners/*:7080' + ), 'routes invalid' def test_route_empty(self): - self.assertIn( - 'success', - self.conf( - { - "listeners": {"*:7080": {"pass": "routes/main"}}, - "routes": {"main": []}, - "applications": {}, - } - ), - 'route empty configure', - ) + assert 'success' in self.conf( + { + "listeners": {"*:7080": {"pass": "routes/main"}}, + "routes": {"main": []}, + "applications": {}, + } + ), 'route empty configure' - self.assertEqual(self.get()['status'], 404, 'route empty') + assert self.get()['status'] == 404, 'route empty' def test_routes_route_empty(self): - self.assertIn( - 'success', - self.conf({}, 'listeners'), - 'routes empty listeners configure', - ) + assert 'success' in self.conf( + {}, 'listeners' + ), 'routes empty listeners configure' - self.assertIn( - 'success', self.conf({}, 'routes'), 'routes empty configure' - ) + assert 'success' in self.conf({}, 'routes'), 'routes empty configure' def test_routes_route_match_absent(self): - self.assertIn( - 'success', - self.conf([{"action": {"return": 200}}], 'routes'), - 'route match absent configure', - ) + assert 'success' in self.conf( + [{"action": {"return": 200}}], 'routes' + ), 'route match absent configure' - self.assertEqual(self.get()['status'], 200, 'route match absent') + assert self.get()['status'] == 200, 'route match absent' def test_routes_route_action_absent(self): - self.skip_alerts.append(r'failed to apply new conf') + skip_alert(r'failed to apply new conf') + + assert 'error' in self.conf( + [{"match": {"method": "GET"}}], 'routes' + ), 'route pass absent configure' - self.assertIn( - 'error', - self.conf([{"match": {"method": "GET"}}], 'routes'), - 'route pass absent configure', + def test_routes_route_pass(self): + assert 'success' in self.conf( + { + "applications": { + "app": { + "type": "python", + "processes": {"spare": 0}, + "path": "/app", + "module": "wsgi", + } + }, + "upstreams": { + "one": { + "servers": { + "127.0.0.1:7081": {}, + "127.0.0.1:7082": {}, + }, + }, + "two": { + "servers": { + "127.0.0.1:7081": {}, + "127.0.0.1:7082": {}, + }, + }, + }, + } ) - def test_routes_route_pass_absent(self): - self.assertIn( - 'error', - self.conf([{"match": {"method": "GET"}, "action": {}}], 'routes'), - 'route pass absent configure', + assert 'success' in self.conf( + [{"action": {"pass": "routes"}}], 'routes' + ) + assert 'success' in self.conf( + [{"action": {"pass": "applications/app"}}], 'routes' + ) + assert 'success' in self.conf( + [{"action": {"pass": "upstreams/one"}}], 'routes' ) - def test_routes_action_unique(self): - self.assertIn( - 'success', - self.conf( - { - "listeners": { - "*:7080": {"pass": "routes"}, - "*:7081": {"pass": "applications/app"}, + def test_routes_route_pass_absent(self): + assert 'error' in self.conf( + [{"match": {"method": "GET"}, "action": {}}], 'routes' + ), 'route pass absent configure' + + def test_routes_route_pass_invalid(self): + assert 'success' in self.conf( + { + "applications": { + "app": { + "type": "python", + "processes": {"spare": 0}, + "path": "/app", + "module": "wsgi", + } + }, + "upstreams": { + "one": { + "servers": { + "127.0.0.1:7081": {}, + "127.0.0.1:7082": {}, + }, }, - "routes": [{"action": {"proxy": "http://127.0.0.1:7081"}}], - "applications": { - "app": { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - } + "two": { + "servers": { + "127.0.0.1:7081": {}, + "127.0.0.1:7082": {}, + }, }, - } - ), + }, + } ) - self.assertIn( - 'error', - self.conf( - {"proxy": "http://127.0.0.1:7081", "share": self.testdir}, - 'routes/0/action', - ), - 'proxy share', - ) - self.assertIn( - 'error', - self.conf( - { - "proxy": "http://127.0.0.1:7081", - "pass": "applications/app", + assert 'error' in self.conf( + [{"action": {"pass": "blah"}}], 'routes' + ), 'route pass invalid' + assert 'error' in self.conf( + [{"action": {"pass": "routes/blah"}}], 'routes' + ), 'route pass routes invalid' + assert 'error' in self.conf( + [{"action": {"pass": "applications/blah"}}], 'routes' + ), 'route pass applications invalid' + assert 'error' in self.conf( + [{"action": {"pass": "upstreams/blah"}}], 'routes' + ), 'route pass upstreams invalid' + + def test_routes_action_unique(self): + assert 'success' in self.conf( + { + "listeners": { + "*:7080": {"pass": "routes"}, + "*:7081": {"pass": "applications/app"}, }, - 'routes/0/action', - ), - 'proxy pass', - ) - self.assertIn( - 'error', - self.conf( - {"share": self.testdir, "pass": "applications/app"}, - 'routes/0/action', - ), - 'share pass', + "routes": [{"action": {"proxy": "http://127.0.0.1:7081"}}], + "applications": { + "app": { + "type": "python", + "processes": {"spare": 0}, + "path": "/app", + "module": "wsgi", + } + }, + } ) + assert 'error' in self.conf( + {"proxy": "http://127.0.0.1:7081", "share": self.temp_dir}, + 'routes/0/action', + ), 'proxy share' + assert 'error' in self.conf( + {"proxy": "http://127.0.0.1:7081", "pass": "applications/app",}, + 'routes/0/action', + ), 'proxy pass' + assert 'error' in self.conf( + {"share": self.temp_dir, "pass": "applications/app"}, + 'routes/0/action', + ), 'share pass' + def test_routes_rules_two(self): - self.assertIn( - 'success', - self.conf( - [ - {"match": {"method": "GET"}, "action": {"return": 200}}, - {"match": {"method": "POST"}, "action": {"return": 201}}, - ], - 'routes', - ), - 'rules two configure', - ) + assert 'success' in self.conf( + [ + {"match": {"method": "GET"}, "action": {"return": 200}}, + {"match": {"method": "POST"}, "action": {"return": 201}}, + ], + 'routes', + ), 'rules two configure' - self.assertEqual(self.get()['status'], 200, 'rules two match first') - self.assertEqual(self.post()['status'], 201, 'rules two match second') + assert self.get()['status'] == 200, 'rules two match first' + assert self.post()['status'] == 201, 'rules two match second' def test_routes_two(self): - self.assertIn( - 'success', - self.conf( - { - "listeners": {"*:7080": {"pass": "routes/first"}}, - "routes": { - "first": [ - { - "match": {"method": "GET"}, - "action": {"pass": "routes/second"}, - } - ], - "second": [ - { - "match": {"host": "localhost"}, - "action": {"return": 200}, - } - ], - }, - "applications": {}, - } - ), - 'routes two configure', - ) + assert 'success' in self.conf( + { + "listeners": {"*:7080": {"pass": "routes/first"}}, + "routes": { + "first": [ + { + "match": {"method": "GET"}, + "action": {"pass": "routes/second"}, + } + ], + "second": [ + { + "match": {"host": "localhost"}, + "action": {"return": 200}, + } + ], + }, + "applications": {}, + } + ), 'routes two configure' - self.assertEqual(self.get()['status'], 200, 'routes two') + assert self.get()['status'] == 200, 'routes two' def test_routes_match_host_positive(self): self.route_match({"host": "localhost"}) - self.assertEqual(self.get()['status'], 200, 'localhost') + assert self.get()['status'] == 200, 'localhost' self.host('localhost.', 200) self.host('localhost.', 200) self.host('.localhost', 404) self.host('www.localhost', 404) self.host('localhost1', 404) - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_routes_match_host_absent(self): self.route_match({"host": "localhost"}) - self.assertEqual( - self.get(headers={'Connection': 'close'})['status'], - 400, - 'match host absent', - ) + assert ( + self.get(headers={'Connection': 'close'})['status'] == 400 + ), 'match host absent' def test_routes_match_host_ipv4(self): self.route_match({"host": "127.0.0.1"}) @@ -503,13 +518,13 @@ class TestRouting(TestApplicationProto): def test_routes_match_host_positive_many(self): self.route_match({"host": ["localhost", "example.com"]}) - self.assertEqual(self.get()['status'], 200, 'localhost') + assert self.get()['status'] == 200, 'localhost' self.host('example.com', 200) def test_routes_match_host_positive_and_negative(self): self.route_match({"host": ["*example.com", "!www.example.com"]}) - self.assertEqual(self.get()['status'], 404, 'localhost') + assert self.get()['status'] == 404, 'localhost' self.host('example.com', 200) self.host('www.example.com', 404) self.host('!www.example.com', 200) @@ -535,380 +550,278 @@ class TestRouting(TestApplicationProto): self.route_match({"host": ""}) self.host('', 200) - self.assertEqual( - self.get(http_10=True, headers={})['status'], - 200, - 'match host empty 2', - ) - self.assertEqual(self.get()['status'], 404, 'match host empty 3') + assert ( + self.get(http_10=True, headers={})['status'] == 200 + ), 'match host empty 2' + assert self.get()['status'] == 404, 'match host empty 3' def test_routes_match_uri_positive(self): self.route_match({"uri": ["/blah", "/slash/"]}) - self.assertEqual(self.get()['status'], 404, '/') - self.assertEqual(self.get(url='/blah')['status'], 200, '/blah') - self.assertEqual(self.get(url='/blah#foo')['status'], 200, '/blah#foo') - self.assertEqual(self.get(url='/blah?var')['status'], 200, '/blah?var') - self.assertEqual(self.get(url='//blah')['status'], 200, '//blah') - self.assertEqual( - self.get(url='/slash/foo/../')['status'], 200, 'relative' - ) - self.assertEqual(self.get(url='/slash/./')['status'], 200, '/slash/./') - self.assertEqual( - self.get(url='/slash//.//')['status'], 200, 'adjacent slashes' - ) - self.assertEqual(self.get(url='/%')['status'], 400, 'percent') - self.assertEqual(self.get(url='/%1')['status'], 400, 'percent digit') - self.assertEqual(self.get(url='/%A')['status'], 400, 'percent letter') - self.assertEqual( - self.get(url='/slash/.?args')['status'], 200, 'dot args' - ) - self.assertEqual( - self.get(url='/slash/.#frag')['status'], 200, 'dot frag' - ) - self.assertEqual( - self.get(url='/slash/foo/..?args')['status'], - 200, - 'dot dot args', - ) - self.assertEqual( - self.get(url='/slash/foo/..#frag')['status'], - 200, - 'dot dot frag', - ) - self.assertEqual( - self.get(url='/slash/.')['status'], 200, 'trailing dot' - ) - self.assertEqual( - self.get(url='/slash/foo/..')['status'], - 200, - 'trailing dot dot', - ) + assert self.get()['status'] == 404, '/' + assert self.get(url='/blah')['status'] == 200, '/blah' + assert self.get(url='/blah#foo')['status'] == 200, '/blah#foo' + assert self.get(url='/blah?var')['status'] == 200, '/blah?var' + assert self.get(url='//blah')['status'] == 200, '//blah' + assert self.get(url='/slash/foo/../')['status'] == 200, 'relative' + assert self.get(url='/slash/./')['status'] == 200, '/slash/./' + assert self.get(url='/slash//.//')['status'] == 200, 'adjacent slashes' + assert self.get(url='/%')['status'] == 400, 'percent' + assert self.get(url='/%1')['status'] == 400, 'percent digit' + assert self.get(url='/%A')['status'] == 400, 'percent letter' + assert self.get(url='/slash/.?args')['status'] == 200, 'dot args' + assert self.get(url='/slash/.#frag')['status'] == 200, 'dot frag' + assert ( + self.get(url='/slash/foo/..?args')['status'] == 200 + ), 'dot dot args' + assert ( + self.get(url='/slash/foo/..#frag')['status'] == 200 + ), 'dot dot frag' + assert self.get(url='/slash/.')['status'] == 200, 'trailing dot' + assert ( + self.get(url='/slash/foo/..')['status'] == 200 + ), 'trailing dot dot' def test_routes_match_uri_case_sensitive(self): self.route_match({"uri": "/BLAH"}) - self.assertEqual(self.get(url='/blah')['status'], 404, '/blah') - self.assertEqual(self.get(url='/BlaH')['status'], 404, '/BlaH') - self.assertEqual(self.get(url='/BLAH')['status'], 200, '/BLAH') + assert self.get(url='/blah')['status'] == 404, '/blah' + assert self.get(url='/BlaH')['status'] == 404, '/BlaH' + assert self.get(url='/BLAH')['status'] == 200, '/BLAH' def test_routes_match_uri_normalize(self): self.route_match({"uri": "/blah"}) - self.assertEqual( - self.get(url='/%62%6c%61%68')['status'], 200, 'normalize' - ) + assert self.get(url='/%62%6c%61%68')['status'] == 200, 'normalize' def test_routes_match_empty_array(self): self.route_match({"uri": []}) - self.assertEqual(self.get(url='/blah')['status'], 200, 'empty array') + assert self.get(url='/blah')['status'] == 200, 'empty array' def test_routes_reconfigure(self): - self.assertIn('success', self.conf([], 'routes'), 'redefine') - self.assertEqual(self.get()['status'], 404, 'redefine request') + assert 'success' in self.conf([], 'routes'), 'redefine' + assert self.get()['status'] == 404, 'redefine request' - self.assertIn( - 'success', - self.conf([{"action": {"return": 200}}], 'routes'), - 'redefine 2', - ) - self.assertEqual(self.get()['status'], 200, 'redefine request 2') + assert 'success' in self.conf( + [{"action": {"return": 200}}], 'routes' + ), 'redefine 2' + assert self.get()['status'] == 200, 'redefine request 2' - self.assertIn('success', self.conf([], 'routes'), 'redefine 3') - self.assertEqual(self.get()['status'], 404, 'redefine request 3') + assert 'success' in self.conf([], 'routes'), 'redefine 3' + assert self.get()['status'] == 404, 'redefine request 3' - self.assertIn( - 'success', - self.conf( - { - "listeners": {"*:7080": {"pass": "routes/main"}}, - "routes": {"main": [{"action": {"return": 200}}]}, - "applications": {}, - } - ), - 'redefine 4', - ) - self.assertEqual(self.get()['status'], 200, 'redefine request 4') + assert 'success' in self.conf( + { + "listeners": {"*:7080": {"pass": "routes/main"}}, + "routes": {"main": [{"action": {"return": 200}}]}, + "applications": {}, + } + ), 'redefine 4' + assert self.get()['status'] == 200, 'redefine request 4' - self.assertIn( - 'success', self.conf_delete('routes/main/0'), 'redefine 5' - ) - self.assertEqual(self.get()['status'], 404, 'redefine request 5') + assert 'success' in self.conf_delete('routes/main/0'), 'redefine 5' + assert self.get()['status'] == 404, 'redefine request 5' - self.assertIn( - 'success', - self.conf_post({"action": {"return": 200}}, 'routes/main'), - 'redefine 6', - ) - self.assertEqual(self.get()['status'], 200, 'redefine request 6') + assert 'success' in self.conf_post( + {"action": {"return": 200}}, 'routes/main' + ), 'redefine 6' + assert self.get()['status'] == 200, 'redefine request 6' - self.assertIn( - 'error', - self.conf({"action": {"return": 200}}, 'routes/main/2'), - 'redefine 7', - ) - self.assertIn( - 'success', - self.conf({"action": {"return": 201}}, 'routes/main/1'), - 'redefine 8', - ) + assert 'error' in self.conf( + {"action": {"return": 200}}, 'routes/main/2' + ), 'redefine 7' + assert 'success' in self.conf( + {"action": {"return": 201}}, 'routes/main/1' + ), 'redefine 8' - self.assertEqual( - len(self.conf_get('routes/main')), 2, 'redefine conf 8' - ) - self.assertEqual(self.get()['status'], 200, 'redefine request 8') + assert len(self.conf_get('routes/main')) == 2, 'redefine conf 8' + assert self.get()['status'] == 200, 'redefine request 8' def test_routes_edit(self): self.route_match({"method": "GET"}) - self.assertEqual(self.get()['status'], 200, 'routes edit GET') - self.assertEqual(self.post()['status'], 404, 'routes edit POST') - - self.assertIn( - 'success', - self.conf_post( - {"match": {"method": "POST"}, "action": {"return": 200}}, - 'routes', - ), - 'routes edit configure 2', - ) - self.assertEqual( - 'GET', - self.conf_get('routes/0/match/method'), - 'routes edit configure 2 check', - ) - self.assertEqual( - 'POST', - self.conf_get('routes/1/match/method'), - 'routes edit configure 2 check 2', - ) - - self.assertEqual(self.get()['status'], 200, 'routes edit GET 2') - self.assertEqual(self.post()['status'], 200, 'routes edit POST 2') - - self.assertIn( - 'success', self.conf_delete('routes/0'), 'routes edit configure 3', - ) - - self.assertEqual(self.get()['status'], 404, 'routes edit GET 3') - self.assertEqual(self.post()['status'], 200, 'routes edit POST 3') - - self.assertIn( - 'error', - self.conf_delete('routes/1'), - 'routes edit configure invalid', - ) - self.assertIn( - 'error', - self.conf_delete('routes/-1'), - 'routes edit configure invalid 2', - ) - self.assertIn( - 'error', - self.conf_delete('routes/blah'), - 'routes edit configure invalid 3', - ) - - self.assertEqual(self.get()['status'], 404, 'routes edit GET 4') - self.assertEqual(self.post()['status'], 200, 'routes edit POST 4') - - self.assertIn( - 'success', self.conf_delete('routes/0'), 'routes edit configure 5', - ) - - self.assertEqual(self.get()['status'], 404, 'routes edit GET 5') - self.assertEqual(self.post()['status'], 404, 'routes edit POST 5') + assert self.get()['status'] == 200, 'routes edit GET' + assert self.post()['status'] == 404, 'routes edit POST' + + assert 'success' in self.conf_post( + {"match": {"method": "POST"}, "action": {"return": 200}}, 'routes', + ), 'routes edit configure 2' + assert 'GET' == self.conf_get( + 'routes/0/match/method' + ), 'routes edit configure 2 check' + assert 'POST' == self.conf_get( + 'routes/1/match/method' + ), 'routes edit configure 2 check 2' + + assert self.get()['status'] == 200, 'routes edit GET 2' + assert self.post()['status'] == 200, 'routes edit POST 2' + + assert 'success' in self.conf_delete( + 'routes/0' + ), 'routes edit configure 3' + + assert self.get()['status'] == 404, 'routes edit GET 3' + assert self.post()['status'] == 200, 'routes edit POST 3' + + assert 'error' in self.conf_delete( + 'routes/1' + ), 'routes edit configure invalid' + assert 'error' in self.conf_delete( + 'routes/-1' + ), 'routes edit configure invalid 2' + assert 'error' in self.conf_delete( + 'routes/blah' + ), 'routes edit configure invalid 3' + + assert self.get()['status'] == 404, 'routes edit GET 4' + assert self.post()['status'] == 200, 'routes edit POST 4' + + assert 'success' in self.conf_delete( + 'routes/0' + ), 'routes edit configure 5' + + assert self.get()['status'] == 404, 'routes edit GET 5' + assert self.post()['status'] == 404, 'routes edit POST 5' + + assert 'success' in self.conf_post( + {"match": {"method": "POST"}, "action": {"return": 200}}, 'routes', + ), 'routes edit configure 6' + + assert self.get()['status'] == 404, 'routes edit GET 6' + assert self.post()['status'] == 200, 'routes edit POST 6' + + assert 'success' in self.conf( + { + "listeners": {"*:7080": {"pass": "routes/main"}}, + "routes": {"main": [{"action": {"return": 200}}]}, + "applications": {}, + } + ), 'route edit configure 7' - self.assertIn( - 'success', - self.conf_post( - {"match": {"method": "POST"}, "action": {"return": 200}}, - 'routes', - ), - 'routes edit configure 6', - ) + assert 'error' in self.conf_delete( + 'routes/0' + ), 'routes edit configure invalid 4' + assert 'error' in self.conf_delete( + 'routes/main' + ), 'routes edit configure invalid 5' - self.assertEqual(self.get()['status'], 404, 'routes edit GET 6') - self.assertEqual(self.post()['status'], 200, 'routes edit POST 6') + assert self.get()['status'] == 200, 'routes edit GET 7' - self.assertIn( - 'success', - self.conf( - { - "listeners": {"*:7080": {"pass": "routes/main"}}, - "routes": {"main": [{"action": {"return": 200}}]}, - "applications": {}, - } - ), - 'route edit configure 7', - ) - - self.assertIn( - 'error', - self.conf_delete('routes/0'), - 'routes edit configure invalid 4', - ) - self.assertIn( - 'error', - self.conf_delete('routes/main'), - 'routes edit configure invalid 5', - ) - - self.assertEqual(self.get()['status'], 200, 'routes edit GET 7') - - self.assertIn( - 'success', - self.conf_delete('listeners/*:7080'), - 'route edit configure 8', - ) - self.assertIn( - 'success', - self.conf_delete('routes/main'), - 'route edit configure 9', - ) + assert 'success' in self.conf_delete( + 'listeners/*:7080' + ), 'route edit configure 8' + assert 'success' in self.conf_delete( + 'routes/main' + ), 'route edit configure 9' def test_match_edit(self): - self.skip_alerts.append(r'failed to apply new conf') + skip_alert(r'failed to apply new conf') self.route_match({"method": ["GET", "POST"]}) - self.assertEqual(self.get()['status'], 200, 'match edit GET') - self.assertEqual(self.post()['status'], 200, 'match edit POST') - self.assertEqual(self.put()['status'], 404, 'match edit PUT') - - self.assertIn( - 'success', - self.conf_post('\"PUT\"', 'routes/0/match/method'), - 'match edit configure 2', - ) - self.assertListEqual( - ['GET', 'POST', 'PUT'], - self.conf_get('routes/0/match/method'), - 'match edit configure 2 check', - ) - - self.assertEqual(self.get()['status'], 200, 'match edit GET 2') - self.assertEqual(self.post()['status'], 200, 'match edit POST 2') - self.assertEqual(self.put()['status'], 200, 'match edit PUT 2') - - self.assertIn( - 'success', - self.conf_delete('routes/0/match/method/1'), - 'match edit configure 3', - ) - self.assertListEqual( - ['GET', 'PUT'], - self.conf_get('routes/0/match/method'), - 'match edit configure 3 check', - ) - - self.assertEqual(self.get()['status'], 200, 'match edit GET 3') - self.assertEqual(self.post()['status'], 404, 'match edit POST 3') - self.assertEqual(self.put()['status'], 200, 'match edit PUT 3') - - self.assertIn( - 'success', - self.conf_delete('routes/0/match/method/1'), - 'match edit configure 4', - ) - self.assertListEqual( - ['GET'], - self.conf_get('routes/0/match/method'), - 'match edit configure 4 check', - ) - - self.assertEqual(self.get()['status'], 200, 'match edit GET 4') - self.assertEqual(self.post()['status'], 404, 'match edit POST 4') - self.assertEqual(self.put()['status'], 404, 'match edit PUT 4') - - self.assertIn( - 'error', - self.conf_delete('routes/0/match/method/1'), - 'match edit configure invalid', - ) - self.assertIn( - 'error', - self.conf_delete('routes/0/match/method/-1'), - 'match edit configure invalid 2', - ) - self.assertIn( - 'error', - self.conf_delete('routes/0/match/method/blah'), - 'match edit configure invalid 3', - ) - self.assertListEqual( - ['GET'], - self.conf_get('routes/0/match/method'), - 'match edit configure 5 check', - ) - - self.assertEqual(self.get()['status'], 200, 'match edit GET 5') - self.assertEqual(self.post()['status'], 404, 'match edit POST 5') - self.assertEqual(self.put()['status'], 404, 'match edit PUT 5') - - self.assertIn( - 'success', - self.conf_delete('routes/0/match/method/0'), - 'match edit configure 6', - ) - self.assertListEqual( - [], - self.conf_get('routes/0/match/method'), - 'match edit configure 6 check', - ) - - self.assertEqual(self.get()['status'], 200, 'match edit GET 6') - self.assertEqual(self.post()['status'], 200, 'match edit POST 6') - self.assertEqual(self.put()['status'], 200, 'match edit PUT 6') - - self.assertIn( - 'success', - self.conf('"GET"', 'routes/0/match/method'), - 'match edit configure 7', - ) - - self.assertEqual(self.get()['status'], 200, 'match edit GET 7') - self.assertEqual(self.post()['status'], 404, 'match edit POST 7') - self.assertEqual(self.put()['status'], 404, 'match edit PUT 7') - - self.assertIn( - 'error', - self.conf_delete('routes/0/match/method/0'), - 'match edit configure invalid 5', - ) - self.assertIn( - 'error', - self.conf({}, 'routes/0/action'), - 'match edit configure invalid 6', - ) - - self.assertIn( - 'success', - self.conf({}, 'routes/0/match'), - 'match edit configure 8', - ) - - self.assertEqual(self.get()['status'], 200, 'match edit GET 8') + assert self.get()['status'] == 200, 'match edit GET' + assert self.post()['status'] == 200, 'match edit POST' + assert self.put()['status'] == 404, 'match edit PUT' + + assert 'success' in self.conf_post( + '\"PUT\"', 'routes/0/match/method' + ), 'match edit configure 2' + assert ['GET', 'POST', 'PUT'] == self.conf_get( + 'routes/0/match/method' + ), 'match edit configure 2 check' + + assert self.get()['status'] == 200, 'match edit GET 2' + assert self.post()['status'] == 200, 'match edit POST 2' + assert self.put()['status'] == 200, 'match edit PUT 2' + + assert 'success' in self.conf_delete( + 'routes/0/match/method/1' + ), 'match edit configure 3' + assert ['GET', 'PUT'] == self.conf_get( + 'routes/0/match/method' + ), 'match edit configure 3 check' + + assert self.get()['status'] == 200, 'match edit GET 3' + assert self.post()['status'] == 404, 'match edit POST 3' + assert self.put()['status'] == 200, 'match edit PUT 3' + + assert 'success' in self.conf_delete( + 'routes/0/match/method/1' + ), 'match edit configure 4' + assert ['GET'] == self.conf_get( + 'routes/0/match/method' + ), 'match edit configure 4 check' + + assert self.get()['status'] == 200, 'match edit GET 4' + assert self.post()['status'] == 404, 'match edit POST 4' + assert self.put()['status'] == 404, 'match edit PUT 4' + + assert 'error' in self.conf_delete( + 'routes/0/match/method/1' + ), 'match edit configure invalid' + assert 'error' in self.conf_delete( + 'routes/0/match/method/-1' + ), 'match edit configure invalid 2' + assert 'error' in self.conf_delete( + 'routes/0/match/method/blah' + ), 'match edit configure invalid 3' + assert ['GET'] == self.conf_get( + 'routes/0/match/method' + ), 'match edit configure 5 check' + + assert self.get()['status'] == 200, 'match edit GET 5' + assert self.post()['status'] == 404, 'match edit POST 5' + assert self.put()['status'] == 404, 'match edit PUT 5' + + assert 'success' in self.conf_delete( + 'routes/0/match/method/0' + ), 'match edit configure 6' + assert [] == self.conf_get( + 'routes/0/match/method' + ), 'match edit configure 6 check' + + assert self.get()['status'] == 200, 'match edit GET 6' + assert self.post()['status'] == 200, 'match edit POST 6' + assert self.put()['status'] == 200, 'match edit PUT 6' + + assert 'success' in self.conf( + '"GET"', 'routes/0/match/method' + ), 'match edit configure 7' + + assert self.get()['status'] == 200, 'match edit GET 7' + assert self.post()['status'] == 404, 'match edit POST 7' + assert self.put()['status'] == 404, 'match edit PUT 7' + + assert 'error' in self.conf_delete( + 'routes/0/match/method/0' + ), 'match edit configure invalid 5' + assert 'error' in self.conf( + {}, 'routes/0/action' + ), 'match edit configure invalid 6' + + assert 'success' in self.conf( + {}, 'routes/0/match' + ), 'match edit configure 8' + + assert self.get()['status'] == 200, 'match edit GET 8' def test_routes_match_rules(self): self.route_match({"method": "GET", "host": "localhost", "uri": "/"}) - self.assertEqual(self.get()['status'], 200, 'routes match rules') + assert self.get()['status'] == 200, 'routes match rules' def test_routes_loop(self): - self.assertIn( - 'success', - self.route({"match": {"uri": "/"}, "action": {"pass": "routes"}}), - 'routes loop configure', - ) + assert 'success' in self.route( + {"match": {"uri": "/"}, "action": {"pass": "routes"}} + ), 'routes loop configure' - self.assertEqual(self.get()['status'], 500, 'routes loop') + assert self.get()['status'] == 500, 'routes loop' def test_routes_match_headers(self): self.route_match({"headers": {"host": "localhost"}}) - self.assertEqual(self.get()['status'], 200, 'match headers') + assert self.get()['status'] == 200, 'match headers' self.host('Localhost', 200) self.host('localhost.com', 404) self.host('llocalhost', 404) @@ -917,134 +830,122 @@ class TestRouting(TestApplicationProto): def test_routes_match_headers_multiple(self): self.route_match({"headers": {"host": "localhost", "x-blah": "test"}}) - self.assertEqual(self.get()['status'], 404, 'match headers multiple') - self.assertEqual( + assert self.get()['status'] == 404, 'match headers multiple' + assert ( self.get( headers={ "Host": "localhost", "X-blah": "test", "Connection": "close", } - )['status'], - 200, - 'match headers multiple 2', - ) + )['status'] + == 200 + ), 'match headers multiple 2' - self.assertEqual( + assert ( self.get( headers={ "Host": "localhost", "X-blah": "", "Connection": "close", } - )['status'], - 404, - 'match headers multiple 3', - ) + )['status'] + == 404 + ), 'match headers multiple 3' def test_routes_match_headers_multiple_values(self): self.route_match({"headers": {"x-blah": "test"}}) - self.assertEqual( + assert ( self.get( headers={ "Host": "localhost", "X-blah": ["test", "test", "test"], "Connection": "close", } - )['status'], - 200, - 'match headers multiple values', - ) - self.assertEqual( + )['status'] + == 200 + ), 'match headers multiple values' + assert ( self.get( headers={ "Host": "localhost", "X-blah": ["test", "blah", "test"], "Connection": "close", } - )['status'], - 404, - 'match headers multiple values 2', - ) - self.assertEqual( + )['status'] + == 404 + ), 'match headers multiple values 2' + assert ( self.get( headers={ "Host": "localhost", "X-blah": ["test", "", "test"], "Connection": "close", } - )['status'], - 404, - 'match headers multiple values 3', - ) + )['status'] + == 404 + ), 'match headers multiple values 3' def test_routes_match_headers_multiple_rules(self): self.route_match({"headers": {"x-blah": ["test", "blah"]}}) - self.assertEqual( - self.get()['status'], 404, 'match headers multiple rules' - ) - self.assertEqual( + assert self.get()['status'] == 404, 'match headers multiple rules' + assert ( self.get( headers={ "Host": "localhost", "X-blah": "test", "Connection": "close", } - )['status'], - 200, - 'match headers multiple rules 2', - ) - self.assertEqual( + )['status'] + == 200 + ), 'match headers multiple rules 2' + assert ( self.get( headers={ "Host": "localhost", "X-blah": "blah", "Connection": "close", } - )['status'], - 200, - 'match headers multiple rules 3', - ) - self.assertEqual( + )['status'] + == 200 + ), 'match headers multiple rules 3' + assert ( self.get( headers={ "Host": "localhost", "X-blah": ["test", "blah", "test"], "Connection": "close", } - )['status'], - 200, - 'match headers multiple rules 4', - ) + )['status'] + == 200 + ), 'match headers multiple rules 4' - self.assertEqual( + assert ( self.get( headers={ "Host": "localhost", "X-blah": ["blah", ""], "Connection": "close", } - )['status'], - 404, - 'match headers multiple rules 5', - ) + )['status'] + == 404 + ), 'match headers multiple rules 5' def test_routes_match_headers_case_insensitive(self): self.route_match({"headers": {"X-BLAH": "TEST"}}) - self.assertEqual( + assert ( self.get( headers={ "Host": "localhost", "x-blah": "test", "Connection": "close", } - )['status'], - 200, - 'match headers case insensitive', - ) + )['status'] + == 200 + ), 'match headers case insensitive' def test_routes_match_headers_invalid(self): self.route_match_invalid({"headers": ["blah"]}) @@ -1054,29 +955,30 @@ class TestRouting(TestApplicationProto): def test_routes_match_headers_empty_rule(self): self.route_match({"headers": {"host": ""}}) - self.assertEqual(self.get()['status'], 404, 'localhost') + assert self.get()['status'] == 404, 'localhost' self.host('', 200) def test_routes_match_headers_empty(self): self.route_match({"headers": {}}) - self.assertEqual(self.get()['status'], 200, 'empty') + assert self.get()['status'] == 200, 'empty' self.route_match({"headers": []}) - self.assertEqual(self.get()['status'], 200, 'empty 2') + assert self.get()['status'] == 200, 'empty 2' def test_routes_match_headers_rule_array_empty(self): self.route_match({"headers": {"blah": []}}) - self.assertEqual(self.get()['status'], 404, 'array empty') - self.assertEqual( + assert self.get()['status'] == 404, 'array empty' + assert ( self.get( headers={ "Host": "localhost", "blah": "foo", "Connection": "close", } - )['status'], 200, 'match headers rule array empty 2' - ) + )['status'] + == 200 + ), 'match headers rule array empty 2' def test_routes_match_headers_array(self): self.route_match( @@ -1090,52 +992,48 @@ class TestRouting(TestApplicationProto): } ) - self.assertEqual(self.get()['status'], 404, 'match headers array') - self.assertEqual( + assert self.get()['status'] == 404, 'match headers array' + assert ( self.get( headers={ "Host": "localhost", "x-header1": "foo123", "Connection": "close", } - )['status'], - 200, - 'match headers array 2', - ) - self.assertEqual( + )['status'] + == 200 + ), 'match headers array 2' + assert ( self.get( headers={ "Host": "localhost", "x-header2": "bar", "Connection": "close", } - )['status'], - 200, - 'match headers array 3', - ) - self.assertEqual( + )['status'] + == 200 + ), 'match headers array 3' + assert ( self.get( headers={ "Host": "localhost", "x-header3": "bar", "Connection": "close", } - )['status'], - 200, - 'match headers array 4', - ) - self.assertEqual( + )['status'] + == 200 + ), 'match headers array 4' + assert ( self.get( headers={ "Host": "localhost", "x-header1": "bar", "Connection": "close", } - )['status'], - 404, - 'match headers array 5', - ) - self.assertEqual( + )['status'] + == 404 + ), 'match headers array 5' + assert ( self.get( headers={ "Host": "localhost", @@ -1143,49 +1041,44 @@ class TestRouting(TestApplicationProto): "x-header4": "foo", "Connection": "close", } - )['status'], - 200, - 'match headers array 6', - ) + )['status'] + == 200 + ), 'match headers array 6' - self.assertIn( - 'success', - self.conf_delete('routes/0/match/headers/1'), - 'match headers array configure 2', - ) + assert 'success' in self.conf_delete( + 'routes/0/match/headers/1' + ), 'match headers array configure 2' - self.assertEqual( + assert ( self.get( headers={ "Host": "localhost", "x-header2": "bar", "Connection": "close", } - )['status'], - 404, - 'match headers array 7', - ) - self.assertEqual( + )['status'] + == 404 + ), 'match headers array 7' + assert ( self.get( headers={ "Host": "localhost", "x-header3": "foo", "Connection": "close", } - )['status'], - 200, - 'match headers array 8', - ) + )['status'] + == 200 + ), 'match headers array 8' def test_routes_match_arguments(self): self.route_match({"arguments": {"foo": "bar"}}) - self.assertEqual(self.get()['status'], 404, 'args') - self.assertEqual(self.get(url='/?foo=bar')['status'], 200, 'args 2') - self.assertEqual(self.get(url='/?foo=bar1')['status'], 404, 'args 3') - self.assertEqual(self.get(url='/?1foo=bar')['status'], 404, 'args 4') - self.assertEqual(self.get(url='/?Foo=bar')['status'], 404, 'case') - self.assertEqual(self.get(url='/?foo=Bar')['status'], 404, 'case 2') + assert self.get()['status'] == 404, 'args' + assert self.get(url='/?foo=bar')['status'] == 200, 'args 2' + assert self.get(url='/?foo=bar1')['status'] == 404, 'args 3' + assert self.get(url='/?1foo=bar')['status'] == 404, 'args 4' + assert self.get(url='/?Foo=bar')['status'] == 404, 'case' + assert self.get(url='/?foo=Bar')['status'] == 404, 'case 2' def test_routes_match_arguments_chars(self): chars = ( @@ -1195,15 +1088,30 @@ class TestRouting(TestApplicationProto): chars_enc = "" for h1 in ["2", "3", "4", "5", "6", "7"]: - for h2 in ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", - "B", "C", "D", "E", "F", + for h2 in [ + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "A", + "B", + "C", + "D", + "E", + "F", ]: chars_enc += "%" + h1 + h2 chars_enc = chars_enc[:-3] def check_args(args, query): self.route_match({"arguments": args}) - self.assertEqual(self.get(url='/?' + query)['status'], 200) + assert self.get(url='/?' + query)['status'] == 200 check_args({chars: chars}, chars + '=' + chars) check_args({chars: chars}, chars + '=' + chars_enc) @@ -1216,175 +1124,167 @@ class TestRouting(TestApplicationProto): def test_routes_match_arguments_empty(self): self.route_match({"arguments": {}}) - self.assertEqual(self.get()['status'], 200, 'arguments empty') + assert self.get()['status'] == 200, 'arguments empty' self.route_match({"arguments": []}) - self.assertEqual(self.get()['status'], 200, 'arguments empty 2') + assert self.get()['status'] == 200, 'arguments empty 2' def test_routes_match_arguments_space(self): self.route_match({"arguments": {"+fo o%20": "%20b+a r"}}) - self.assertEqual(self.get(url='/? fo o = b a r&')['status'], 200) - self.assertEqual(self.get(url='/?+fo+o+=+b+a+r&')['status'], 200) - self.assertEqual( - self.get(url='/?%20fo%20o%20=%20b%20a%20r&')['status'], 200 - ) + assert self.get(url='/? fo o = b a r&')['status'] == 200 + assert self.get(url='/?+fo+o+=+b+a+r&')['status'] == 200 + assert self.get(url='/?%20fo%20o%20=%20b%20a%20r&')['status'] == 200 self.route_match({"arguments": {"%20foo": " bar"}}) - self.assertEqual(self.get(url='/? foo= bar')['status'], 200) - self.assertEqual(self.get(url='/?+foo=+bar')['status'], 200) - self.assertEqual(self.get(url='/?%20foo=%20bar')['status'], 200) - self.assertEqual(self.get(url='/?+foo= bar')['status'], 200) - self.assertEqual(self.get(url='/?%20foo=+bar')['status'], 200) + assert self.get(url='/? foo= bar')['status'] == 200 + assert self.get(url='/?+foo=+bar')['status'] == 200 + assert self.get(url='/?%20foo=%20bar')['status'] == 200 + assert self.get(url='/?+foo= bar')['status'] == 200 + assert self.get(url='/?%20foo=+bar')['status'] == 200 def test_routes_match_arguments_equal(self): self.route_match({"arguments": {"=": "="}}) - self.assertEqual(self.get(url='/?%3D=%3D')['status'], 200) - self.assertEqual(self.get(url='/?%3D==')['status'], 200) - self.assertEqual(self.get(url='/?===')['status'], 404) - self.assertEqual(self.get(url='/?%3D%3D%3D')['status'], 404) - self.assertEqual(self.get(url='/?==%3D')['status'], 404) + assert self.get(url='/?%3D=%3D')['status'] == 200 + assert self.get(url='/?%3D==')['status'] == 200 + assert self.get(url='/?===')['status'] == 404 + assert self.get(url='/?%3D%3D%3D')['status'] == 404 + assert self.get(url='/?==%3D')['status'] == 404 def test_routes_match_arguments_enc(self): self.route_match({"arguments": {"Ю": "н"}}) - self.assertEqual(self.get(url='/?%D0%AE=%D0%BD')['status'], 200) - self.assertEqual(self.get(url='/?%d0%ae=%d0%Bd')['status'], 200) + assert self.get(url='/?%D0%AE=%D0%BD')['status'] == 200 + assert self.get(url='/?%d0%ae=%d0%Bd')['status'] == 200 def test_routes_match_arguments_hash(self): self.route_match({"arguments": {"#": "#"}}) - self.assertEqual(self.get(url='/?%23=%23')['status'], 200) - self.assertEqual(self.get(url='/?%23=%23#')['status'], 200) - self.assertEqual(self.get(url='/?#=#')['status'], 404) - self.assertEqual(self.get(url='/?%23=#')['status'], 404) + assert self.get(url='/?%23=%23')['status'] == 200 + assert self.get(url='/?%23=%23#')['status'] == 200 + assert self.get(url='/?#=#')['status'] == 404 + assert self.get(url='/?%23=#')['status'] == 404 def test_routes_match_arguments_wildcard(self): self.route_match({"arguments": {"foo": "*"}}) - self.assertEqual(self.get(url='/?foo')['status'], 200) - self.assertEqual(self.get(url='/?foo=')['status'], 200) - self.assertEqual(self.get(url='/?foo=blah')['status'], 200) - self.assertEqual(self.get(url='/?blah=foo')['status'], 404) + assert self.get(url='/?foo')['status'] == 200 + assert self.get(url='/?foo=')['status'] == 200 + assert self.get(url='/?foo=blah')['status'] == 200 + assert self.get(url='/?blah=foo')['status'] == 404 self.route_match({"arguments": {"foo": "%25*"}}) - self.assertEqual(self.get(url='/?foo=%xx')['status'], 200) + assert self.get(url='/?foo=%xx')['status'] == 200 self.route_match({"arguments": {"foo": "%2A*"}}) - self.assertEqual(self.get(url='/?foo=*xx')['status'], 200) - self.assertEqual(self.get(url='/?foo=xx')['status'], 404) + assert self.get(url='/?foo=*xx')['status'] == 200 + assert self.get(url='/?foo=xx')['status'] == 404 self.route_match({"arguments": {"foo": "*%2A"}}) - self.assertEqual(self.get(url='/?foo=xx*')['status'], 200) - self.assertEqual(self.get(url='/?foo=xx*x')['status'], 404) + assert self.get(url='/?foo=xx*')['status'] == 200 + assert self.get(url='/?foo=xx*x')['status'] == 404 self.route_match({"arguments": {"foo": "1*2"}}) - self.assertEqual(self.get(url='/?foo=12')['status'], 200) - self.assertEqual(self.get(url='/?foo=1blah2')['status'], 200) - self.assertEqual(self.get(url='/?foo=1%2A2')['status'], 200) - self.assertEqual(self.get(url='/?foo=x12')['status'], 404) + assert self.get(url='/?foo=12')['status'] == 200 + assert self.get(url='/?foo=1blah2')['status'] == 200 + assert self.get(url='/?foo=1%2A2')['status'] == 200 + assert self.get(url='/?foo=x12')['status'] == 404 self.route_match({"arguments": {"foo": "bar*", "%25": "%25"}}) - self.assertEqual(self.get(url='/?foo=barxx&%=%')['status'], 200) - self.assertEqual(self.get(url='/?foo=barxx&x%=%')['status'], 404) + assert self.get(url='/?foo=barxx&%=%')['status'] == 200 + assert self.get(url='/?foo=barxx&x%=%')['status'] == 404 def test_routes_match_arguments_negative(self): + self.route_match({"arguments": {"foo": "!"}}) + assert self.get(url='/?bar')['status'] == 404 + assert self.get(url='/?foo')['status'] == 404 + assert self.get(url='/?foo=')['status'] == 404 + assert self.get(url='/?foo=%25')['status'] == 200 + + self.route_match({"arguments": {"foo": "!*"}}) + assert self.get(url='/?bar')['status'] == 404 + assert self.get(url='/?foo')['status'] == 404 + assert self.get(url='/?foo=')['status'] == 404 + assert self.get(url='/?foo=blah')['status'] == 404 + self.route_match({"arguments": {"foo": "!%25"}}) - self.assertEqual(self.get(url='/?foo=blah')['status'], 200) - self.assertEqual(self.get(url='/?foo=%')['status'], 404) + assert self.get(url='/?foo=blah')['status'] == 200 + assert self.get(url='/?foo=%')['status'] == 404 self.route_match({"arguments": {"foo": "%21blah"}}) - self.assertEqual(self.get(url='/?foo=%21blah')['status'], 200) - self.assertEqual(self.get(url='/?foo=!blah')['status'], 200) - self.assertEqual(self.get(url='/?foo=bar')['status'], 404) + assert self.get(url='/?foo=%21blah')['status'] == 200 + assert self.get(url='/?foo=!blah')['status'] == 200 + assert self.get(url='/?foo=bar')['status'] == 404 self.route_match({"arguments": {"foo": "!!%21*a"}}) - self.assertEqual(self.get(url='/?foo=blah')['status'], 200) - self.assertEqual(self.get(url='/?foo=!blah')['status'], 200) - self.assertEqual(self.get(url='/?foo=!!a')['status'], 404) - self.assertEqual(self.get(url='/?foo=!!bla')['status'], 404) + assert self.get(url='/?foo=blah')['status'] == 200 + assert self.get(url='/?foo=!blah')['status'] == 200 + assert self.get(url='/?foo=!!a')['status'] == 404 + assert self.get(url='/?foo=!!bla')['status'] == 404 def test_routes_match_arguments_percent(self): self.route_match({"arguments": {"%25": "%25"}}) - self.assertEqual(self.get(url='/?%=%')['status'], 200) - self.assertEqual(self.get(url='/?%25=%25')['status'], 200) - self.assertEqual(self.get(url='/?%25=%')['status'], 200) + assert self.get(url='/?%=%')['status'] == 200 + assert self.get(url='/?%25=%25')['status'] == 200 + assert self.get(url='/?%25=%')['status'] == 200 self.route_match({"arguments": {"%251": "%252"}}) - self.assertEqual(self.get(url='/?%1=%2')['status'], 200) - self.assertEqual(self.get(url='/?%251=%252')['status'], 200) - self.assertEqual(self.get(url='/?%251=%2')['status'], 200) + assert self.get(url='/?%1=%2')['status'] == 200 + assert self.get(url='/?%251=%252')['status'] == 200 + assert self.get(url='/?%251=%2')['status'] == 200 self.route_match({"arguments": {"%25%21%251": "%25%24%252"}}) - self.assertEqual(self.get(url='/?%!%1=%$%2')['status'], 200) - self.assertEqual(self.get(url='/?%25!%251=%25$%252')['status'], 200) - self.assertEqual(self.get(url='/?%25!%1=%$%2')['status'], 200) + assert self.get(url='/?%!%1=%$%2')['status'] == 200 + assert self.get(url='/?%25!%251=%25$%252')['status'] == 200 + assert self.get(url='/?%25!%1=%$%2')['status'] == 200 def test_routes_match_arguments_ampersand(self): self.route_match({"arguments": {"foo": "&"}}) - self.assertEqual(self.get(url='/?foo=%26')['status'], 200) - self.assertEqual(self.get(url='/?foo=%26&')['status'], 200) - self.assertEqual(self.get(url='/?foo=%26%26')['status'], 404) - self.assertEqual(self.get(url='/?foo=&')['status'], 404) + assert self.get(url='/?foo=%26')['status'] == 200 + assert self.get(url='/?foo=%26&')['status'] == 200 + assert self.get(url='/?foo=%26%26')['status'] == 404 + assert self.get(url='/?foo=&')['status'] == 404 self.route_match({"arguments": {"&": ""}}) - self.assertEqual(self.get(url='/?%26=')['status'], 200) - self.assertEqual(self.get(url='/?%26=&')['status'], 200) - self.assertEqual(self.get(url='/?%26=%26')['status'], 404) - self.assertEqual(self.get(url='/?&=')['status'], 404) + assert self.get(url='/?%26=')['status'] == 200 + assert self.get(url='/?%26=&')['status'] == 200 + assert self.get(url='/?%26=%26')['status'] == 404 + assert self.get(url='/?&=')['status'] == 404 def test_routes_match_arguments_complex(self): self.route_match({"arguments": {"foo": ""}}) - self.assertEqual(self.get(url='/?foo')['status'], 200, 'complex') - self.assertEqual( - self.get(url='/?blah=blah&foo=')['status'], 200, 'complex 2' - ) - self.assertEqual( - self.get(url='/?&&&foo&&&')['status'], 200, 'complex 3' - ) - self.assertEqual( - self.get(url='/?foo&foo=bar&foo')['status'], 404, 'complex 4' - ) - self.assertEqual( - self.get(url='/?foo=&foo')['status'], 200, 'complex 5' - ) - self.assertEqual( - self.get(url='/?&=&foo&==&')['status'], 200, 'complex 6' - ) - self.assertEqual( - self.get(url='/?&=&bar&==&')['status'], 404, 'complex 7' - ) + assert self.get(url='/?foo')['status'] == 200, 'complex' + assert self.get(url='/?blah=blah&foo=')['status'] == 200, 'complex 2' + assert self.get(url='/?&&&foo&&&')['status'] == 200, 'complex 3' + assert self.get(url='/?foo&foo=bar&foo')['status'] == 404, 'complex 4' + assert self.get(url='/?foo=&foo')['status'] == 200, 'complex 5' + assert self.get(url='/?&=&foo&==&')['status'] == 200, 'complex 6' + assert self.get(url='/?&=&bar&==&')['status'] == 404, 'complex 7' def test_routes_match_arguments_multiple(self): self.route_match({"arguments": {"foo": "bar", "blah": "test"}}) - self.assertEqual(self.get()['status'], 404, 'multiple') - self.assertEqual( - self.get(url='/?foo=bar&blah=test')['status'], 200, 'multiple 2' - ) - self.assertEqual( - self.get(url='/?foo=bar&blah')['status'], 404, 'multiple 3' - ) - self.assertEqual( - self.get(url='/?foo=bar&blah=tes')['status'], 404, 'multiple 4' - ) - self.assertEqual( - self.get(url='/?foo=b%61r&bl%61h=t%65st')['status'], - 200, - 'multiple 5', - ) + assert self.get()['status'] == 404, 'multiple' + assert ( + self.get(url='/?foo=bar&blah=test')['status'] == 200 + ), 'multiple 2' + assert self.get(url='/?foo=bar&blah')['status'] == 404, 'multiple 3' + assert ( + self.get(url='/?foo=bar&blah=tes')['status'] == 404 + ), 'multiple 4' + assert ( + self.get(url='/?foo=b%61r&bl%61h=t%65st')['status'] == 200 + ), 'multiple 5' def test_routes_match_arguments_multiple_rules(self): self.route_match({"arguments": {"foo": ["bar", "blah"]}}) - self.assertEqual(self.get()['status'], 404, 'rules') - self.assertEqual(self.get(url='/?foo=bar')['status'], 200, 'rules 2') - self.assertEqual(self.get(url='/?foo=blah')['status'], 200, 'rules 3') - self.assertEqual( - self.get(url='/?foo=blah&foo=bar&foo=blah')['status'], - 200, - 'rules 4', - ) - self.assertEqual( - self.get(url='/?foo=blah&foo=bar&foo=')['status'], 404, 'rules 5' - ) + assert self.get()['status'] == 404, 'rules' + assert self.get(url='/?foo=bar')['status'] == 200, 'rules 2' + assert self.get(url='/?foo=blah')['status'] == 200, 'rules 3' + assert ( + self.get(url='/?foo=blah&foo=bar&foo=blah')['status'] == 200 + ), 'rules 4' + assert ( + self.get(url='/?foo=blah&foo=bar&foo=')['status'] == 404 + ), 'rules 5' def test_routes_match_arguments_array(self): self.route_match( @@ -1398,27 +1298,23 @@ class TestRouting(TestApplicationProto): } ) - self.assertEqual(self.get()['status'], 404, 'arr') - self.assertEqual(self.get(url='/?var1=val123')['status'], 200, 'arr 2') - self.assertEqual(self.get(url='/?var2=val2')['status'], 200, 'arr 3') - self.assertEqual(self.get(url='/?var3=bar')['status'], 200, 'arr 4') - self.assertEqual(self.get(url='/?var1=bar')['status'], 404, 'arr 5') - self.assertEqual( - self.get(url='/?var1=bar&var4=foo')['status'], 200, 'arr 6' - ) + assert self.get()['status'] == 404, 'arr' + assert self.get(url='/?var1=val123')['status'] == 200, 'arr 2' + assert self.get(url='/?var2=val2')['status'] == 200, 'arr 3' + assert self.get(url='/?var3=bar')['status'] == 200, 'arr 4' + assert self.get(url='/?var1=bar')['status'] == 404, 'arr 5' + assert self.get(url='/?var1=bar&var4=foo')['status'] == 200, 'arr 6' - self.assertIn( - 'success', - self.conf_delete('routes/0/match/arguments/1'), - 'match arguments array configure 2', - ) + assert 'success' in self.conf_delete( + 'routes/0/match/arguments/1' + ), 'match arguments array configure 2' - self.assertEqual(self.get(url='/?var2=val2')['status'], 404, 'arr 7') - self.assertEqual(self.get(url='/?var3=foo')['status'], 200, 'arr 8') + assert self.get(url='/?var2=val2')['status'] == 404, 'arr 7' + assert self.get(url='/?var3=foo')['status'] == 200, 'arr 8' def test_routes_match_arguments_invalid(self): # TODO remove it after controller fixed - self.skip_alerts.append(r'failed to apply new conf') + skip_alert(r'failed to apply new conf') self.route_match_invalid({"arguments": ["var"]}) self.route_match_invalid({"arguments": [{"var1": {}}]}) @@ -1434,7 +1330,7 @@ class TestRouting(TestApplicationProto): def test_routes_match_cookies(self): self.route_match({"cookies": {"foO": "bar"}}) - self.assertEqual(self.get()['status'], 404, 'cookie') + assert self.get()['status'] == 404, 'cookie' self.cookie('foO=bar', 200) self.cookie('foO=bar;1', 200) self.cookie(['foO=bar', 'blah=blah'], 200) @@ -1446,10 +1342,10 @@ class TestRouting(TestApplicationProto): def test_routes_match_cookies_empty(self): self.route_match({"cookies": {}}) - self.assertEqual(self.get()['status'], 200, 'cookies empty') + assert self.get()['status'] == 200, 'cookies empty' self.route_match({"cookies": []}) - self.assertEqual(self.get()['status'], 200, 'cookies empty 2') + assert self.get()['status'] == 200, 'cookies empty 2' def test_routes_match_cookies_invalid(self): self.route_match_invalid({"cookies": ["var"]}) @@ -1458,7 +1354,7 @@ class TestRouting(TestApplicationProto): def test_routes_match_cookies_multiple(self): self.route_match({"cookies": {"foo": "bar", "blah": "blah"}}) - self.assertEqual(self.get()['status'], 404, 'multiple') + assert self.get()['status'] == 404, 'multiple' self.cookie('foo=bar; blah=blah', 200) self.cookie(['foo=bar', 'blah=blah'], 200) self.cookie(['foo=bar; blah', 'blah'], 404) @@ -1474,12 +1370,12 @@ class TestRouting(TestApplicationProto): def test_routes_match_cookies_multiple_rules(self): self.route_match({"cookies": {"blah": ["test", "blah"]}}) - self.assertEqual(self.get()['status'], 404, 'multiple rules') + assert self.get()['status'] == 404, 'multiple rules' self.cookie('blah=test', 200) self.cookie('blah=blah', 200) self.cookie(['blah=blah', 'blah=test', 'blah=blah'], 200) self.cookie(['blah=blah; blah=test', 'blah=blah'], 200) - self.cookie(['blah=blah', 'blah'], 200) # invalid cookie + self.cookie(['blah=blah', 'blah'], 200) # invalid cookie def test_routes_match_cookies_array(self): self.route_match( @@ -1493,7 +1389,7 @@ class TestRouting(TestApplicationProto): } ) - self.assertEqual(self.get()['status'], 404, 'cookies array') + assert self.get()['status'] == 404, 'cookies array' self.cookie('var1=val123', 200) self.cookie('var2=val2', 200) self.cookie(' var2=val2 ', 200) @@ -1503,11 +1399,9 @@ class TestRouting(TestApplicationProto): self.cookie('var1=bar; var4=foo;', 200) self.cookie(['var1=bar', 'var4=foo'], 200) - self.assertIn( - 'success', - self.conf_delete('routes/0/match/cookies/1'), - 'match cookies array configure 2', - ) + assert 'success' in self.conf_delete( + 'routes/0/match/cookies/1' + ), 'match cookies array configure 2' self.cookie('var2=val2', 404) self.cookie('var3=foo', 200) @@ -1535,22 +1429,22 @@ class TestRouting(TestApplicationProto): sock2, port2 = sock_port() self.route_match({"source": "127.0.0.1:" + str(port)}) - self.assertEqual(self.get(sock=sock)['status'], 200, 'exact') - self.assertEqual(self.get(sock=sock2)['status'], 404, 'exact 2') + assert self.get(sock=sock)['status'] == 200, 'exact' + assert self.get(sock=sock2)['status'] == 404, 'exact 2' sock, port = sock_port() sock2, port2 = sock_port() self.route_match({"source": "!127.0.0.1:" + str(port)}) - self.assertEqual(self.get(sock=sock)['status'], 404, 'negative') - self.assertEqual(self.get(sock=sock2)['status'], 200, 'negative 2') + assert self.get(sock=sock)['status'] == 404, 'negative' + assert self.get(sock=sock2)['status'] == 200, 'negative 2' sock, port = sock_port() sock2, port2 = sock_port() self.route_match({"source": ["*:" + str(port), "!127.0.0.1"]}) - self.assertEqual(self.get(sock=sock)['status'], 404, 'negative 3') - self.assertEqual(self.get(sock=sock2)['status'], 404, 'negative 4') + assert self.get(sock=sock)['status'] == 404, 'negative 3' + assert self.get(sock=sock2)['status'] == 404, 'negative 4' sock, port = sock_port() sock2, port2 = sock_port() @@ -1558,8 +1452,8 @@ class TestRouting(TestApplicationProto): self.route_match( {"source": "127.0.0.1:" + str(port) + "-" + str(port)} ) - self.assertEqual(self.get(sock=sock)['status'], 200, 'range single') - self.assertEqual(self.get(sock=sock2)['status'], 404, 'range single 2') + assert self.get(sock=sock)['status'] == 200, 'range single' + assert self.get(sock=sock2)['status'] == 404, 'range single 2' socks = [ sock_port(), @@ -1578,11 +1472,11 @@ class TestRouting(TestApplicationProto): + str(socks[3][1]) # fourth port number } ) - self.assertEqual(self.get(sock=socks[0][0])['status'], 404, 'range') - self.assertEqual(self.get(sock=socks[1][0])['status'], 200, 'range 2') - self.assertEqual(self.get(sock=socks[2][0])['status'], 200, 'range 3') - self.assertEqual(self.get(sock=socks[3][0])['status'], 200, 'range 4') - self.assertEqual(self.get(sock=socks[4][0])['status'], 404, 'range 5') + assert self.get(sock=socks[0][0])['status'] == 404, 'range' + assert self.get(sock=socks[1][0])['status'] == 200, 'range 2' + assert self.get(sock=socks[2][0])['status'] == 200, 'range 3' + assert self.get(sock=socks[3][0])['status'] == 200, 'range 4' + assert self.get(sock=socks[4][0])['status'] == 404, 'range 5' socks = [ sock_port(), @@ -1599,218 +1493,194 @@ class TestRouting(TestApplicationProto): ] } ) - self.assertEqual(self.get(sock=socks[0][0])['status'], 200, 'array') - self.assertEqual(self.get(sock=socks[1][0])['status'], 404, 'array 2') - self.assertEqual(self.get(sock=socks[2][0])['status'], 200, 'array 3') + assert self.get(sock=socks[0][0])['status'] == 200, 'array' + assert self.get(sock=socks[1][0])['status'] == 404, 'array 2' + assert self.get(sock=socks[2][0])['status'] == 200, 'array 3' def test_routes_source_addr(self): - self.assertIn( - 'success', - self.conf( - { - "*:7080": {"pass": "routes"}, - "[::1]:7081": {"pass": "routes"}, - }, - 'listeners', - ), - 'source listeners configure', - ) + assert 'success' in self.conf( + {"*:7080": {"pass": "routes"}, "[::1]:7081": {"pass": "routes"},}, + 'listeners', + ), 'source listeners configure' def get_ipv6(): return self.get(sock_type='ipv6', port=7081) self.route_match({"source": "127.0.0.1"}) - self.assertEqual(self.get()['status'], 200, 'exact') - self.assertEqual(get_ipv6()['status'], 404, 'exact ipv6') + assert self.get()['status'] == 200, 'exact' + assert get_ipv6()['status'] == 404, 'exact ipv6' self.route_match({"source": ["127.0.0.1"]}) - self.assertEqual(self.get()['status'], 200, 'exact 2') - self.assertEqual(get_ipv6()['status'], 404, 'exact 2 ipv6') + assert self.get()['status'] == 200, 'exact 2' + assert get_ipv6()['status'] == 404, 'exact 2 ipv6' self.route_match({"source": "!127.0.0.1"}) - self.assertEqual(self.get()['status'], 404, 'exact neg') - self.assertEqual(get_ipv6()['status'], 200, 'exact neg ipv6') + assert self.get()['status'] == 404, 'exact neg' + assert get_ipv6()['status'] == 200, 'exact neg ipv6' self.route_match({"source": "127.0.0.2"}) - self.assertEqual(self.get()['status'], 404, 'exact 3') - self.assertEqual(get_ipv6()['status'], 404, 'exact 3 ipv6') + assert self.get()['status'] == 404, 'exact 3' + assert get_ipv6()['status'] == 404, 'exact 3 ipv6' self.route_match({"source": "127.0.0.1-127.0.0.1"}) - self.assertEqual(self.get()['status'], 200, 'range single') - self.assertEqual(get_ipv6()['status'], 404, 'range single ipv6') + assert self.get()['status'] == 200, 'range single' + assert get_ipv6()['status'] == 404, 'range single ipv6' self.route_match({"source": "127.0.0.2-127.0.0.2"}) - self.assertEqual(self.get()['status'], 404, 'range single 2') - self.assertEqual(get_ipv6()['status'], 404, 'range single 2 ipv6') + assert self.get()['status'] == 404, 'range single 2' + assert get_ipv6()['status'] == 404, 'range single 2 ipv6' self.route_match({"source": "127.0.0.2-127.0.0.3"}) - self.assertEqual(self.get()['status'], 404, 'range') - self.assertEqual(get_ipv6()['status'], 404, 'range ipv6') + assert self.get()['status'] == 404, 'range' + assert get_ipv6()['status'] == 404, 'range ipv6' self.route_match({"source": "127.0.0.1-127.0.0.2"}) - self.assertEqual(self.get()['status'], 200, 'range 2') - self.assertEqual(get_ipv6()['status'], 404, 'range 2 ipv6') + assert self.get()['status'] == 200, 'range 2' + assert get_ipv6()['status'] == 404, 'range 2 ipv6' self.route_match({"source": "127.0.0.0-127.0.0.2"}) - self.assertEqual(self.get()['status'], 200, 'range 3') - self.assertEqual(get_ipv6()['status'], 404, 'range 3 ipv6') + assert self.get()['status'] == 200, 'range 3' + assert get_ipv6()['status'] == 404, 'range 3 ipv6' self.route_match({"source": "127.0.0.0-127.0.0.1"}) - self.assertEqual(self.get()['status'], 200, 'range 4') - self.assertEqual(get_ipv6()['status'], 404, 'range 4 ipv6') + assert self.get()['status'] == 200, 'range 4' + assert get_ipv6()['status'] == 404, 'range 4 ipv6' self.route_match({"source": "126.0.0.0-127.0.0.0"}) - self.assertEqual(self.get()['status'], 404, 'range 5') - self.assertEqual(get_ipv6()['status'], 404, 'range 5 ipv6') + assert self.get()['status'] == 404, 'range 5' + assert get_ipv6()['status'] == 404, 'range 5 ipv6' self.route_match({"source": "126.126.126.126-127.0.0.2"}) - self.assertEqual(self.get()['status'], 200, 'range 6') - self.assertEqual(get_ipv6()['status'], 404, 'range 6 ipv6') + assert self.get()['status'] == 200, 'range 6' + assert get_ipv6()['status'] == 404, 'range 6 ipv6' def test_routes_source_ipv6(self): - self.assertIn( - 'success', - self.conf( - { - "[::1]:7080": {"pass": "routes"}, - "127.0.0.1:7081": {"pass": "routes"}, - }, - 'listeners', - ), - 'source listeners configure', - ) + assert 'success' in self.conf( + { + "[::1]:7080": {"pass": "routes"}, + "127.0.0.1:7081": {"pass": "routes"}, + }, + 'listeners', + ), 'source listeners configure' self.route_match({"source": "::1"}) - self.assertEqual(self.get(sock_type='ipv6')['status'], 200, 'exact') - self.assertEqual(self.get(port=7081)['status'], 404, 'exact ipv4') + assert self.get(sock_type='ipv6')['status'] == 200, 'exact' + assert self.get(port=7081)['status'] == 404, 'exact ipv4' self.route_match({"source": ["::1"]}) - self.assertEqual(self.get(sock_type='ipv6')['status'], 200, 'exact 2') - self.assertEqual(self.get(port=7081)['status'], 404, 'exact 2 ipv4') + assert self.get(sock_type='ipv6')['status'] == 200, 'exact 2' + assert self.get(port=7081)['status'] == 404, 'exact 2 ipv4' self.route_match({"source": "!::1"}) - self.assertEqual(self.get(sock_type='ipv6')['status'], 404, 'exact neg') - self.assertEqual(self.get(port=7081)['status'], 200, 'exact neg ipv4') + assert self.get(sock_type='ipv6')['status'] == 404, 'exact neg' + assert self.get(port=7081)['status'] == 200, 'exact neg ipv4' self.route_match({"source": "::2"}) - self.assertEqual(self.get(sock_type='ipv6')['status'], 404, 'exact 3') - self.assertEqual(self.get(port=7081)['status'], 404, 'exact 3 ipv4') + assert self.get(sock_type='ipv6')['status'] == 404, 'exact 3' + assert self.get(port=7081)['status'] == 404, 'exact 3 ipv4' self.route_match({"source": "::1-::1"}) - self.assertEqual(self.get(sock_type='ipv6')['status'], 200, 'range') - self.assertEqual(self.get(port=7081)['status'], 404, 'range ipv4') + assert self.get(sock_type='ipv6')['status'] == 200, 'range' + assert self.get(port=7081)['status'] == 404, 'range ipv4' self.route_match({"source": "::2-::2"}) - self.assertEqual(self.get(sock_type='ipv6')['status'], 404, 'range 2') - self.assertEqual(self.get(port=7081)['status'], 404, 'range 2 ipv4') + assert self.get(sock_type='ipv6')['status'] == 404, 'range 2' + assert self.get(port=7081)['status'] == 404, 'range 2 ipv4' self.route_match({"source": "::2-::3"}) - self.assertEqual(self.get(sock_type='ipv6')['status'], 404, 'range 3') - self.assertEqual(self.get(port=7081)['status'], 404, 'range 3 ipv4') + assert self.get(sock_type='ipv6')['status'] == 404, 'range 3' + assert self.get(port=7081)['status'] == 404, 'range 3 ipv4' self.route_match({"source": "::1-::2"}) - self.assertEqual(self.get(sock_type='ipv6')['status'], 200, 'range 4') - self.assertEqual(self.get(port=7081)['status'], 404, 'range 4 ipv4') + assert self.get(sock_type='ipv6')['status'] == 200, 'range 4' + assert self.get(port=7081)['status'] == 404, 'range 4 ipv4' self.route_match({"source": "::0-::2"}) - self.assertEqual(self.get(sock_type='ipv6')['status'], 200, 'range 5') - self.assertEqual(self.get(port=7081)['status'], 404, 'range 5 ipv4') + assert self.get(sock_type='ipv6')['status'] == 200, 'range 5' + assert self.get(port=7081)['status'] == 404, 'range 5 ipv4' self.route_match({"source": "::0-::1"}) - self.assertEqual(self.get(sock_type='ipv6')['status'], 200, 'range 6') - self.assertEqual(self.get(port=7081)['status'], 404, 'range 6 ipv4') + assert self.get(sock_type='ipv6')['status'] == 200, 'range 6' + assert self.get(port=7081)['status'] == 404, 'range 6 ipv4' def test_routes_source_cidr(self): - self.assertIn( - 'success', - self.conf( - { - "*:7080": {"pass": "routes"}, - "[::1]:7081": {"pass": "routes"}, - }, - 'listeners', - ), - 'source listeners configure', - ) + assert 'success' in self.conf( + {"*:7080": {"pass": "routes"}, "[::1]:7081": {"pass": "routes"},}, + 'listeners', + ), 'source listeners configure' def get_ipv6(): return self.get(sock_type='ipv6', port=7081) self.route_match({"source": "127.0.0.1/32"}) - self.assertEqual(self.get()['status'], 200, '32') - self.assertEqual(get_ipv6()['status'], 404, '32 ipv6') + assert self.get()['status'] == 200, '32' + assert get_ipv6()['status'] == 404, '32 ipv6' self.route_match({"source": "127.0.0.0/32"}) - self.assertEqual(self.get()['status'], 404, '32 2') - self.assertEqual(get_ipv6()['status'], 404, '32 2 ipv6') + assert self.get()['status'] == 404, '32 2' + assert get_ipv6()['status'] == 404, '32 2 ipv6' self.route_match({"source": "127.0.0.0/31"}) - self.assertEqual(self.get()['status'], 200, '31') - self.assertEqual(get_ipv6()['status'], 404, '31 ipv6') + assert self.get()['status'] == 200, '31' + assert get_ipv6()['status'] == 404, '31 ipv6' self.route_match({"source": "0.0.0.0/1"}) - self.assertEqual(self.get()['status'], 200, '1') - self.assertEqual(get_ipv6()['status'], 404, '1 ipv6') + assert self.get()['status'] == 200, '1' + assert get_ipv6()['status'] == 404, '1 ipv6' self.route_match({"source": "0.0.0.0/0"}) - self.assertEqual(self.get()['status'], 200, '0') - self.assertEqual(get_ipv6()['status'], 404, '0 ipv6') + assert self.get()['status'] == 200, '0' + assert get_ipv6()['status'] == 404, '0 ipv6' def test_routes_source_cidr_ipv6(self): - self.assertIn( - 'success', - self.conf( - { - "[::1]:7080": {"pass": "routes"}, - "127.0.0.1:7081": {"pass": "routes"}, - }, - 'listeners', - ), - 'source listeners configure', - ) + assert 'success' in self.conf( + { + "[::1]:7080": {"pass": "routes"}, + "127.0.0.1:7081": {"pass": "routes"}, + }, + 'listeners', + ), 'source listeners configure' self.route_match({"source": "::1/128"}) - self.assertEqual(self.get(sock_type='ipv6')['status'], 200, '128') - self.assertEqual(self.get(port=7081)['status'], 404, '128 ipv4') + assert self.get(sock_type='ipv6')['status'] == 200, '128' + assert self.get(port=7081)['status'] == 404, '128 ipv4' self.route_match({"source": "::0/128"}) - self.assertEqual(self.get(sock_type='ipv6')['status'], 404, '128 2') - self.assertEqual(self.get(port=7081)['status'], 404, '128 ipv4') + assert self.get(sock_type='ipv6')['status'] == 404, '128 2' + assert self.get(port=7081)['status'] == 404, '128 ipv4' self.route_match({"source": "::0/127"}) - self.assertEqual(self.get(sock_type='ipv6')['status'], 200, '127') - self.assertEqual(self.get(port=7081)['status'], 404, '127 ipv4') + assert self.get(sock_type='ipv6')['status'] == 200, '127' + assert self.get(port=7081)['status'] == 404, '127 ipv4' self.route_match({"source": "::0/32"}) - self.assertEqual(self.get(sock_type='ipv6')['status'], 200, '32') - self.assertEqual(self.get(port=7081)['status'], 404, '32 ipv4') + assert self.get(sock_type='ipv6')['status'] == 200, '32' + assert self.get(port=7081)['status'] == 404, '32 ipv4' self.route_match({"source": "::0/1"}) - self.assertEqual(self.get(sock_type='ipv6')['status'], 200, '1') - self.assertEqual(self.get(port=7081)['status'], 404, '1 ipv4') + assert self.get(sock_type='ipv6')['status'] == 200, '1' + assert self.get(port=7081)['status'] == 404, '1 ipv4' self.route_match({"source": "::/0"}) - self.assertEqual(self.get(sock_type='ipv6')['status'], 200, '0') - self.assertEqual(self.get(port=7081)['status'], 404, '0 ipv4') + assert self.get(sock_type='ipv6')['status'] == 200, '0' + assert self.get(port=7081)['status'] == 404, '0 ipv4' def test_routes_source_unix(self): - addr = self.testdir + '/sock' + addr = self.temp_dir + '/sock' - self.assertIn( - 'success', - self.conf({"unix:" + addr: {"pass": "routes"}}, 'listeners'), - 'source listeners configure', - ) + assert 'success' in self.conf( + {"unix:" + addr: {"pass": "routes"}}, 'listeners' + ), 'source listeners configure' self.route_match({"source": "!0.0.0.0/0"}) - self.assertEqual( - self.get(sock_type='unix', addr=addr)['status'], 200, 'unix ipv4' - ) + assert ( + self.get(sock_type='unix', addr=addr)['status'] == 200 + ), 'unix ipv4' self.route_match({"source": "!::/0"}) - self.assertEqual( - self.get(sock_type='unix', addr=addr)['status'], 200, 'unix ipv6' - ) + assert ( + self.get(sock_type='unix', addr=addr)['status'] == 200 + ), 'unix ipv6' def test_routes_match_source(self): self.route_match({"source": "::"}) @@ -1863,7 +1733,7 @@ class TestRouting(TestApplicationProto): } ) self.route_match({"source": "*:0-65535"}) - self.assertEqual(self.get()['status'], 200, 'source any') + assert self.get()['status'] == 200, 'source any' def test_routes_match_source_invalid(self): self.route_match_invalid({"source": "127"}) @@ -1888,104 +1758,84 @@ class TestRouting(TestApplicationProto): self.route_match_invalid({"source": "*:65536"}) def test_routes_match_destination(self): - self.assertIn( - 'success', - self.conf( - {"*:7080": {"pass": "routes"}, "*:7081": {"pass": "routes"}}, - 'listeners', - ), - 'listeners configure', - ) + assert 'success' in self.conf( + {"*:7080": {"pass": "routes"}, "*:7081": {"pass": "routes"}}, + 'listeners', + ), 'listeners configure' self.route_match({"destination": "*:7080"}) - self.assertEqual(self.get()['status'], 200, 'dest') - self.assertEqual(self.get(port=7081)['status'], 404, 'dest 2') + assert self.get()['status'] == 200, 'dest' + assert self.get(port=7081)['status'] == 404, 'dest 2' self.route_match({"destination": ["127.0.0.1:7080"]}) - self.assertEqual(self.get()['status'], 200, 'dest 3') - self.assertEqual(self.get(port=7081)['status'], 404, 'dest 4') + assert self.get()['status'] == 200, 'dest 3' + assert self.get(port=7081)['status'] == 404, 'dest 4' self.route_match({"destination": "!*:7080"}) - self.assertEqual(self.get()['status'], 404, 'dest neg') - self.assertEqual(self.get(port=7081)['status'], 200, 'dest neg 2') + assert self.get()['status'] == 404, 'dest neg' + assert self.get(port=7081)['status'] == 200, 'dest neg 2' self.route_match({"destination": ['!*:7080', '!*:7081']}) - self.assertEqual(self.get()['status'], 404, 'dest neg 3') - self.assertEqual(self.get(port=7081)['status'], 404, 'dest neg 4') + assert self.get()['status'] == 404, 'dest neg 3' + assert self.get(port=7081)['status'] == 404, 'dest neg 4' self.route_match({"destination": ['!*:7081', '!*:7082']}) - self.assertEqual(self.get()['status'], 200, 'dest neg 5') + assert self.get()['status'] == 200, 'dest neg 5' self.route_match({"destination": ['*:7080', '!*:7080']}) - self.assertEqual(self.get()['status'], 404, 'dest neg 6') + assert self.get()['status'] == 404, 'dest neg 6' self.route_match( {"destination": ['127.0.0.1:7080', '*:7081', '!*:7080']} ) - self.assertEqual(self.get()['status'], 404, 'dest neg 7') - self.assertEqual(self.get(port=7081)['status'], 200, 'dest neg 8') + assert self.get()['status'] == 404, 'dest neg 7' + assert self.get(port=7081)['status'] == 200, 'dest neg 8' self.route_match({"destination": ['!*:7081', '!*:7082', '*:7083']}) - self.assertEqual(self.get()['status'], 404, 'dest neg 9') + assert self.get()['status'] == 404, 'dest neg 9' self.route_match( {"destination": ['*:7081', '!127.0.0.1:7080', '*:7080']} ) - self.assertEqual(self.get()['status'], 404, 'dest neg 10') - self.assertEqual(self.get(port=7081)['status'], 200, 'dest neg 11') + assert self.get()['status'] == 404, 'dest neg 10' + assert self.get(port=7081)['status'] == 200, 'dest neg 11' - self.assertIn( - 'success', - self.conf_delete('routes/0/match/destination/0'), - 'remove destination rule', - ) - self.assertEqual(self.get()['status'], 404, 'dest neg 12') - self.assertEqual(self.get(port=7081)['status'], 404, 'dest neg 13') + assert 'success' in self.conf_delete( + 'routes/0/match/destination/0' + ), 'remove destination rule' + assert self.get()['status'] == 404, 'dest neg 12' + assert self.get(port=7081)['status'] == 404, 'dest neg 13' - self.assertIn( - 'success', - self.conf_delete('routes/0/match/destination/0'), - 'remove destination rule 2', - ) - self.assertEqual(self.get()['status'], 200, 'dest neg 14') - self.assertEqual(self.get(port=7081)['status'], 404, 'dest neg 15') + assert 'success' in self.conf_delete( + 'routes/0/match/destination/0' + ), 'remove destination rule 2' + assert self.get()['status'] == 200, 'dest neg 14' + assert self.get(port=7081)['status'] == 404, 'dest neg 15' - self.assertIn( - 'success', - self.conf_post("\"!127.0.0.1\"", 'routes/0/match/destination'), - 'add destination rule', - ) - self.assertEqual(self.get()['status'], 404, 'dest neg 16') - self.assertEqual(self.get(port=7081)['status'], 404, 'dest neg 17') + assert 'success' in self.conf_post( + "\"!127.0.0.1\"", 'routes/0/match/destination' + ), 'add destination rule' + assert self.get()['status'] == 404, 'dest neg 16' + assert self.get(port=7081)['status'] == 404, 'dest neg 17' def test_routes_match_destination_proxy(self): - self.assertIn( - 'success', - self.conf( - { - "listeners": { - "*:7080": {"pass": "routes/first"}, - "*:7081": {"pass": "routes/second"}, - }, - "routes": { - "first": [ - {"action": {"proxy": "http://127.0.0.1:7081"}} - ], - "second": [ - { - "match": {"destination": ["127.0.0.1:7081"]}, - "action": {"return": 200}, - } - ], - }, - "applications": {}, - } - ), - 'proxy configure', - ) - - self.assertEqual(self.get()['status'], 200, 'proxy') - + assert 'success' in self.conf( + { + "listeners": { + "*:7080": {"pass": "routes/first"}, + "*:7081": {"pass": "routes/second"}, + }, + "routes": { + "first": [{"action": {"proxy": "http://127.0.0.1:7081"}}], + "second": [ + { + "match": {"destination": ["127.0.0.1:7081"]}, + "action": {"return": 200}, + } + ], + }, + "applications": {}, + } + ), 'proxy configure' -if __name__ == '__main__': - TestRouting.main() + assert self.get()['status'] == 200, 'proxy' diff --git a/test/test_routing_tls.py b/test/test_routing_tls.py index a9b8f88d..76cfb485 100644 --- a/test/test_routing_tls.py +++ b/test/test_routing_tls.py @@ -7,36 +7,22 @@ class TestRoutingTLS(TestApplicationTLS): def test_routes_match_scheme_tls(self): self.certificate() - self.assertIn( - 'success', - self.conf( - { - "listeners": { - "*:7080": {"pass": "routes"}, - "*:7081": { - "pass": "routes", - "tls": {"certificate": 'default'}, - }, + assert 'success' in self.conf( + { + "listeners": { + "*:7080": {"pass": "routes"}, + "*:7081": { + "pass": "routes", + "tls": {"certificate": 'default'}, }, - "routes": [ - { - "match": {"scheme": "http"}, - "action": {"return": 200}, - }, - { - "match": {"scheme": "https"}, - "action": {"return": 201}, - }, - ], - "applications": {}, - } - ), - 'scheme configure', - ) + }, + "routes": [ + {"match": {"scheme": "http"}, "action": {"return": 200}}, + {"match": {"scheme": "https"}, "action": {"return": 201}}, + ], + "applications": {}, + } + ), 'scheme configure' - self.assertEqual(self.get()['status'], 200, 'http') - self.assertEqual(self.get_ssl(port=7081)['status'], 201, 'https') - - -if __name__ == '__main__': - TestRoutingTLS.main() + assert self.get()['status'] == 200, 'http' + assert self.get_ssl(port=7081)['status'] == 201, 'https' diff --git a/test/test_ruby_application.py b/test/test_ruby_application.py index 4709df6c..f84935f8 100644 --- a/test/test_ruby_application.py +++ b/test/test_ruby_application.py @@ -1,5 +1,8 @@ -import unittest +import re +import pytest + +from conftest import skip_alert from unit.applications.lang.ruby import TestApplicationRuby @@ -21,173 +24,151 @@ class TestRubyApplication(TestApplicationRuby): body=body, ) - self.assertEqual(resp['status'], 200, 'status') + assert resp['status'] == 200, 'status' headers = resp['headers'] header_server = headers.pop('Server') - self.assertRegex(header_server, r'Unit/[\d\.]+', 'server header') - self.assertEqual( - headers.pop('Server-Software'), - header_server, - 'server software header', - ) + assert re.search(r'Unit/[\d\.]+', header_server), 'server header' + assert ( + headers.pop('Server-Software') == header_server + ), 'server software header' date = headers.pop('Date') - self.assertEqual(date[-4:], ' GMT', 'date header timezone') - self.assertLess( - abs(self.date_to_sec_epoch(date) - self.sec_epoch()), - 5, - 'date header', - ) - - self.assertDictEqual( - headers, - { - 'Connection': 'close', - 'Content-Length': str(len(body)), - 'Content-Type': 'text/html', - 'Request-Method': 'POST', - 'Request-Uri': '/', - 'Http-Host': 'localhost', - 'Server-Protocol': 'HTTP/1.1', - 'Custom-Header': 'blah', - 'Rack-Version': '13', - 'Rack-Url-Scheme': 'http', - 'Rack-Multithread': 'false', - 'Rack-Multiprocess': 'true', - 'Rack-Run-Once': 'false', - 'Rack-Hijack-Q': 'false', - 'Rack-Hijack': '', - 'Rack-Hijack-IO': '', - }, - 'headers', - ) - self.assertEqual(resp['body'], body, 'body') + assert date[-4:] == ' GMT', 'date header timezone' + assert ( + abs(self.date_to_sec_epoch(date) - self.sec_epoch()) < 5 + ), 'date header' + + assert headers == { + 'Connection': 'close', + 'Content-Length': str(len(body)), + 'Content-Type': 'text/html', + 'Request-Method': 'POST', + 'Request-Uri': '/', + 'Http-Host': 'localhost', + 'Server-Protocol': 'HTTP/1.1', + 'Custom-Header': 'blah', + 'Rack-Version': '13', + 'Rack-Url-Scheme': 'http', + 'Rack-Multithread': 'false', + 'Rack-Multiprocess': 'true', + 'Rack-Run-Once': 'false', + 'Rack-Hijack-Q': 'false', + 'Rack-Hijack': '', + 'Rack-Hijack-IO': '', + }, 'headers' + assert resp['body'] == body, 'body' def test_ruby_application_query_string(self): self.load('query_string') resp = self.get(url='/?var1=val1&var2=val2') - self.assertEqual( - resp['headers']['Query-String'], - 'var1=val1&var2=val2', - 'Query-String header', - ) + assert ( + resp['headers']['Query-String'] == 'var1=val1&var2=val2' + ), 'Query-String header' def test_ruby_application_query_string_empty(self): self.load('query_string') resp = self.get(url='/?') - self.assertEqual(resp['status'], 200, 'query string empty status') - self.assertEqual( - resp['headers']['Query-String'], '', 'query string empty' - ) + assert resp['status'] == 200, 'query string empty status' + assert resp['headers']['Query-String'] == '', 'query string empty' def test_ruby_application_query_string_absent(self): self.load('query_string') resp = self.get() - self.assertEqual(resp['status'], 200, 'query string absent status') - self.assertEqual( - resp['headers']['Query-String'], '', 'query string absent' - ) + assert resp['status'] == 200, 'query string absent status' + assert resp['headers']['Query-String'] == '', 'query string absent' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_ruby_application_server_port(self): self.load('server_port') - self.assertEqual( - self.get()['headers']['Server-Port'], '7080', 'Server-Port header' - ) + assert ( + self.get()['headers']['Server-Port'] == '7080' + ), 'Server-Port header' def test_ruby_application_status_int(self): self.load('status_int') - self.assertEqual(self.get()['status'], 200, 'status int') + assert self.get()['status'] == 200, 'status int' def test_ruby_application_input_read_empty(self): self.load('input_read_empty') - self.assertEqual(self.get()['body'], '', 'read empty') + assert self.get()['body'] == '', 'read empty' def test_ruby_application_input_read_parts(self): self.load('input_read_parts') - self.assertEqual( - self.post(body='0123456789')['body'], - '012345678', - 'input read parts', - ) + assert ( + self.post(body='0123456789')['body'] == '012345678' + ), 'input read parts' def test_ruby_application_input_read_buffer(self): self.load('input_read_buffer') - self.assertEqual( - self.post(body='0123456789')['body'], - '0123456789', - 'input read buffer', - ) + assert ( + self.post(body='0123456789')['body'] == '0123456789' + ), 'input read buffer' def test_ruby_application_input_read_buffer_not_empty(self): self.load('input_read_buffer_not_empty') - self.assertEqual( - self.post(body='0123456789')['body'], - '0123456789', - 'input read buffer not empty', - ) + assert ( + self.post(body='0123456789')['body'] == '0123456789' + ), 'input read buffer not empty' def test_ruby_application_input_gets(self): self.load('input_gets') body = '0123456789' - self.assertEqual(self.post(body=body)['body'], body, 'input gets') + assert self.post(body=body)['body'] == body, 'input gets' def test_ruby_application_input_gets_2(self): self.load('input_gets') - self.assertEqual( - self.post(body='01234\n56789\n')['body'], '01234\n', 'input gets 2' - ) + assert ( + self.post(body='01234\n56789\n')['body'] == '01234\n' + ), 'input gets 2' def test_ruby_application_input_gets_all(self): self.load('input_gets_all') body = '\n01234\n56789\n\n' - self.assertEqual(self.post(body=body)['body'], body, 'input gets all') + assert self.post(body=body)['body'] == body, 'input gets all' def test_ruby_application_input_each(self): self.load('input_each') body = '\n01234\n56789\n\n' - self.assertEqual(self.post(body=body)['body'], body, 'input each') + assert self.post(body=body)['body'] == body, 'input each' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_ruby_application_input_rewind(self): self.load('input_rewind') body = '0123456789' - self.assertEqual(self.post(body=body)['body'], body, 'input rewind') + assert self.post(body=body)['body'] == body, 'input rewind' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_ruby_application_syntax_error(self): - self.skip_alerts.extend( - [ - r'Failed to parse rack script', - r'syntax error', - r'new_from_string', - r'parse_file', - ] + skip_alert( + r'Failed to parse rack script', + r'syntax error', + r'new_from_string', + r'parse_file', ) self.load('syntax_error') - self.assertEqual(self.get()['status'], 500, 'syntax error') + assert self.get()['status'] == 500, 'syntax error' def test_ruby_application_errors_puts(self): self.load('errors_puts') @@ -196,10 +177,10 @@ class TestRubyApplication(TestApplicationRuby): self.stop() - self.assertIsNotNone( - self.wait_for_record(r'\[error\].+Error in application'), - 'errors puts', - ) + assert ( + self.wait_for_record(r'\[error\].+Error in application') + is not None + ), 'errors puts' def test_ruby_application_errors_puts_int(self): self.load('errors_puts_int') @@ -208,9 +189,9 @@ class TestRubyApplication(TestApplicationRuby): self.stop() - self.assertIsNotNone( - self.wait_for_record(r'\[error\].+1234567890'), 'errors puts int' - ) + assert ( + self.wait_for_record(r'\[error\].+1234567890') is not None + ), 'errors puts int' def test_ruby_application_errors_write(self): self.load('errors_write') @@ -219,15 +200,15 @@ class TestRubyApplication(TestApplicationRuby): self.stop() - self.assertIsNotNone( - self.wait_for_record(r'\[error\].+Error in application'), - 'errors write', - ) + assert ( + self.wait_for_record(r'\[error\].+Error in application') + is not None + ), 'errors write' def test_ruby_application_errors_write_to_s_custom(self): self.load('errors_write_to_s_custom') - self.assertEqual(self.get()['status'], 200, 'errors write to_s custom') + assert self.get()['status'] == 200, 'errors write to_s custom' def test_ruby_application_errors_write_int(self): self.load('errors_write_int') @@ -236,9 +217,9 @@ class TestRubyApplication(TestApplicationRuby): self.stop() - self.assertIsNotNone( - self.wait_for_record(r'\[error\].+1234567890'), 'errors write int' - ) + assert ( + self.wait_for_record(r'\[error\].+1234567890') is not None + ), 'errors write int' def test_ruby_application_at_exit(self): self.load('at_exit') @@ -249,79 +230,81 @@ class TestRubyApplication(TestApplicationRuby): self.stop() - self.assertIsNotNone( - self.wait_for_record(r'\[error\].+At exit called\.'), 'at exit' - ) + assert ( + self.wait_for_record(r'\[error\].+At exit called\.') is not None + ), 'at exit' def test_ruby_application_header_custom(self): self.load('header_custom') resp = self.post(body="\ntc=one,two\ntc=three,four,\n\n") - self.assertEqual( - resp['headers']['Custom-Header'], - ['', 'tc=one,two', 'tc=three,four,', '', ''], - 'header custom', - ) + assert resp['headers']['Custom-Header'] == [ + '', + 'tc=one,two', + 'tc=three,four,', + '', + '', + ], 'header custom' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_ruby_application_header_custom_non_printable(self): self.load('header_custom') - self.assertEqual( - self.post(body='\b')['status'], 500, 'header custom non printable' - ) + assert ( + self.post(body='\b')['status'] == 500 + ), 'header custom non printable' def test_ruby_application_header_status(self): self.load('header_status') - self.assertEqual(self.get()['status'], 200, 'header status') + assert self.get()['status'] == 200, 'header status' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_ruby_application_header_rack(self): self.load('header_rack') - self.assertEqual(self.get()['status'], 500, 'header rack') + assert self.get()['status'] == 500, 'header rack' def test_ruby_application_body_empty(self): self.load('body_empty') - self.assertEqual(self.get()['body'], '', 'body empty') + assert self.get()['body'] == '', 'body empty' def test_ruby_application_body_array(self): self.load('body_array') - self.assertEqual(self.get()['body'], '0123456789', 'body array') + assert self.get()['body'] == '0123456789', 'body array' def test_ruby_application_body_large(self): self.load('mirror') body = '0123456789' * 1000 - self.assertEqual(self.post(body=body)['body'], body, 'body large') + assert self.post(body=body)['body'] == body, 'body large' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_ruby_application_body_each_error(self): self.load('body_each_error') - self.assertEqual(self.get()['status'], 500, 'body each error status') + assert self.get()['status'] == 500, 'body each error status' self.stop() - self.assertIsNotNone( - self.wait_for_record(r'\[error\].+Failed to run ruby script'), - 'body each error', - ) + assert ( + self.wait_for_record(r'\[error\].+Failed to run ruby script') + is not None + ), 'body each error' def test_ruby_application_body_file(self): self.load('body_file') - self.assertEqual(self.get()['body'], 'body\n', 'body file') + assert self.get()['body'] == 'body\n', 'body file' def test_ruby_keepalive_body(self): self.load('mirror') - self.assertEqual(self.get()['status'], 200, 'init') + assert self.get()['status'] == 200, 'init' body = '0123456789' * 500 (resp, sock) = self.post( @@ -335,7 +318,7 @@ class TestRubyApplication(TestApplicationRuby): read_timeout=1, ) - self.assertEqual(resp['body'], body, 'keep-alive 1') + assert resp['body'] == body, 'keep-alive 1' body = '0123456789' resp = self.post( @@ -348,31 +331,22 @@ class TestRubyApplication(TestApplicationRuby): body=body, ) - self.assertEqual(resp['body'], body, 'keep-alive 2') + assert resp['body'] == body, 'keep-alive 2' def test_ruby_application_constants(self): self.load('constants') resp = self.get() - self.assertEqual(resp['status'], 200, 'status') + assert resp['status'] == 200, 'status' headers = resp['headers'] - self.assertGreater(len(headers['X-Copyright']), 0, 'RUBY_COPYRIGHT') - self.assertGreater( - len(headers['X-Description']), 0, 'RUBY_DESCRIPTION' - ) - self.assertGreater(len(headers['X-Engine']), 0, 'RUBY_ENGINE') - self.assertGreater( - len(headers['X-Engine-Version']), 0, 'RUBY_ENGINE_VERSION' - ) - self.assertGreater(len(headers['X-Patchlevel']), 0, 'RUBY_PATCHLEVEL') - self.assertGreater(len(headers['X-Platform']), 0, 'RUBY_PLATFORM') - self.assertGreater( - len(headers['X-Release-Date']), 0, 'RUBY_RELEASE_DATE' - ) - self.assertGreater(len(headers['X-Revision']), 0, 'RUBY_REVISION') - self.assertGreater(len(headers['X-Version']), 0, 'RUBY_VERSION') - -if __name__ == '__main__': - TestRubyApplication.main() + assert len(headers['X-Copyright']) > 0, 'RUBY_COPYRIGHT' + assert len(headers['X-Description']) > 0, 'RUBY_DESCRIPTION' + assert len(headers['X-Engine']) > 0, 'RUBY_ENGINE' + assert len(headers['X-Engine-Version']) > 0, 'RUBY_ENGINE_VERSION' + assert len(headers['X-Patchlevel']) > 0, 'RUBY_PATCHLEVEL' + assert len(headers['X-Platform']) > 0, 'RUBY_PLATFORM' + assert len(headers['X-Release-Date']) > 0, 'RUBY_RELEASE_DATE' + assert len(headers['X-Revision']) > 0, 'RUBY_REVISION' + assert len(headers['X-Version']) > 0, 'RUBY_VERSION' diff --git a/test/test_ruby_isolation.py b/test/test_ruby_isolation.py index 9bac162e..13ca0e16 100644 --- a/test/test_ruby_isolation.py +++ b/test/test_ruby_isolation.py @@ -1,7 +1,7 @@ -import os -import shutil -import unittest +import pytest + +from conftest import option from unit.applications.lang.ruby import TestApplicationRuby from unit.feature.isolation import TestFeatureIsolation @@ -12,60 +12,39 @@ class TestRubyIsolation(TestApplicationRuby): isolation = TestFeatureIsolation() @classmethod - def setUpClass(cls, complete_check=True): - unit = super().setUpClass(complete_check=False) + def setup_class(cls, complete_check=True): + unit = super().setup_class(complete_check=False) - TestFeatureIsolation().check(cls.available, unit.testdir) + TestFeatureIsolation().check(cls.available, unit.temp_dir) return unit if not complete_check else unit.complete() - def test_ruby_isolation_rootfs(self): + def test_ruby_isolation_rootfs(self, is_su): isolation_features = self.available['features']['isolation'].keys() if 'mnt' not in isolation_features: - print('requires mnt ns') - raise unittest.SkipTest() + pytest.skip('requires mnt ns') - if not self.is_su: + if not is_su: if 'user' not in isolation_features: - print('requires unprivileged userns or root') - raise unittest.SkipTest() + pytest.skip('requires unprivileged userns or root') if not 'unprivileged_userns_clone' in isolation_features: - print('requires unprivileged userns or root') - raise unittest.SkipTest() - - os.mkdir(self.testdir + '/ruby') + pytest.skip('requires unprivileged userns or root') - shutil.copytree( - self.current_dir + '/ruby/status_int', - self.testdir + '/ruby/status_int', - ) isolation = { - 'namespaces': {'credential': not self.is_su, 'mount': True}, - 'rootfs': self.testdir, + 'namespaces': {'credential': not is_su, 'mount': True}, + 'rootfs': option.test_dir, } self.load('status_int', isolation=isolation) - self.assertIn( - 'success', - self.conf( - '"/ruby/status_int/config.ru"', - 'applications/status_int/script', - ), + assert 'success' in self.conf( + '"/ruby/status_int/config.ru"', 'applications/status_int/script', ) - self.assertIn( - 'success', - self.conf( - '"/ruby/status_int"', - 'applications/status_int/working_directory', - ), + assert 'success' in self.conf( + '"/ruby/status_int"', 'applications/status_int/working_directory', ) - self.assertEqual(self.get()['status'], 200, 'status int') - - -if __name__ == '__main__': - TestRubyIsolation.main() + assert self.get()['status'] == 200, 'status int' diff --git a/test/test_settings.py b/test/test_settings.py index 6600358d..b0af6b04 100644 --- a/test/test_settings.py +++ b/test/test_settings.py @@ -1,6 +1,8 @@ +import re import socket import time -import unittest + +import pytest from unit.applications.lang.python import TestApplicationPython @@ -32,7 +34,7 @@ Connection: close raw=True, ) - self.assertEqual(resp['status'], 408, 'status header read timeout') + assert resp['status'] == 408, 'status header read timeout' def test_settings_header_read_timeout_update(self): self.load('empty') @@ -83,9 +85,7 @@ Connection: close raw=True, ) - self.assertEqual( - resp['status'], 408, 'status header read timeout update' - ) + assert resp['status'] == 408, 'status header read timeout update' def test_settings_body_read_timeout(self): self.load('empty') @@ -109,7 +109,7 @@ Connection: close resp = self.http(b"""0123456789""", sock=sock, raw=True) - self.assertEqual(resp['status'], 408, 'status body read timeout') + assert resp['status'] == 408, 'status body read timeout' def test_settings_body_read_timeout_update(self): self.load('empty') @@ -144,9 +144,7 @@ Connection: close resp = self.http(b"""6789""", sock=sock, raw=True) - self.assertEqual( - resp['status'], 200, 'status body read timeout update' - ) + assert resp['status'] == 200, 'status body read timeout update' def test_settings_send_timeout(self): self.load('mirror') @@ -155,7 +153,7 @@ Connection: close self.conf({'http': {'send_timeout': 1}}, 'settings') - addr = self.testdir + '/sock' + addr = self.temp_dir + '/sock' self.conf({"unix:" + addr: {'application': 'mirror'}}, 'listeners') @@ -182,13 +180,13 @@ Connection: close sock.close() - self.assertRegex(data, r'200 OK', 'status send timeout') - self.assertLess(len(data), data_len, 'data send timeout') + assert re.search(r'200 OK', data), 'status send timeout' + assert len(data) < data_len, 'data send timeout' def test_settings_idle_timeout(self): self.load('empty') - self.assertEqual(self.get()['status'], 200, 'init') + assert self.get()['status'] == 200, 'init' self.conf({'http': {'idle_timeout': 2}}, 'settings') @@ -204,17 +202,33 @@ Connection: close headers={'Host': 'localhost', 'Connection': 'close'}, sock=sock ) - self.assertEqual(resp['status'], 408, 'status idle timeout') + assert resp['status'] == 408, 'status idle timeout' + + def test_settings_idle_timeout_2(self): + self.load('empty') + + assert self.get()['status'] == 200, 'init' + + self.conf({'http': {'idle_timeout': 1}}, 'settings') + + _, sock = self.http(b'', start=True, raw=True, no_recv=True) + + time.sleep(3) + + assert ( + self.get( + headers={'Host': 'localhost', 'Connection': 'close'}, sock=sock + )['status'] + == 408 + ), 'status idle timeout' def test_settings_max_body_size(self): self.load('empty') self.conf({'http': {'max_body_size': 5}}, 'settings') - self.assertEqual(self.post(body='01234')['status'], 200, 'status size') - self.assertEqual( - self.post(body='012345')['status'], 413, 'status size max' - ) + assert self.post(body='01234')['status'] == 200, 'status size' + assert self.post(body='012345')['status'] == 413, 'status size max' def test_settings_max_body_size_large(self): self.load('mirror') @@ -223,32 +237,26 @@ Connection: close body = '0123456789abcdef' * 4 * 64 * 1024 resp = self.post(body=body, read_buffer_size=1024 * 1024) - self.assertEqual(resp['status'], 200, 'status size 4') - self.assertEqual(resp['body'], body, 'status body 4') + assert resp['status'] == 200, 'status size 4' + assert resp['body'] == body, 'status body 4' body = '0123456789abcdef' * 8 * 64 * 1024 resp = self.post(body=body, read_buffer_size=1024 * 1024) - self.assertEqual(resp['status'], 200, 'status size 8') - self.assertEqual(resp['body'], body, 'status body 8') + assert resp['status'] == 200, 'status size 8' + assert resp['body'] == body, 'status body 8' body = '0123456789abcdef' * 16 * 64 * 1024 resp = self.post(body=body, read_buffer_size=1024 * 1024) - self.assertEqual(resp['status'], 200, 'status size 16') - self.assertEqual(resp['body'], body, 'status body 16') + assert resp['status'] == 200, 'status size 16' + assert resp['body'] == body, 'status body 16' body = '0123456789abcdef' * 32 * 64 * 1024 resp = self.post(body=body, read_buffer_size=1024 * 1024) - self.assertEqual(resp['status'], 200, 'status size 32') - self.assertEqual(resp['body'], body, 'status body 32') + assert resp['status'] == 200, 'status size 32' + assert resp['body'] == body, 'status body 32' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_settings_negative_value(self): - self.assertIn( - 'error', - self.conf({'http': {'max_body_size': -1}}, 'settings'), - 'settings negative value', - ) - - -if __name__ == '__main__': - TestSettings.main() + assert 'error' in self.conf( + {'http': {'max_body_size': -1}}, 'settings' + ), 'settings negative value' diff --git a/test/test_share_fallback.py b/test/test_share_fallback.py index ca5e2678..391d0836 100644 --- a/test/test_share_fallback.py +++ b/test/test_share_fallback.py @@ -1,20 +1,21 @@ import os +from conftest import skip_alert from unit.applications.proto import TestApplicationProto class TestStatic(TestApplicationProto): prerequisites = {} - def setUp(self): - super().setUp() + def setup_method(self): + super().setup_method() - os.makedirs(self.testdir + '/assets/dir') - with open(self.testdir + '/assets/index.html', 'w') as index: + os.makedirs(self.temp_dir + '/assets/dir') + with open(self.temp_dir + '/assets/index.html', 'w') as index: index.write('0123456789') - os.makedirs(self.testdir + '/assets/403') - os.chmod(self.testdir + '/assets/403', 0o000) + os.makedirs(self.temp_dir + '/assets/403') + os.chmod(self.temp_dir + '/assets/403', 0o000) self._load_conf( { @@ -22,48 +23,46 @@ class TestStatic(TestApplicationProto): "*:7080": {"pass": "routes"}, "*:7081": {"pass": "routes"}, }, - "routes": [{"action": {"share": self.testdir + "/assets"}}], + "routes": [{"action": {"share": self.temp_dir + "/assets"}}], "applications": {}, } ) - def tearDown(self): - os.chmod(self.testdir + '/assets/403', 0o777) + def teardown_method(self): + os.chmod(self.temp_dir + '/assets/403', 0o777) - super().tearDown() + super().teardown_method() def action_update(self, conf): - self.assertIn('success', self.conf(conf, 'routes/0/action')) + assert 'success' in self.conf(conf, 'routes/0/action') def test_fallback(self): self.action_update({"share": "/blah"}) - self.assertEqual(self.get()['status'], 404, 'bad path no fallback') + assert self.get()['status'] == 404, 'bad path no fallback' self.action_update({"share": "/blah", "fallback": {"return": 200}}) resp = self.get() - self.assertEqual(resp['status'], 200, 'bad path fallback status') - self.assertEqual(resp['body'], '', 'bad path fallback') + assert resp['status'] == 200, 'bad path fallback status' + assert resp['body'] == '', 'bad path fallback' def test_fallback_valid_path(self): self.action_update( - {"share": self.testdir + "/assets", "fallback": {"return": 200}} + {"share": self.temp_dir + "/assets", "fallback": {"return": 200}} ) resp = self.get() - self.assertEqual(resp['status'], 200, 'fallback status') - self.assertEqual(resp['body'], '0123456789', 'fallback') + assert resp['status'] == 200, 'fallback status' + assert resp['body'] == '0123456789', 'fallback' resp = self.get(url='/403/') - self.assertEqual(resp['status'], 200, 'fallback status 403') - self.assertEqual(resp['body'], '', 'fallback 403') + assert resp['status'] == 200, 'fallback status 403' + assert resp['body'] == '', 'fallback 403' resp = self.post() - self.assertEqual(resp['status'], 200, 'fallback status 405') - self.assertEqual(resp['body'], '', 'fallback 405') + assert resp['status'] == 200, 'fallback status 405' + assert resp['body'] == '', 'fallback 405' - self.assertEqual( - self.get(url='/dir')['status'], 301, 'fallback status 301' - ) + assert self.get(url='/dir')['status'] == 301, 'fallback status 301' def test_fallback_nested(self): self.action_update( @@ -77,62 +76,56 @@ class TestStatic(TestApplicationProto): ) resp = self.get() - self.assertEqual(resp['status'], 200, 'fallback nested status') - self.assertEqual(resp['body'], '', 'fallback nested') + assert resp['status'] == 200, 'fallback nested status' + assert resp['body'] == '', 'fallback nested' def test_fallback_share(self): self.action_update( { "share": "/blah", - "fallback": {"share": self.testdir + "/assets"}, + "fallback": {"share": self.temp_dir + "/assets"}, } ) resp = self.get() - self.assertEqual(resp['status'], 200, 'fallback share status') - self.assertEqual(resp['body'], '0123456789', 'fallback share') + assert resp['status'] == 200, 'fallback share status' + assert resp['body'] == '0123456789', 'fallback share' resp = self.head() - self.assertEqual(resp['status'], 200, 'fallback share status HEAD') - self.assertEqual(resp['body'], '', 'fallback share HEAD') + assert resp['status'] == 200, 'fallback share status HEAD' + assert resp['body'] == '', 'fallback share HEAD' - self.assertEqual( - self.get(url='/dir')['status'], 301, 'fallback share status 301' - ) + assert ( + self.get(url='/dir')['status'] == 301 + ), 'fallback share status 301' def test_fallback_proxy(self): - self.assertIn( - 'success', - self.conf( - [ - { - "match": {"destination": "*:7081"}, - "action": {"return": 200}, - }, - { - "action": { - "share": "/blah", - "fallback": {"proxy": "http://127.0.0.1:7081"}, - } - }, - ], - 'routes', - ), - 'configure fallback proxy route', - ) + assert 'success' in self.conf( + [ + { + "match": {"destination": "*:7081"}, + "action": {"return": 200}, + }, + { + "action": { + "share": "/blah", + "fallback": {"proxy": "http://127.0.0.1:7081"}, + } + }, + ], + 'routes', + ), 'configure fallback proxy route' resp = self.get() - self.assertEqual(resp['status'], 200, 'fallback proxy status') - self.assertEqual(resp['body'], '', 'fallback proxy') + assert resp['status'] == 200, 'fallback proxy status' + assert resp['body'] == '', 'fallback proxy' def test_fallback_proxy_loop(self): - self.skip_alerts.extend( - [ - r'open.*/blah/index.html.*failed', - r'accept.*failed', - r'socket.*failed', - r'new connections are not accepted', - ] + skip_alert( + r'open.*/blah/index.html.*failed', + r'accept.*failed', + r'socket.*failed', + r'new connections are not accepted', ) self.action_update( @@ -140,12 +133,12 @@ class TestStatic(TestApplicationProto): ) self.get(no_recv=True) - self.assertIn('success', self.conf_delete('listeners/*:7081')) + assert 'success' in self.conf_delete('listeners/*:7081') self.get(read_timeout=1) def test_fallback_invalid(self): def check_error(conf): - self.assertIn('error', self.conf(conf, 'routes/0/action')) + assert 'error' in self.conf(conf, 'routes/0/action') check_error({"share": "/blah", "fallback": {}}) check_error({"share": "/blah", "fallback": ""}) @@ -154,7 +147,3 @@ class TestStatic(TestApplicationProto): {"proxy": "http://127.0.0.1:7081", "fallback": {"share": "/blah"}} ) check_error({"fallback": {"share": "/blah"}}) - - -if __name__ == '__main__': - TestStatic.main() diff --git a/test/test_static.py b/test/test_static.py index bee5db28..0b82b4e8 100644 --- a/test/test_static.py +++ b/test/test_static.py @@ -1,21 +1,24 @@ import os import socket -import unittest +import pytest + +from conftest import waitforfiles from unit.applications.proto import TestApplicationProto class TestStatic(TestApplicationProto): prerequisites = {} - def setUp(self): - super().setUp() + def setup_method(self): + super().setup_method() - os.makedirs(self.testdir + '/assets/dir') - with open(self.testdir + '/assets/index.html', 'w') as index, \ - open(self.testdir + '/assets/README', 'w') as readme, \ - open(self.testdir + '/assets/log.log', 'w') as log, \ - open(self.testdir + '/assets/dir/file', 'w') as file: + os.makedirs(self.temp_dir + '/assets/dir') + with open(self.temp_dir + '/assets/index.html', 'w') as index, open( + self.temp_dir + '/assets/README', 'w' + ) as readme, open(self.temp_dir + '/assets/log.log', 'w') as log, open( + self.temp_dir + '/assets/dir/file', 'w' + ) as file: index.write('0123456789') readme.write('readme') log.write('[debug]') @@ -24,7 +27,7 @@ class TestStatic(TestApplicationProto): self._load_conf( { "listeners": {"*:7080": {"pass": "routes"}}, - "routes": [{"action": {"share": self.testdir + "/assets"}}], + "routes": [{"action": {"share": self.temp_dir + "/assets"}}], "settings": { "http": { "static": { @@ -36,126 +39,98 @@ class TestStatic(TestApplicationProto): ) def test_static_index(self): - self.assertEqual( - self.get(url='/index.html')['body'], '0123456789', 'index' - ) - self.assertEqual(self.get(url='/')['body'], '0123456789', 'index 2') - self.assertEqual(self.get(url='//')['body'], '0123456789', 'index 3') - self.assertEqual(self.get(url='/.')['body'], '0123456789', 'index 4') - self.assertEqual(self.get(url='/./')['body'], '0123456789', 'index 5') - self.assertEqual( - self.get(url='/?blah')['body'], '0123456789', 'index vars' - ) - self.assertEqual( - self.get(url='/#blah')['body'], '0123456789', 'index anchor' - ) - self.assertEqual( - self.get(url='/dir/')['status'], 404, 'index not found' - ) + assert self.get(url='/index.html')['body'] == '0123456789', 'index' + assert self.get(url='/')['body'] == '0123456789', 'index 2' + assert self.get(url='//')['body'] == '0123456789', 'index 3' + assert self.get(url='/.')['body'] == '0123456789', 'index 4' + assert self.get(url='/./')['body'] == '0123456789', 'index 5' + assert self.get(url='/?blah')['body'] == '0123456789', 'index vars' + assert self.get(url='/#blah')['body'] == '0123456789', 'index anchor' + assert self.get(url='/dir/')['status'] == 404, 'index not found' resp = self.get(url='/index.html/') - self.assertEqual(resp['status'], 404, 'index not found 2 status') - self.assertEqual( - resp['headers']['Content-Type'], - 'text/html', - 'index not found 2 Content-Type', - ) + assert resp['status'] == 404, 'index not found 2 status' + assert ( + resp['headers']['Content-Type'] == 'text/html' + ), 'index not found 2 Content-Type' def test_static_large_file(self): file_size = 32 * 1024 * 1024 - with open(self.testdir + '/assets/large', 'wb') as f: + with open(self.temp_dir + '/assets/large', 'wb') as f: f.seek(file_size - 1) f.write(b'\0') - self.assertEqual( - len( - self.get(url='/large', read_buffer_size=1024 * 1024)['body'] - ), - file_size, - 'large file', - ) + assert ( + len(self.get(url='/large', read_buffer_size=1024 * 1024)['body']) + == file_size + ), 'large file' def test_static_etag(self): etag = self.get(url='/')['headers']['ETag'] etag_2 = self.get(url='/README')['headers']['ETag'] - self.assertNotEqual(etag, etag_2, 'different ETag') - self.assertEqual( - etag, self.get(url='/')['headers']['ETag'], 'same ETag' - ) + assert etag != etag_2, 'different ETag' + assert etag == self.get(url='/')['headers']['ETag'], 'same ETag' - with open(self.testdir + '/assets/index.html', 'w') as f: + with open(self.temp_dir + '/assets/index.html', 'w') as f: f.write('blah') - self.assertNotEqual( - etag, self.get(url='/')['headers']['ETag'], 'new ETag' - ) + assert etag != self.get(url='/')['headers']['ETag'], 'new ETag' def test_static_redirect(self): resp = self.get(url='/dir') - self.assertEqual(resp['status'], 301, 'redirect status') - self.assertEqual( - resp['headers']['Location'], '/dir/', 'redirect Location' - ) - self.assertNotIn( - 'Content-Type', resp['headers'], 'redirect Content-Type' - ) + assert resp['status'] == 301, 'redirect status' + assert resp['headers']['Location'] == '/dir/', 'redirect Location' + assert 'Content-Type' not in resp['headers'], 'redirect Content-Type' def test_static_space_in_name(self): os.rename( - self.testdir + '/assets/dir/file', - self.testdir + '/assets/dir/fi le', - ) - self.waitforfiles(self.testdir + '/assets/dir/fi le') - self.assertEqual( - self.get(url='/dir/fi le')['body'], 'blah', 'file name' + self.temp_dir + '/assets/dir/file', + self.temp_dir + '/assets/dir/fi le', ) + assert waitforfiles(self.temp_dir + '/assets/dir/fi le') + assert self.get(url='/dir/fi le')['body'] == 'blah', 'file name' - os.rename(self.testdir + '/assets/dir', self.testdir + '/assets/di r') - self.waitforfiles(self.testdir + '/assets/di r/fi le') - self.assertEqual( - self.get(url='/di r/fi le')['body'], 'blah', 'dir name' - ) + os.rename(self.temp_dir + '/assets/dir', self.temp_dir + '/assets/di r') + assert waitforfiles(self.temp_dir + '/assets/di r/fi le') + assert self.get(url='/di r/fi le')['body'] == 'blah', 'dir name' os.rename( - self.testdir + '/assets/di r', self.testdir + '/assets/ di r ' - ) - self.waitforfiles(self.testdir + '/assets/ di r /fi le') - self.assertEqual( - self.get(url='/ di r /fi le')['body'], 'blah', 'dir name enclosing' - ) - - self.assertEqual( - self.get(url='/%20di%20r%20/fi le')['body'], 'blah', 'dir encoded' - ) - self.assertEqual( - self.get(url='/ di r %2Ffi le')['body'], 'blah', 'slash encoded' - ) - self.assertEqual( - self.get(url='/ di r /fi%20le')['body'], 'blah', 'file encoded' - ) - self.assertEqual( - self.get(url='/%20di%20r%20%2Ffi%20le')['body'], 'blah', 'encoded' - ) - self.assertEqual( - self.get(url='/%20%64%69%20%72%20%2F%66%69%20%6C%65')['body'], - 'blah', - 'encoded 2', - ) + self.temp_dir + '/assets/di r', self.temp_dir + '/assets/ di r ' + ) + assert waitforfiles(self.temp_dir + '/assets/ di r /fi le') + assert ( + self.get(url='/ di r /fi le')['body'] == 'blah' + ), 'dir name enclosing' + + assert ( + self.get(url='/%20di%20r%20/fi le')['body'] == 'blah' + ), 'dir encoded' + assert ( + self.get(url='/ di r %2Ffi le')['body'] == 'blah' + ), 'slash encoded' + assert ( + self.get(url='/ di r /fi%20le')['body'] == 'blah' + ), 'file encoded' + assert ( + self.get(url='/%20di%20r%20%2Ffi%20le')['body'] == 'blah' + ), 'encoded' + assert ( + self.get(url='/%20%64%69%20%72%20%2F%66%69%20%6C%65')['body'] + == 'blah' + ), 'encoded 2' os.rename( - self.testdir + '/assets/ di r /fi le', - self.testdir + '/assets/ di r / fi le ', - ) - self.waitforfiles(self.testdir + '/assets/ di r / fi le ') - self.assertEqual( - self.get(url='/%20di%20r%20/%20fi%20le%20')['body'], - 'blah', - 'file name enclosing', + self.temp_dir + '/assets/ di r /fi le', + self.temp_dir + '/assets/ di r / fi le ', ) + assert waitforfiles(self.temp_dir + '/assets/ di r / fi le ') + assert ( + self.get(url='/%20di%20r%20/%20fi%20le%20')['body'] == 'blah' + ), 'file name enclosing' try: - print('файл') + open(self.temp_dir + '/ф а', 'a').close() utf8 = True except: @@ -163,267 +138,190 @@ class TestStatic(TestApplicationProto): if utf8: os.rename( - self.testdir + '/assets/ di r / fi le ', - self.testdir + '/assets/ di r /фа йл', - ) - self.waitforfiles(self.testdir + '/assets/ di r /фа йл') - self.assertEqual( - self.get(url='/ di r /фа йл')['body'], 'blah', 'file name 2' + self.temp_dir + '/assets/ di r / fi le ', + self.temp_dir + '/assets/ di r /фа йл', ) + assert waitforfiles(self.temp_dir + '/assets/ di r /фа йл') + assert ( + self.get(url='/ di r /фа йл')['body'] == 'blah' + ), 'file name 2' os.rename( - self.testdir + '/assets/ di r ', - self.testdir + '/assets/ди ректория', - ) - self.waitforfiles(self.testdir + '/assets/ди ректория/фа йл') - self.assertEqual( - self.get(url='/ди ректория/фа йл')['body'], 'blah', 'dir name 2' + self.temp_dir + '/assets/ di r ', + self.temp_dir + '/assets/ди ректория', ) + assert waitforfiles(self.temp_dir + '/assets/ди ректория/фа йл') + assert ( + self.get(url='/ди ректория/фа йл')['body'] == 'blah' + ), 'dir name 2' def test_static_unix_socket(self): sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - sock.bind(self.testdir + '/assets/unix_socket') + sock.bind(self.temp_dir + '/assets/unix_socket') - self.assertEqual(self.get(url='/unix_socket')['status'], 404, 'socket') + assert self.get(url='/unix_socket')['status'] == 404, 'socket' sock.close() def test_static_unix_fifo(self): - os.mkfifo(self.testdir + '/assets/fifo') + os.mkfifo(self.temp_dir + '/assets/fifo') - self.assertEqual(self.get(url='/fifo')['status'], 404, 'fifo') + assert self.get(url='/fifo')['status'] == 404, 'fifo' def test_static_symlink(self): - os.symlink(self.testdir + '/assets/dir', self.testdir + '/assets/link') + os.symlink(self.temp_dir + '/assets/dir', self.temp_dir + '/assets/link') - self.assertEqual(self.get(url='/dir')['status'], 301, 'dir') - self.assertEqual(self.get(url='/dir/file')['status'], 200, 'file') - self.assertEqual(self.get(url='/link')['status'], 301, 'symlink dir') - self.assertEqual( - self.get(url='/link/file')['status'], 200, 'symlink file' - ) + assert self.get(url='/dir')['status'] == 301, 'dir' + assert self.get(url='/dir/file')['status'] == 200, 'file' + assert self.get(url='/link')['status'] == 301, 'symlink dir' + assert self.get(url='/link/file')['status'] == 200, 'symlink file' def test_static_method(self): resp = self.head() - self.assertEqual(resp['status'], 200, 'HEAD status') - self.assertEqual(resp['body'], '', 'HEAD empty body') + assert resp['status'] == 200, 'HEAD status' + assert resp['body'] == '', 'HEAD empty body' - self.assertEqual(self.delete()['status'], 405, 'DELETE') - self.assertEqual(self.post()['status'], 405, 'POST') - self.assertEqual(self.put()['status'], 405, 'PUT') + assert self.delete()['status'] == 405, 'DELETE' + assert self.post()['status'] == 405, 'POST' + assert self.put()['status'] == 405, 'PUT' def test_static_path(self): - self.assertEqual( - self.get(url='/dir/../dir/file')['status'], 200, 'relative' - ) + assert self.get(url='/dir/../dir/file')['status'] == 200, 'relative' - self.assertEqual(self.get(url='./')['status'], 400, 'path invalid') - self.assertEqual(self.get(url='../')['status'], 400, 'path invalid 2') - self.assertEqual(self.get(url='/..')['status'], 400, 'path invalid 3') - self.assertEqual( - self.get(url='../assets/')['status'], 400, 'path invalid 4' - ) - self.assertEqual( - self.get(url='/../assets/')['status'], 400, 'path invalid 5' - ) + assert self.get(url='./')['status'] == 400, 'path invalid' + assert self.get(url='../')['status'] == 400, 'path invalid 2' + assert self.get(url='/..')['status'] == 400, 'path invalid 3' + assert self.get(url='../assets/')['status'] == 400, 'path invalid 4' + assert self.get(url='/../assets/')['status'] == 400, 'path invalid 5' def test_static_two_clients(self): _, sock = self.get(url='/', start=True, no_recv=True) _, sock2 = self.get(url='/', start=True, no_recv=True) - self.assertEqual(sock.recv(1), b'H', 'client 1') - self.assertEqual(sock2.recv(1), b'H', 'client 2') - self.assertEqual(sock.recv(1), b'T', 'client 1 again') - self.assertEqual(sock2.recv(1), b'T', 'client 2 again') + assert sock.recv(1) == b'H', 'client 1' + assert sock2.recv(1) == b'H', 'client 2' + assert sock.recv(1) == b'T', 'client 1 again' + assert sock2.recv(1) == b'T', 'client 2 again' sock.close() sock2.close() def test_static_mime_types(self): - self.assertIn( - 'success', - self.conf( - { - "text/x-code/x-blah/x-blah": "readme", - "text/plain": [".html", ".log", "file"], - }, - 'settings/http/static/mime_types', - ), - 'configure mime_types', - ) - - self.assertEqual( - self.get(url='/README')['headers']['Content-Type'], - 'text/x-code/x-blah/x-blah', - 'mime_types string case insensitive', - ) - self.assertEqual( - self.get(url='/index.html')['headers']['Content-Type'], - 'text/plain', - 'mime_types html', - ) - self.assertEqual( - self.get(url='/')['headers']['Content-Type'], - 'text/plain', - 'mime_types index default', - ) - self.assertEqual( - self.get(url='/dir/file')['headers']['Content-Type'], - 'text/plain', - 'mime_types file in dir', - ) + assert 'success' in self.conf( + { + "text/x-code/x-blah/x-blah": "readme", + "text/plain": [".html", ".log", "file"], + }, + 'settings/http/static/mime_types', + ), 'configure mime_types' + + assert ( + self.get(url='/README')['headers']['Content-Type'] + == 'text/x-code/x-blah/x-blah' + ), 'mime_types string case insensitive' + assert ( + self.get(url='/index.html')['headers']['Content-Type'] + == 'text/plain' + ), 'mime_types html' + assert ( + self.get(url='/')['headers']['Content-Type'] == 'text/plain' + ), 'mime_types index default' + assert ( + self.get(url='/dir/file')['headers']['Content-Type'] + == 'text/plain' + ), 'mime_types file in dir' def test_static_mime_types_partial_match(self): - self.assertIn( - 'success', - self.conf( - { - "text/x-blah": ["ile", "fil", "f", "e", ".file"], - }, - 'settings/http/static/mime_types', - ), - 'configure mime_types', - ) - self.assertNotIn( - 'Content-Type', self.get(url='/dir/file'), 'partial match' - ) + assert 'success' in self.conf( + {"text/x-blah": ["ile", "fil", "f", "e", ".file"],}, + 'settings/http/static/mime_types', + ), 'configure mime_types' + assert 'Content-Type' not in self.get(url='/dir/file'), 'partial match' def test_static_mime_types_reconfigure(self): - self.assertIn( - 'success', - self.conf( - { - "text/x-code": "readme", - "text/plain": [".html", ".log", "file"], - }, - 'settings/http/static/mime_types', - ), - 'configure mime_types', - ) - - self.assertEqual( - self.conf_get('settings/http/static/mime_types'), - {'text/x-code': 'readme', 'text/plain': ['.html', '.log', 'file']}, - 'mime_types get', - ) - self.assertEqual( - self.conf_get('settings/http/static/mime_types/text%2Fx-code'), - 'readme', - 'mime_types get string', - ) - self.assertEqual( - self.conf_get('settings/http/static/mime_types/text%2Fplain'), - ['.html', '.log', 'file'], - 'mime_types get array', - ) - self.assertEqual( - self.conf_get('settings/http/static/mime_types/text%2Fplain/1'), - '.log', - 'mime_types get array element', - ) - - self.assertIn( - 'success', - self.conf_delete('settings/http/static/mime_types/text%2Fplain/2'), - 'mime_types remove array element', - ) - self.assertNotIn( - 'Content-Type', - self.get(url='/dir/file')['headers'], - 'mime_types removed', - ) - - self.assertIn( - 'success', - self.conf_post( - '"file"', 'settings/http/static/mime_types/text%2Fplain' - ), - 'mime_types add array element', - ) - self.assertEqual( - self.get(url='/dir/file')['headers']['Content-Type'], - 'text/plain', - 'mime_types reverted', - ) - - self.assertIn( - 'success', - self.conf( - '"file"', 'settings/http/static/mime_types/text%2Fplain' - ), - 'configure mime_types update', - ) - self.assertEqual( - self.get(url='/dir/file')['headers']['Content-Type'], - 'text/plain', - 'mime_types updated', - ) - self.assertNotIn( - 'Content-Type', - self.get(url='/log.log')['headers'], - 'mime_types updated 2', - ) - - self.assertIn( - 'success', - self.conf( - '".log"', 'settings/http/static/mime_types/text%2Fblahblahblah' - ), - 'configure mime_types create', - ) - self.assertEqual( - self.get(url='/log.log')['headers']['Content-Type'], - 'text/blahblahblah', - 'mime_types create', - ) + assert 'success' in self.conf( + { + "text/x-code": "readme", + "text/plain": [".html", ".log", "file"], + }, + 'settings/http/static/mime_types', + ), 'configure mime_types' + + assert self.conf_get('settings/http/static/mime_types') == { + 'text/x-code': 'readme', + 'text/plain': ['.html', '.log', 'file'], + }, 'mime_types get' + assert ( + self.conf_get('settings/http/static/mime_types/text%2Fx-code') + == 'readme' + ), 'mime_types get string' + assert self.conf_get( + 'settings/http/static/mime_types/text%2Fplain' + ) == ['.html', '.log', 'file'], 'mime_types get array' + assert ( + self.conf_get('settings/http/static/mime_types/text%2Fplain/1') + == '.log' + ), 'mime_types get array element' + + assert 'success' in self.conf_delete( + 'settings/http/static/mime_types/text%2Fplain/2' + ), 'mime_types remove array element' + assert ( + 'Content-Type' not in self.get(url='/dir/file')['headers'] + ), 'mime_types removed' + + assert 'success' in self.conf_post( + '"file"', 'settings/http/static/mime_types/text%2Fplain' + ), 'mime_types add array element' + assert ( + self.get(url='/dir/file')['headers']['Content-Type'] + == 'text/plain' + ), 'mime_types reverted' + + assert 'success' in self.conf( + '"file"', 'settings/http/static/mime_types/text%2Fplain' + ), 'configure mime_types update' + assert ( + self.get(url='/dir/file')['headers']['Content-Type'] + == 'text/plain' + ), 'mime_types updated' + assert ( + 'Content-Type' not in self.get(url='/log.log')['headers'] + ), 'mime_types updated 2' + + assert 'success' in self.conf( + '".log"', 'settings/http/static/mime_types/text%2Fblahblahblah' + ), 'configure mime_types create' + assert ( + self.get(url='/log.log')['headers']['Content-Type'] + == 'text/blahblahblah' + ), 'mime_types create' def test_static_mime_types_correct(self): - self.assertIn( - 'error', - self.conf( - {"text/x-code": "readme", "text/plain": "readme"}, - 'settings/http/static/mime_types', - ), - 'mime_types same extensions', - ) - self.assertIn( - 'error', - self.conf( - {"text/x-code": [".h", ".c"], "text/plain": ".c"}, - 'settings/http/static/mime_types', - ), - 'mime_types same extensions array', - ) - self.assertIn( - 'error', - self.conf( - { - "text/x-code": [".h", ".c", "readme"], - "text/plain": "README", - }, - 'settings/http/static/mime_types', - ), - 'mime_types same extensions case insensitive', - ) - - @unittest.skip('not yet') + assert 'error' in self.conf( + {"text/x-code": "readme", "text/plain": "readme"}, + 'settings/http/static/mime_types', + ), 'mime_types same extensions' + assert 'error' in self.conf( + {"text/x-code": [".h", ".c"], "text/plain": ".c"}, + 'settings/http/static/mime_types', + ), 'mime_types same extensions array' + assert 'error' in self.conf( + {"text/x-code": [".h", ".c", "readme"], "text/plain": "README",}, + 'settings/http/static/mime_types', + ), 'mime_types same extensions case insensitive' + + @pytest.mark.skip('not yet') def test_static_mime_types_invalid(self): - self.assertIn( - 'error', - self.http( - b"""PUT /config/settings/http/static/mime_types/%0%00% HTTP/1.1\r + assert 'error' in self.http( + b"""PUT /config/settings/http/static/mime_types/%0%00% HTTP/1.1\r Host: localhost\r Connection: close\r Content-Length: 6\r \r \"blah\"""", - raw_resp=True, - raw=True, - sock_type='unix', - addr=self.testdir + '/control.unit.sock', - ), - 'mime_types invalid', - ) - -if __name__ == '__main__': - TestStatic.main() + raw_resp=True, + raw=True, + sock_type='unix', + addr=self.temp_dir + '/control.unit.sock', + ), 'mime_types invalid' diff --git a/test/test_tls.py b/test/test_tls.py index a0434174..518a834c 100644 --- a/test/test_tls.py +++ b/test/test_tls.py @@ -2,8 +2,10 @@ import io import re import ssl import subprocess -import unittest +import pytest + +from conftest import skip_alert from unit.applications.tls import TestApplicationTLS @@ -11,7 +13,7 @@ class TestTLS(TestApplicationTLS): prerequisites = {'modules': {'python': 'any', 'openssl': 'any'}} def findall(self, pattern): - with open(self.testdir + '/unit.log', 'r', errors='ignore') as f: + with open(self.temp_dir + '/unit.log', 'r', errors='ignore') as f: return re.findall(pattern, f.read()) def openssl_date_to_sec_epoch(self, date): @@ -38,7 +40,7 @@ class TestTLS(TestApplicationTLS): self.add_tls() - self.assertEqual(self.get_ssl()['status'], 200, 'add listener option') + assert self.get_ssl()['status'] == 200, 'add listener option' def test_tls_listener_option_remove(self): self.load('empty') @@ -51,18 +53,16 @@ class TestTLS(TestApplicationTLS): self.remove_tls() - self.assertEqual(self.get()['status'], 200, 'remove listener option') + assert self.get()['status'] == 200, 'remove listener option' def test_tls_certificate_remove(self): self.load('empty') self.certificate() - self.assertIn( - 'success', - self.conf_delete('/certificates/default'), - 'remove certificate', - ) + assert 'success' in self.conf_delete( + '/certificates/default' + ), 'remove certificate' def test_tls_certificate_remove_used(self): self.load('empty') @@ -71,11 +71,9 @@ class TestTLS(TestApplicationTLS): self.add_tls() - self.assertIn( - 'error', - self.conf_delete('/certificates/default'), - 'remove certificate', - ) + assert 'error' in self.conf_delete( + '/certificates/default' + ), 'remove certificate' def test_tls_certificate_remove_nonexisting(self): self.load('empty') @@ -84,13 +82,11 @@ class TestTLS(TestApplicationTLS): self.add_tls() - self.assertIn( - 'error', - self.conf_delete('/certificates/blah'), - 'remove nonexistings certificate', - ) + assert 'error' in self.conf_delete( + '/certificates/blah' + ), 'remove nonexistings certificate' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_tls_certificate_update(self): self.load('empty') @@ -102,20 +98,18 @@ class TestTLS(TestApplicationTLS): self.certificate() - self.assertNotEqual( - cert_old, self.get_server_certificate(), 'update certificate' - ) + assert cert_old != self.get_server_certificate(), 'update certificate' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_tls_certificate_key_incorrect(self): self.load('empty') self.certificate('first', False) self.certificate('second', False) - self.assertIn( - 'error', self.certificate_load('first', 'second'), 'key incorrect' - ) + assert 'error' in self.certificate_load( + 'first', 'second' + ), 'key incorrect' def test_tls_certificate_change(self): self.load('empty') @@ -129,20 +123,16 @@ class TestTLS(TestApplicationTLS): self.add_tls(cert='new') - self.assertNotEqual( - cert_old, self.get_server_certificate(), 'change certificate' - ) + assert cert_old != self.get_server_certificate(), 'change certificate' def test_tls_certificate_key_rsa(self): self.load('empty') self.certificate() - self.assertEqual( - self.conf_get('/certificates/default/key'), - 'RSA (2048 bits)', - 'certificate key rsa', - ) + assert ( + self.conf_get('/certificates/default/key') == 'RSA (2048 bits)' + ), 'certificate key rsa' def test_tls_certificate_key_ec(self): self.load('empty') @@ -155,8 +145,10 @@ class TestTLS(TestApplicationTLS): 'ecparam', '-noout', '-genkey', - '-out', self.testdir + '/ec.key', - '-name', 'prime256v1', + '-out', + self.temp_dir + '/ec.key', + '-name', + 'prime256v1', ], stderr=subprocess.STDOUT, ) @@ -167,19 +159,23 @@ class TestTLS(TestApplicationTLS): 'req', '-x509', '-new', - '-subj', '/CN=ec/', - '-config', self.testdir + '/openssl.conf', - '-key', self.testdir + '/ec.key', - '-out', self.testdir + '/ec.crt', + '-subj', + '/CN=ec/', + '-config', + self.temp_dir + '/openssl.conf', + '-key', + self.temp_dir + '/ec.key', + '-out', + self.temp_dir + '/ec.crt', ], stderr=subprocess.STDOUT, ) self.certificate_load('ec') - self.assertEqual( - self.conf_get('/certificates/ec/key'), 'ECDH', 'certificate key ec' - ) + assert ( + self.conf_get('/certificates/ec/key') == 'ECDH' + ), 'certificate key ec' def test_tls_certificate_chain_options(self): self.load('empty') @@ -188,35 +184,29 @@ class TestTLS(TestApplicationTLS): chain = self.conf_get('/certificates/default/chain') - self.assertEqual(len(chain), 1, 'certificate chain length') + assert len(chain) == 1, 'certificate chain length' cert = chain[0] - self.assertEqual( - cert['subject']['common_name'], - 'default', - 'certificate subject common name', - ) - self.assertEqual( - cert['issuer']['common_name'], - 'default', - 'certificate issuer common name', - ) + assert ( + cert['subject']['common_name'] == 'default' + ), 'certificate subject common name' + assert ( + cert['issuer']['common_name'] == 'default' + ), 'certificate issuer common name' - self.assertLess( + assert ( abs( self.sec_epoch() - self.openssl_date_to_sec_epoch(cert['validity']['since']) - ), - 5, - 'certificate validity since', - ) - self.assertEqual( + ) + < 5 + ), 'certificate validity since' + assert ( self.openssl_date_to_sec_epoch(cert['validity']['until']) - - self.openssl_date_to_sec_epoch(cert['validity']['since']), - 2592000, - 'certificate validity until', - ) + - self.openssl_date_to_sec_epoch(cert['validity']['since']) + == 2592000 + ), 'certificate validity until' def test_tls_certificate_chain(self): self.load('empty') @@ -228,10 +218,14 @@ class TestTLS(TestApplicationTLS): 'openssl', 'req', '-new', - '-subj', '/CN=int/', - '-config', self.testdir + '/openssl.conf', - '-out', self.testdir + '/int.csr', - '-keyout', self.testdir + '/int.key', + '-subj', + '/CN=int/', + '-config', + self.temp_dir + '/openssl.conf', + '-out', + self.temp_dir + '/int.csr', + '-keyout', + self.temp_dir + '/int.key', ], stderr=subprocess.STDOUT, ) @@ -241,15 +235,19 @@ class TestTLS(TestApplicationTLS): 'openssl', 'req', '-new', - '-subj', '/CN=end/', - '-config', self.testdir + '/openssl.conf', - '-out', self.testdir + '/end.csr', - '-keyout', self.testdir + '/end.key', + '-subj', + '/CN=end/', + '-config', + self.temp_dir + '/openssl.conf', + '-out', + self.temp_dir + '/end.csr', + '-keyout', + self.temp_dir + '/end.key', ], stderr=subprocess.STDOUT, ) - with open(self.testdir + '/ca.conf', 'w') as f: + with open(self.temp_dir + '/ca.conf', 'w') as f: f.write( """[ ca ] default_ca = myca @@ -269,16 +267,16 @@ commonName = supplied [ myca_extensions ] basicConstraints = critical,CA:TRUE""" % { - 'dir': self.testdir, - 'database': self.testdir + '/certindex', - 'certserial': self.testdir + '/certserial', + 'dir': self.temp_dir, + 'database': self.temp_dir + '/certindex', + 'certserial': self.temp_dir + '/certserial', } ) - with open(self.testdir + '/certserial', 'w') as f: + with open(self.temp_dir + '/certserial', 'w') as f: f.write('1000') - with open(self.testdir + '/certindex', 'w') as f: + with open(self.temp_dir + '/certindex', 'w') as f: f.write('') subprocess.call( @@ -286,12 +284,18 @@ basicConstraints = critical,CA:TRUE""" 'openssl', 'ca', '-batch', - '-subj', '/CN=int/', - '-config', self.testdir + '/ca.conf', - '-keyfile', self.testdir + '/root.key', - '-cert', self.testdir + '/root.crt', - '-in', self.testdir + '/int.csr', - '-out', self.testdir + '/int.crt', + '-subj', + '/CN=int/', + '-config', + self.temp_dir + '/ca.conf', + '-keyfile', + self.temp_dir + '/root.key', + '-cert', + self.temp_dir + '/root.crt', + '-in', + self.temp_dir + '/int.csr', + '-out', + self.temp_dir + '/int.crt', ], stderr=subprocess.STDOUT, ) @@ -301,50 +305,50 @@ basicConstraints = critical,CA:TRUE""" 'openssl', 'ca', '-batch', - '-subj', '/CN=end/', - '-config', self.testdir + '/ca.conf', - '-keyfile', self.testdir + '/int.key', - '-cert', self.testdir + '/int.crt', - '-in', self.testdir + '/end.csr', - '-out', self.testdir + '/end.crt', + '-subj', + '/CN=end/', + '-config', + self.temp_dir + '/ca.conf', + '-keyfile', + self.temp_dir + '/int.key', + '-cert', + self.temp_dir + '/int.crt', + '-in', + self.temp_dir + '/end.csr', + '-out', + self.temp_dir + '/end.crt', ], stderr=subprocess.STDOUT, ) - crt_path = self.testdir + '/end-int.crt' - end_path = self.testdir + '/end.crt' - int_path = self.testdir + '/int.crt' + crt_path = self.temp_dir + '/end-int.crt' + end_path = self.temp_dir + '/end.crt' + int_path = self.temp_dir + '/int.crt' - with open(crt_path, 'wb') as crt, \ - open(end_path, 'rb') as end, \ - open(int_path, 'rb') as int: + with open(crt_path, 'wb') as crt, open(end_path, 'rb') as end, open( + int_path, 'rb' + ) as int: crt.write(end.read() + int.read()) self.context = ssl.create_default_context() self.context.check_hostname = False self.context.verify_mode = ssl.CERT_REQUIRED - self.context.load_verify_locations(self.testdir + '/root.crt') + self.context.load_verify_locations(self.temp_dir + '/root.crt') # incomplete chain - self.assertIn( - 'success', - self.certificate_load('end', 'end'), - 'certificate chain end upload', - ) + assert 'success' in self.certificate_load( + 'end', 'end' + ), 'certificate chain end upload' chain = self.conf_get('/certificates/end/chain') - self.assertEqual(len(chain), 1, 'certificate chain end length') - self.assertEqual( - chain[0]['subject']['common_name'], - 'end', - 'certificate chain end subject common name', - ) - self.assertEqual( - chain[0]['issuer']['common_name'], - 'int', - 'certificate chain end issuer common name', - ) + assert len(chain) == 1, 'certificate chain end length' + assert ( + chain[0]['subject']['common_name'] == 'end' + ), 'certificate chain end subject common name' + assert ( + chain[0]['issuer']['common_name'] == 'int' + ), 'certificate chain end issuer common name' self.add_tls(cert='end') @@ -353,79 +357,61 @@ basicConstraints = critical,CA:TRUE""" except ssl.SSLError: resp = None - self.assertEqual(resp, None, 'certificate chain incomplete chain') + assert resp == None, 'certificate chain incomplete chain' # intermediate - self.assertIn( - 'success', - self.certificate_load('int', 'int'), - 'certificate chain int upload', - ) + assert 'success' in self.certificate_load( + 'int', 'int' + ), 'certificate chain int upload' chain = self.conf_get('/certificates/int/chain') - self.assertEqual(len(chain), 1, 'certificate chain int length') - self.assertEqual( - chain[0]['subject']['common_name'], - 'int', - 'certificate chain int subject common name', - ) - self.assertEqual( - chain[0]['issuer']['common_name'], - 'root', - 'certificate chain int issuer common name', - ) + assert len(chain) == 1, 'certificate chain int length' + assert ( + chain[0]['subject']['common_name'] == 'int' + ), 'certificate chain int subject common name' + assert ( + chain[0]['issuer']['common_name'] == 'root' + ), 'certificate chain int issuer common name' self.add_tls(cert='int') - self.assertEqual( - self.get_ssl()['status'], 200, 'certificate chain intermediate' - ) + assert ( + self.get_ssl()['status'] == 200 + ), 'certificate chain intermediate' # intermediate server - self.assertIn( - 'success', - self.certificate_load('end-int', 'end'), - 'certificate chain end-int upload', - ) + assert 'success' in self.certificate_load( + 'end-int', 'end' + ), 'certificate chain end-int upload' chain = self.conf_get('/certificates/end-int/chain') - self.assertEqual(len(chain), 2, 'certificate chain end-int length') - self.assertEqual( - chain[0]['subject']['common_name'], - 'end', - 'certificate chain end-int int subject common name', - ) - self.assertEqual( - chain[0]['issuer']['common_name'], - 'int', - 'certificate chain end-int int issuer common name', - ) - self.assertEqual( - chain[1]['subject']['common_name'], - 'int', - 'certificate chain end-int end subject common name', - ) - self.assertEqual( - chain[1]['issuer']['common_name'], - 'root', - 'certificate chain end-int end issuer common name', - ) + assert len(chain) == 2, 'certificate chain end-int length' + assert ( + chain[0]['subject']['common_name'] == 'end' + ), 'certificate chain end-int int subject common name' + assert ( + chain[0]['issuer']['common_name'] == 'int' + ), 'certificate chain end-int int issuer common name' + assert ( + chain[1]['subject']['common_name'] == 'int' + ), 'certificate chain end-int end subject common name' + assert ( + chain[1]['issuer']['common_name'] == 'root' + ), 'certificate chain end-int end issuer common name' self.add_tls(cert='end-int') - self.assertEqual( - self.get_ssl()['status'], - 200, - 'certificate chain intermediate server', - ) + assert ( + self.get_ssl()['status'] == 200 + ), 'certificate chain intermediate server' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_tls_reconfigure(self): self.load('empty') - self.assertEqual(self.get()['status'], 200, 'init') + assert self.get()['status'] == 200, 'init' self.certificate() @@ -435,21 +421,17 @@ basicConstraints = critical,CA:TRUE""" read_timeout=1, ) - self.assertEqual(resp['status'], 200, 'initial status') + assert resp['status'] == 200, 'initial status' self.add_tls() - self.assertEqual( - self.get(sock=sock)['status'], 200, 'reconfigure status' - ) - self.assertEqual( - self.get_ssl()['status'], 200, 'reconfigure tls status' - ) + assert self.get(sock=sock)['status'] == 200, 'reconfigure status' + assert self.get_ssl()['status'] == 200, 'reconfigure tls status' def test_tls_keepalive(self): self.load('mirror') - self.assertEqual(self.get()['status'], 200, 'init') + assert self.get()['status'] == 200, 'init' self.certificate() @@ -466,7 +448,7 @@ basicConstraints = critical,CA:TRUE""" read_timeout=1, ) - self.assertEqual(resp['body'], '0123456789', 'keepalive 1') + assert resp['body'] == '0123456789', 'keepalive 1' resp = self.post_ssl( headers={ @@ -478,13 +460,13 @@ basicConstraints = critical,CA:TRUE""" body='0123456789', ) - self.assertEqual(resp['body'], '0123456789', 'keepalive 2') + assert resp['body'] == '0123456789', 'keepalive 2' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_tls_keepalive_certificate_remove(self): self.load('empty') - self.assertEqual(self.get()['status'], 200, 'init') + assert self.get()['status'] == 200, 'init' self.certificate() @@ -506,19 +488,17 @@ basicConstraints = critical,CA:TRUE""" except: resp = None - self.assertEqual(resp, None, 'keepalive remove certificate') + assert resp == None, 'keepalive remove certificate' - @unittest.skip('not yet') + @pytest.mark.skip('not yet') def test_tls_certificates_remove_all(self): self.load('empty') self.certificate() - self.assertIn( - 'success', - self.conf_delete('/certificates'), - 'remove all certificates', - ) + assert 'success' in self.conf_delete( + '/certificates' + ), 'remove all certificates' def test_tls_application_respawn(self): self.load('mirror') @@ -544,11 +524,11 @@ basicConstraints = critical,CA:TRUE""" subprocess.call(['kill', '-9', app_id]) - self.skip_alerts.append(r'process %s exited on signal 9' % app_id) + skip_alert(r'process %s exited on signal 9' % app_id) self.wait_for_record( re.compile( - ' (?!' + app_id + '#)(\d+)#\d+ "mirror" application started' + r' (?!' + app_id + r'#)(\d+)#\d+ "mirror" application started' ) ) @@ -562,15 +542,13 @@ basicConstraints = critical,CA:TRUE""" body='0123456789', ) - self.assertEqual(resp['status'], 200, 'application respawn status') - self.assertEqual( - resp['body'], '0123456789', 'application respawn body' - ) + assert resp['status'] == 200, 'application respawn status' + assert resp['body'] == '0123456789', 'application respawn body' def test_tls_url_scheme(self): self.load('variables') - self.assertEqual( + assert ( self.post( headers={ 'Host': 'localhost', @@ -578,16 +556,15 @@ basicConstraints = critical,CA:TRUE""" 'Custom-Header': '', 'Connection': 'close', } - )['headers']['Wsgi-Url-Scheme'], - 'http', - 'url scheme http', - ) + )['headers']['Wsgi-Url-Scheme'] + == 'http' + ), 'url scheme http' self.certificate() self.add_tls(application='variables') - self.assertEqual( + assert ( self.post_ssl( headers={ 'Host': 'localhost', @@ -595,10 +572,9 @@ basicConstraints = critical,CA:TRUE""" 'Custom-Header': '', 'Connection': 'close', } - )['headers']['Wsgi-Url-Scheme'], - 'https', - 'url scheme https', - ) + )['headers']['Wsgi-Url-Scheme'] + == 'https' + ), 'url scheme https' def test_tls_big_upload(self): self.load('upload') @@ -610,15 +586,14 @@ basicConstraints = critical,CA:TRUE""" filename = 'test.txt' data = '0123456789' * 9000 - res = self.post_ssl(body={ - 'file': { - 'filename': filename, - 'type': 'text/plain', - 'data': io.StringIO(data), + res = self.post_ssl( + body={ + 'file': { + 'filename': filename, + 'type': 'text/plain', + 'data': io.StringIO(data), + } } - }) - self.assertEqual(res['status'], 200, 'status ok') - self.assertEqual(res['body'], filename + data) - -if __name__ == '__main__': - TestTLS.main() + ) + assert res['status'] == 200, 'status ok' + assert res['body'] == filename + data diff --git a/test/test_upstreams_rr.py b/test/test_upstreams_rr.py index 2f74fbde..2ecf1d9a 100644 --- a/test/test_upstreams_rr.py +++ b/test/test_upstreams_rr.py @@ -1,50 +1,47 @@ import os import re +from conftest import option from unit.applications.lang.python import TestApplicationPython class TestUpstreamsRR(TestApplicationPython): prerequisites = {'modules': {'python': 'any'}} - def setUp(self): - super().setUp() + def setup_method(self): + super().setup_method() - self.assertIn( - 'success', - self.conf( - { - "listeners": { - "*:7080": {"pass": "upstreams/one"}, - "*:7090": {"pass": "upstreams/two"}, - "*:7081": {"pass": "routes/one"}, - "*:7082": {"pass": "routes/two"}, - "*:7083": {"pass": "routes/three"}, - }, - "upstreams": { - "one": { - "servers": { - "127.0.0.1:7081": {}, - "127.0.0.1:7082": {}, - }, - }, - "two": { - "servers": { - "127.0.0.1:7081": {}, - "127.0.0.1:7082": {}, - }, + assert 'success' in self.conf( + { + "listeners": { + "*:7080": {"pass": "upstreams/one"}, + "*:7090": {"pass": "upstreams/two"}, + "*:7081": {"pass": "routes/one"}, + "*:7082": {"pass": "routes/two"}, + "*:7083": {"pass": "routes/three"}, + }, + "upstreams": { + "one": { + "servers": { + "127.0.0.1:7081": {}, + "127.0.0.1:7082": {}, }, }, - "routes": { - "one": [{"action": {"return": 200}}], - "two": [{"action": {"return": 201}}], - "three": [{"action": {"return": 202}}], + "two": { + "servers": { + "127.0.0.1:7081": {}, + "127.0.0.1:7082": {}, + }, }, - "applications": {}, }, - ), - 'upstreams initial configuration', - ) + "routes": { + "one": [{"action": {"return": 200}}], + "two": [{"action": {"return": 201}}], + "three": [{"action": {"return": 202}}], + }, + "applications": {}, + }, + ), 'upstreams initial configuration' self.cpu_count = os.cpu_count() @@ -91,113 +88,87 @@ Connection: close def test_upstreams_rr_no_weight(self): resps = self.get_resps() - self.assertEqual(sum(resps), 100, 'no weight sum') - self.assertLessEqual( - abs(resps[0] - resps[1]), self.cpu_count, 'no weight' - ) + assert sum(resps) == 100, 'no weight sum' + assert abs(resps[0] - resps[1]) <= self.cpu_count, 'no weight' - self.assertIn( - 'success', - self.conf_delete('upstreams/one/servers/127.0.0.1:7081'), - 'no weight server remove', - ) + assert 'success' in self.conf_delete( + 'upstreams/one/servers/127.0.0.1:7081' + ), 'no weight server remove' resps = self.get_resps(req=50) - self.assertEqual(resps[1], 50, 'no weight 2') + assert resps[1] == 50, 'no weight 2' - self.assertIn( - 'success', - self.conf({}, 'upstreams/one/servers/127.0.0.1:7081'), - 'no weight server revert', - ) + assert 'success' in self.conf( + {}, 'upstreams/one/servers/127.0.0.1:7081' + ), 'no weight server revert' resps = self.get_resps() - self.assertEqual(sum(resps), 100, 'no weight 3 sum') - self.assertLessEqual( - abs(resps[0] - resps[1]), self.cpu_count, 'no weight 3' - ) + assert sum(resps) == 100, 'no weight 3 sum' + assert abs(resps[0] - resps[1]) <= self.cpu_count, 'no weight 3' - self.assertIn( - 'success', - self.conf({}, 'upstreams/one/servers/127.0.0.1:7083'), - 'no weight server new', - ) + assert 'success' in self.conf( + {}, 'upstreams/one/servers/127.0.0.1:7083' + ), 'no weight server new' resps = self.get_resps() - self.assertEqual(sum(resps), 100, 'no weight 4 sum') - self.assertLessEqual( - max(resps) - min(resps), self.cpu_count, 'no weight 4' - ) + assert sum(resps) == 100, 'no weight 4 sum' + assert max(resps) - min(resps) <= self.cpu_count, 'no weight 4' resps = self.get_resps_sc(req=30) - self.assertEqual(resps[0], 10, 'no weight 4 0') - self.assertEqual(resps[1], 10, 'no weight 4 1') - self.assertEqual(resps[2], 10, 'no weight 4 2') + assert resps[0] == 10, 'no weight 4 0' + assert resps[1] == 10, 'no weight 4 1' + assert resps[2] == 10, 'no weight 4 2' def test_upstreams_rr_weight(self): - self.assertIn( - 'success', - self.conf({"weight": 3}, 'upstreams/one/servers/127.0.0.1:7081'), - 'configure weight', - ) + assert 'success' in self.conf( + {"weight": 3}, 'upstreams/one/servers/127.0.0.1:7081' + ), 'configure weight' resps = self.get_resps_sc() - self.assertEqual(resps[0], 75, 'weight 3 0') - self.assertEqual(resps[1], 25, 'weight 3 1') + assert resps[0] == 75, 'weight 3 0' + assert resps[1] == 25, 'weight 3 1' - self.assertIn( - 'success', - self.conf_delete('upstreams/one/servers/127.0.0.1:7081/weight'), - 'configure weight remove', - ) + assert 'success' in self.conf_delete( + 'upstreams/one/servers/127.0.0.1:7081/weight' + ), 'configure weight remove' resps = self.get_resps_sc(req=10) - self.assertEqual(resps[0], 5, 'weight 0 0') - self.assertEqual(resps[1], 5, 'weight 0 1') + assert resps[0] == 5, 'weight 0 0' + assert resps[1] == 5, 'weight 0 1' - self.assertIn( - 'success', - self.conf('1', 'upstreams/one/servers/127.0.0.1:7081/weight'), - 'configure weight 1', - ) + assert 'success' in self.conf( + '1', 'upstreams/one/servers/127.0.0.1:7081/weight' + ), 'configure weight 1' resps = self.get_resps_sc() - self.assertEqual(resps[0], 50, 'weight 1 0') - self.assertEqual(resps[1], 50, 'weight 1 1') + assert resps[0] == 50, 'weight 1 0' + assert resps[1] == 50, 'weight 1 1' - self.assertIn( - 'success', - self.conf( - { - "127.0.0.1:7081": {"weight": 3}, - "127.0.0.1:7083": {"weight": 2}, - }, - 'upstreams/one/servers', - ), - 'configure weight 2', - ) + assert 'success' in self.conf( + { + "127.0.0.1:7081": {"weight": 3}, + "127.0.0.1:7083": {"weight": 2}, + }, + 'upstreams/one/servers', + ), 'configure weight 2' resps = self.get_resps_sc() - self.assertEqual(resps[0], 60, 'weight 2 0') - self.assertEqual(resps[2], 40, 'weight 2 1') + assert resps[0] == 60, 'weight 2 0' + assert resps[2] == 40, 'weight 2 1' def test_upstreams_rr_weight_rational(self): def set_weights(w1, w2): - self.assertIn( - 'success', - self.conf( - { - "127.0.0.1:7081": {"weight": w1}, - "127.0.0.1:7082": {"weight": w2}, - }, - 'upstreams/one/servers', - ), - 'configure weights', - ) + assert 'success' in self.conf( + { + "127.0.0.1:7081": {"weight": w1}, + "127.0.0.1:7082": {"weight": w2}, + }, + 'upstreams/one/servers', + ), 'configure weights' def check_reqs(w1, w2, reqs=10): resps = self.get_resps_sc(req=reqs) - self.assertEqual(resps[0], reqs * w1 / (w1 + w2), 'weight 1') - self.assertEqual(resps[1], reqs * w2 / (w1 + w2), 'weight 2') + assert resps[0] == reqs * w1 / (w1 + w2), 'weight 1' + assert resps[1] == reqs * w2 / (w1 + w2), 'weight 2' def check_weights(w1, w2): set_weights(w1, w2) @@ -207,39 +178,33 @@ Connection: close check_weights(0, 999999.0123456) check_weights(1, 9) check_weights(100000, 900000) - check_weights(1, .25) check_weights(1, 0.25) - check_weights(0.2, .8) + check_weights(1, 0.25) + check_weights(0.2, 0.8) check_weights(1, 1.5) - check_weights(1e-3, 1E-3) + check_weights(1e-3, 1e-3) check_weights(1e-20, 1e-20) check_weights(1e4, 1e4) check_weights(1000000, 1000000) set_weights(0.25, 0.25) - self.assertIn( - 'success', - self.conf_delete('upstreams/one/servers/127.0.0.1:7081/weight'), - 'delete weight', - ) + assert 'success' in self.conf_delete( + 'upstreams/one/servers/127.0.0.1:7081/weight' + ), 'delete weight' check_reqs(1, 0.25) - self.assertIn( - 'success', - self.conf( - { - "127.0.0.1:7081": {"weight": 0.1}, - "127.0.0.1:7082": {"weight": 1}, - "127.0.0.1:7083": {"weight": 0.9}, - }, - 'upstreams/one/servers', - ), - 'configure weights', - ) + assert 'success' in self.conf( + { + "127.0.0.1:7081": {"weight": 0.1}, + "127.0.0.1:7082": {"weight": 1}, + "127.0.0.1:7083": {"weight": 0.9}, + }, + 'upstreams/one/servers', + ), 'configure weights' resps = self.get_resps_sc(req=20) - self.assertEqual(resps[0], 1, 'weight 3 1') - self.assertEqual(resps[1], 10, 'weight 3 2') - self.assertEqual(resps[2], 9, 'weight 3 3') + assert resps[0] == 1, 'weight 3 1' + assert resps[1] == 10, 'weight 3 2' + assert resps[2] == 9, 'weight 3 3' def test_upstreams_rr_independent(self): def sum_resps(*args): @@ -250,90 +215,77 @@ Connection: close return sum resps = self.get_resps_sc(req=30, port=7090) - self.assertEqual(resps[0], 15, 'dep two before 0') - self.assertEqual(resps[1], 15, 'dep two before 1') + assert resps[0] == 15, 'dep two before 0' + assert resps[1] == 15, 'dep two before 1' resps = self.get_resps_sc(req=30) - self.assertEqual(resps[0], 15, 'dep one before 0') - self.assertEqual(resps[1], 15, 'dep one before 1') + assert resps[0] == 15, 'dep one before 0' + assert resps[1] == 15, 'dep one before 1' - self.assertIn( - 'success', - self.conf('2', 'upstreams/two/servers/127.0.0.1:7081/weight'), - 'configure dep weight', - ) + assert 'success' in self.conf( + '2', 'upstreams/two/servers/127.0.0.1:7081/weight' + ), 'configure dep weight' resps = self.get_resps_sc(req=30, port=7090) - self.assertEqual(resps[0], 20, 'dep two 0') - self.assertEqual(resps[1], 10, 'dep two 1') + assert resps[0] == 20, 'dep two 0' + assert resps[1] == 10, 'dep two 1' resps = self.get_resps_sc(req=30) - self.assertEqual(resps[0], 15, 'dep one 0') - self.assertEqual(resps[1], 15, 'dep one 1') + assert resps[0] == 15, 'dep one 0' + assert resps[1] == 15, 'dep one 1' - self.assertIn( - 'success', - self.conf('1', 'upstreams/two/servers/127.0.0.1:7081/weight'), - 'configure dep weight 1', - ) + assert 'success' in self.conf( + '1', 'upstreams/two/servers/127.0.0.1:7081/weight' + ), 'configure dep weight 1' r_one, r_two = [0, 0], [0, 0] for _ in range(10): r_one = sum_resps(r_one, self.get_resps(req=10)) r_two = sum_resps(r_two, self.get_resps(req=10, port=7090)) - - self.assertEqual(sum(r_one), 100, 'dep one mix sum') - self.assertLessEqual( - abs(r_one[0] - r_one[1]), self.cpu_count, 'dep one mix' - ) - self.assertEqual(sum(r_two), 100, 'dep two mix sum') - self.assertLessEqual( - abs(r_two[0] - r_two[1]), self.cpu_count, 'dep two mix' - ) + assert sum(r_one) == 100, 'dep one mix sum' + assert abs(r_one[0] - r_one[1]) <= self.cpu_count, 'dep one mix' + assert sum(r_two) == 100, 'dep two mix sum' + assert abs(r_two[0] - r_two[1]) <= self.cpu_count, 'dep two mix' def test_upstreams_rr_delay(self): - self.assertIn( - 'success', - self.conf( - { - "listeners": { - "*:7080": {"pass": "upstreams/one"}, - "*:7081": {"pass": "routes"}, - "*:7082": {"pass": "routes"}, - }, - "upstreams": { - "one": { - "servers": { - "127.0.0.1:7081": {}, - "127.0.0.1:7082": {}, - }, + assert 'success' in self.conf( + { + "listeners": { + "*:7080": {"pass": "upstreams/one"}, + "*:7081": {"pass": "routes"}, + "*:7082": {"pass": "routes"}, + }, + "upstreams": { + "one": { + "servers": { + "127.0.0.1:7081": {}, + "127.0.0.1:7082": {}, }, }, - "routes": [ - { - "match": {"destination": "*:7081"}, - "action": {"pass": "applications/delayed"}, - }, - { - "match": {"destination": "*:7082"}, - "action": {"return": 201}, - }, - ], - "applications": { - "delayed": { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir + "/python/delayed", - "working_directory": self.current_dir - + "/python/delayed", - "module": "wsgi", - } + }, + "routes": [ + { + "match": {"destination": "*:7081"}, + "action": {"pass": "applications/delayed"}, }, + { + "match": {"destination": "*:7082"}, + "action": {"return": 201}, + }, + ], + "applications": { + "delayed": { + "type": "python", + "processes": {"spare": 0}, + "path": option.test_dir + "/python/delayed", + "working_directory": option.test_dir + + "/python/delayed", + "module": "wsgi", + } }, - ), - 'upstreams initial configuration', - ) + }, + ), 'upstreams initial configuration' req = 50 @@ -357,12 +309,12 @@ Connection: close resp = self.recvall(socks[i]).decode() socks[i].close() - m = re.search('HTTP/1.1 20(\d)', resp) - self.assertIsNotNone(m, 'status') + m = re.search(r'HTTP/1.1 20(\d)', resp) + assert m is not None, 'status' resps[int(m.group(1))] += 1 - self.assertEqual(sum(resps), req, 'delay sum') - self.assertLessEqual(abs(resps[0] - resps[1]), self.cpu_count, 'delay') + assert sum(resps) == req, 'delay sum' + assert abs(resps[0] - resps[1]) <= self.cpu_count, 'delay' def test_upstreams_rr_active_req(self): conns = 5 @@ -389,59 +341,46 @@ Connection: close # Send one more request and read response to make sure that previous # requests had enough time to reach server. - self.assertEqual(self.get()['body'], '') - - self.assertIn( - 'success', - self.conf( - {"127.0.0.1:7083": {"weight": 2}}, 'upstreams/one/servers', - ), - 'active req new server', - ) - self.assertIn( - 'success', - self.conf_delete('upstreams/one/servers/127.0.0.1:7083'), - 'active req server remove', - ) - self.assertIn( - 'success', self.conf_delete('listeners/*:7080'), 'delete listener' - ) - self.assertIn( - 'success', - self.conf_delete('upstreams/one'), - 'active req upstream remove', - ) + assert self.get()['body'] == '' + + assert 'success' in self.conf( + {"127.0.0.1:7083": {"weight": 2}}, 'upstreams/one/servers', + ), 'active req new server' + assert 'success' in self.conf_delete( + 'upstreams/one/servers/127.0.0.1:7083' + ), 'active req server remove' + assert 'success' in self.conf_delete( + 'listeners/*:7080' + ), 'delete listener' + assert 'success' in self.conf_delete( + 'upstreams/one' + ), 'active req upstream remove' for i in range(conns): - self.assertEqual( - self.http(b'', sock=socks[i], raw=True)['body'], - '', - 'active req GET', - ) + assert ( + self.http(b'', sock=socks[i], raw=True)['body'] == '' + ), 'active req GET' - self.assertEqual( - self.http(b"""0123456789""", sock=socks2[i], raw=True)['body'], - '', - 'active req POST', - ) + assert ( + self.http(b"""0123456789""", sock=socks2[i], raw=True)['body'] + == '' + ), 'active req POST' def test_upstreams_rr_bad_server(self): - self.assertIn( - 'success', - self.conf({"weight": 1}, 'upstreams/one/servers/127.0.0.1:7084'), - 'configure bad server', - ) + assert 'success' in self.conf( + {"weight": 1}, 'upstreams/one/servers/127.0.0.1:7084' + ), 'configure bad server' resps = self.get_resps_sc(req=30) - self.assertEqual(resps[0], 10, 'bad server 0') - self.assertEqual(resps[1], 10, 'bad server 1') - self.assertEqual(sum(resps), 20, 'bad server sum') + assert resps[0] == 10, 'bad server 0' + assert resps[1] == 10, 'bad server 1' + assert sum(resps) == 20, 'bad server sum' def test_upstreams_rr_pipeline(self): resps = self.get_resps_sc() - self.assertEqual(resps[0], 50, 'pipeline 0') - self.assertEqual(resps[1], 50, 'pipeline 1') + assert resps[0] == 50, 'pipeline 0' + assert resps[1] == 50, 'pipeline 1' def test_upstreams_rr_post(self): resps = [0, 0] @@ -449,120 +388,87 @@ Connection: close resps[self.get()['status'] % 10] += 1 resps[self.post(body='0123456789')['status'] % 10] += 1 - self.assertEqual(sum(resps), 100, 'post sum') - self.assertLessEqual(abs(resps[0] - resps[1]), self.cpu_count, 'post') + assert sum(resps) == 100, 'post sum' + assert abs(resps[0] - resps[1]) <= self.cpu_count, 'post' def test_upstreams_rr_unix(self): - addr_0 = self.testdir + '/sock_0' - addr_1 = self.testdir + '/sock_1' - - self.assertIn( - 'success', - self.conf( - { - "*:7080": {"pass": "upstreams/one"}, - "unix:" + addr_0: {"pass": "routes/one"}, - "unix:" + addr_1: {"pass": "routes/two"}, - }, - 'listeners', - ), - 'configure listeners unix', - ) - - self.assertIn( - 'success', - self.conf( - {"unix:" + addr_0: {}, "unix:" + addr_1: {}}, - 'upstreams/one/servers', - ), - 'configure servers unix', - ) + addr_0 = self.temp_dir + '/sock_0' + addr_1 = self.temp_dir + '/sock_1' + + assert 'success' in self.conf( + { + "*:7080": {"pass": "upstreams/one"}, + "unix:" + addr_0: {"pass": "routes/one"}, + "unix:" + addr_1: {"pass": "routes/two"}, + }, + 'listeners', + ), 'configure listeners unix' + + assert 'success' in self.conf( + {"unix:" + addr_0: {}, "unix:" + addr_1: {}}, + 'upstreams/one/servers', + ), 'configure servers unix' resps = self.get_resps_sc() - self.assertEqual(resps[0], 50, 'unix 0') - self.assertEqual(resps[1], 50, 'unix 1') + assert resps[0] == 50, 'unix 0' + assert resps[1] == 50, 'unix 1' def test_upstreams_rr_ipv6(self): - self.assertIn( - 'success', - self.conf( - { - "*:7080": {"pass": "upstreams/one"}, - "[::1]:7081": {"pass": "routes/one"}, - "[::1]:7082": {"pass": "routes/two"}, - }, - 'listeners', - ), - 'configure listeners ipv6', - ) - - self.assertIn( - 'success', - self.conf( - {"[::1]:7081": {}, "[::1]:7082": {}}, 'upstreams/one/servers' - ), - 'configure servers ipv6', - ) + assert 'success' in self.conf( + { + "*:7080": {"pass": "upstreams/one"}, + "[::1]:7081": {"pass": "routes/one"}, + "[::1]:7082": {"pass": "routes/two"}, + }, + 'listeners', + ), 'configure listeners ipv6' + + assert 'success' in self.conf( + {"[::1]:7081": {}, "[::1]:7082": {}}, 'upstreams/one/servers' + ), 'configure servers ipv6' resps = self.get_resps_sc() - self.assertEqual(resps[0], 50, 'ipv6 0') - self.assertEqual(resps[1], 50, 'ipv6 1') + assert resps[0] == 50, 'ipv6 0' + assert resps[1] == 50, 'ipv6 1' def test_upstreams_rr_servers_empty(self): - self.assertIn( - 'success', - self.conf({}, 'upstreams/one/servers'), - 'configure servers empty', - ) - self.assertEqual(self.get()['status'], 502, 'servers empty') - - self.assertIn( - 'success', - self.conf( - {"127.0.0.1:7081": {"weight": 0}}, 'upstreams/one/servers' - ), - 'configure servers empty one', - ) - self.assertEqual(self.get()['status'], 502, 'servers empty one') - self.assertIn( - 'success', - self.conf( - { - "127.0.0.1:7081": {"weight": 0}, - "127.0.0.1:7082": {"weight": 0}, - }, - 'upstreams/one/servers', - ), - 'configure servers empty two', - ) - self.assertEqual(self.get()['status'], 502, 'servers empty two') + assert 'success' in self.conf( + {}, 'upstreams/one/servers' + ), 'configure servers empty' + assert self.get()['status'] == 502, 'servers empty' + + assert 'success' in self.conf( + {"127.0.0.1:7081": {"weight": 0}}, 'upstreams/one/servers' + ), 'configure servers empty one' + assert self.get()['status'] == 502, 'servers empty one' + assert 'success' in self.conf( + { + "127.0.0.1:7081": {"weight": 0}, + "127.0.0.1:7082": {"weight": 0}, + }, + 'upstreams/one/servers', + ), 'configure servers empty two' + assert self.get()['status'] == 502, 'servers empty two' def test_upstreams_rr_invalid(self): - self.assertIn( - 'error', self.conf({}, 'upstreams'), 'upstreams empty', - ) - self.assertIn( - 'error', self.conf({}, 'upstreams/one'), 'named upstreams empty', - ) - self.assertIn( - 'error', - self.conf({}, 'upstreams/one/servers/127.0.0.1'), - 'invalid address', - ) - self.assertIn( - 'error', - self.conf({}, 'upstreams/one/servers/127.0.0.1:7081/blah'), - 'invalid server option', - ) + assert 'error' in self.conf({}, 'upstreams'), 'upstreams empty' + assert 'error' in self.conf( + {}, 'upstreams/one' + ), 'named upstreams empty' + assert 'error' in self.conf( + {}, 'upstreams/one/servers/127.0.0.1' + ), 'invalid address' + assert 'error' in self.conf( + {}, 'upstreams/one/servers/127.0.0.1:7081/blah' + ), 'invalid server option' def check_weight(w): - self.assertIn( - 'error', - self.conf(w, 'upstreams/one/servers/127.0.0.1:7081/weight'), - 'invalid weight option', - ) + assert 'error' in self.conf( + w, 'upstreams/one/servers/127.0.0.1:7081/weight' + ), 'invalid weight option' + check_weight({}) check_weight('-1') check_weight('1.') @@ -571,7 +477,3 @@ Connection: close check_weight('.01234567890123') check_weight('1000001') check_weight('2e6') - - -if __name__ == '__main__': - TestUpstreamsRR.main() diff --git a/test/test_usr1.py b/test/test_usr1.py index d1db652f..2e48c18f 100644 --- a/test/test_usr1.py +++ b/test/test_usr1.py @@ -1,6 +1,7 @@ import os from subprocess import call +from conftest import waitforfiles from unit.applications.lang.python import TestApplicationPython @@ -12,83 +13,74 @@ class TestUSR1(TestApplicationPython): log = 'access.log' log_new = 'new.log' - log_path = self.testdir + '/' + log + log_path = self.temp_dir + '/' + log - self.assertIn( - 'success', - self.conf('"' + log_path + '"', 'access_log'), - 'access log configure', - ) + assert 'success' in self.conf( + '"' + log_path + '"', 'access_log' + ), 'access log configure' - self.assertTrue(self.waitforfiles(log_path), 'open') + assert waitforfiles(log_path), 'open' - os.rename(log_path, self.testdir + '/' + log_new) + os.rename(log_path, self.temp_dir + '/' + log_new) - self.assertEqual(self.get()['status'], 200) + assert self.get()['status'] == 200 - self.assertIsNotNone( - self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "-" "-"', log_new), - 'rename new', - ) - self.assertFalse(os.path.isfile(log_path), 'rename old') + assert ( + self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "-" "-"', log_new) + is not None + ), 'rename new' + assert not os.path.isfile(log_path), 'rename old' - with open(self.testdir + '/unit.pid', 'r') as f: + with open(self.temp_dir + '/unit.pid', 'r') as f: pid = f.read().rstrip() call(['kill', '-s', 'USR1', pid]) - self.assertTrue(self.waitforfiles(log_path), 'reopen') + assert waitforfiles(log_path), 'reopen' - self.assertEqual(self.get(url='/usr1')['status'], 200) + assert self.get(url='/usr1')['status'] == 200 self.stop() - self.assertIsNotNone( - self.wait_for_record(r'"GET /usr1 HTTP/1.1" 200 0 "-" "-"', log), - 'reopen 2', - ) - self.assertIsNone( - self.search_in_log(r'/usr1', log_new), 'rename new 2' - ) + assert ( + self.wait_for_record(r'"GET /usr1 HTTP/1.1" 200 0 "-" "-"', log) + is not None + ), 'reopen 2' + assert self.search_in_log(r'/usr1', log_new) is None, 'rename new 2' def test_usr1_unit_log(self): self.load('log_body') log_new = 'new.log' - log_path = self.testdir + '/unit.log' - log_path_new = self.testdir + '/' + log_new + log_path = self.temp_dir + '/unit.log' + log_path_new = self.temp_dir + '/' + log_new os.rename(log_path, log_path_new) body = 'body_for_a_log_new' - self.assertEqual(self.post(body=body)['status'], 200) + assert self.post(body=body)['status'] == 200 - self.assertIsNotNone( - self.wait_for_record(body, log_new), 'rename new' - ) - self.assertFalse(os.path.isfile(log_path), 'rename old') + assert self.wait_for_record(body, log_new) is not None, 'rename new' + assert not os.path.isfile(log_path), 'rename old' - with open(self.testdir + '/unit.pid', 'r') as f: + with open(self.temp_dir + '/unit.pid', 'r') as f: pid = f.read().rstrip() call(['kill', '-s', 'USR1', pid]) - self.assertTrue(self.waitforfiles(log_path), 'reopen') + assert waitforfiles(log_path), 'reopen' body = 'body_for_a_log_unit' - self.assertEqual(self.post(body=body)['status'], 200) + assert self.post(body=body)['status'] == 200 self.stop() - self.assertIsNotNone(self.wait_for_record(body), 'rename new') - self.assertIsNone(self.search_in_log(body, log_new), 'rename new 2') + assert self.wait_for_record(body) is not None, 'rename new' + assert self.search_in_log(body, log_new) is None, 'rename new 2' # merge two log files into unit.log to check alerts - with open(log_path, 'w') as unit_log, \ - open(log_path_new, 'r') as unit_log_new: + with open(log_path, 'w') as unit_log, open( + log_path_new, 'r' + ) as unit_log_new: unit_log.write(unit_log_new.read()) - - -if __name__ == '__main__': - TestUSR1.main() diff --git a/test/test_variables.py b/test/test_variables.py index 805c5144..c458b636 100644 --- a/test/test_variables.py +++ b/test/test_variables.py @@ -4,83 +4,117 @@ from unit.applications.proto import TestApplicationProto class TestVariables(TestApplicationProto): prerequisites = {} - def setUp(self): - super().setUp() - - self.assertIn( - 'success', - self.conf( - { - "listeners": {"*:7080": {"pass": "routes/$method"}}, - "routes": { - "GET": [{"action": {"return": 201}}], - "POST": [{"action": {"return": 202}}], - "3": [{"action": {"return": 203}}], - "4": [{"action": {"return": 204}}], - "blahGET}": [{"action": {"return": 205}}], - "5GET": [{"action": {"return": 206}}], - "GETGET": [{"action": {"return": 207}}], - }, + def setup_method(self): + super().setup_method() + + assert 'success' in self.conf( + { + "listeners": {"*:7080": {"pass": "routes/$method"}}, + "routes": { + "GET": [{"action": {"return": 201}}], + "POST": [{"action": {"return": 202}}], + "3": [{"action": {"return": 203}}], + "4*": [{"action": {"return": 204}}], + "blahGET}": [{"action": {"return": 205}}], + "5GET": [{"action": {"return": 206}}], + "GETGET": [{"action": {"return": 207}}], + "localhost": [{"action": {"return": 208}}], }, - ), - 'configure routes', - ) + }, + ), 'configure routes' def conf_routes(self, routes): - self.assertIn( - 'success', - self.conf(routes, 'listeners/*:7080/pass') - ) + assert 'success' in self.conf(routes, 'listeners/*:7080/pass') def test_variables_method(self): - self.assertEqual(self.get()['status'], 201, 'method GET') - self.assertEqual(self.post()['status'], 202, 'method POST') + assert self.get()['status'] == 201, 'method GET' + assert self.post()['status'] == 202, 'method POST' def test_variables_uri(self): self.conf_routes("\"routes$uri\"") - self.assertEqual(self.get(url='/3')['status'], 203, 'uri') - self.assertEqual(self.get(url='/4')['status'], 204, 'uri 2') + assert self.get(url='/3')['status'] == 203, 'uri' + assert self.get(url='/4*')['status'] == 204, 'uri 2' + assert self.get(url='/4%2A')['status'] == 204, 'uri 3' + + def test_variables_host(self): + self.conf_routes("\"routes/$host\"") + + def check_host(host, status=208): + assert ( + self.get(headers={'Host': host, 'Connection': 'close'})[ + 'status' + ] + == status + ) + + check_host('localhost') + check_host('localhost.') + check_host('localhost:7080') + check_host('.localhost', 404) + check_host('www.localhost', 404) + check_host('localhost1', 404) def test_variables_many(self): self.conf_routes("\"routes$uri$method\"") - self.assertEqual(self.get(url='/5')['status'], 206, 'many') + assert self.get(url='/5')['status'] == 206, 'many' self.conf_routes("\"routes${uri}${method}\"") - self.assertEqual(self.get(url='/5')['status'], 206, 'many 2') + assert self.get(url='/5')['status'] == 206, 'many 2' self.conf_routes("\"routes${uri}$method\"") - self.assertEqual(self.get(url='/5')['status'], 206, 'many 3') + assert self.get(url='/5')['status'] == 206, 'many 3' self.conf_routes("\"routes/$method$method\"") - self.assertEqual(self.get()['status'], 207, 'many 4') + assert self.get()['status'] == 207, 'many 4' self.conf_routes("\"routes/$method$uri\"") - self.assertEqual(self.get()['status'], 404, 'no route') - self.assertEqual(self.get(url='/blah')['status'], 404, 'no route 2') + assert self.get()['status'] == 404, 'no route' + assert self.get(url='/blah')['status'] == 404, 'no route 2' def test_variables_replace(self): - self.assertEqual(self.get()['status'], 201) + assert self.get()['status'] == 201 self.conf_routes("\"routes$uri\"") - self.assertEqual(self.get(url='/3')['status'], 203) + assert self.get(url='/3')['status'] == 203 self.conf_routes("\"routes/${method}\"") - self.assertEqual(self.post()['status'], 202) + assert self.post()['status'] == 202 self.conf_routes("\"routes${uri}\"") - self.assertEqual(self.get(url='/4')['status'], 204) + assert self.get(url='/4*')['status'] == 204 self.conf_routes("\"routes/blah$method}\"") - self.assertEqual(self.get()['status'], 205) + assert self.get()['status'] == 205 + + def test_variables_upstream(self): + assert 'success' in self.conf( + { + "listeners": { + "*:7080": {"pass": "upstreams$uri"}, + "*:7081": {"pass": "routes/one"}, + }, + "upstreams": { + "1": { + "servers": { + "127.0.0.1:7081": {}, + }, + }, + }, + "routes": { + "one": [{"action": {"return": 200}}], + }, + }, + ), 'upstreams initial configuration' + + assert self.get(url='/1')['status'] == 200 + assert self.get(url='/2')['status'] == 404 def test_variables_invalid(self): def check_variables(routes): - self.assertIn( - 'error', - self.conf(routes, 'listeners/*:7080/pass'), - 'invalid variables', - ) + assert 'error' in self.conf( + routes, 'listeners/*:7080/pass' + ), 'invalid variables' check_variables("\"routes$\"") check_variables("\"routes${\"") @@ -89,6 +123,3 @@ class TestVariables(TestApplicationProto): check_variables("\"routes$uriblah\"") check_variables("\"routes${uri\"") check_variables("\"routes${{uri}\"") - -if __name__ == '__main__': - TestVariables.main() diff --git a/test/unit/applications/lang/go.py b/test/unit/applications/lang/go.py index 83bde4d8..7715bd6c 100644 --- a/test/unit/applications/lang/go.py +++ b/test/unit/applications/lang/go.py @@ -1,30 +1,17 @@ import os import subprocess +from conftest import option from unit.applications.proto import TestApplicationProto class TestApplicationGo(TestApplicationProto): - @classmethod - def setUpClass(cls, complete_check=True): - unit = super().setUpClass(complete_check=False) - - # check go module - - go_app = TestApplicationGo() - go_app.testdir = unit.testdir - proc = go_app.prepare_env('empty', 'app') - if proc and proc.returncode == 0: - cls.available['modules']['go'] = [] - - return unit if not complete_check else unit.complete() - def prepare_env(self, script, name, static=False): - if not os.path.exists(self.testdir + '/go'): - os.mkdir(self.testdir + '/go') + if not os.path.exists(self.temp_dir + '/go'): + os.mkdir(self.temp_dir + '/go') env = os.environ.copy() - env['GOPATH'] = self.pardir + '/build/go' + env['GOPATH'] = option.current_dir + '/build/go' if static: args = [ @@ -35,16 +22,16 @@ class TestApplicationGo(TestApplicationProto): '-ldflags', '-extldflags "-static"', '-o', - self.testdir + '/go/' + name, - self.current_dir + '/go/' + script + '/' + name + '.go', + self.temp_dir + '/go/' + name, + option.test_dir + '/go/' + script + '/' + name + '.go', ] else: args = [ 'go', 'build', '-o', - self.testdir + '/go/' + name, - self.current_dir + '/go/' + script + '/' + name + '.go', + self.temp_dir + '/go/' + name, + option.test_dir + '/go/' + script + '/' + name + '.go', ] try: @@ -59,8 +46,8 @@ class TestApplicationGo(TestApplicationProto): def load(self, script, name='app', **kwargs): static_build = False - wdir = self.current_dir + "/go/" + script - executable = self.testdir + "/go/" + name + wdir = option.test_dir + "/go/" + script + executable = self.temp_dir + "/go/" + name if 'isolation' in kwargs and 'rootfs' in kwargs['isolation']: wdir = "/go/" diff --git a/test/unit/applications/lang/java.py b/test/unit/applications/lang/java.py index c2c6dc51..01cbfa0b 100644 --- a/test/unit/applications/lang/java.py +++ b/test/unit/applications/lang/java.py @@ -3,15 +3,17 @@ import os import shutil import subprocess +import pytest +from conftest import option from unit.applications.proto import TestApplicationProto class TestApplicationJava(TestApplicationProto): def load(self, script, name='app', **kwargs): - app_path = self.testdir + '/java' + app_path = self.temp_dir + '/java' web_inf_path = app_path + '/WEB-INF/' classes_path = web_inf_path + 'classes/' - script_path = self.current_dir + '/java/' + script + '/' + script_path = option.test_dir + '/java/' + script + '/' if not os.path.isdir(app_path): os.makedirs(app_path) @@ -47,14 +49,16 @@ class TestApplicationJava(TestApplicationProto): if not os.path.isdir(classes_path): os.makedirs(classes_path) - classpath = self.pardir + '/build/tomcat-servlet-api-9.0.13.jar' + classpath = ( + option.current_dir + '/build/tomcat-servlet-api-9.0.13.jar' + ) ws_jars = glob.glob( - self.pardir + '/build/websocket-api-java-*.jar' + option.current_dir + '/build/websocket-api-java-*.jar' ) if not ws_jars: - self.fail('websocket api jar not found.') + pytest.fail('websocket api jar not found.') javac = [ 'javac', @@ -69,14 +73,14 @@ class TestApplicationJava(TestApplicationProto): process.communicate() except: - self.fail('Cann\'t run javac process.') + pytest.fail('Cann\'t run javac process.') self._load_conf( { "listeners": {"*:7080": {"pass": "applications/" + script}}, "applications": { script: { - "unit_jars": self.pardir + '/build', + "unit_jars": option.current_dir + '/build', "type": 'java', "processes": {"spare": 0}, "working_directory": script_path, diff --git a/test/unit/applications/lang/node.py b/test/unit/applications/lang/node.py index cf2a99f6..877fc461 100644 --- a/test/unit/applications/lang/node.py +++ b/test/unit/applications/lang/node.py @@ -1,37 +1,27 @@ -import os import shutil from urllib.parse import quote +from conftest import option +from conftest import public_dir from unit.applications.proto import TestApplicationProto class TestApplicationNode(TestApplicationProto): - @classmethod - def setUpClass(cls, complete_check=True): - unit = super().setUpClass(complete_check=False) - - # check node module - - if os.path.exists(unit.pardir + '/node/node_modules'): - cls.available['modules']['node'] = [] - - return unit if not complete_check else unit.complete() - def load(self, script, name='app.js', **kwargs): # copy application shutil.copytree( - self.current_dir + '/node/' + script, self.testdir + '/node' + option.test_dir + '/node/' + script, self.temp_dir + '/node' ) # copy modules shutil.copytree( - self.pardir + '/node/node_modules', - self.testdir + '/node/node_modules', + option.current_dir + '/node/node_modules', + self.temp_dir + '/node/node_modules', ) - self.public_dir(self.testdir + '/node') + public_dir(self.temp_dir + '/node') self._load_conf( { @@ -42,7 +32,7 @@ class TestApplicationNode(TestApplicationProto): script: { "type": "external", "processes": {"spare": 0}, - "working_directory": self.testdir + '/node', + "working_directory": self.temp_dir + '/node', "executable": name, } }, diff --git a/test/unit/applications/lang/perl.py b/test/unit/applications/lang/perl.py index d32aca33..a27c7649 100644 --- a/test/unit/applications/lang/perl.py +++ b/test/unit/applications/lang/perl.py @@ -1,3 +1,4 @@ +from conftest import option from unit.applications.proto import TestApplicationProto @@ -5,14 +6,18 @@ class TestApplicationPerl(TestApplicationProto): application_type = "perl" def load(self, script, name='psgi.pl', **kwargs): - script_path = self.current_dir + '/perl/' + script + script_path = option.test_dir + '/perl/' + script + appication_type = self.get_appication_type() + + if appication_type is None: + appication_type = self.application_type self._load_conf( { "listeners": {"*:7080": {"pass": "applications/" + script}}, "applications": { script: { - "type": self.application_type, + "type": appication_type, "processes": {"spare": 0}, "working_directory": script_path, "script": script_path + '/' + name, diff --git a/test/unit/applications/lang/php.py b/test/unit/applications/lang/php.py index e8c70c62..2d50df2e 100644 --- a/test/unit/applications/lang/php.py +++ b/test/unit/applications/lang/php.py @@ -1,3 +1,4 @@ +from conftest import option from unit.applications.proto import TestApplicationProto @@ -5,14 +6,18 @@ class TestApplicationPHP(TestApplicationProto): application_type = "php" def load(self, script, index='index.php', **kwargs): - script_path = self.current_dir + '/php/' + script + script_path = option.test_dir + '/php/' + script + appication_type = self.get_appication_type() + + if appication_type is None: + appication_type = self.application_type self._load_conf( { "listeners": {"*:7080": {"pass": "applications/" + script}}, "applications": { script: { - "type": self.application_type, + "type": appication_type, "processes": {"spare": 0}, "root": script_path, "working_directory": script_path, diff --git a/test/unit/applications/lang/python.py b/test/unit/applications/lang/python.py index 91559f4b..47b95dac 100644 --- a/test/unit/applications/lang/python.py +++ b/test/unit/applications/lang/python.py @@ -1,20 +1,28 @@ import os import shutil +from urllib.parse import quote +import pytest +from conftest import option from unit.applications.proto import TestApplicationProto class TestApplicationPython(TestApplicationProto): application_type = "python" + load_module = "wsgi" - def load(self, script, name=None, **kwargs): + def load(self, script, name=None, module=None, **kwargs): + print() if name is None: name = script + if module is None: + module = self.load_module + if script[0] == '/': script_path = script else: - script_path = self.current_dir + '/python/' + script + script_path = option.test_dir + '/python/' + script if kwargs.get('isolation') and kwargs['isolation'].get('rootfs'): rootfs = kwargs['isolation']['rootfs'] @@ -27,16 +35,23 @@ class TestApplicationPython(TestApplicationProto): script_path = '/app/python/' + name + appication_type = self.get_appication_type() + + if appication_type is None: + appication_type = self.application_type + self._load_conf( { - "listeners": {"*:7080": {"pass": "applications/" + name}}, + "listeners": { + "*:7080": {"pass": "applications/" + quote(name, '')} + }, "applications": { name: { - "type": self.application_type, + "type": appication_type, "processes": {"spare": 0}, "path": script_path, "working_directory": script_path, - "module": "wsgi", + "module": module, } }, }, diff --git a/test/unit/applications/lang/ruby.py b/test/unit/applications/lang/ruby.py index 8c8acecc..bc3cefc6 100644 --- a/test/unit/applications/lang/ruby.py +++ b/test/unit/applications/lang/ruby.py @@ -1,3 +1,4 @@ +from conftest import option from unit.applications.proto import TestApplicationProto @@ -5,14 +6,18 @@ class TestApplicationRuby(TestApplicationProto): application_type = "ruby" def load(self, script, name='config.ru', **kwargs): - script_path = self.current_dir + '/ruby/' + script + script_path = option.test_dir + '/ruby/' + script + appication_type = self.get_appication_type() + + if appication_type is None: + appication_type = self.application_type self._load_conf( { "listeners": {"*:7080": {"pass": "applications/" + script}}, "applications": { script: { - "type": self.application_type, + "type": appication_type, "processes": {"spare": 0}, "working_directory": script_path, "script": script_path + '/' + name, diff --git a/test/unit/applications/proto.py b/test/unit/applications/proto.py index 244cb5be..2f748c21 100644 --- a/test/unit/applications/proto.py +++ b/test/unit/applications/proto.py @@ -1,6 +1,8 @@ +import os import re import time +from conftest import option from unit.control import TestControl @@ -12,7 +14,7 @@ class TestApplicationProto(TestControl): return time.mktime(time.strptime(date, template)) def search_in_log(self, pattern, name='unit.log'): - with open(self.testdir + '/' + name, 'r', errors='ignore') as f: + with open(self.temp_dir + '/' + name, 'r', errors='ignore') as f: return re.search(pattern, f.read()) def wait_for_record(self, pattern, name='unit.log'): @@ -26,6 +28,16 @@ class TestApplicationProto(TestControl): return found + def get_appication_type(self): + current_test = ( + os.environ.get('PYTEST_CURRENT_TEST').split(':')[-1].split(' ')[0] + ) + + if current_test in option.generated_tests: + return option.generated_tests[current_test] + + return None + def _load_conf(self, conf, **kwargs): if 'applications' in conf: for app in conf['applications'].keys(): @@ -39,6 +51,4 @@ class TestApplicationProto(TestControl): if 'isolation' in kwargs: app_conf['isolation'] = kwargs['isolation'] - self.assertIn( - 'success', self.conf(conf), 'load application configuration' - ) + assert 'success' in self.conf(conf), 'load application configuration' diff --git a/test/unit/applications/tls.py b/test/unit/applications/tls.py index e6a846b2..fdf681ae 100644 --- a/test/unit/applications/tls.py +++ b/test/unit/applications/tls.py @@ -1,40 +1,19 @@ import os -import re import ssl import subprocess +from conftest import option from unit.applications.proto import TestApplicationProto class TestApplicationTLS(TestApplicationProto): - def __init__(self, test): - super().__init__(test) + def setup_method(self): + super().setup_method() self.context = ssl.create_default_context() self.context.check_hostname = False self.context.verify_mode = ssl.CERT_NONE - @classmethod - def setUpClass(cls, complete_check=True): - unit = super().setUpClass(complete_check=False) - - # check tls module - - try: - subprocess.check_output(['which', 'openssl']) - - output = subprocess.check_output( - [unit.unitd, '--version'], stderr=subprocess.STDOUT - ) - - if re.search('--openssl', output.decode()): - cls.available['modules']['openssl'] = [] - - except: - pass - - return unit if not complete_check else unit.complete() - def certificate(self, name='default', load=True): self.openssl_conf() @@ -45,9 +24,9 @@ class TestApplicationTLS(TestApplicationProto): '-x509', '-new', '-subj', '/CN=' + name + '/', - '-config', self.testdir + '/openssl.conf', - '-out', self.testdir + '/' + name + '.crt', - '-keyout', self.testdir + '/' + name + '.key', + '-config', self.temp_dir + '/openssl.conf', + '-out', self.temp_dir + '/' + name + '.crt', + '-keyout', self.temp_dir + '/' + name + '.key', ], stderr=subprocess.STDOUT, ) @@ -59,8 +38,8 @@ class TestApplicationTLS(TestApplicationProto): if key is None: key = crt - key_path = self.testdir + '/' + key + '.key' - crt_path = self.testdir + '/' + crt + '.crt' + key_path = self.temp_dir + '/' + key + '.key' + crt_path = self.temp_dir + '/' + crt + '.crt' with open(key_path, 'rb') as k, open(crt_path, 'rb') as c: return self.conf(k.read() + c.read(), '/certificates/' + crt) @@ -87,7 +66,7 @@ class TestApplicationTLS(TestApplicationProto): return ssl.get_server_certificate(addr, ssl_version=ssl_version) def openssl_conf(self): - conf_path = self.testdir + '/openssl.conf' + conf_path = self.temp_dir + '/openssl.conf' if os.path.exists(conf_path): return @@ -105,7 +84,7 @@ distinguished_name = req_distinguished_name if name is None: name = script - script_path = self.current_dir + '/python/' + script + script_path = option.test_dir + '/python/' + script self._load_conf( { diff --git a/test/unit/applications/websockets.py b/test/unit/applications/websockets.py index e0dd2c0d..cc720a98 100644 --- a/test/unit/applications/websockets.py +++ b/test/unit/applications/websockets.py @@ -2,10 +2,10 @@ import base64 import hashlib import itertools import random -import re import select import struct +import pytest from unit.applications.proto import TestApplicationProto GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" @@ -21,9 +21,6 @@ class TestApplicationWebsocket(TestApplicationProto): OP_PONG = 0x0A CLOSE_CODES = [1000, 1001, 1002, 1003, 1007, 1008, 1009, 1010, 1011] - def __init__(self, preinit=False): - self.preinit = preinit - def key(self): raw_key = bytes(random.getrandbits(8) for _ in range(16)) return base64.b64encode(raw_key).decode() @@ -42,7 +39,7 @@ class TestApplicationWebsocket(TestApplicationProto): 'Upgrade': 'websocket', 'Connection': 'Upgrade', 'Sec-WebSocket-Key': key, - 'Sec-WebSocket-Protocol': 'chat', + 'Sec-WebSocket-Protocol': 'chat, phone, video', 'Sec-WebSocket-Version': 13, } @@ -56,14 +53,11 @@ class TestApplicationWebsocket(TestApplicationProto): while True: rlist = select.select([sock], [], [], 60)[0] if not rlist: - self.fail('Can\'t read response from server.') + pytest.fail('Can\'t read response from server.') resp += sock.recv(4096).decode() - if ( - re.search('101 Switching Protocols', resp) - and resp[-4:] == '\r\n\r\n' - ): + if (resp.startswith('HTTP/') and '\r\n\r\n' in resp): resp = self._resp_to_dict(resp) break @@ -84,7 +78,7 @@ class TestApplicationWebsocket(TestApplicationProto): # For all current cases if the "read_timeout" was changed # than test do not expect to get a response from server. if read_timeout == 60: - self.fail('Can\'t read response from server.') + pytest.fail('Can\'t read response from server.') break data += sock.recv(bytes - len(data)) @@ -130,19 +124,19 @@ class TestApplicationWebsocket(TestApplicationProto): code, = struct.unpack('!H', data[:2]) reason = data[2:].decode('utf-8') if not (code in self.CLOSE_CODES or 3000 <= code < 5000): - self.fail('Invalid status code') + pytest.fail('Invalid status code') frame['code'] = code frame['reason'] = reason elif length == 0: frame['code'] = 1005 frame['reason'] = '' else: - self.fail('Close frame too short') + pytest.fail('Close frame too short') frame['data'] = data if frame['mask']: - self.fail('Received frame with mask') + pytest.fail('Received frame with mask') return frame diff --git a/test/unit/check/go.py b/test/unit/check/go.py new file mode 100644 index 00000000..dd2150eb --- /dev/null +++ b/test/unit/check/go.py @@ -0,0 +1,29 @@ +import os +import subprocess + + +def check_go(current_dir, temp_dir, test_dir): + if not os.path.exists(temp_dir + '/go'): + os.mkdir(temp_dir + '/go') + + env = os.environ.copy() + env['GOPATH'] = current_dir + '/build/go' + + try: + process = subprocess.Popen( + [ + 'go', + 'build', + '-o', + temp_dir + '/go/app', + test_dir + '/go/empty/app.go', + ], + env=env, + ) + process.communicate() + + if process.returncode == 0: + return True + + except: + return None diff --git a/test/unit/check/node.py b/test/unit/check/node.py new file mode 100644 index 00000000..236ba7b5 --- /dev/null +++ b/test/unit/check/node.py @@ -0,0 +1,6 @@ +import os + + +def check_node(current_dir): + if os.path.exists(current_dir + '/node/node_modules'): + return True diff --git a/test/unit/check/tls.py b/test/unit/check/tls.py new file mode 100644 index 00000000..b878ff7d --- /dev/null +++ b/test/unit/check/tls.py @@ -0,0 +1,13 @@ +import re +import subprocess + + +def check_openssl(unitd): + subprocess.check_output(['which', 'openssl']) + + output = subprocess.check_output( + [unitd, '--version'], stderr=subprocess.STDOUT + ) + + if re.search('--openssl', output.decode()): + return True diff --git a/test/unit/control.py b/test/unit/control.py index 029072b5..6fd350f4 100644 --- a/test/unit/control.py +++ b/test/unit/control.py @@ -53,7 +53,7 @@ class TestControl(TestHTTP): args = { 'url': url, 'sock_type': 'unix', - 'addr': self.testdir + '/control.unit.sock', + 'addr': self.temp_dir + '/control.unit.sock', } if conf is not None: diff --git a/test/unit/feature/isolation.py b/test/unit/feature/isolation.py index 4f33d04a..c6f6f3c0 100644 --- a/test/unit/feature/isolation.py +++ b/test/unit/feature/isolation.py @@ -13,7 +13,7 @@ from unit.applications.proto import TestApplicationProto class TestFeatureIsolation(TestApplicationProto): allns = ['pid', 'mnt', 'ipc', 'uts', 'cgroup', 'net'] - def check(self, available, testdir): + def check(self, available, temp_dir): test_conf = {"namespaces": {"credential": True}} module = '' @@ -45,7 +45,7 @@ class TestFeatureIsolation(TestApplicationProto): if not module: return - module.testdir = testdir + module.temp_dir = temp_dir module.load(app) resp = module.conf(test_conf, 'applications/' + app + '/isolation') diff --git a/test/unit/http.py b/test/unit/http.py index de3bb2a4..7845f9a8 100644 --- a/test/unit/http.py +++ b/test/unit/http.py @@ -7,25 +7,22 @@ import select import socket import time +import pytest +from conftest import option from unit.main import TestUnit class TestHTTP(TestUnit): def http(self, start_str, **kwargs): - sock_type = ( - 'ipv4' if 'sock_type' not in kwargs else kwargs['sock_type'] - ) - port = 7080 if 'port' not in kwargs else kwargs['port'] - url = '/' if 'url' not in kwargs else kwargs['url'] + sock_type = kwargs.get('sock_type', 'ipv4') + port = kwargs.get('port', 7080) + url = kwargs.get('url', '/') http = 'HTTP/1.0' if 'http_10' in kwargs else 'HTTP/1.1' - headers = ( - {'Host': 'localhost', 'Connection': 'close'} - if 'headers' not in kwargs - else kwargs['headers'] - ) + headers = kwargs.get('headers', + {'Host': 'localhost', 'Connection': 'close'}) - body = b'' if 'body' not in kwargs else kwargs['body'] + body = kwargs.get('body', b'') crlf = '\r\n' if 'addr' not in kwargs: @@ -56,7 +53,7 @@ class TestHTTP(TestUnit): sock.connect(connect_args) except ConnectionRefusedError: sock.close() - self.fail('Client can\'t connect to the server.') + pytest.fail('Client can\'t connect to the server.') else: sock = kwargs['sock'] @@ -90,7 +87,7 @@ class TestHTTP(TestUnit): sock.sendall(req) - encoding = 'utf-8' if 'encoding' not in kwargs else kwargs['encoding'] + encoding = kwargs.get('encoding', 'utf-8') self.log_out(req, encoding) @@ -128,7 +125,7 @@ class TestHTTP(TestUnit): return (resp, sock) def log_out(self, log, encoding): - if TestUnit.detailed: + if option.detailed: print('>>>') log = self.log_truncate(log) try: @@ -137,7 +134,7 @@ class TestHTTP(TestUnit): print(log) def log_in(self, log): - if TestUnit.detailed: + if option.detailed: print('<<<') log = self.log_truncate(log) try: @@ -176,12 +173,8 @@ class TestHTTP(TestUnit): def recvall(self, sock, **kwargs): timeout_default = 60 - timeout = ( - timeout_default - if 'read_timeout' not in kwargs - else kwargs['read_timeout'] - ) - buff_size = 4096 if 'buff_size' not in kwargs else kwargs['buff_size'] + timeout = kwargs.get('read_timeout', timeout_default) + buff_size = kwargs.get('buff_size', 4096) data = b'' while True: @@ -190,7 +183,7 @@ class TestHTTP(TestUnit): # For all current cases if the "read_timeout" was changed # than test do not expect to get a response from server. if timeout == timeout_default: - self.fail('Can\'t read response from server.') + pytest.fail('Can\'t read response from server.') break try: @@ -243,28 +236,28 @@ class TestHTTP(TestUnit): chunks = raw_body.split(crlf) if len(chunks) < 3: - self.fail('Invalid chunked body') + pytest.fail('Invalid chunked body') if chunks.pop() != b'': - self.fail('No CRLF at the end of the body') + pytest.fail('No CRLF at the end of the body') try: last_size = int(chunks[-2], 16) except: - self.fail('Invalid zero size chunk') + pytest.fail('Invalid zero size chunk') if last_size != 0 or chunks[-1] != b'': - self.fail('Incomplete body') + pytest.fail('Incomplete body') body = b'' while len(chunks) >= 2: try: size = int(chunks.pop(0), 16) except: - self.fail('Invalid chunk size %s' % str(size)) + pytest.fail('Invalid chunk size %s' % str(size)) if size == 0: - self.assertEqual(len(chunks), 1, 'last zero size') + assert len(chunks) == 1, 'last zero size' break temp_body = crlf.join(chunks) @@ -280,8 +273,8 @@ class TestHTTP(TestUnit): def _parse_json(self, resp): headers = resp['headers'] - self.assertIn('Content-Type', headers) - self.assertEqual(headers['Content-Type'], 'application/json') + assert 'Content-Type' in headers + assert headers['Content-Type'] == 'application/json' resp['body'] = json.loads(resp['body']) @@ -305,7 +298,7 @@ class TestHTTP(TestUnit): sock.close() - self.assertTrue(ret, 'socket connected') + assert ret, 'socket connected' def form_encode(self, fields): is_multipart = False @@ -345,7 +338,7 @@ class TestHTTP(TestUnit): datatype = value['type'] if not isinstance(value['data'], io.IOBase): - self.fail('multipart encoding of file requires a stream.') + pytest.fail('multipart encoding of file requires a stream.') data = value['data'].read() @@ -353,7 +346,7 @@ class TestHTTP(TestUnit): data = value else: - self.fail('multipart requires a string or stream data') + pytest.fail('multipart requires a string or stream data') body += ( "--%s\r\nContent-Disposition: form-data; name=\"%s\"" diff --git a/test/unit/main.py b/test/unit/main.py index 83aa9139..d5940995 100644 --- a/test/unit/main.py +++ b/test/unit/main.py @@ -1,90 +1,26 @@ -import argparse import atexit -import fcntl import os -import platform import re import shutil import signal import stat import subprocess -import sys import tempfile import time -import unittest from multiprocessing import Process +import pytest +from conftest import _check_alerts +from conftest import _print_log +from conftest import option +from conftest import public_dir +from conftest import waitforfiles -class TestUnit(unittest.TestCase): - - current_dir = os.path.abspath( - os.path.join(os.path.dirname(__file__), os.pardir) - ) - pardir = os.path.abspath( - os.path.join(os.path.dirname(__file__), os.pardir, os.pardir) - ) - is_su = os.geteuid() == 0 - uid = os.geteuid() - gid = os.getegid() - architecture = platform.architecture()[0] - system = platform.system() - maxDiff = None - - detailed = False - save_log = False - print_log = False - unsafe = False - - def __init__(self, methodName='runTest'): - super().__init__(methodName) - - if re.match(r'.*\/run\.py$', sys.argv[0]): - args, rest = TestUnit._parse_args() - - TestUnit._set_args(args) - - def run(self, result=None): - if not hasattr(self, 'application_type'): - return super().run(result) - - # rerun test for each available module version - - type = self.application_type - for module in self.prerequisites['modules']: - if module in self.available['modules']: - prereq_version = self.prerequisites['modules'][module] - available_versions = self.available['modules'][module] - - if prereq_version == 'all': - for version in available_versions: - self.application_type = type + ' ' + version - super().run(result) - elif prereq_version == 'any': - self.application_type = type + ' ' + available_versions[0] - super().run(result) - else: - for version in available_versions: - if version.startswith(prereq_version): - self.application_type = type + ' ' + version - super().run(result) +class TestUnit(): @classmethod - def main(cls): - args, rest = TestUnit._parse_args() - - for i, arg in enumerate(rest): - if arg[:5] == 'test_': - rest[i] = cls.__name__ + '.' + arg - - sys.argv = sys.argv[:1] + rest - - TestUnit._set_args(args) - - unittest.main() - - @classmethod - def setUpClass(cls, complete_check=True): - cls.available = {'modules': {}, 'features': {}} + def setup_class(cls, complete_check=True): + cls.available = option.available unit = TestUnit() unit._run() @@ -92,7 +28,7 @@ class TestUnit(unittest.TestCase): # read unit.log for i in range(50): - with open(unit.testdir + '/unit.log', 'r') as f: + with open(unit.temp_dir + '/unit.log', 'r') as f: log = f.read() m = re.search('controller started', log) @@ -102,17 +38,9 @@ class TestUnit(unittest.TestCase): break if m is None: - unit._print_log() + _print_log(path=unit.temp_dir + '/unit.log') exit("Unit is writing log too long") - # discover available modules from unit.log - - for module in re.findall(r'module: ([a-zA-Z]+) (.*) ".*"$', log, re.M): - if module[0] not in cls.available['modules']: - cls.available['modules'][module[0]] = [module[1]] - else: - cls.available['modules'][module[0]].append(module[1]) - def check(available, prerequisites): missed = [] @@ -128,8 +56,7 @@ class TestUnit(unittest.TestCase): missed.append(module) if missed: - print('Unit has no ' + ', '.join(missed) + ' module(s)') - raise unittest.SkipTest() + pytest.skip('Unit has no ' + ', '.join(missed) + ' module(s)') # check features @@ -143,13 +70,12 @@ class TestUnit(unittest.TestCase): missed.append(feature) if missed: - print(', '.join(missed) + ' feature(s) not supported') - raise unittest.SkipTest() + pytest.skip(', '.join(missed) + ' feature(s) not supported') def destroy(): unit.stop() - unit._check_alerts(log) - shutil.rmtree(unit.testdir) + _check_alerts(log) + shutil.rmtree(unit.temp_dir) def complete(): destroy() @@ -161,92 +87,66 @@ class TestUnit(unittest.TestCase): unit.complete = complete return unit - def setUp(self): + def setup_method(self): self._run() def _run(self): - build_dir = self.pardir + '/build' + build_dir = option.current_dir + '/build' self.unitd = build_dir + '/unitd' if not os.path.isfile(self.unitd): exit("Could not find unit") - self.testdir = tempfile.mkdtemp(prefix='unit-test-') + self.temp_dir = tempfile.mkdtemp(prefix='unit-test-') - self.public_dir(self.testdir) + public_dir(self.temp_dir) if oct(stat.S_IMODE(os.stat(build_dir).st_mode)) != '0o777': - self.public_dir(build_dir) + public_dir(build_dir) - os.mkdir(self.testdir + '/state') + os.mkdir(self.temp_dir + '/state') - with open(self.testdir + '/unit.log', 'w') as log: + with open(self.temp_dir + '/unit.log', 'w') as log: self._p = subprocess.Popen( [ self.unitd, '--no-daemon', - '--modules', self.pardir + '/build', - '--state', self.testdir + '/state', - '--pid', self.testdir + '/unit.pid', - '--log', self.testdir + '/unit.log', - '--control', 'unix:' + self.testdir + '/control.unit.sock', - '--tmp', self.testdir, + '--modules', build_dir, + '--state', self.temp_dir + '/state', + '--pid', self.temp_dir + '/unit.pid', + '--log', self.temp_dir + '/unit.log', + '--control', 'unix:' + self.temp_dir + '/control.unit.sock', + '--tmp', self.temp_dir, ], stderr=log, ) atexit.register(self.stop) - if not self.waitforfiles(self.testdir + '/control.unit.sock'): - self._print_log() + if not waitforfiles(self.temp_dir + '/control.unit.sock'): + _print_log(path=self.temp_dir + '/unit.log') exit("Could not start unit") self._started = True - self.skip_alerts = [ - r'read signalfd\(4\) failed', - r'sendmsg.+failed', - r'recvmsg.+failed', - ] - self.skip_sanitizer = False - - def tearDown(self): + def teardown_method(self): self.stop() - # detect errors and failures for current test - - def list2reason(exc_list): - if exc_list and exc_list[-1][0] is self: - return exc_list[-1][1] - - if hasattr(self, '_outcome'): - result = self.defaultTestResult() - self._feedErrorsToResult(result, self._outcome.errors) - else: - result = getattr( - self, '_outcomeForDoCleanups', self._resultForDoCleanups - ) - - success = not list2reason(result.errors) and not list2reason( - result.failures - ) - # check unit.log for alerts - unit_log = self.testdir + '/unit.log' + unit_log = self.temp_dir + '/unit.log' with open(unit_log, 'r', encoding='utf-8', errors='ignore') as f: - self._check_alerts(f.read()) + _check_alerts(f.read()) # remove unit.log - if not TestUnit.save_log and success: - shutil.rmtree(self.testdir) - + if not option.save_log: + shutil.rmtree(self.temp_dir) else: - self._print_log() + _print_log(path=self.temp_dir) - self.assertListEqual(self.stop_errors, [None, None], 'stop errors') + assert self.stop_errors == [None, None], 'stop errors' def stop(self): if not self._started: @@ -301,121 +201,3 @@ class TestUnit(unittest.TestCase): if fail: return 'Fail to stop process' - - def waitforfiles(self, *files): - for i in range(50): - wait = False - ret = False - - for f in files: - if not os.path.exists(f): - wait = True - break - - if wait: - time.sleep(0.1) - - else: - ret = True - break - - return ret - - def public_dir(self, path): - os.chmod(path, 0o777) - - for root, dirs, files in os.walk(path): - for d in dirs: - os.chmod(os.path.join(root, d), 0o777) - for f in files: - os.chmod(os.path.join(root, f), 0o777) - - def _check_alerts(self, log): - found = False - - alerts = re.findall('.+\[alert\].+', log) - - if alerts: - print('All alerts/sanitizer errors found in log:') - [print(alert) for alert in alerts] - found = True - - if self.skip_alerts: - for skip in self.skip_alerts: - alerts = [al for al in alerts if re.search(skip, al) is None] - - if alerts: - self._print_log(log) - self.assertFalse(alerts, 'alert(s)') - - if not self.skip_sanitizer: - sanitizer_errors = re.findall('.+Sanitizer.+', log) - - if sanitizer_errors: - self._print_log(log) - self.assertFalse(sanitizer_errors, 'sanitizer error(s)') - - if found: - print('skipped.') - - @staticmethod - def _parse_args(): - parser = argparse.ArgumentParser(add_help=False) - - parser.add_argument( - '-d', - '--detailed', - dest='detailed', - action='store_true', - help='Detailed output for tests', - ) - parser.add_argument( - '-l', - '--log', - dest='save_log', - action='store_true', - help='Save unit.log after the test execution', - ) - parser.add_argument( - '-r', - '--reprint_log', - dest='print_log', - action='store_true', - help='Print unit.log to stdout in case of errors', - ) - parser.add_argument( - '-u', - '--unsafe', - dest='unsafe', - action='store_true', - help='Run unsafe tests', - ) - - return parser.parse_known_args() - - @staticmethod - def _set_args(args): - TestUnit.detailed = args.detailed - TestUnit.save_log = args.save_log - TestUnit.print_log = args.print_log - TestUnit.unsafe = args.unsafe - - # set stdout to non-blocking - - if TestUnit.detailed or TestUnit.print_log: - fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, 0) - - def _print_log(self, data=None): - path = self.testdir + '/unit.log' - - print('Path to unit.log:\n' + path + '\n') - - if TestUnit.print_log: - os.set_blocking(sys.stdout.fileno(), True) - sys.stdout.flush() - - if data is None: - with open(path, 'r', encoding='utf-8', errors='ignore') as f: - shutil.copyfileobj(f, sys.stdout) - else: - sys.stdout.write(data) |