From c093ee7ec50233feb3ff0444c91e394abee4c52a Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Fri, 26 Mar 2021 15:42:58 +0000 Subject: Tests: added test for Ruby default encoding. --- test/ruby/encoding/config.ru | 8 ++++++++ test/test_ruby_application.py | 47 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 test/ruby/encoding/config.ru (limited to 'test') diff --git a/test/ruby/encoding/config.ru b/test/ruby/encoding/config.ru new file mode 100644 index 00000000..60bf0efa --- /dev/null +++ b/test/ruby/encoding/config.ru @@ -0,0 +1,8 @@ +app = Proc.new do |env| + ['200', { + 'Content-Length' => '0', + 'X-Enc' => Encoding.default_external.to_s, + }, ['']] +end + +run app diff --git a/test/test_ruby_application.py b/test/test_ruby_application.py index b18a6cee..12a078b7 100644 --- a/test/test_ruby_application.py +++ b/test/test_ruby_application.py @@ -1,4 +1,5 @@ import re +import subprocess import pytest from unit.applications.lang.ruby import TestApplicationRuby @@ -223,6 +224,52 @@ class TestRubyApplication(TestApplicationRuby): self.wait_for_record(r'\[error\].+At exit called\.') is not None ), 'at exit' + def test_ruby_application_encoding(self): + self.load('encoding') + + try: + locales = subprocess.check_output( + ['locale', '-a'], stderr=subprocess.STDOUT, + ).decode().split('\n') + + except (FileNotFoundError, subprocess.CalledProcessError): + pytest.skip('require locale') + + def get_locale(pattern): + return next( + ( + l + for l in locales + if re.match(pattern, l.upper()) is not None + ), + None, + ) + + utf8 = get_locale(r'.*UTF[-_]?8') + iso88591 = get_locale(r'.*ISO[-_]?8859[-_]?1') + + def check_locale(enc): + assert 'success' in self.conf( + {"LC_CTYPE": enc}, '/config/applications/encoding/environment', + ) + + resp = self.get() + assert resp['status'] == 200, 'status' + + enc_default = re.sub(r'[-_]', '', resp['headers']['X-Enc']).upper() + assert ( + enc_default == re.sub(r'[-_]', '', enc.split('.')[-1]).upper() + ) + + if utf8: + check_locale(utf8) + + if iso88591: + check_locale(iso88591) + + if not utf8 and not iso88591: + pytest.skip('no available locales') + def test_ruby_application_header_custom(self): self.load('header_custom') -- cgit From e8577afc2126001db03d4b8ac1dd8670a2504322 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Fri, 26 Mar 2021 21:06:23 +0000 Subject: Tests: SNI. --- test/test_tls_sni.py | 286 ++++++++++++++++++++++++++++++++++++++++++ test/unit/applications/tls.py | 21 +++- test/unit/http.py | 3 +- 3 files changed, 306 insertions(+), 4 deletions(-) create mode 100644 test/test_tls_sni.py (limited to 'test') diff --git a/test/test_tls_sni.py b/test/test_tls_sni.py new file mode 100644 index 00000000..7da05e6e --- /dev/null +++ b/test/test_tls_sni.py @@ -0,0 +1,286 @@ +import subprocess +import ssl + +import pytest +from unit.applications.tls import TestApplicationTLS +from unit.option import option + + +class TestTLSSNI(TestApplicationTLS): + prerequisites = {'modules': {'openssl': 'any'}} + + def setup_method(self): + self._load_conf( + { + "listeners": {"*:7080": {"pass": "routes"}}, + "routes": [{"action": {"return": 200}}], + "applications": {}, + } + ) + + def openssl_date_to_sec_epoch(self, date): + return self.date_to_sec_epoch(date, '%b %d %H:%M:%S %Y %Z') + + def add_tls(self, cert='default'): + assert 'success' in self.conf( + { + "pass": "routes", + "tls": {"certificate": cert} + }, + 'listeners/*:7080', + ) + + def remove_tls(self): + assert 'success' in self.conf({"pass": "routes"}, 'listeners/*:7080') + + def generate_ca_conf(self): + with open(option.temp_dir + '/ca.conf', 'w') as f: + f.write( + """[ ca ] +default_ca = myca + +[ myca ] +new_certs_dir = %(dir)s +database = %(database)s +default_md = sha256 +policy = myca_policy +serial = %(certserial)s +default_days = 1 +x509_extensions = myca_extensions +copy_extensions = copy + +[ myca_policy ] +commonName = optional + +[ myca_extensions ] +basicConstraints = critical,CA:TRUE""" + % { + 'dir': option.temp_dir, + 'database': option.temp_dir + '/certindex', + 'certserial': option.temp_dir + '/certserial', + } + ) + + with open(option.temp_dir + '/certserial', 'w') as f: + f.write('1000') + + with open(option.temp_dir + '/certindex', 'w') as f: + f.write('') + + def config_bundles(self, bundles): + self.certificate('root', False) + + for b in bundles: + self.openssl_conf(rewrite=True, alt_names=bundles[b]['alt_names']) + subj = ( + '/CN={}/'.format(bundles[b]['subj']) + if 'subj' in bundles[b] + else '/' + ) + + subprocess.call( + [ + 'openssl', + 'req', + '-new', + '-subj', + subj, + '-config', + option.temp_dir + '/openssl.conf', + '-out', + option.temp_dir + '/{}.csr'.format(b), + '-keyout', + option.temp_dir + '/{}.key'.format(b), + ], + stderr=subprocess.STDOUT, + ) + + self.generate_ca_conf() + + for b in bundles: + subj = ( + '/CN={}/'.format(bundles[b]['subj']) + if 'subj' in bundles[b] + else '/' + ) + + subprocess.call( + [ + 'openssl', + 'ca', + '-batch', + '-subj', + subj, + '-config', + option.temp_dir + '/ca.conf', + '-keyfile', + option.temp_dir + '/root.key', + '-cert', + option.temp_dir + '/root.crt', + '-in', + option.temp_dir + '/{}.csr'.format(b), + '-out', + option.temp_dir + '/{}.crt'.format(b), + ], + stderr=subprocess.STDOUT, + ) + + self.context = ssl.create_default_context() + self.context.check_hostname = False + self.context.verify_mode = ssl.CERT_REQUIRED + self.context.load_verify_locations(option.temp_dir + '/root.crt') + + self.load_certs(bundles) + + def load_certs(self, bundles): + for bname, bvalue in bundles.items(): + assert 'success' in self.certificate_load( + bname, bname + ), 'certificate {} upload'.format(bvalue['subj']) + + def check_cert(self, host, expect): + resp, sock = self.get_ssl( + headers={ + 'Host': host, + 'Content-Length': '0', + 'Connection': 'close', + }, + start=True, + ) + + assert resp['status'] == 200 + assert sock.getpeercert()['subject'][0][0][1] == expect + + def test_tls_sni(self): + bundles = { + "default": { + "subj": "default", + "alt_names": ["default"], + }, + "localhost.com": { + "subj": "localhost.com", + "alt_names": ["alt1.localhost.com"], + }, + "example.com": { + "subj": "example.com", + "alt_names": ["alt1.example.com", "alt2.example.com"], + }, + } + self.config_bundles(bundles) + self.add_tls(["default", "localhost.com", "example.com"]) + + self.check_cert('alt1.localhost.com', bundles['localhost.com']['subj']) + self.check_cert('alt2.example.com', bundles['example.com']['subj']) + self.check_cert('blah', bundles['default']['subj']) + + def test_tls_sni_upper_case(self): + bundles = { + "localhost.com": {"subj": "LOCALHOST.COM", "alt_names": []}, + "example.com": { + "subj": "example.com", + "alt_names": ["ALT1.EXAMPLE.COM", "*.ALT2.EXAMPLE.COM"], + }, + } + self.config_bundles(bundles) + self.add_tls(["localhost.com", "example.com"]) + + self.check_cert('localhost.com', bundles['localhost.com']['subj']) + self.check_cert('LOCALHOST.COM', bundles['localhost.com']['subj']) + self.check_cert('EXAMPLE.COM', bundles['localhost.com']['subj']) + self.check_cert('ALT1.EXAMPLE.COM', bundles['example.com']['subj']) + self.check_cert('WWW.ALT2.EXAMPLE.COM', bundles['example.com']['subj']) + + def test_tls_sni_only_bundle(self): + bundles = { + "localhost.com": { + "subj": "localhost.com", + "alt_names": ["alt1.localhost.com", "alt2.localhost.com"], + } + } + self.config_bundles(bundles) + self.add_tls(["localhost.com"]) + + self.check_cert('domain.com', bundles['localhost.com']['subj']) + self.check_cert('alt1.domain.com', bundles['localhost.com']['subj']) + + def test_tls_sni_wildcard(self): + bundles = { + "localhost.com": { + "subj": "localhost.com", + "alt_names": [], + }, + "example.com": { + "subj": "example.com", + "alt_names": ["*.example.com", "*.alt.example.com"], + }, + } + self.config_bundles(bundles) + self.add_tls(["localhost.com", "example.com"]) + + self.check_cert('example.com', bundles['localhost.com']['subj']) + self.check_cert('www.example.com', bundles['example.com']['subj']) + self.check_cert('alt.example.com', bundles['example.com']['subj']) + self.check_cert('www.alt.example.com', bundles['example.com']['subj']) + self.check_cert('www.alt.example.ru', bundles['localhost.com']['subj']) + + def test_tls_sni_duplicated_bundle(self): + bundles = { + "localhost.com": { + "subj": "localhost.com", + "alt_names": ["localhost.com", "alt2.localhost.com"], + } + } + self.config_bundles(bundles) + self.add_tls(["localhost.com", "localhost.com"]) + + self.check_cert('localhost.com', bundles['localhost.com']['subj']) + self.check_cert('alt2.localhost.com', bundles['localhost.com']['subj']) + + def test_tls_sni_same_alt(self): + bundles = { + "localhost": {"subj": "subj1", "alt_names": "same.altname.com"}, + "example": {"subj": "subj2", "alt_names": "same.altname.com"}, + } + self.config_bundles(bundles) + self.add_tls(["localhost", "example"]) + + self.check_cert('localhost', bundles['localhost']['subj']) + self.check_cert('example', bundles['localhost']['subj']) + + def test_tls_sni_empty_cn(self): + bundles = { + "localhost": { + "alt_names": ["alt.localhost.com"], + } + } + self.config_bundles(bundles) + self.add_tls(["localhost"]) + + resp, sock = self.get_ssl( + headers={ + 'Host': 'domain.com', + 'Content-Length': '0', + 'Connection': 'close', + }, + start=True, + ) + + assert resp['status'] == 200 + assert sock.getpeercert()['subjectAltName'][0][1] == 'alt.localhost.com' + + def test_tls_sni_invalid(self): + self.config_bundles({"localhost": {"subj": "subj1", "alt_names": ''}}) + self.add_tls(["localhost"]) + + def check_certificate(cert): + assert 'error' in self.conf( + {"pass": "routes", "tls": {"certificate": cert}}, + 'listeners/*:7080', + ) + + check_certificate('') + check_certificate('blah') + check_certificate([]) + check_certificate(['blah']) + check_certificate(['localhost', 'blah']) + check_certificate(['localhost', []]) diff --git a/test/unit/applications/tls.py b/test/unit/applications/tls.py index b0cd5abb..490ae916 100644 --- a/test/unit/applications/tls.py +++ b/test/unit/applications/tls.py @@ -63,19 +63,34 @@ class TestApplicationTLS(TestApplicationProto): return ssl.get_server_certificate(addr, ssl_version=ssl_version) - def openssl_conf(self): + def openssl_conf(self, rewrite=False, alt_names=[]): conf_path = option.temp_dir + '/openssl.conf' - if os.path.exists(conf_path): + if not rewrite and os.path.exists(conf_path): return + # Generates alt_names section with dns names + a_names = "[alt_names]\n" + for i, k in enumerate(alt_names, 1): + a_names += "DNS.%d = %s\n" % (i, k) + + # Generates section for sign request extension + a_sec = """req_extensions = myca_req_extensions + +[ myca_req_extensions ] +subjectAltName = @alt_names + +{a_names}""".format(a_names=a_names) + with open(conf_path, 'w') as f: f.write( """[ req ] default_bits = 2048 encrypt_key = no distinguished_name = req_distinguished_name -[ req_distinguished_name ]""" + +{a_sec} +[ req_distinguished_name ]""".format(a_sec=a_sec if alt_names else "") ) def load(self, script, name=None): diff --git a/test/unit/http.py b/test/unit/http.py index 57e6ed3a..7706fe05 100644 --- a/test/unit/http.py +++ b/test/unit/http.py @@ -44,7 +44,8 @@ class TestHTTP(): sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) if 'wrapper' in kwargs: - sock = kwargs['wrapper'](sock) + server_hostname = headers.get('Host', 'localhost') + sock = kwargs['wrapper'](sock, server_hostname=server_hostname) connect_args = addr if sock_type == 'unix' else (addr, port) try: -- cgit From 0ae75733f7e63c7f2c190edb1425c0031262dc71 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Wed, 31 Mar 2021 03:24:01 +0100 Subject: Tests: added file descriptor leak detection. --- test/conftest.py | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++ test/test_respawn.py | 6 ++- 2 files changed, 132 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/conftest.py b/test/conftest.py index 20ac6e81..7b3314e2 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -56,6 +56,12 @@ def pytest_addoption(parser): type=str, help="Default user for non-privileged processes of unitd", ) + parser.addoption( + "--fds-threshold", + type=int, + default=0, + help="File descriptors threshold", + ) parser.addoption( "--restart", default=False, @@ -67,12 +73,23 @@ def pytest_addoption(parser): unit_instance = {} unit_log_copy = "unit.log.copy" _processes = [] +_fds_check = { + 'main': {'fds': 0, 'skip': False}, + 'router': {'name': 'unit: router', 'pid': -1, 'fds': 0, 'skip': False}, + 'controller': { + 'name': 'unit: controller', + 'pid': -1, + 'fds': 0, + 'skip': False, + }, +} http = TestHTTP() def pytest_configure(config): option.config = config.option option.detailed = config.option.detailed + option.fds_threshold = config.option.fds_threshold option.print_log = config.option.print_log option.save_log = config.option.save_log option.unsafe = config.option.unsafe @@ -257,6 +274,10 @@ def run(request): ] option.skip_sanitizer = False + _fds_check['main']['skip'] = False + _fds_check['router']['skip'] = False + _fds_check['router']['skip'] = False + yield # stop unit @@ -304,6 +325,50 @@ def run(request): else: shutil.rmtree(path) + # check descriptors (wait for some time before check) + + def waitforfds(diff): + for i in range(600): + fds_diff = diff() + + if fds_diff <= option.fds_threshold: + break + + time.sleep(0.1) + + return fds_diff + + ps = _fds_check['main'] + if not ps['skip']: + fds_diff = waitforfds( + lambda: _count_fds(unit_instance['pid']) - ps['fds'] + ) + ps['fds'] += fds_diff + + assert ( + fds_diff <= option.fds_threshold + ), 'descriptors leak main process' + + else: + ps['fds'] = _count_fds(unit_instance['pid']) + + for name in ['controller', 'router']: + ps = _fds_check[name] + ps_pid = ps['pid'] + ps['pid'] = pid_by_name(ps['name']) + + if not ps['skip']: + fds_diff = waitforfds(lambda: _count_fds(ps['pid']) - ps['fds']) + ps['fds'] += fds_diff + + assert ps['pid'] == ps_pid, 'same pid %s' % name + assert fds_diff <= option.fds_threshold, ( + 'descriptors leak %s' % name + ) + + else: + ps['fds'] = _count_fds(ps['pid']) + # print unit.log in case of error if hasattr(request.node, 'rep_call') and request.node.rep_call.failed: @@ -371,6 +436,21 @@ def unit_run(): unit_instance['control_sock'] = temp_dir + '/control.unit.sock' unit_instance['unitd'] = unitd + with open(temp_dir + '/unit.pid', 'r') as f: + unit_instance['pid'] = f.read().rstrip() + + _clear_conf(unit_instance['temp_dir'] + '/control.unit.sock') + + _fds_check['main']['fds'] = _count_fds(unit_instance['pid']) + + router = _fds_check['router'] + router['pid'] = pid_by_name(router['name']) + router['fds'] = _count_fds(router['pid']) + + controller = _fds_check['controller'] + controller['pid'] = pid_by_name(controller['name']) + controller['fds'] = _count_fds(controller['pid']) + return unit_instance @@ -492,6 +572,32 @@ def _clear_conf(sock, log=None): check_success(resp) +def _count_fds(pid): + procfile = '/proc/%s/fd' % pid + if os.path.isdir(procfile): + return len(os.listdir(procfile)) + + try: + out = subprocess.check_output( + ['procstat', '-f', pid], stderr=subprocess.STDOUT, + ).decode() + return len(out.splitlines()) + + except (FileNotFoundError, subprocess.CalledProcessError): + pass + + try: + out = subprocess.check_output( + ['lsof', '-n', '-p', pid], stderr=subprocess.STDOUT, + ).decode() + return len(out.splitlines()) + + except (FileNotFoundError, subprocess.CalledProcessError): + pass + + return 0 + + def run_process(target, *args): global _processes @@ -517,6 +623,18 @@ def stop_processes(): return 'Fail to stop process(es)' +def pid_by_name(name): + output = subprocess.check_output(['ps', 'ax', '-O', 'ppid']).decode() + m = re.search( + r'\s*(\d+)\s*' + str(unit_instance['pid']) + r'.*' + name, output + ) + return None if m is None else m.group(1) + + +def find_proc(name, ps_output): + return re.findall(str(unit_instance['pid']) + r'.*' + name, ps_output) + + @pytest.fixture() def skip_alert(): def _skip(*alerts): @@ -525,6 +643,16 @@ def skip_alert(): return _skip +@pytest.fixture() +def skip_fds_check(): + def _skip(main=False, router=False, controller=False): + _fds_check['main']['skip'] = main + _fds_check['router']['skip'] = router + _fds_check['controller']['skip'] = controller + + return _skip + + @pytest.fixture def temp_dir(request): return unit_instance['temp_dir'] diff --git a/test/test_respawn.py b/test/test_respawn.py index ed85ee95..50c19186 100644 --- a/test/test_respawn.py +++ b/test/test_respawn.py @@ -58,7 +58,8 @@ class TestRespawn(TestApplicationPython): assert len(self.find_proc(self.PATTERN_CONTROLLER, unit_pid, out)) == 1 assert len(self.find_proc(self.app_name, unit_pid, out)) == 1 - def test_respawn_router(self, skip_alert, unit_pid): + def test_respawn_router(self, skip_alert, unit_pid, skip_fds_check): + skip_fds_check(router=True) pid = self.pid_by_name(self.PATTERN_ROUTER, unit_pid) self.kill_pids(pid) @@ -68,7 +69,8 @@ class TestRespawn(TestApplicationPython): self.smoke_test(unit_pid) - def test_respawn_controller(self, skip_alert, unit_pid): + def test_respawn_controller(self, skip_alert, unit_pid, skip_fds_check): + skip_fds_check(controller=True) pid = self.pid_by_name(self.PATTERN_CONTROLLER, unit_pid) self.kill_pids(pid) -- cgit From f43265ba2c0c4a08a3c513fb11dca9835388a001 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Wed, 31 Mar 2021 23:42:00 +0100 Subject: Tests: removed skip_alert(). --- test/test_routing.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'test') diff --git a/test/test_routing.py b/test/test_routing.py index be9a1faf..cb9c3fd2 100644 --- a/test/test_routing.py +++ b/test/test_routing.py @@ -1362,10 +1362,7 @@ class TestRouting(TestApplicationProto): 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, skip_alert): - # TODO remove it after controller fixed - skip_alert(r'failed to apply new conf') - + def test_routes_match_arguments_invalid(self): self.route_match_invalid({"arguments": ["var"]}) self.route_match_invalid({"arguments": [{"var1": {}}]}) self.route_match_invalid({"arguments": {"": "bar"}}) -- cgit From 46d8567dd7c2a9af025f1de13084a9efd7118e20 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Thu, 1 Apr 2021 00:05:44 +0100 Subject: Tests: unset LC_ALL variable in Ruby encoding test. This change is necessary to set Encoding.default_external value correctly. --- test/test_ruby_application.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/test_ruby_application.py b/test/test_ruby_application.py index 12a078b7..17491619 100644 --- a/test/test_ruby_application.py +++ b/test/test_ruby_application.py @@ -250,7 +250,8 @@ class TestRubyApplication(TestApplicationRuby): def check_locale(enc): assert 'success' in self.conf( - {"LC_CTYPE": enc}, '/config/applications/encoding/environment', + {"LC_CTYPE": enc, "LC_ALL": ""}, + '/config/applications/encoding/environment', ) resp = self.get() -- cgit From 6c97a1a069f0ae8cf683c8364fb7f9dabc5e89cb Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Mon, 5 Apr 2021 14:03:05 +0100 Subject: Tests: style. --- test/conftest.py | 38 +++--- test/python/atexit/wsgi.py | 1 + test/python/body_io/wsgi.py | 1 + test/python/callable/wsgi.py | 1 + test/python/ctx_iter_atexit/wsgi.py | 16 ++- test/python/custom_header/wsgi.py | 11 +- test/python/delayed/asgi.py | 27 ++-- test/python/empty/asgi.py | 14 +- test/python/environment/wsgi.py | 1 + test/python/header_fields/wsgi.py | 7 +- test/python/host/wsgi.py | 13 +- test/python/iter_exception/wsgi.py | 4 +- test/python/legacy/asgi.py | 15 ++- test/python/legacy_force/asgi.py | 15 ++- test/python/mirror/asgi.py | 19 ++- test/python/mirror/wsgi.py | 4 +- test/python/path/wsgi.py | 1 + test/python/query_string/asgi.py | 18 +-- test/python/query_string/wsgi.py | 11 +- test/python/server_port/asgi.py | 18 +-- test/python/server_port/wsgi.py | 8 +- test/python/threading/asgi.py | 14 +- test/python/threads/asgi.py | 19 +-- test/python/threads/wsgi.py | 14 +- test/python/upload/wsgi.py | 10 +- test/python/user_group/wsgi.py | 17 +-- test/python/variables/asgi.py | 39 +++--- test/python/variables/wsgi.py | 33 ++--- test/python/websockets/mirror/asgi.py | 18 +-- test/python/websockets/subprotocol/asgi.py | 30 +++-- test/test_access_log.py | 1 + test/test_asgi_application.py | 13 +- test/test_asgi_lifespan.py | 1 + test/test_asgi_websockets.py | 208 +++++++++++++++-------------- test/test_configuration.py | 1 + test/test_go_application.py | 8 +- test/test_go_isolation.py | 14 +- test/test_go_isolation_rootfs.py | 1 + test/test_http_header.py | 1 + test/test_java_application.py | 11 +- test/test_java_isolation_rootfs.py | 1 + test/test_java_websockets.py | 197 ++++++++++++++------------- test/test_node_application.py | 5 +- test/test_node_websockets.py | 197 ++++++++++++++------------- test/test_perl_application.py | 1 + test/test_php_application.py | 14 +- test/test_php_isolation.py | 5 +- test/test_proxy.py | 10 +- test/test_python_application.py | 10 +- test/test_python_isolation.py | 18 +-- test/test_python_isolation_chroot.py | 4 +- test/test_python_procman.py | 1 + test/test_respawn.py | 7 +- test/test_routing.py | 11 +- test/test_ruby_application.py | 12 +- test/test_ruby_isolation.py | 1 + test/test_settings.py | 1 + test/test_share_fallback.py | 6 +- test/test_static.py | 11 +- test/test_tls.py | 3 +- test/test_tls_sni.py | 28 ++-- test/test_variables.py | 12 +- test/unit/applications/tls.py | 22 ++- test/unit/applications/websockets.py | 18 +-- test/unit/check/isolation.py | 4 +- test/unit/http.py | 23 ++-- test/unit/option.py | 3 +- 67 files changed, 698 insertions(+), 623 deletions(-) (limited to 'test') diff --git a/test/conftest.py b/test/conftest.py index 7b3314e2..38e1138e 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -6,7 +6,6 @@ import platform import re import shutil import signal -import socket import stat import subprocess import sys @@ -15,11 +14,12 @@ import time from multiprocessing import Process import pytest + from unit.check.go import check_go from unit.check.isolation import check_isolation from unit.check.node import check_node -from unit.check.tls import check_openssl from unit.check.regex import check_regex +from unit.check.tls import check_openssl from unit.http import TestHTTP from unit.option import option from unit.utils import public_dir @@ -85,6 +85,7 @@ _fds_check = { } http = TestHTTP() + def pytest_configure(config): option.config = config.option @@ -115,9 +116,11 @@ def pytest_configure(config): def pytest_generate_tests(metafunc): cls = metafunc.cls - if (not hasattr(cls, 'application_type') - or cls.application_type == None - or cls.application_type == 'external'): + if ( + not hasattr(cls, 'application_type') + or cls.application_type == None + or cls.application_type == 'external' + ): return type = cls.application_type @@ -216,6 +219,7 @@ def pytest_sessionstart(session): elif option.save_log: open(unit_instance['temp_dir'] + '/' + unit_log_copy, 'w').close() + @pytest.hookimpl(tryfirst=True, hookwrapper=True) def pytest_runtest_makereport(item, call): # execute all other hooks to obtain the report object @@ -320,7 +324,9 @@ def run(request): public_dir(path) - if os.path.isfile(path) or stat.S_ISSOCK(os.stat(path).st_mode): + if os.path.isfile(path) or stat.S_ISSOCK( + os.stat(path).st_mode + ): os.remove(path) else: shutil.rmtree(path) @@ -384,6 +390,7 @@ def run(request): _check_alerts(log=log) + def unit_run(): global unit_instance @@ -482,7 +489,6 @@ def unit_stop(): return 'Could not terminate unit' - def _check_alerts(path=None, log=None): if path is None: path = unit_instance['log'] @@ -554,24 +560,21 @@ def _clear_conf(sock, log=None): return try: - certs = json.loads(http.get( - url='/certificates', - sock_type='unix', - addr=sock, - )['body']).keys() + certs = json.loads( + http.get(url='/certificates', sock_type='unix', addr=sock,)['body'] + ).keys() except json.JSONDecodeError: pytest.fail('Can\'t parse certificates list.') for cert in certs: resp = http.delete( - url='/certificates/' + cert, - sock_type='unix', - addr=sock, + url='/certificates/' + cert, sock_type='unix', addr=sock, )['body'] check_success(resp) + def _count_fds(pid): procfile = '/proc/%s/fd' % pid if os.path.isdir(procfile): @@ -606,6 +609,7 @@ def run_process(target, *args): _processes.append(process) + def stop_processes(): if not _processes: return @@ -657,18 +661,22 @@ def skip_fds_check(): def temp_dir(request): return unit_instance['temp_dir'] + @pytest.fixture def is_unsafe(request): return request.config.getoption("--unsafe") + @pytest.fixture def is_su(request): return os.geteuid() == 0 + @pytest.fixture def unit_pid(request): return unit_instance['process'].pid + def pytest_sessionfinish(session): if not option.restart and option.save_log: print('Path to unit.log:\n' + unit_instance['log'] + '\n') diff --git a/test/python/atexit/wsgi.py b/test/python/atexit/wsgi.py index a5a9918d..b64b8477 100644 --- a/test/python/atexit/wsgi.py +++ b/test/python/atexit/wsgi.py @@ -1,5 +1,6 @@ import atexit + def application(environ, start_response): def at_exit(): environ['wsgi.errors'].write('At exit called.\n') diff --git a/test/python/body_io/wsgi.py b/test/python/body_io/wsgi.py index 14303b5f..58ce76a4 100644 --- a/test/python/body_io/wsgi.py +++ b/test/python/body_io/wsgi.py @@ -1,5 +1,6 @@ import io + def application(env, start_response): start_response('200', [('Content-Length', '10')]) f = io.BytesIO(b'0123456789') diff --git a/test/python/callable/wsgi.py b/test/python/callable/wsgi.py index 365f82fa..374ecb28 100644 --- a/test/python/callable/wsgi.py +++ b/test/python/callable/wsgi.py @@ -2,6 +2,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/ctx_iter_atexit/wsgi.py b/test/python/ctx_iter_atexit/wsgi.py index d0b33daa..b2f12c35 100644 --- a/test/python/ctx_iter_atexit/wsgi.py +++ b/test/python/ctx_iter_atexit/wsgi.py @@ -1,5 +1,6 @@ import atexit + class application: def __init__(self, environ, start_response): self.environ = environ @@ -11,13 +12,14 @@ class application: content_length = int(self.environ.get('CONTENT_LENGTH', 0)) body = bytes(self.environ['wsgi.input'].read(content_length)) - self.start('200', [ - ('Content-Type', self.environ.get('CONTENT_TYPE')), - ('Content-Length', str(len(body))) - ]) + self.start( + '200', + [ + ('Content-Type', self.environ.get('CONTENT_TYPE')), + ('Content-Length', str(len(body))), + ], + ) yield body def _atexit(self): - self.start('200', [ - ('Content-Length', '0') - ]) + self.start('200', [('Content-Length', '0')]) diff --git a/test/python/custom_header/wsgi.py b/test/python/custom_header/wsgi.py index 44f145d1..44fc2af5 100644 --- a/test/python/custom_header/wsgi.py +++ b/test/python/custom_header/wsgi.py @@ -1,7 +1,10 @@ def application(environ, start_response): - start_response('200', [ - ('Content-Length', '0'), - ('Custom-Header', environ.get('HTTP_CUSTOM_HEADER')) - ]) + start_response( + '200', + [ + ('Content-Length', '0'), + ('Custom-Header', environ.get('HTTP_CUSTOM_HEADER')), + ], + ) return [] diff --git a/test/python/delayed/asgi.py b/test/python/delayed/asgi.py index d5cad929..1cb15a92 100644 --- a/test/python/delayed/asgi.py +++ b/test/python/delayed/asgi.py @@ -1,5 +1,6 @@ import asyncio + async def application(scope, receive, send): assert scope['type'] == 'http' @@ -28,13 +29,13 @@ async def application(scope, receive, send): 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()), - ] - }) + await send( + { + 'type': 'http.response.start', + 'status': 200, + 'headers': [(b'content-length', str(len(body)).encode()),], + } + ) if not body: await sleep(delay) @@ -42,10 +43,12 @@ async def application(scope, receive, send): 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 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 index 58b7c1f2..14a40629 100644 --- a/test/python/empty/asgi.py +++ b/test/python/empty/asgi.py @@ -1,10 +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'), - ] - }) + await send( + { + 'type': 'http.response.start', + 'status': 200, + 'headers': [(b'content-length', b'0')], + } + ) diff --git a/test/python/environment/wsgi.py b/test/python/environment/wsgi.py index fa3a1d2b..d1564f29 100644 --- a/test/python/environment/wsgi.py +++ b/test/python/environment/wsgi.py @@ -1,5 +1,6 @@ import os + def application(env, start_response): body = '' vars = env.get('HTTP_X_VARIABLES').split(',') diff --git a/test/python/header_fields/wsgi.py b/test/python/header_fields/wsgi.py index bd1ba0e2..41144528 100644 --- a/test/python/header_fields/wsgi.py +++ b/test/python/header_fields/wsgi.py @@ -2,8 +2,7 @@ def application(environ, start_response): h = (k for k, v in environ.items() if k.startswith('HTTP_')) - start_response('200', [ - ('Content-Length', '0'), - ('All-Headers', ','.join(h)) - ]) + start_response( + '200', [('Content-Length', '0'), ('All-Headers', ','.join(h))] + ) return [] diff --git a/test/python/host/wsgi.py b/test/python/host/wsgi.py index db7de306..0a08bc36 100644 --- a/test/python/host/wsgi.py +++ b/test/python/host/wsgi.py @@ -1,7 +1,10 @@ def application(env, start_response): - start_response('200', [ - ('Content-Length', '0'), - ('X-Server-Name', env.get('SERVER_NAME')), - ('X-Http-Host', str(env.get('HTTP_HOST'))) - ]) + start_response( + '200', + [ + ('Content-Length', '0'), + ('X-Server-Name', env.get('SERVER_NAME')), + ('X-Http-Host', str(env.get('HTTP_HOST'))), + ], + ) return [] diff --git a/test/python/iter_exception/wsgi.py b/test/python/iter_exception/wsgi.py index 66a09af7..2779a845 100644 --- a/test/python/iter_exception/wsgi.py +++ b/test/python/iter_exception/wsgi.py @@ -8,7 +8,9 @@ class application: def __iter__(self): self.__i = 0 self._skip_level = int(self.environ.get('HTTP_X_SKIP', 0)) - self._not_skip_close = int(self.environ.get('HTTP_X_NOT_SKIP_CLOSE', 0)) + self._not_skip_close = int( + self.environ.get('HTTP_X_NOT_SKIP_CLOSE', 0) + ) self._is_chunked = self.environ.get('HTTP_X_CHUNKED') headers = [(('Content-Length', '10'))] diff --git a/test/python/legacy/asgi.py b/test/python/legacy/asgi.py index f065d026..1d45cc4f 100644 --- a/test/python/legacy/asgi.py +++ b/test/python/legacy/asgi.py @@ -3,11 +3,12 @@ def application(scope): return app_http + async def app_http(receive, send): - await send({ - 'type': 'http.response.start', - 'status': 200, - 'headers': [ - (b'content-length', b'0'), - ] - }) + await send( + { + 'type': 'http.response.start', + 'status': 200, + 'headers': [(b'content-length', b'0'),], + } + ) diff --git a/test/python/legacy_force/asgi.py b/test/python/legacy_force/asgi.py index 2e5859f2..ad2785f2 100644 --- a/test/python/legacy_force/asgi.py +++ b/test/python/legacy_force/asgi.py @@ -7,11 +7,12 @@ def application(scope, receive=None, send=None): else: return app_http(receive, send) + async def app_http(receive, send): - await send({ - 'type': 'http.response.start', - 'status': 200, - 'headers': [ - (b'content-length', b'0'), - ] - }) + await send( + { + 'type': 'http.response.start', + 'status': 200, + 'headers': [(b'content-length', b'0'),], + } + ) diff --git a/test/python/mirror/asgi.py b/test/python/mirror/asgi.py index 7088e893..18a66a4c 100644 --- a/test/python/mirror/asgi.py +++ b/test/python/mirror/asgi.py @@ -8,15 +8,12 @@ async def application(scope, receive, send): 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.start', + 'status': 200, + 'headers': [(b'content-length', str(len(body)).encode())], + } + ) - await send({ - 'type': 'http.response.body', - 'body': body, - }) + await send({'type': 'http.response.body', 'body': body}) diff --git a/test/python/mirror/wsgi.py b/test/python/mirror/wsgi.py index eb1fb922..3cd95437 100644 --- a/test/python/mirror/wsgi.py +++ b/test/python/mirror/wsgi.py @@ -3,7 +3,5 @@ def application(environ, start_response): content_length = int(environ.get('CONTENT_LENGTH', 0)) body = bytes(environ['wsgi.input'].read(content_length)) - start_response('200', [ - ('Content-Length', str(len(body))) - ]) + start_response('200', [('Content-Length', str(len(body)))]) return [body] diff --git a/test/python/path/wsgi.py b/test/python/path/wsgi.py index 2807f6ef..da7e1ff1 100644 --- a/test/python/path/wsgi.py +++ b/test/python/path/wsgi.py @@ -1,6 +1,7 @@ import os import sys + def application(environ, start_response): body = os.pathsep.join(sys.path).encode() diff --git a/test/python/query_string/asgi.py b/test/python/query_string/asgi.py index 28f4d107..5b659f9c 100644 --- a/test/python/query_string/asgi.py +++ b/test/python/query_string/asgi.py @@ -1,11 +1,13 @@ 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']), - ] - }) + 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/query_string/wsgi.py b/test/python/query_string/wsgi.py index 90f1c7ec..54a67b03 100644 --- a/test/python/query_string/wsgi.py +++ b/test/python/query_string/wsgi.py @@ -1,7 +1,10 @@ def application(environ, start_response): - start_response('200', [ - ('Content-Length', '0'), - ('Query-String', environ.get('QUERY_STRING')) - ]) + start_response( + '200', + [ + ('Content-Length', '0'), + ('Query-String', environ.get('QUERY_STRING')), + ], + ) return [] diff --git a/test/python/server_port/asgi.py b/test/python/server_port/asgi.py index e79ced00..810a182c 100644 --- a/test/python/server_port/asgi.py +++ b/test/python/server_port/asgi.py @@ -1,11 +1,13 @@ 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()), - ] - }) + 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/server_port/wsgi.py b/test/python/server_port/wsgi.py index 89cd82b3..c796da95 100644 --- a/test/python/server_port/wsgi.py +++ b/test/python/server_port/wsgi.py @@ -1,7 +1,7 @@ def application(environ, start_response): - start_response('200', [ - ('Content-Length', '0'), - ('Server-Port', environ.get('SERVER_PORT')) - ]) + start_response( + '200', + [('Content-Length', '0'), ('Server-Port', environ.get('SERVER_PORT'))], + ) return [] diff --git a/test/python/threading/asgi.py b/test/python/threading/asgi.py index 3c978e50..c4169a24 100644 --- a/test/python/threading/asgi.py +++ b/test/python/threading/asgi.py @@ -33,10 +33,10 @@ async def application(scope, receive, send): Foo(Foo.num).start() Foo.num += 10 - await send({ - 'type': 'http.response.start', - 'status': 200, - 'headers': [ - (b'content-length', b'0'), - ] - }) + await send( + { + 'type': 'http.response.start', + 'status': 200, + 'headers': [(b'content-length', b'0')], + } + ) diff --git a/test/python/threads/asgi.py b/test/python/threads/asgi.py index d51ae431..ff4e52ad 100644 --- a/test/python/threads/asgi.py +++ b/test/python/threads/asgi.py @@ -2,6 +2,7 @@ import asyncio import time import threading + async def application(scope, receive, send): assert scope['type'] == 'http' @@ -17,11 +18,13 @@ async def application(scope, receive, send): time.sleep(delay) - await send({ - 'type': 'http.response.start', - 'status': 200, - 'headers': [ - (b'content-length', b'0'), - (b'x-thread', str(threading.currentThread().ident).encode()), - ] - }) + await send( + { + 'type': 'http.response.start', + 'status': 200, + 'headers': [ + (b'content-length', b'0'), + (b'x-thread', str(threading.currentThread().ident).encode()), + ], + } + ) diff --git a/test/python/threads/wsgi.py b/test/python/threads/wsgi.py index 1cc8ffe2..cc283cfe 100644 --- a/test/python/threads/wsgi.py +++ b/test/python/threads/wsgi.py @@ -1,15 +1,19 @@ import time import threading + def application(environ, start_response): delay = float(environ.get('HTTP_X_DELAY', 0)) time.sleep(delay) - start_response('200', [ - ('Content-Length', '0'), - ('Wsgi-Multithread', str(environ['wsgi.multithread'])), - ('X-Thread', str(threading.currentThread().ident)) - ]) + start_response( + '200', + [ + ('Content-Length', '0'), + ('Wsgi-Multithread', str(environ['wsgi.multithread'])), + ('X-Thread', str(threading.currentThread().ident)), + ], + ) return [] diff --git a/test/python/upload/wsgi.py b/test/python/upload/wsgi.py index 37ee89eb..953c5ecc 100644 --- a/test/python/upload/wsgi.py +++ b/test/python/upload/wsgi.py @@ -1,6 +1,7 @@ from tempfile import TemporaryFile import os, cgi + def read(environ): length = int(environ.get('CONTENT_LENGTH', 0)) @@ -11,6 +12,7 @@ def read(environ): environ['wsgi.input'] = body return body + def application(environ, start_response): file = read(environ) @@ -19,9 +21,9 @@ def application(environ, start_response): filename = form['file'].filename data = filename.encode() + form['file'].file.read() - start_response('200 OK', [ - ('Content-Type', 'text/plain'), - ('Content-Length', str(len(data))), - ]) + start_response( + '200 OK', + [('Content-Type', 'text/plain'), ('Content-Length', str(len(data)))], + ) return data diff --git a/test/python/user_group/wsgi.py b/test/python/user_group/wsgi.py index f5deb87d..4003c064 100644 --- a/test/python/user_group/wsgi.py +++ b/test/python/user_group/wsgi.py @@ -1,18 +1,19 @@ import json import os + def application(environ, start_response): uid = os.geteuid() gid = os.getegid() - out = json.dumps({ - 'UID': uid, - 'GID': gid, - }).encode('utf-8') + out = json.dumps({'UID': uid, 'GID': gid,}).encode('utf-8') - start_response('200 OK', [ - ('Content-Length', str(len(out))), - ('Content-Type', 'application/json') - ]) + start_response( + '200 OK', + [ + ('Content-Length', str(len(out))), + ('Content-Type', 'application/json'), + ], + ) return [out] diff --git a/test/python/variables/asgi.py b/test/python/variables/asgi.py index dd1cca72..5a4f55e8 100644 --- a/test/python/variables/asgi.py +++ b/test/python/variables/asgi.py @@ -17,24 +17,23 @@ async def application(scope, receive, send): 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.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, - }) + await send({'type': 'http.response.body', 'body': body}) diff --git a/test/python/variables/wsgi.py b/test/python/variables/wsgi.py index 53991e5e..5d77902d 100644 --- a/test/python/variables/wsgi.py +++ b/test/python/variables/wsgi.py @@ -3,19 +3,22 @@ def application(environ, start_response): content_length = int(environ.get('CONTENT_LENGTH', 0)) body = bytes(environ['wsgi.input'].read(content_length)) - start_response('200', [ - ('Content-Type', environ.get('CONTENT_TYPE')), - ('Content-Length', str(len(body))), - ('Request-Method', environ.get('REQUEST_METHOD')), - ('Request-Uri', environ.get('REQUEST_URI')), - ('Http-Host', environ.get('HTTP_HOST')), - ('Server-Protocol', environ.get('SERVER_PROTOCOL')), - ('Server-Software', environ.get('SERVER_SOFTWARE')), - ('Custom-Header', environ.get('HTTP_CUSTOM_HEADER')), - ('Wsgi-Version', str(environ['wsgi.version'])), - ('Wsgi-Url-Scheme', environ['wsgi.url_scheme']), - ('Wsgi-Multithread', str(environ['wsgi.multithread'])), - ('Wsgi-Multiprocess', str(environ['wsgi.multiprocess'])), - ('Wsgi-Run-Once', str(environ['wsgi.run_once'])) - ]) + start_response( + '200', + [ + ('Content-Type', environ.get('CONTENT_TYPE')), + ('Content-Length', str(len(body))), + ('Request-Method', environ.get('REQUEST_METHOD')), + ('Request-Uri', environ.get('REQUEST_URI')), + ('Http-Host', environ.get('HTTP_HOST')), + ('Server-Protocol', environ.get('SERVER_PROTOCOL')), + ('Server-Software', environ.get('SERVER_SOFTWARE')), + ('Custom-Header', environ.get('HTTP_CUSTOM_HEADER')), + ('Wsgi-Version', str(environ['wsgi.version'])), + ('Wsgi-Url-Scheme', environ['wsgi.url_scheme']), + ('Wsgi-Multithread', str(environ['wsgi.multithread'])), + ('Wsgi-Multiprocess', str(environ['wsgi.multiprocess'])), + ('Wsgi-Run-Once', str(environ['wsgi.run_once'])), + ], + ) return [body] diff --git a/test/python/websockets/mirror/asgi.py b/test/python/websockets/mirror/asgi.py index 0f1d9953..72a32d67 100644 --- a/test/python/websockets/mirror/asgi.py +++ b/test/python/websockets/mirror/asgi.py @@ -3,16 +3,16 @@ async def application(scope, receive, send): while True: m = await receive() if m['type'] == 'websocket.connect': - await send({ - 'type': 'websocket.accept', - }) + 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), - }) + await send( + { + 'type': 'websocket.send', + 'bytes': m.get('bytes', None), + 'text': m.get('text', None), + } + ) if m['type'] == 'websocket.disconnect': - break; + break diff --git a/test/python/websockets/subprotocol/asgi.py b/test/python/websockets/subprotocol/asgi.py index 92263dd7..0385bb9d 100644 --- a/test/python/websockets/subprotocol/asgi.py +++ b/test/python/websockets/subprotocol/asgi.py @@ -6,20 +6,24 @@ async def application(scope, receive, send): if m['type'] == 'websocket.connect': subprotocols = scope['subprotocols'] - await send({ - 'type': 'websocket.accept', - 'headers': [ - (b'x-subprotocols', str(subprotocols).encode()), - ], - 'subprotocol': subprotocols[0], - }) + 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), - }) + await send( + { + 'type': 'websocket.send', + 'bytes': m.get('bytes', None), + 'text': m.get('text', None), + } + ) if m['type'] == 'websocket.disconnect': - break; + break diff --git a/test/test_access_log.py b/test/test_access_log.py index 65d5e50a..72a78c33 100644 --- a/test/test_access_log.py +++ b/test/test_access_log.py @@ -1,6 +1,7 @@ import time import pytest + from unit.applications.lang.python import TestApplicationPython from unit.option import option diff --git a/test/test_asgi_application.py b/test/test_asgi_application.py index 886a160b..70b2e4c3 100644 --- a/test/test_asgi_application.py +++ b/test/test_asgi_application.py @@ -3,13 +3,15 @@ import time from distutils.version import LooseVersion import pytest + from unit.applications.lang.python import TestApplicationPython from unit.option import option class TestASGIApplication(TestApplicationPython): - prerequisites = {'modules': {'python': - lambda v: LooseVersion(v) >= LooseVersion('3.5')}} + prerequisites = { + 'modules': {'python': lambda v: LooseVersion(v) >= LooseVersion('3.5')} + } load_module = 'asgi' def findall(self, pattern): @@ -31,7 +33,8 @@ Content-Type: text/html Connection: close custom-header: BLAH -%s""" % (len(body), body.encode()), +%s""" + % (len(body), body.encode()), raw=True, ) @@ -145,7 +148,7 @@ custom-header: BLAH assert 'success' in self.conf( '{"http":{"max_body_size": ' + str(max_body_size) + ' }}', - 'settings' + 'settings', ) assert self.get()['status'] == 200, 'init' @@ -398,7 +401,7 @@ Connection: close socks.append(sock) - time.sleep(1.0) # required to avoid greedy request reading + time.sleep(1.0) # required to avoid greedy request reading threads = set() diff --git a/test/test_asgi_lifespan.py b/test/test_asgi_lifespan.py index 3ecece43..43286e22 100644 --- a/test/test_asgi_lifespan.py +++ b/test/test_asgi_lifespan.py @@ -2,6 +2,7 @@ import os from distutils.version import LooseVersion import pytest + from conftest import unit_stop from unit.applications.lang.python import TestApplicationPython from unit.option import option diff --git a/test/test_asgi_websockets.py b/test/test_asgi_websockets.py index 7218d526..140bcb9a 100644 --- a/test/test_asgi_websockets.py +++ b/test/test_asgi_websockets.py @@ -3,14 +3,16 @@ import time from distutils.version import LooseVersion import pytest + from unit.applications.lang.python import TestApplicationPython from unit.applications.websockets import TestApplicationWebsocket from unit.option import option class TestASGIWebsockets(TestApplicationPython): - prerequisites = {'modules': {'python': - lambda v: LooseVersion(v) >= LooseVersion('3.5')}} + prerequisites = { + 'modules': {'python': lambda v: LooseVersion(v) >= LooseVersion('3.5')} + } load_module = 'asgi' ws = TestApplicationWebsocket() @@ -74,7 +76,9 @@ class TestASGIWebsockets(TestApplicationPython): sock.close() assert resp['status'] == 101, 'status' - assert resp['headers']['x-subprotocols'] == "('chat', 'phone', 'video')", 'subprotocols' + assert ( + resp['headers']['x-subprotocols'] == "('chat', 'phone', 'video')" + ), 'subprotocols' assert resp['headers']['sec-websocket-protocol'] == 'chat', 'key' def test_asgi_websockets_mirror(self): @@ -159,7 +163,7 @@ class TestASGIWebsockets(TestApplicationPython): 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 + sock, self.ws.OP_CONT, 'fragment2', length=2 ** 64 - 1 ) self.check_close(sock, 1009) # 1009 - CLOSE_TOO_LARGE @@ -231,7 +235,7 @@ class TestASGIWebsockets(TestApplicationPython): @pytest.mark.skip('not yet') def test_asgi_websockets_handshake_upgrade_absent( - self + self, ): # FAIL https://tools.ietf.org/html/rfc6455#section-4.2.1 self.load('websockets/mirror') @@ -324,7 +328,9 @@ class TestASGIWebsockets(TestApplicationPython): }, ) - assert 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_asgi_websockets_handshake_method_invalid(self): self.load('websockets/mirror') @@ -419,14 +425,14 @@ class TestASGIWebsockets(TestApplicationPython): 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 + 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) @@ -445,14 +451,14 @@ class TestASGIWebsockets(TestApplicationPython): 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 + 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) @@ -470,11 +476,11 @@ class TestASGIWebsockets(TestApplicationPython): self.check_frame(frame, True, op_pong, payload, decode=decode) - check_ping('') # 2_1 - check_ping('Hello, world!') # 2_2 + 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 + check_ping(b'\xfe' * 125, decode=False) # 2_4 + check_ping(b'\xfe' * 125, chopsize=1, decode=False) # 2_6 self.close_connection(sock) @@ -935,7 +941,9 @@ class TestASGIWebsockets(TestApplicationPython): frame = self.ws.frame_read(sock) if frame['opcode'] == self.ws.OP_TEXT: - self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2') + self.check_frame( + frame, True, self.ws.OP_TEXT, 'fragment1fragment2' + ) frame = None self.check_close(sock, 1002, frame=frame) @@ -1092,27 +1100,27 @@ class TestASGIWebsockets(TestApplicationPython): 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 + # 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') @@ -1239,15 +1247,15 @@ class TestASGIWebsockets(TestApplicationPython): 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) + # # 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') @@ -1350,52 +1358,52 @@ class TestASGIWebsockets(TestApplicationPython): 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_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 + 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_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 diff --git a/test/test_configuration.py b/test/test_configuration.py index b7417264..7feb3adb 100644 --- a/test/test_configuration.py +++ b/test/test_configuration.py @@ -1,4 +1,5 @@ import pytest + from unit.control import TestControl diff --git a/test/test_go_application.py b/test/test_go_application.py index e833d190..438ce2e0 100644 --- a/test/test_go_application.py +++ b/test/test_go_application.py @@ -129,11 +129,9 @@ class TestGoApplication(TestApplicationGo): def test_go_application_command_line_arguments_type(self): self.load('command_line_arguments') - assert 'error' in \ - self.conf( - '' "a b c", 'applications/command_line_arguments/arguments' - ), \ - 'arguments type' + assert 'error' in self.conf( + '' "a b c", 'applications/command_line_arguments/arguments' + ), 'arguments type' def test_go_application_command_line_arguments_0(self): self.load('command_line_arguments') diff --git a/test/test_go_isolation.py b/test/test_go_isolation.py index e8fa26c6..e02ef1cf 100644 --- a/test/test_go_isolation.py +++ b/test/test_go_isolation.py @@ -3,10 +3,12 @@ import os import pwd import pytest + from unit.applications.lang.go import TestApplicationGo from unit.option import option from unit.utils import getns + class TestGoIsolation(TestApplicationGo): prerequisites = {'modules': {'go': 'any'}, 'features': ['isolation']} @@ -279,7 +281,7 @@ class TestGoIsolation(TestApplicationGo): isolation['namespaces'] = { 'mount': True, 'credential': True, - 'pid': True + 'pid': True, } self.load('ns_inspect', isolation=isolation) @@ -337,12 +339,10 @@ class TestGoIsolation(TestApplicationGo): isolation['namespaces'] = { 'mount': True, 'credential': True, - 'pid': True + 'pid': True, } - isolation['automount'] = { - 'tmpfs': False - } + isolation['automount'] = {'tmpfs': False} self.load('ns_inspect', isolation=isolation) @@ -352,9 +352,7 @@ class TestGoIsolation(TestApplicationGo): "/ /tmp" not in obj['Mounts'] and "tmpfs" not in obj['Mounts'] ), 'app has no /tmp mounted' - isolation['automount'] = { - 'tmpfs': True - } + isolation['automount'] = {'tmpfs': True} self.load('ns_inspect', isolation=isolation) diff --git a/test/test_go_isolation_rootfs.py b/test/test_go_isolation_rootfs.py index 2bded5ec..1cc59c67 100644 --- a/test/test_go_isolation_rootfs.py +++ b/test/test_go_isolation_rootfs.py @@ -1,6 +1,7 @@ import os import pytest + from unit.applications.lang.go import TestApplicationGo diff --git a/test/test_http_header.py b/test/test_http_header.py index ca355eb7..fdb557cf 100644 --- a/test/test_http_header.py +++ b/test/test_http_header.py @@ -1,4 +1,5 @@ import pytest + from unit.applications.lang.python import TestApplicationPython diff --git a/test/test_java_application.py b/test/test_java_application.py index 4a67f291..3fd5c26e 100644 --- a/test/test_java_application.py +++ b/test/test_java_application.py @@ -7,6 +7,7 @@ from unit.applications.lang.java import TestApplicationJava from unit.option import option from unit.utils import public_dir + class TestJavaApplication(TestApplicationJava): prerequisites = {'modules': {'java': 'all'}} @@ -712,9 +713,9 @@ class TestJavaApplication(TestApplicationJava): assert ( 'javax.servlet.include.request_uri: /data/test' in body ) == True, 'include request uri' - #assert ( + # assert ( # 'javax.servlet.include.context_path: ' in body - #) == True, 'include request context path' + # ) == True, 'include request context path' assert ( 'javax.servlet.include.servlet_path: /data' in body ) == True, 'include request servlet path' @@ -754,9 +755,9 @@ class TestJavaApplication(TestApplicationJava): assert ( 'javax.servlet.include.request_uri: null' in body ) == True, 'include request uri' - #assert ( + # assert ( # 'javax.servlet.include.context_path: null' in body - #) == True, 'include request context path' + # ) == True, 'include request context path' assert ( 'javax.servlet.include.servlet_path: null' in body ) == True, 'include request servlet path' @@ -1034,7 +1035,7 @@ class TestJavaApplication(TestApplicationJava): socks.append(sock) - time.sleep(0.25) # required to avoid greedy request reading + time.sleep(0.25) # required to avoid greedy request reading threads = set() diff --git a/test/test_java_isolation_rootfs.py b/test/test_java_isolation_rootfs.py index 91773981..a401e23b 100644 --- a/test/test_java_isolation_rootfs.py +++ b/test/test_java_isolation_rootfs.py @@ -2,6 +2,7 @@ import os import subprocess import pytest + from unit.applications.lang.java import TestApplicationJava from unit.option import option diff --git a/test/test_java_websockets.py b/test/test_java_websockets.py index df9e0885..df0f76e8 100644 --- a/test/test_java_websockets.py +++ b/test/test_java_websockets.py @@ -2,6 +2,7 @@ import struct import time import pytest + from unit.applications.lang.java import TestApplicationJava from unit.applications.websockets import TestApplicationWebsocket from unit.option import option @@ -163,7 +164,7 @@ class TestJavaWebsockets(TestApplicationJava): @pytest.mark.skip('not yet') def test_java_websockets_handshake_upgrade_absent( - self + self, ): # FAIL https://tools.ietf.org/html/rfc6455#section-4.2.1 self.load('websockets_mirror') @@ -256,7 +257,9 @@ class TestJavaWebsockets(TestApplicationJava): }, ) - assert 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') @@ -351,14 +354,14 @@ class TestJavaWebsockets(TestApplicationJava): frame = self.ws.message_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 + 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) @@ -377,14 +380,14 @@ class TestJavaWebsockets(TestApplicationJava): frame = self.ws.message_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 + 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) @@ -402,11 +405,11 @@ class TestJavaWebsockets(TestApplicationJava): self.check_frame(frame, True, op_pong, payload, decode=decode) - check_ping('') # 2_1 - check_ping('Hello, world!') # 2_2 + 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 + check_ping(b'\xfe' * 125, decode=False) # 2_4 + check_ping(b'\xfe' * 125, chopsize=1, decode=False) # 2_6 self.close_connection(sock) @@ -867,7 +870,9 @@ class TestJavaWebsockets(TestApplicationJava): frame = self.ws.frame_read(sock) if frame['opcode'] == self.ws.OP_TEXT: - self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2') + self.check_frame( + frame, True, self.ws.OP_TEXT, 'fragment1fragment2' + ) frame = None self.check_close(sock, 1002, frame=frame) @@ -1024,27 +1029,27 @@ class TestJavaWebsockets(TestApplicationJava): 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 + # 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_java_websockets_7_1_1__7_5_1(self): self.load('websockets_mirror') @@ -1171,15 +1176,15 @@ class TestJavaWebsockets(TestApplicationJava): 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) + # # 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_java_websockets_7_7_X__7_9_X(self): self.load('websockets_mirror') @@ -1282,52 +1287,52 @@ class TestJavaWebsockets(TestApplicationJava): 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_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 + 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_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 diff --git a/test/test_node_application.py b/test/test_node_application.py index b277dc3a..52ad72ee 100644 --- a/test/test_node_application.py +++ b/test/test_node_application.py @@ -1,6 +1,7 @@ import re import pytest + from unit.applications.lang.node import TestApplicationNode from unit.utils import waitforfiles @@ -205,7 +206,9 @@ class TestNodeApplication(TestApplicationNode): def test_node_application_status_message(self): self.load('status_message') - assert re.search(r'200 blah', self.get(raw_resp=True)), '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') diff --git a/test/test_node_websockets.py b/test/test_node_websockets.py index d5f79811..51515f4e 100644 --- a/test/test_node_websockets.py +++ b/test/test_node_websockets.py @@ -2,6 +2,7 @@ import struct import time import pytest + from unit.applications.lang.node import TestApplicationNode from unit.applications.websockets import TestApplicationWebsocket from unit.option import option @@ -182,7 +183,7 @@ class TestNodeWebsockets(TestApplicationNode): @pytest.mark.skip('not yet') def test_node_websockets_handshake_upgrade_absent( - self + self, ): # FAIL https://tools.ietf.org/html/rfc6455#section-4.2.1 self.load('websockets/mirror') @@ -275,7 +276,9 @@ class TestNodeWebsockets(TestApplicationNode): }, ) - assert 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') @@ -370,14 +373,14 @@ class TestNodeWebsockets(TestApplicationNode): 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 + 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) @@ -396,14 +399,14 @@ class TestNodeWebsockets(TestApplicationNode): 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 + 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) @@ -421,11 +424,11 @@ class TestNodeWebsockets(TestApplicationNode): self.check_frame(frame, True, op_pong, payload, decode=decode) - check_ping('') # 2_1 - check_ping('Hello, world!') # 2_2 + 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 + check_ping(b'\xfe' * 125, decode=False) # 2_4 + check_ping(b'\xfe' * 125, chopsize=1, decode=False) # 2_6 self.close_connection(sock) @@ -886,7 +889,9 @@ class TestNodeWebsockets(TestApplicationNode): frame = self.ws.frame_read(sock) if frame['opcode'] == self.ws.OP_TEXT: - self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2') + self.check_frame( + frame, True, self.ws.OP_TEXT, 'fragment1fragment2' + ) frame = None self.check_close(sock, 1002, frame=frame) @@ -1043,27 +1048,27 @@ class TestNodeWebsockets(TestApplicationNode): 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 + # 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_node_websockets_7_1_1__7_5_1(self): self.load('websockets/mirror') @@ -1190,15 +1195,15 @@ class TestNodeWebsockets(TestApplicationNode): 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) + # # 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_node_websockets_7_7_X__7_9_X(self): self.load('websockets/mirror') @@ -1301,52 +1306,52 @@ class TestNodeWebsockets(TestApplicationNode): 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_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 + 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_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 diff --git a/test/test_perl_application.py b/test/test_perl_application.py index dfd8be6c..e906aaca 100644 --- a/test/test_perl_application.py +++ b/test/test_perl_application.py @@ -1,6 +1,7 @@ import re import pytest + from unit.applications.lang.perl import TestApplicationPerl diff --git a/test/test_php_application.py b/test/test_php_application.py index e73c67ba..de3da939 100644 --- a/test/test_php_application.py +++ b/test/test_php_application.py @@ -5,9 +5,11 @@ import time from subprocess import call import pytest + from unit.applications.lang.php import TestApplicationPHP from unit.option import option + class TestPHPApplication(TestApplicationPHP): prerequisites = {'modules': {'php': 'all'}} @@ -428,11 +430,13 @@ class TestPHPApplication(TestApplicationPHP): self.load('auth') def check_auth(auth): - resp = self.get(headers={ - 'Host': 'localhost', - 'Authorization': auth, - 'Connection': 'close', - }) + resp = self.get( + headers={ + 'Host': 'localhost', + 'Authorization': auth, + 'Connection': 'close', + } + ) assert resp['status'] == 200, 'status' assert resp['headers']['X-Digest'] == 'not set', 'Digest' diff --git a/test/test_php_isolation.py b/test/test_php_isolation.py index 2e458023..8db6b590 100644 --- a/test/test_php_isolation.py +++ b/test/test_php_isolation.py @@ -1,4 +1,5 @@ import pytest + from unit.applications.lang.php import TestApplicationPHP from unit.option import option @@ -28,7 +29,7 @@ class TestPHPIsolation(TestApplicationPHP): isolation['namespaces'] = { 'mount': True, 'credential': True, - 'pid': True + 'pid': True, } self.load('phpinfo', isolation=isolation) @@ -64,7 +65,7 @@ class TestPHPIsolation(TestApplicationPHP): isolation['namespaces'] = { 'mount': True, 'credential': True, - 'pid': True + 'pid': True, } self.load('list-extensions', isolation=isolation) diff --git a/test/test_proxy.py b/test/test_proxy.py index 7e7c7246..3d59cf24 100644 --- a/test/test_proxy.py +++ b/test/test_proxy.py @@ -3,6 +3,7 @@ import socket import time import pytest + from conftest import run_process from unit.applications.lang.python import TestApplicationPython from unit.option import option @@ -464,9 +465,9 @@ Content-Length: 10 def test_proxy_invalid(self): def check_proxy(proxy): - assert 'error' in \ - 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') @@ -502,7 +503,8 @@ Content-Length: 10 "type": "python", "processes": {"spare": 0}, "path": option.test_dir + "/python/mirror", - "working_directory": option.test_dir + "/python/mirror", + "working_directory": option.test_dir + + "/python/mirror", "module": "wsgi", }, }, diff --git a/test/test_python_application.py b/test/test_python_application.py index 41f6f538..fd99a3af 100644 --- a/test/test_python_application.py +++ b/test/test_python_application.py @@ -5,6 +5,7 @@ import re import time import pytest + from unit.applications.lang.python import TestApplicationPython from unit.option import option @@ -31,7 +32,8 @@ Content-Type: text/html Connection: close custom-header: BLAH -%s""" % (len(body), body.encode()), +%s""" + % (len(body), body.encode()), raw=True, ) @@ -816,7 +818,11 @@ last line: 987654321 assert ['/new', *sys_path] == get_path(), 'check path update' set_path('["/blah1", "/blah2"]') - assert ['/blah1', '/blah2', *sys_path] == get_path(), 'check path array' + assert [ + '/blah1', + '/blah2', + *sys_path, + ] == get_path(), 'check path array' def test_python_application_path_invalid(self): self.load('path') diff --git a/test/test_python_isolation.py b/test/test_python_isolation.py index 680f2c03..93f85264 100644 --- a/test/test_python_isolation.py +++ b/test/test_python_isolation.py @@ -1,5 +1,5 @@ - import pytest + from unit.applications.lang.python import TestApplicationPython from unit.option import option from unit.utils import findmnt @@ -32,7 +32,7 @@ class TestPythonIsolation(TestApplicationPython): isolation['namespaces'] = { 'mount': True, 'credential': True, - 'pid': True + 'pid': True, } self.load('ns_inspect', isolation=isolation) @@ -43,8 +43,7 @@ class TestPythonIsolation(TestApplicationPython): ), 'temp_dir does not exists in rootfs' assert ( - self.getjson(url='/?path=/proc/self')['body']['FileExists'] - == True + self.getjson(url='/?path=/proc/self')['body']['FileExists'] == True ), 'no /proc/self' assert ( @@ -66,15 +65,12 @@ class TestPythonIsolation(TestApplicationPython): if not is_su: pytest.skip('requires root') - isolation = { - 'rootfs': temp_dir, - 'automount': {'language_deps': False} - } + isolation = {'rootfs': temp_dir, 'automount': {'language_deps': False}} self.load('empty', isolation=isolation) assert findmnt().find(temp_dir) == -1 - assert (self.get()['status'] != 200), 'disabled language_deps' + assert self.get()['status'] != 200, 'disabled language_deps' assert findmnt().find(temp_dir) == -1 isolation['automount']['language_deps'] = True @@ -82,7 +78,7 @@ class TestPythonIsolation(TestApplicationPython): self.load('empty', isolation=isolation) assert findmnt().find(temp_dir) == -1 - assert (self.get()['status'] == 200), 'enabled language_deps' + assert self.get()['status'] == 200, 'enabled language_deps' assert waitformount(temp_dir), 'language_deps mount' self.conf({"listeners": {}, "applications": {}}) @@ -90,8 +86,6 @@ class TestPythonIsolation(TestApplicationPython): assert waitforunmount(temp_dir), 'language_deps unmount' def test_python_isolation_procfs(self, is_su, temp_dir): - isolation_features = option.available['features']['isolation'].keys() - if not is_su: pytest.skip('requires root') diff --git a/test/test_python_isolation_chroot.py b/test/test_python_isolation_chroot.py index 7281f5f6..54fbad12 100644 --- a/test/test_python_isolation_chroot.py +++ b/test/test_python_isolation_chroot.py @@ -1,4 +1,5 @@ import pytest + from unit.applications.lang.python import TestApplicationPython @@ -21,8 +22,7 @@ class TestPythonIsolation(TestApplicationPython): ), 'temp_dir does not exists in rootfs' assert ( - self.getjson(url='/?path=/proc/self')['body']['FileExists'] - == True + self.getjson(url='/?path=/proc/self')['body']['FileExists'] == True ), 'no /proc/self' assert ( diff --git a/test/test_python_procman.py b/test/test_python_procman.py index ac403ce4..b0d0f5af 100644 --- a/test/test_python_procman.py +++ b/test/test_python_procman.py @@ -3,6 +3,7 @@ import subprocess import time import pytest + from unit.applications.lang.python import TestApplicationPython from unit.option import option diff --git a/test/test_respawn.py b/test/test_respawn.py index 50c19186..edbfa2a8 100644 --- a/test/test_respawn.py +++ b/test/test_respawn.py @@ -76,9 +76,10 @@ class TestRespawn(TestApplicationPython): self.kill_pids(pid) skip_alert(r'process %s exited on signal 9' % pid) - assert self.wait_for_process( - self.PATTERN_CONTROLLER, unit_pid - ) is not None + assert ( + self.wait_for_process(self.PATTERN_CONTROLLER, unit_pid) + is not None + ) assert self.get()['status'] == 200 diff --git a/test/test_routing.py b/test/test_routing.py index cb9c3fd2..7392c1ab 100644 --- a/test/test_routing.py +++ b/test/test_routing.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- import pytest + from unit.applications.proto import TestApplicationProto from unit.option import option @@ -232,11 +233,11 @@ class TestRouting(TestApplicationProto): if not option.available['modules']['regex']: pytest.skip('requires regex') - self.route_match({"uri":"~"}) + self.route_match({"uri": "~"}) assert self.get(url='/')['status'] == 200, 'empty regexp' assert self.get(url='/anything')['status'] == 200, '/anything' - self.route_match({"uri":"!~"}) + self.route_match({"uri": "!~"}) assert self.get(url='/')['status'] == 404, 'empty regexp 2' assert self.get(url='/nothing')['status'] == 404, '/nothing' @@ -336,8 +337,7 @@ class TestRouting(TestApplicationProto): "type": "python", "processes": {"spare": 0}, "path": option.test_dir + '/python/empty', - "working_directory": option.test_dir - + '/python/empty', + "working_directory": option.test_dir + '/python/empty', "module": "wsgi", } }, @@ -495,8 +495,7 @@ class TestRouting(TestApplicationProto): 'routes/0/action', ), 'proxy pass' assert 'error' in self.conf( - {"share": temp_dir, "pass": "applications/app"}, - 'routes/0/action', + {"share": temp_dir, "pass": "applications/app"}, 'routes/0/action', ), 'share pass' def test_routes_rules_two(self): diff --git a/test/test_ruby_application.py b/test/test_ruby_application.py index 17491619..ddd31f59 100644 --- a/test/test_ruby_application.py +++ b/test/test_ruby_application.py @@ -2,6 +2,7 @@ import re import subprocess import pytest + from unit.applications.lang.ruby import TestApplicationRuby @@ -208,7 +209,6 @@ class TestRubyApplication(TestApplicationRuby): self.get() - assert ( self.wait_for_record(r'\[error\].+1234567890') is not None ), 'errors write int' @@ -228,9 +228,13 @@ class TestRubyApplication(TestApplicationRuby): self.load('encoding') try: - locales = subprocess.check_output( - ['locale', '-a'], stderr=subprocess.STDOUT, - ).decode().split('\n') + locales = ( + subprocess.check_output( + ['locale', '-a'], stderr=subprocess.STDOUT, + ) + .decode() + .split('\n') + ) except (FileNotFoundError, subprocess.CalledProcessError): pytest.skip('require locale') diff --git a/test/test_ruby_isolation.py b/test/test_ruby_isolation.py index c49b6732..8443d857 100644 --- a/test/test_ruby_isolation.py +++ b/test/test_ruby_isolation.py @@ -2,6 +2,7 @@ import os import shutil import pytest + from unit.applications.lang.ruby import TestApplicationRuby from unit.option import option diff --git a/test/test_settings.py b/test/test_settings.py index c59ca8b9..d129dec9 100644 --- a/test/test_settings.py +++ b/test/test_settings.py @@ -3,6 +3,7 @@ import socket import time import pytest + from unit.applications.lang.python import TestApplicationPython diff --git a/test/test_share_fallback.py b/test/test_share_fallback.py index 46464670..0b1c270e 100644 --- a/test/test_share_fallback.py +++ b/test/test_share_fallback.py @@ -1,6 +1,7 @@ import os import pytest + from unit.applications.proto import TestApplicationProto from unit.option import option @@ -81,10 +82,7 @@ class TestStatic(TestApplicationProto): def test_fallback_share(self, temp_dir): self.action_update( - { - "share": "/blah", - "fallback": {"share": temp_dir + "/assets"}, - } + {"share": "/blah", "fallback": {"share": temp_dir + "/assets"},} ) resp = self.get() diff --git a/test/test_static.py b/test/test_static.py index 3e85b435..d8319292 100644 --- a/test/test_static.py +++ b/test/test_static.py @@ -2,6 +2,7 @@ import os import socket import pytest + from unit.applications.proto import TestApplicationProto from unit.option import option from unit.utils import waitforfiles @@ -85,8 +86,7 @@ class TestStatic(TestApplicationProto): def test_static_space_in_name(self, temp_dir): os.rename( - temp_dir + '/assets/dir/file', - temp_dir + '/assets/dir/fi le', + temp_dir + '/assets/dir/file', temp_dir + '/assets/dir/fi le', ) assert waitforfiles(temp_dir + '/assets/dir/fi le') assert self.get(url='/dir/fi le')['body'] == 'blah', 'file name' @@ -95,9 +95,7 @@ class TestStatic(TestApplicationProto): assert waitforfiles(temp_dir + '/assets/di r/fi le') assert self.get(url='/di r/fi le')['body'] == 'blah', 'dir name' - os.rename( - temp_dir + '/assets/di r', temp_dir + '/assets/ di r ' - ) + os.rename(temp_dir + '/assets/di r', temp_dir + '/assets/ di r ') assert waitforfiles(temp_dir + '/assets/ di r /fi le') assert ( self.get(url='/ di r /fi le')['body'] == 'blah' @@ -150,8 +148,7 @@ class TestStatic(TestApplicationProto): ), 'file name 2' os.rename( - temp_dir + '/assets/ di r ', - temp_dir + '/assets/ди ректория', + temp_dir + '/assets/ di r ', temp_dir + '/assets/ди ректория', ) assert waitforfiles(temp_dir + '/assets/ди ректория/фа йл') assert ( diff --git a/test/test_tls.py b/test/test_tls.py index 206ea828..63422dfb 100644 --- a/test/test_tls.py +++ b/test/test_tls.py @@ -4,6 +4,7 @@ import ssl import subprocess import pytest + from unit.applications.tls import TestApplicationTLS from unit.option import option @@ -22,7 +23,7 @@ class TestTLS(TestApplicationTLS): assert 'success' in self.conf( { "pass": "applications/" + application, - "tls": {"certificate": cert} + "tls": {"certificate": cert}, }, 'listeners/*:' + str(port), ) diff --git a/test/test_tls_sni.py b/test/test_tls_sni.py index 7da05e6e..2e5424e2 100644 --- a/test/test_tls_sni.py +++ b/test/test_tls_sni.py @@ -1,7 +1,8 @@ -import subprocess import ssl +import subprocess import pytest + from unit.applications.tls import TestApplicationTLS from unit.option import option @@ -23,10 +24,7 @@ class TestTLSSNI(TestApplicationTLS): def add_tls(self, cert='default'): assert 'success' in self.conf( - { - "pass": "routes", - "tls": {"certificate": cert} - }, + {"pass": "routes", "tls": {"certificate": cert}}, 'listeners/*:7080', ) @@ -153,10 +151,7 @@ basicConstraints = critical,CA:TRUE""" def test_tls_sni(self): bundles = { - "default": { - "subj": "default", - "alt_names": ["default"], - }, + "default": {"subj": "default", "alt_names": ["default"]}, "localhost.com": { "subj": "localhost.com", "alt_names": ["alt1.localhost.com"], @@ -205,10 +200,7 @@ basicConstraints = critical,CA:TRUE""" def test_tls_sni_wildcard(self): bundles = { - "localhost.com": { - "subj": "localhost.com", - "alt_names": [], - }, + "localhost.com": {"subj": "localhost.com", "alt_names": []}, "example.com": { "subj": "example.com", "alt_names": ["*.example.com", "*.alt.example.com"], @@ -248,11 +240,7 @@ basicConstraints = critical,CA:TRUE""" self.check_cert('example', bundles['localhost']['subj']) def test_tls_sni_empty_cn(self): - bundles = { - "localhost": { - "alt_names": ["alt.localhost.com"], - } - } + bundles = {"localhost": {"alt_names": ["alt.localhost.com"]}} self.config_bundles(bundles) self.add_tls(["localhost"]) @@ -266,7 +254,9 @@ basicConstraints = critical,CA:TRUE""" ) assert resp['status'] == 200 - assert sock.getpeercert()['subjectAltName'][0][1] == 'alt.localhost.com' + assert ( + sock.getpeercert()['subjectAltName'][0][1] == 'alt.localhost.com' + ) def test_tls_sni_invalid(self): self.config_bundles({"localhost": {"subj": "subj1", "alt_names": ''}}) diff --git a/test/test_variables.py b/test/test_variables.py index bbb8f769..139d867e 100644 --- a/test/test_variables.py +++ b/test/test_variables.py @@ -92,16 +92,8 @@ class TestVariables(TestApplicationProto): "*:7080": {"pass": "upstreams$uri"}, "*:7081": {"pass": "routes/one"}, }, - "upstreams": { - "1": { - "servers": { - "127.0.0.1:7081": {}, - }, - }, - }, - "routes": { - "one": [{"action": {"return": 200}}], - }, + "upstreams": {"1": {"servers": {"127.0.0.1:7081": {}}}}, + "routes": {"one": [{"action": {"return": 200}}]}, }, ), 'upstreams initial configuration' diff --git a/test/unit/applications/tls.py b/test/unit/applications/tls.py index 490ae916..95eeac55 100644 --- a/test/unit/applications/tls.py +++ b/test/unit/applications/tls.py @@ -21,10 +21,14 @@ class TestApplicationTLS(TestApplicationProto): 'req', '-x509', '-new', - '-subj', '/CN=' + name + '/', - '-config', option.temp_dir + '/openssl.conf', - '-out', option.temp_dir + '/' + name + '.crt', - '-keyout', option.temp_dir + '/' + name + '.key', + '-subj', + '/CN=' + name + '/', + '-config', + option.temp_dir + '/openssl.conf', + '-out', + option.temp_dir + '/' + name + '.crt', + '-keyout', + option.temp_dir + '/' + name + '.key', ], stderr=subprocess.STDOUT, ) @@ -75,12 +79,14 @@ class TestApplicationTLS(TestApplicationProto): a_names += "DNS.%d = %s\n" % (i, k) # Generates section for sign request extension - a_sec = """req_extensions = myca_req_extensions + a_sec = """req_extensions = myca_req_extensions [ myca_req_extensions ] subjectAltName = @alt_names -{a_names}""".format(a_names=a_names) +{a_names}""".format( + a_names=a_names + ) with open(conf_path, 'w') as f: f.write( @@ -90,7 +96,9 @@ encrypt_key = no distinguished_name = req_distinguished_name {a_sec} -[ req_distinguished_name ]""".format(a_sec=a_sec if alt_names else "") +[ req_distinguished_name ]""".format( + a_sec=a_sec if alt_names else "" + ) ) def load(self, script, name=None): diff --git a/test/unit/applications/websockets.py b/test/unit/applications/websockets.py index cc720a98..aa83339c 100644 --- a/test/unit/applications/websockets.py +++ b/test/unit/applications/websockets.py @@ -43,11 +43,7 @@ class TestApplicationWebsocket(TestApplicationProto): 'Sec-WebSocket-Version': 13, } - _, sock = self.get( - headers=headers, - no_recv=True, - start=True, - ) + _, sock = self.get(headers=headers, no_recv=True, start=True,) resp = '' while True: @@ -57,7 +53,7 @@ class TestApplicationWebsocket(TestApplicationProto): resp += sock.recv(4096).decode() - if (resp.startswith('HTTP/') and '\r\n\r\n' in resp): + if resp.startswith('HTTP/') and '\r\n\r\n' in resp: resp = self._resp_to_dict(resp) break @@ -90,8 +86,8 @@ class TestApplicationWebsocket(TestApplicationProto): frame = {} - head1, = struct.unpack('!B', recv_bytes(sock, 1)) - head2, = struct.unpack('!B', recv_bytes(sock, 1)) + (head1,) = struct.unpack('!B', recv_bytes(sock, 1)) + (head2,) = struct.unpack('!B', recv_bytes(sock, 1)) frame['fin'] = bool(head1 & 0b10000000) frame['rsv1'] = bool(head1 & 0b01000000) @@ -103,10 +99,10 @@ class TestApplicationWebsocket(TestApplicationProto): length = head2 & 0b01111111 if length == 126: data = recv_bytes(sock, 2) - length, = struct.unpack('!H', data) + (length,) = struct.unpack('!H', data) elif length == 127: data = recv_bytes(sock, 8) - length, = struct.unpack('!Q', data) + (length,) = struct.unpack('!Q', data) if frame['mask']: mask_bits = recv_bytes(sock, 4) @@ -121,7 +117,7 @@ class TestApplicationWebsocket(TestApplicationProto): if frame['opcode'] == self.OP_CLOSE: if length >= 2: - code, = struct.unpack('!H', data[:2]) + (code,) = struct.unpack('!H', data[:2]) reason = data[2:].decode('utf-8') if not (code in self.CLOSE_CODES or 3000 <= code < 5000): pytest.fail('Invalid status code') diff --git a/test/unit/check/isolation.py b/test/unit/check/isolation.py index fe5a41f8..7c83ae35 100644 --- a/test/unit/check/isolation.py +++ b/test/unit/check/isolation.py @@ -12,6 +12,7 @@ from unit.utils import getns allns = ['pid', 'mnt', 'ipc', 'uts', 'cgroup', 'net'] http = TestHTTP() + def check_isolation(): test_conf = {"namespaces": {"credential": True}} available = option.available @@ -117,8 +118,7 @@ def check_isolation(): "body_empty": { "type": "perl", "processes": {"spare": 0}, - "working_directory": option.test_dir - + "/perl/body_empty", + "working_directory": option.test_dir + "/perl/body_empty", "script": option.test_dir + "/perl/body_empty/psgi.pl", "isolation": {"namespaces": {"credential": True}}, } diff --git a/test/unit/http.py b/test/unit/http.py index 7706fe05..797b7681 100644 --- a/test/unit/http.py +++ b/test/unit/http.py @@ -10,15 +10,16 @@ import pytest from unit.option import option -class TestHTTP(): +class TestHTTP: def http(self, start_str, **kwargs): 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 = kwargs.get('headers', - {'Host': 'localhost', 'Connection': 'close'}) + headers = kwargs.get( + 'headers', {'Host': 'localhost', 'Connection': 'close'} + ) body = kwargs.get('body', b'') crlf = '\r\n' @@ -305,8 +306,9 @@ class TestHTTP(): return body, content_type def form_url_encode(self, fields): - data = "&".join("%s=%s" % (name, value) - for name, value in fields.items()).encode() + data = "&".join( + "%s=%s" % (name, value) for name, value in fields.items() + ).encode() return data, 'application/x-www-form-urlencoded' def multipart_encode(self, fields): @@ -326,7 +328,9 @@ class TestHTTP(): datatype = value['type'] if not isinstance(value['data'], io.IOBase): - pytest.fail('multipart encoding of file requires a stream.') + pytest.fail( + 'multipart encoding of file requires a stream.' + ) data = value['data'].read() @@ -336,9 +340,10 @@ class TestHTTP(): else: pytest.fail('multipart requires a string or stream data') - body += ( - "--%s\r\nContent-Disposition: form-data; name=\"%s\"" - ) % (boundary, field) + body += ("--%s\r\nContent-Disposition: form-data; name=\"%s\"") % ( + boundary, + field, + ) if filename != '': body += "; filename=\"%s\"" % filename diff --git a/test/unit/option.py b/test/unit/option.py index 677d806e..cb3803dc 100644 --- a/test/unit/option.py +++ b/test/unit/option.py @@ -1,4 +1,4 @@ -class Options(): +class Options: _options = { 'skip_alerts': [], 'skip_sanitizer': False, @@ -13,4 +13,5 @@ class Options(): raise AttributeError + option = Options() -- cgit From 74b1b1fc17726d805b00dee6b5547254f5cf230c Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Thu, 8 Apr 2021 19:11:11 +0300 Subject: Tests: preserving unit.log when run without restart. Introducing "unit.log.Log" class for "unit.log" file management. Moving "findall()" function into TestApplicationProto. Using "os.kill()" to send signals. --- test/conftest.py | 39 +++++++++-------------------- test/test_access_log.py | 2 +- test/test_asgi_application.py | 4 --- test/test_php_application.py | 39 +++++++++++------------------ test/test_python_application.py | 5 ---- test/test_tls.py | 5 ---- test/test_usr1.py | 55 +++++++++++++++++++++++------------------ test/unit/applications/proto.py | 18 +++++++++----- test/unit/log.py | 23 +++++++++++++++++ 9 files changed, 94 insertions(+), 96 deletions(-) create mode 100644 test/unit/log.py (limited to 'test') diff --git a/test/conftest.py b/test/conftest.py index 38e1138e..b9f5c60b 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -22,6 +22,7 @@ from unit.check.regex import check_regex from unit.check.tls import check_openssl from unit.http import TestHTTP from unit.option import option +from unit.log import Log from unit.utils import public_dir from unit.utils import waitforfiles @@ -71,7 +72,6 @@ def pytest_addoption(parser): unit_instance = {} -unit_log_copy = "unit.log.copy" _processes = [] _fds_check = { 'main': {'fds': 0, 'skip': False}, @@ -165,12 +165,11 @@ def pytest_sessionstart(session): option.available = {'modules': {}, 'features': {}} unit = unit_run() - option.temp_dir = unit['temp_dir'] # read unit.log for i in range(50): - with open(unit['temp_dir'] + '/unit.log', 'r') as f: + with open(Log.get_path(), 'r') as f: log = f.read() m = re.search('controller started', log) @@ -216,9 +215,6 @@ def pytest_sessionstart(session): if option.restart: shutil.rmtree(unit_instance['temp_dir']) - elif option.save_log: - open(unit_instance['temp_dir'] + '/' + unit_log_copy, 'w').close() - @pytest.hookimpl(tryfirst=True, hookwrapper=True) def pytest_runtest_makereport(item, call): @@ -269,7 +265,6 @@ def check_prerequisites(request): @pytest.fixture(autouse=True) def run(request): unit = unit_run() - option.temp_dir = unit['temp_dir'] option.skip_alerts = [ r'read signalfd\(4\) failed', @@ -291,34 +286,25 @@ def run(request): # prepare log - with open( - unit_instance['log'], 'r', encoding='utf-8', errors='ignore' - ) as f: + with Log.open(encoding='utf-8') as f: log = f.read() - - if not option.restart and option.save_log: - with open(unit_instance['temp_dir'] + '/' + unit_log_copy, 'a') as f: - f.write(log) - - # remove unit.log + Log.set_pos(f.tell()) if not option.save_log and option.restart: shutil.rmtree(unit['temp_dir']) + Log.set_pos(0) # clean temp_dir before the next test if not option.restart: _clear_conf(unit['temp_dir'] + '/control.unit.sock', log) - open(unit['log'], 'w').close() - for item in os.listdir(unit['temp_dir']): if item not in [ 'control.unit.sock', 'state', 'unit.pid', 'unit.log', - unit_log_copy, ]: path = os.path.join(unit['temp_dir'], item) @@ -439,10 +425,12 @@ def unit_run(): exit('Could not start unit') 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 + option.temp_dir = temp_dir + Log.temp_dir = temp_dir + with open(temp_dir + '/unit.pid', 'r') as f: unit_instance['pid'] = f.read().rstrip() @@ -489,12 +477,9 @@ def unit_stop(): return 'Could not terminate unit' -def _check_alerts(path=None, log=None): - if path is None: - path = unit_instance['log'] - +def _check_alerts(log=None): if log is None: - with open(path, 'r', encoding='utf-8', errors='ignore') as f: + with Log.open(encoding='utf-8') as f: log = f.read() found = False @@ -526,7 +511,7 @@ def _check_alerts(path=None, log=None): def _print_log(data=None): - path = unit_instance['log'] + path = Log.get_path() print('Path to unit.log:\n' + path + '\n') @@ -679,7 +664,7 @@ def unit_pid(request): def pytest_sessionfinish(session): if not option.restart and option.save_log: - print('Path to unit.log:\n' + unit_instance['log'] + '\n') + print('Path to unit.log:\n' + Log.get_path() + '\n') option.restart = True diff --git a/test/test_access_log.py b/test/test_access_log.py index 72a78c33..ba254c5e 100644 --- a/test/test_access_log.py +++ b/test/test_access_log.py @@ -249,7 +249,7 @@ Connection: close assert self.search_in_log(r'/delete', 'access.log') is None, 'delete' - def test_access_log_change(self, temp_dir): + def test_access_log_change(self): self.load('empty') self.get() diff --git a/test/test_asgi_application.py b/test/test_asgi_application.py index 70b2e4c3..f503fa82 100644 --- a/test/test_asgi_application.py +++ b/test/test_asgi_application.py @@ -14,10 +14,6 @@ class TestASGIApplication(TestApplicationPython): } load_module = 'asgi' - def findall(self, pattern): - with open(option.temp_dir + '/unit.log', 'r', errors='ignore') as f: - return re.findall(pattern, f.read()) - def test_asgi_application_variables(self): self.load('variables') diff --git a/test/test_php_application.py b/test/test_php_application.py index de3da939..350ac0d0 100644 --- a/test/test_php_application.py +++ b/test/test_php_application.py @@ -1,8 +1,8 @@ import os import re import shutil +import signal import time -from subprocess import call import pytest @@ -95,37 +95,29 @@ class TestPHPApplication(TestApplicationPHP): assert resp['status'] == 200, 'query string empty status' assert resp['headers']['Query-String'] == '', 'query string empty' - def test_php_application_fastcgi_finish_request(self, temp_dir): + def test_php_application_fastcgi_finish_request(self, unit_pid): self.load('fastcgi_finish_request') assert self.get()['body'] == '0123' - with open(temp_dir + '/unit.pid', 'r') as f: - pid = f.read().rstrip() + os.kill(unit_pid, signal.SIGUSR1); - call(['kill', '-s', 'USR1', pid]) + errs = self.findall(r'Error in fastcgi_finish_request') - with open(temp_dir + '/unit.log', 'r', errors='ignore') as f: - errs = re.findall(r'Error in fastcgi_finish_request', f.read()) + assert len(errs) == 0, 'no error' - assert len(errs) == 0, 'no error' - - def test_php_application_fastcgi_finish_request_2(self, temp_dir): + def test_php_application_fastcgi_finish_request_2(self, unit_pid): self.load('fastcgi_finish_request') resp = self.get(url='/?skip') assert resp['status'] == 200 assert resp['body'] == '' - with open(temp_dir + '/unit.pid', 'r') as f: - pid = f.read().rstrip() - - call(['kill', '-s', 'USR1', pid]) + os.kill(unit_pid, signal.SIGUSR1); - with open(temp_dir + '/unit.log', 'r', errors='ignore') as f: - errs = re.findall(r'Error in fastcgi_finish_request', f.read()) + errs = self.findall(r'Error in fastcgi_finish_request') - assert len(errs) == 0, 'no error' + assert len(errs) == 0, 'no error' def test_php_application_query_string_absent(self): self.load('query_string') @@ -538,7 +530,7 @@ class TestPHPApplication(TestApplicationPHP): r'012345', self.get()['body'] ), 'disable_classes before' - def test_php_application_error_log(self, temp_dir): + def test_php_application_error_log(self): self.load('error_log') assert self.get()['status'] == 200, 'status' @@ -551,14 +543,13 @@ class TestPHPApplication(TestApplicationPHP): assert self.wait_for_record(pattern) is not None, 'errors print' - with open(temp_dir + '/unit.log', 'r', errors='ignore') as f: - errs = re.findall(pattern, f.read()) + errs = self.findall(pattern) - assert len(errs) == 2, 'error_log count' + assert len(errs) == 2, 'error_log count' - date = errs[0].split('[')[0] - date2 = errs[1].split('[')[0] - assert date != date2, 'date diff' + date = errs[0].split('[')[0] + date2 = errs[1].split('[')[0] + assert date != date2, 'date diff' def test_php_application_script(self): assert 'success' in self.conf( diff --git a/test/test_python_application.py b/test/test_python_application.py index fd99a3af..48c3d603 100644 --- a/test/test_python_application.py +++ b/test/test_python_application.py @@ -7,16 +7,11 @@ import time import pytest from unit.applications.lang.python import TestApplicationPython -from unit.option import option class TestPythonApplication(TestApplicationPython): prerequisites = {'modules': {'python': 'all'}} - def findall(self, pattern): - with open(option.temp_dir + '/unit.log', 'r', errors='ignore') as f: - return re.findall(pattern, f.read()) - def test_python_application_variables(self): self.load('variables') diff --git a/test/test_tls.py b/test/test_tls.py index 63422dfb..abdca167 100644 --- a/test/test_tls.py +++ b/test/test_tls.py @@ -6,16 +6,11 @@ import subprocess import pytest from unit.applications.tls import TestApplicationTLS -from unit.option import option class TestTLS(TestApplicationTLS): prerequisites = {'modules': {'python': 'any', 'openssl': 'any'}} - def findall(self, pattern): - with open(option.temp_dir + '/unit.log', 'r', errors='ignore') as f: - return re.findall(pattern, f.read()) - def openssl_date_to_sec_epoch(self, date): return self.date_to_sec_epoch(date, '%b %d %H:%M:%S %Y %Z') diff --git a/test/test_usr1.py b/test/test_usr1.py index dbb5265c..9a12b747 100644 --- a/test/test_usr1.py +++ b/test/test_usr1.py @@ -1,14 +1,15 @@ import os -from subprocess import call +import signal from unit.applications.lang.python import TestApplicationPython +from unit.log import Log from unit.utils import waitforfiles class TestUSR1(TestApplicationPython): prerequisites = {'modules': {'python': 'any'}} - def test_usr1_access_log(self, temp_dir): + def test_usr1_access_log(self, temp_dir, unit_pid): self.load('empty') log = 'access.log' @@ -31,10 +32,7 @@ class TestUSR1(TestApplicationPython): ), 'rename new' assert not os.path.isfile(log_path), 'rename old' - with open(temp_dir + '/unit.pid', 'r') as f: - pid = f.read().rstrip() - - call(['kill', '-s', 'USR1', pid]) + os.kill(unit_pid, signal.SIGUSR1) assert waitforfiles(log_path), 'reopen' @@ -46,7 +44,7 @@ class TestUSR1(TestApplicationPython): ), 'reopen 2' assert self.search_in_log(r'/usr1', log_new) is None, 'rename new 2' - def test_usr1_unit_log(self, temp_dir): + def test_usr1_unit_log(self, temp_dir, unit_pid): self.load('log_body') log_new = 'new.log' @@ -55,28 +53,37 @@ class TestUSR1(TestApplicationPython): os.rename(log_path, log_path_new) - body = 'body_for_a_log_new' - assert self.post(body=body)['status'] == 200 + Log.swap(log_new) - assert self.wait_for_record(body, log_new) is not None, 'rename new' - assert not os.path.isfile(log_path), 'rename old' + try: + body = 'body_for_a_log_new\n' + assert self.post(body=body)['status'] == 200 - with open(temp_dir + '/unit.pid', 'r') as f: - pid = f.read().rstrip() + assert ( + self.wait_for_record(body, log_new) is not None + ), 'rename new' + assert not os.path.isfile(log_path), 'rename old' - call(['kill', '-s', 'USR1', pid]) + os.kill(unit_pid, signal.SIGUSR1) - assert waitforfiles(log_path), 'reopen' + assert waitforfiles(log_path), 'reopen' + + body = 'body_for_a_log_unit\n' + assert self.post(body=body)['status'] == 200 + + assert self.wait_for_record(body) is not None, 'rename new' + assert self.search_in_log(body, log_new) is None, 'rename new 2' - body = 'body_for_a_log_unit' - assert self.post(body=body)['status'] == 200 + finally: + # merge two log files into unit.log to check alerts - assert self.wait_for_record(body) is not None, 'rename new' - assert self.search_in_log(body, log_new) is None, 'rename new 2' + with open(log_path, 'r', errors='ignore') as unit_log: + log = unit_log.read() - # merge two log files into unit.log to check alerts + with open(log_path, 'w') as unit_log, open( + log_path_new, 'r', errors='ignore' + ) as unit_log_new: + unit_log.write(unit_log_new.read()) + unit_log.write(log) - with open(log_path, 'w') as unit_log, open( - log_path_new, 'r' - ) as unit_log_new: - unit_log.write(unit_log_new.read()) + Log.swap(log_new) diff --git a/test/unit/applications/proto.py b/test/unit/applications/proto.py index 5c400621..92754c03 100644 --- a/test/unit/applications/proto.py +++ b/test/unit/applications/proto.py @@ -4,6 +4,7 @@ import time from unit.control import TestControl from unit.option import option +from unit.log import Log class TestApplicationProto(TestControl): @@ -15,18 +16,23 @@ class TestApplicationProto(TestControl): def date_to_sec_epoch(self, date, template='%a, %d %b %Y %H:%M:%S %Z'): return time.mktime(time.strptime(date, template)) + def findall(self, pattern, name='unit.log'): + with Log.open(name) as f: + return re.findall(pattern, f.read()) + def search_in_log(self, pattern, name='unit.log'): - with open(option.temp_dir + '/' + name, 'r', errors='ignore') as f: + with Log.open(name) as f: return re.search(pattern, f.read()) def wait_for_record(self, pattern, name='unit.log', wait=150): - for i in range(wait): - found = self.search_in_log(pattern, name) + with Log.open(name) as f: + for i in range(wait): + found = re.search(pattern, f.read()) - if found is not None: - break + if found is not None: + break - time.sleep(0.1) + time.sleep(0.1) return found diff --git a/test/unit/log.py b/test/unit/log.py new file mode 100644 index 00000000..7263443d --- /dev/null +++ b/test/unit/log.py @@ -0,0 +1,23 @@ +UNIT_LOG = 'unit.log' + + +class Log: + temp_dir = None + pos = {} + + def open(name=UNIT_LOG, encoding=None): + f = open(Log.get_path(name), 'r', encoding=encoding, errors='ignore') + f.seek(Log.pos.get(name, 0)) + + return f + + def set_pos(pos, name=UNIT_LOG): + Log.pos[name] = pos + + def swap(name): + pos = Log.pos.get(UNIT_LOG, 0) + Log.pos[UNIT_LOG] = Log.pos.get(name, 0) + Log.pos[name] = pos + + def get_path(name=UNIT_LOG): + return Log.temp_dir + '/' + name -- cgit From 5b332cae832c9f8245280fa60a6edc2ce48202c6 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Wed, 14 Apr 2021 15:56:03 +0100 Subject: Tests: fixed "skip" descriptors check flag for controller. --- test/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/conftest.py b/test/conftest.py index b9f5c60b..0eaf54be 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -275,7 +275,7 @@ def run(request): _fds_check['main']['skip'] = False _fds_check['router']['skip'] = False - _fds_check['router']['skip'] = False + _fds_check['controller']['skip'] = False yield -- cgit From e0a061955bba69aaf28022d405362c8a5e444ff6 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Wed, 5 May 2021 12:36:57 +0100 Subject: Tests: added tests for openat2() features. --- test/conftest.py | 2 + test/test_share_chroot.py | 108 ++++++++++++++++++++++++++++++++++ test/test_share_mount.py | 142 +++++++++++++++++++++++++++++++++++++++++++++ test/test_share_symlink.py | 96 ++++++++++++++++++++++++++++++ test/test_static.py | 8 --- test/unit/check/chroot.py | 32 ++++++++++ 6 files changed, 380 insertions(+), 8 deletions(-) create mode 100644 test/test_share_chroot.py create mode 100644 test/test_share_mount.py create mode 100644 test/test_share_symlink.py create mode 100644 test/unit/check/chroot.py (limited to 'test') diff --git a/test/conftest.py b/test/conftest.py index 0eaf54be..a084953a 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -15,6 +15,7 @@ from multiprocessing import Process import pytest +from unit.check.chroot import check_chroot from unit.check.go import check_go from unit.check.isolation import check_isolation from unit.check.node import check_node @@ -204,6 +205,7 @@ def pytest_sessionstart(session): k: v for k, v in option.available['modules'].items() if v is not None } + check_chroot() check_isolation() _clear_conf(unit['temp_dir'] + '/control.unit.sock') diff --git a/test/test_share_chroot.py b/test/test_share_chroot.py new file mode 100644 index 00000000..7e53d3f7 --- /dev/null +++ b/test/test_share_chroot.py @@ -0,0 +1,108 @@ +import os +from pathlib import Path + +import pytest + +from unit.applications.proto import TestApplicationProto + + +class TestShareChroot(TestApplicationProto): + prerequisites = {'features': ['chroot']} + + @pytest.fixture(autouse=True) + def setup_method_fixture(self, temp_dir): + os.makedirs(temp_dir + '/assets/dir') + with open(temp_dir + '/assets/index.html', 'w') as index, open( + temp_dir + '/assets/dir/file', 'w' + ) as file: + index.write('0123456789') + file.write('blah') + + test = Path(__file__) + self.test_path = '/' + test.parent.name + '/' + test.name + + self._load_conf( + { + "listeners": {"*:7080": {"pass": "routes"}}, + "routes": [{"action": {"share": temp_dir + "/assets"}}], + } + ) + + def test_share_chroot(self, temp_dir): + assert self.get(url='/dir/file')['status'] == 200, 'default chroot' + assert self.get(url='/index.html')['status'] == 200, 'default chroot 2' + + assert 'success' in self.conf( + { + "share": temp_dir + "/assets", + "chroot": temp_dir + "/assets/dir", + }, + 'routes/0/action', + ), 'configure chroot' + + assert self.get(url='/dir/file')['status'] == 200, 'chroot' + assert self.get(url='/index.html')['status'] == 403, 'chroot 403 2' + assert self.get(url='/file')['status'] == 403, 'chroot 403' + + def test_share_chroot_permission(self, temp_dir): + os.chmod(temp_dir + '/assets/dir', 0o100) + + assert 'success' in self.conf( + { + "share": temp_dir + "/assets", + "chroot": temp_dir + "/assets/dir", + }, + 'routes/0/action', + ), 'configure chroot' + + assert self.get(url='/dir/file')['status'] == 200, 'chroot' + + def test_share_chroot_empty(self, temp_dir): + assert 'success' in self.conf( + {"share": temp_dir + "/assets", "chroot": ""}, 'routes/0/action', + ), 'configure chroot empty absolute' + + assert ( + self.get(url='/dir/file')['status'] == 200 + ), 'chroot empty absolute' + + assert 'success' in self.conf( + {"share": ".", "chroot": ""}, 'routes/0/action', + ), 'configure chroot empty relative' + + assert ( + self.get(url=self.test_path)['status'] == 200 + ), 'chroot empty relative' + + def test_share_chroot_relative(self, is_su, temp_dir): + if is_su: + pytest.skip('does\'t work under root') + + assert 'success' in self.conf( + {"share": temp_dir + "/assets", "chroot": "."}, 'routes/0/action', + ), 'configure relative chroot' + + assert self.get(url='/dir/file')['status'] == 403, 'relative chroot' + + assert 'success' in self.conf( + {"share": "."}, 'routes/0/action', + ), 'configure relative share' + + assert self.get(url=self.test_path)['status'] == 200, 'relative share' + + assert 'success' in self.conf( + {"share": ".", "chroot": "."}, 'routes/0/action', + ), 'configure relative' + + assert self.get(url=self.test_path)['status'] == 200, 'relative' + + def test_share_chroot_invalid(self, temp_dir): + assert 'error' in self.conf( + {"share": temp_dir, "chroot": True}, 'routes/0/action', + ), 'configure chroot error' + assert 'error' in self.conf( + {"share": temp_dir, "symlinks": "True"}, 'routes/0/action', + ), 'configure symlink error' + assert 'error' in self.conf( + {"share": temp_dir, "mount": "True"}, 'routes/0/action', + ), 'configure mount error' diff --git a/test/test_share_mount.py b/test/test_share_mount.py new file mode 100644 index 00000000..f46e1279 --- /dev/null +++ b/test/test_share_mount.py @@ -0,0 +1,142 @@ +import os +import subprocess + +import pytest + +from unit.applications.proto import TestApplicationProto + + +class TestShareMount(TestApplicationProto): + prerequisites = {'features': ['chroot']} + + @pytest.fixture(autouse=True) + def setup_method_fixture(self, is_su, temp_dir): + if not is_su: + pytest.skip('requires root') + + os.makedirs(temp_dir + '/assets/dir/mount') + os.makedirs(temp_dir + '/assets/dir/dir') + os.makedirs(temp_dir + '/assets/mount') + with open(temp_dir + '/assets/index.html', 'w') as index, open( + temp_dir + '/assets/dir/dir/file', 'w' + ) as file, open(temp_dir + '/assets/mount/index.html', 'w') as mount: + index.write('index') + file.write('file') + mount.write('mount') + + try: + process = subprocess.Popen( + [ + "mount", + "--bind", + temp_dir + "/assets/mount", + temp_dir + "/assets/dir/mount", + ], + stderr=subprocess.STDOUT, + ) + + process.communicate() + + except KeyboardInterrupt: + raise + + except: + pytest.fail('Can\'t run mount process.') + + self._load_conf( + { + "listeners": {"*:7080": {"pass": "routes"}}, + "routes": [{"action": {"share": temp_dir + "/assets/dir"}}], + } + ) + + yield + + try: + process = subprocess.Popen( + ["umount", "--lazy", temp_dir + "/assets/dir/mount"], + stderr=subprocess.STDOUT, + ) + + process.communicate() + + except KeyboardInterrupt: + raise + + except: + pytest.fail('Can\'t run umount process.') + + def test_share_mount(self, temp_dir, skip_alert): + skip_alert(r'opening.*failed') + + resp = self.get(url='/mount/') + resp['status'] == 200 + resp['body'] == 'mount' + + assert 'success' in self.conf( + {"share": temp_dir + "/assets/dir", "traverse_mounts": False}, + 'routes/0/action', + ), 'configure mount disable' + + assert self.get(url='/mount/')['status'] == 403 + + assert 'success' in self.conf( + {"share": temp_dir + "/assets/dir", "traverse_mounts": True}, + 'routes/0/action', + ), 'configure mount enable' + + resp = self.get(url='/mount/') + resp['status'] == 200 + resp['body'] == 'mount' + + def test_share_mount_two_blocks(self, temp_dir, skip_alert): + skip_alert(r'opening.*failed') + + os.symlink(temp_dir + '/assets/dir', temp_dir + '/assets/link') + + assert 'success' in self.conf( + [ + { + "match": {"method": "HEAD"}, + "action": { + "share": temp_dir + "/assets/dir", + "traverse_mounts": False, + }, + }, + { + "match": {"method": "GET"}, + "action": { + "share": temp_dir + "/assets/dir", + "traverse_mounts": True, + }, + }, + ], + 'routes', + ), 'configure two options' + + assert self.get(url='/mount/')['status'] == 200, 'block enabled' + assert self.head(url='/mount/')['status'] == 403, 'block disabled' + + def test_share_mount_chroot(self, temp_dir, skip_alert): + skip_alert(r'opening.*failed') + + assert 'success' in self.conf( + { + "share": temp_dir + "/assets/dir", + "chroot": temp_dir + "/assets", + }, + 'routes/0/action', + ), 'configure chroot mount default' + + self.get(url='/mount/')['status'] == 200, 'chroot' + + assert 'success' in self.conf( + { + "share": temp_dir + "/assets/dir", + "chroot": temp_dir + "/assets", + "traverse_mounts": False, + }, + 'routes/0/action', + ), 'configure chroot mount disable' + + self.get(url='/mount/')['status'] == 403, 'chroot mount' diff --git a/test/test_share_symlink.py b/test/test_share_symlink.py new file mode 100644 index 00000000..3970b605 --- /dev/null +++ b/test/test_share_symlink.py @@ -0,0 +1,96 @@ +import os + +import pytest + +from unit.applications.proto import TestApplicationProto + + +class TestShareSymlink(TestApplicationProto): + prerequisites = {'features': ['chroot']} + + @pytest.fixture(autouse=True) + def setup_method_fixture(self, temp_dir): + os.makedirs(temp_dir + '/assets/dir/dir') + with open(temp_dir + '/assets/index.html', 'w') as index, open( + temp_dir + '/assets/dir/file', 'w' + ) as file: + index.write('0123456789') + file.write('blah') + + self._load_conf( + { + "listeners": {"*:7080": {"pass": "routes"}}, + "routes": [{"action": {"share": temp_dir + "/assets"}}], + } + ) + + def test_share_symlink(self, temp_dir, skip_alert): + skip_alert(r'opening.*failed') + + os.symlink(temp_dir + '/assets/dir', temp_dir + '/assets/link') + + 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' + + assert 'success' in self.conf( + {"share": temp_dir + "/assets", "follow_symlinks": False}, + 'routes/0/action', + ), 'configure symlink disable' + + assert self.get(url='/link/file')['status'] == 403, 'symlink disabled' + + assert 'success' in self.conf( + {"share": temp_dir + "/assets", "follow_symlinks": True}, + 'routes/0/action', + ), 'configure symlink enable' + + assert self.get(url='/link/file')['status'] == 200, 'symlink enabled' + + def test_share_symlink_two_blocks(self, temp_dir, skip_alert): + skip_alert(r'opening.*failed') + + os.symlink(temp_dir + '/assets/dir', temp_dir + '/assets/link') + + assert 'success' in self.conf( + [ + { + "match": {"method": "HEAD"}, + "action": { + "share": temp_dir + "/assets", + "follow_symlinks": False, + }, + }, + { + "match": {"method": "GET"}, + "action": { + "share": temp_dir + "/assets", + "follow_symlinks": True, + }, + }, + ], + 'routes', + ), 'configure two options' + + assert self.get(url='/link/file')['status'] == 200, 'block enabled' + assert self.head(url='/link/file')['status'] == 403, 'block disabled' + + def test_share_symlink_chroot(self, temp_dir, skip_alert): + skip_alert(r'opening.*failed') + + os.symlink( + temp_dir + '/assets/dir/file', temp_dir + '/assets/dir/dir/link' + ) + + assert self.get(url='/dir/dir/link')['status'] == 200, 'default chroot' + + assert 'success' in self.conf( + { + "share": temp_dir + "/assets", + "chroot": temp_dir + "/assets/dir/dir", + }, + 'routes/0/action', + ), 'configure chroot' + + assert self.get(url='/dir/dir/link')['status'] == 404, 'chroot' diff --git a/test/test_static.py b/test/test_static.py index d8319292..669e265d 100644 --- a/test/test_static.py +++ b/test/test_static.py @@ -168,14 +168,6 @@ class TestStatic(TestApplicationProto): assert self.get(url='/fifo')['status'] == 404, 'fifo' - def test_static_symlink(self, temp_dir): - os.symlink(temp_dir + '/assets/dir', temp_dir + '/assets/link') - - 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() assert resp['status'] == 200, 'HEAD status' diff --git a/test/unit/check/chroot.py b/test/unit/check/chroot.py new file mode 100644 index 00000000..40b75058 --- /dev/null +++ b/test/unit/check/chroot.py @@ -0,0 +1,32 @@ +import json + +from unit.http import TestHTTP +from unit.option import option + +http = TestHTTP() + + +def check_chroot(): + available = option.available + + resp = http.put( + url='/config', + sock_type='unix', + addr=option.temp_dir + '/control.unit.sock', + body=json.dumps( + { + "listeners": {"*:7080": {"pass": "routes"}}, + "routes": [ + { + "action": { + "share": option.temp_dir, + "chroot": option.temp_dir, + } + } + ], + } + ), + ) + + if 'success' in resp['body']: + available['features']['chroot'] = True -- cgit From 6703b68ed00e7cc8132c0aaf3049ed30889de8a8 Mon Sep 17 00:00:00 2001 From: Oisin Canty Date: Thu, 6 May 2021 14:22:36 +0000 Subject: Tests: MIME filtering --- test/test_share_types.py | 170 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 test/test_share_types.py (limited to 'test') diff --git a/test/test_share_types.py b/test/test_share_types.py new file mode 100644 index 00000000..98ad106b --- /dev/null +++ b/test/test_share_types.py @@ -0,0 +1,170 @@ +import os +from pathlib import Path + +import pytest +from unit.applications.proto import TestApplicationProto +from unit.option import option + + +class TestShareTypes(TestApplicationProto): + prerequisites = {} + + @pytest.fixture(autouse=True) + def setup_method_fixture(self, temp_dir): + Path(temp_dir + '/assets').mkdir() + for ext in ['.xml', '.mp4', '.php', '', '.txt', '.html', '.png']: + Path(temp_dir + '/assets/file' + ext).write_text(ext) + + Path(temp_dir + '/assets/index.html').write_text('index') + + self._load_conf( + { + "listeners": { + "*:7080": {"pass": "routes"}, + "*:7081": {"pass": "routes"}, + }, + "routes": [{"action": {"share": temp_dir + "/assets"}}], + "applications": {}, + } + ) + + def action_update(self, conf): + assert 'success' in self.conf(conf, 'routes/0/action') + + def check_body(self, http_url, body): + resp = self.get(url=http_url) + assert resp['status'] == 200, 'status' + assert resp['body'] == body, 'body' + + def test_share_types_basic(self, temp_dir): + self.action_update({"share": temp_dir + "/assets"}) + self.check_body('/index.html', 'index') + self.check_body('/file.xml', '.xml') + + self.action_update( + {"share": temp_dir + "/assets", "types": "application/xml"} + ) + self.check_body('/file.xml', '.xml') + + self.action_update( + {"share": temp_dir + "/assets", "types": ["application/xml"]} + ) + self.check_body('/file.xml', '.xml') + + self.action_update({"share": temp_dir + "/assets", "types": [""]}) + assert self.get(url='/file.xml')['status'] == 403, 'no mtype' + + def test_share_types_wildcard(self, temp_dir): + self.action_update( + {"share": temp_dir + "/assets", "types": ["application/*"]} + ) + self.check_body('/file.xml', '.xml') + assert self.get(url='/file.mp4')['status'] == 403, 'app * mtype mp4' + + self.action_update( + {"share": temp_dir + "/assets", "types": ["video/*"]} + ) + assert self.get(url='/file.xml')['status'] == 403, 'video * mtype xml' + self.check_body('/file.mp4', '.mp4') + + def test_share_types_negation(self, temp_dir): + self.action_update( + {"share": temp_dir + "/assets", "types": ["!application/xml"]} + ) + assert self.get(url='/file.xml')['status'] == 403, 'forbidden negation' + self.check_body('/file.mp4', '.mp4') + + # sorting negation + self.action_update( + { + "share": temp_dir + "/assets", + "types": ["!video/*", "image/png", "!image/jpg"], + } + ) + assert self.get(url='/file.mp4')['status'] == 403, 'negation sort mp4' + self.check_body('/file.png', '.png') + assert self.get(url='/file.jpg')['status'] == 403, 'negation sort jpg' + + def test_share_types_regex(self, temp_dir): + self.action_update( + {"share": temp_dir + "/assets", "types": ["~text/(html|plain)"]} + ) + assert self.get(url='/file.php')['status'] == 403, 'regex fail' + self.check_body('/file.html', '.html') + self.check_body('/file.txt', '.txt') + + def test_share_types_case(self, temp_dir): + self.action_update( + {"share": temp_dir + "/assets", "types": ["!APpliCaTiOn/xMl"]} + ) + self.check_body('/file.mp4', '.mp4') + assert ( + self.get(url='/file.xml')['status'] == 403 + ), 'mixed case xml negation' + + self.action_update( + {"share": temp_dir + "/assets", "types": ["vIdEo/mp4"]} + ) + assert self.get(url='/file.mp4')['status'] == 200, 'mixed case' + assert ( + self.get(url='/file.xml')['status'] == 403 + ), 'mixed case video negation' + + self.action_update( + {"share": temp_dir + "/assets", "types": ["vIdEo/*"]} + ) + self.check_body('/file.mp4', '.mp4') + assert ( + self.get(url='/file.xml')['status'] == 403 + ), 'mixed case video * negation' + + def test_share_types_fallback(self, temp_dir): + assert 'success' in self.conf( + [ + { + "match": {"destination": "*:7081"}, + "action": {"return": 200}, + }, + { + "action": { + "share": temp_dir + "/assets", + "types": ["!application/php"], + "fallback": {"proxy": "http://127.0.0.1:7081"}, + } + }, + ], + 'routes', + ), 'configure fallback proxy route' + + self.check_body('/file.php', '') + self.check_body('/file.mp4', '.mp4') + + def test_share_types_index(self, temp_dir): + self.action_update( + {"share": temp_dir + "/assets", "types": "application/xml"} + ) + self.check_body('/', 'index') + self.check_body('/file.xml', '.xml') + assert self.get(url='/file.mp4')['status'] == 403, 'forbidden mtype' + + def test_share_types_custom_mime(self, temp_dir): + self._load_conf( + { + "listeners": {"*:7080": {"pass": "routes"}}, + "routes": [{"action": {"share": temp_dir + "/assets"}}], + "applications": {}, + "settings": { + "http": { + "static": {"mime_types": {"test/mime-type": ["file"]}} + } + }, + } + ) + + self.action_update({"share": temp_dir + "/assets", "types": [""]}) + assert self.get(url='/file')['status'] == 403, 'forbidden custom mime' + + self.action_update( + {"share": temp_dir + "/assets", "types": ["test/mime-type"]} + ) + self.check_body('/file', '') -- cgit From b9e8d8073ce9da9c1019ca885d99bca7ff727ba1 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Fri, 7 May 2021 16:55:42 +0100 Subject: Tests: PHP test with getting variable before the script is loaded. --- test/php/fastcgi_finish_request/index.php | 2 ++ test/php/fastcgi_finish_request/server.php | 4 ++++ test/test_php_application.py | 14 ++++++++++++-- 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 test/php/fastcgi_finish_request/server.php (limited to 'test') diff --git a/test/php/fastcgi_finish_request/index.php b/test/php/fastcgi_finish_request/index.php index a6211303..fbfae71b 100644 --- a/test/php/fastcgi_finish_request/index.php +++ b/test/php/fastcgi_finish_request/index.php @@ -8,4 +8,6 @@ if (!fastcgi_finish_request()) { } echo "4567"; + +include 'server.php'; ?> diff --git a/test/php/fastcgi_finish_request/server.php b/test/php/fastcgi_finish_request/server.php new file mode 100644 index 00000000..af71c5f2 --- /dev/null +++ b/test/php/fastcgi_finish_request/server.php @@ -0,0 +1,4 @@ + diff --git a/test/test_php_application.py b/test/test_php_application.py index 350ac0d0..66e2ef7d 100644 --- a/test/test_php_application.py +++ b/test/test_php_application.py @@ -98,9 +98,14 @@ class TestPHPApplication(TestApplicationPHP): def test_php_application_fastcgi_finish_request(self, unit_pid): self.load('fastcgi_finish_request') + assert 'success' in self.conf( + {"admin": {"auto_globals_jit": "1"}}, + 'applications/fastcgi_finish_request/options', + ) + assert self.get()['body'] == '0123' - os.kill(unit_pid, signal.SIGUSR1); + os.kill(unit_pid, signal.SIGUSR1) errs = self.findall(r'Error in fastcgi_finish_request') @@ -109,11 +114,16 @@ class TestPHPApplication(TestApplicationPHP): def test_php_application_fastcgi_finish_request_2(self, unit_pid): self.load('fastcgi_finish_request') + assert 'success' in self.conf( + {"admin": {"auto_globals_jit": "1"}}, + 'applications/fastcgi_finish_request/options', + ) + resp = self.get(url='/?skip') assert resp['status'] == 200 assert resp['body'] == '' - os.kill(unit_pid, signal.SIGUSR1); + os.kill(unit_pid, signal.SIGUSR1) errs = self.findall(r'Error in fastcgi_finish_request') -- cgit From a17f7e03d4c34f3dc7cf71ee25c6efc337949d99 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Fri, 7 May 2021 17:42:48 +0100 Subject: Tests: added test for TLS with empty Subject field. --- test/test_tls.py | 239 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 130 insertions(+), 109 deletions(-) (limited to 'test') diff --git a/test/test_tls.py b/test/test_tls.py index abdca167..d4d1900c 100644 --- a/test/test_tls.py +++ b/test/test_tls.py @@ -6,6 +6,7 @@ import subprocess import pytest from unit.applications.tls import TestApplicationTLS +from unit.option import option class TestTLS(TestApplicationTLS): @@ -28,6 +29,91 @@ class TestTLS(TestApplicationTLS): {"pass": "applications/" + application}, 'listeners/*:' + str(port) ) + def req(self, name='localhost', subject=None, x509=False): + subj = subject if subject is not None else '/CN=' + name + '/' + + subprocess.call( + [ + 'openssl', + 'req', + '-new', + '-subj', + subj, + '-config', + option.temp_dir + '/openssl.conf', + '-out', + option.temp_dir + '/' + name + '.csr', + '-keyout', + option.temp_dir + '/' + name + '.key', + ], + stderr=subprocess.STDOUT, + ) + + def generate_ca_conf(self): + with open(option.temp_dir + '/ca.conf', 'w') as f: + f.write( + """[ ca ] +default_ca = myca + +[ myca ] +new_certs_dir = %(dir)s +database = %(database)s +default_md = sha256 +policy = myca_policy +serial = %(certserial)s +default_days = 1 +x509_extensions = myca_extensions +copy_extensions = copy + +[ myca_policy ] +commonName = optional + +[ myca_extensions ] +basicConstraints = critical,CA:TRUE""" + % { + 'dir': option.temp_dir, + 'database': option.temp_dir + '/certindex', + 'certserial': option.temp_dir + '/certserial', + } + ) + + with open(option.temp_dir + '/certserial', 'w') as f: + f.write('1000') + + with open(option.temp_dir + '/certindex', 'w') as f: + f.write('') + + with open(option.temp_dir + '/certindex.attr', 'w') as f: + f.write('') + + def ca(self, cert='root', out='localhost'): + subprocess.call( + [ + 'openssl', + 'ca', + '-batch', + '-config', + option.temp_dir + '/ca.conf', + '-keyfile', + option.temp_dir + '/' + cert + '.key', + '-cert', + option.temp_dir + '/' + cert + '.crt', + '-in', + option.temp_dir + '/' + out + '.csr', + '-out', + option.temp_dir + '/' + out + '.crt', + ], + stderr=subprocess.STDOUT, + ) + + def set_certificate_req_context(self, cert='root'): + self.context = ssl.create_default_context() + self.context.check_hostname = False + self.context.verify_mode = ssl.CERT_REQUIRED + self.context.load_verify_locations( + option.temp_dir + '/' + cert + '.crt' + ) + def test_tls_listener_option_add(self): self.load('empty') @@ -208,113 +294,13 @@ class TestTLS(TestApplicationTLS): self.certificate('root', False) - subprocess.call( - [ - 'openssl', - 'req', - '-new', - '-subj', - '/CN=int/', - '-config', - temp_dir + '/openssl.conf', - '-out', - temp_dir + '/int.csr', - '-keyout', - temp_dir + '/int.key', - ], - stderr=subprocess.STDOUT, - ) + self.req('int') + self.req('end') - subprocess.call( - [ - 'openssl', - 'req', - '-new', - '-subj', - '/CN=end/', - '-config', - temp_dir + '/openssl.conf', - '-out', - temp_dir + '/end.csr', - '-keyout', - temp_dir + '/end.key', - ], - stderr=subprocess.STDOUT, - ) - - with open(temp_dir + '/ca.conf', 'w') as f: - f.write( - """[ ca ] -default_ca = myca - -[ myca ] -new_certs_dir = %(dir)s -database = %(database)s -default_md = sha256 -policy = myca_policy -serial = %(certserial)s -default_days = 1 -x509_extensions = myca_extensions - -[ myca_policy ] -commonName = supplied - -[ myca_extensions ] -basicConstraints = critical,CA:TRUE""" - % { - 'dir': temp_dir, - 'database': temp_dir + '/certindex', - 'certserial': temp_dir + '/certserial', - } - ) + self.generate_ca_conf() - with open(temp_dir + '/certserial', 'w') as f: - f.write('1000') - - with open(temp_dir + '/certindex', 'w') as f: - f.write('') - - subprocess.call( - [ - 'openssl', - 'ca', - '-batch', - '-subj', - '/CN=int/', - '-config', - temp_dir + '/ca.conf', - '-keyfile', - temp_dir + '/root.key', - '-cert', - temp_dir + '/root.crt', - '-in', - temp_dir + '/int.csr', - '-out', - temp_dir + '/int.crt', - ], - stderr=subprocess.STDOUT, - ) - - subprocess.call( - [ - 'openssl', - 'ca', - '-batch', - '-subj', - '/CN=end/', - '-config', - temp_dir + '/ca.conf', - '-keyfile', - temp_dir + '/int.key', - '-cert', - temp_dir + '/int.crt', - '-in', - temp_dir + '/end.csr', - '-out', - temp_dir + '/end.crt', - ], - stderr=subprocess.STDOUT, - ) + self.ca(cert='root', out='int') + self.ca(cert='int', out='end') crt_path = temp_dir + '/end-int.crt' end_path = temp_dir + '/end.crt' @@ -325,10 +311,7 @@ basicConstraints = critical,CA:TRUE""" ) 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(temp_dir + '/root.crt') + self.set_certificate_req_context() # incomplete chain @@ -402,6 +385,44 @@ basicConstraints = critical,CA:TRUE""" self.get_ssl()['status'] == 200 ), 'certificate chain intermediate server' + def test_tls_certificate_empty_cn(self, temp_dir): + self.certificate('root', False) + + self.req(subject='/') + + self.generate_ca_conf() + self.ca() + + self.set_certificate_req_context() + + assert 'success' in self.certificate_load('localhost', 'localhost') + + cert = self.conf_get('/certificates/localhost') + assert cert['chain'][0]['subject'] == {}, 'empty subject' + assert cert['chain'][0]['issuer']['common_name'] == 'root', 'issuer' + + def test_tls_certificate_empty_cn_san(self, temp_dir): + self.certificate('root', False) + + self.openssl_conf( + rewrite=True, alt_names=["example.com", "www.example.net"] + ) + + self.req(subject='/') + + self.generate_ca_conf() + self.ca() + + self.set_certificate_req_context() + + assert 'success' in self.certificate_load('localhost', 'localhost') + + cert = self.conf_get('/certificates/localhost') + assert cert['chain'][0]['subject'] == { + 'alt_names': ['example.com', 'www.example.net'] + }, 'subject alt_names' + assert cert['chain'][0]['issuer']['common_name'] == 'root', 'issuer' + @pytest.mark.skip('not yet') def test_tls_reconfigure(self): self.load('empty') -- cgit From 07c6bf165d0e414da3827c7b2aebf5044a7e6093 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Tue, 11 May 2021 15:30:12 +0100 Subject: Tests: temporary dir removed after tests execution. --- test/conftest.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'test') diff --git a/test/conftest.py b/test/conftest.py index a084953a..c2781571 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -671,4 +671,10 @@ def pytest_sessionfinish(session): option.restart = True unit_stop() + + public_dir(option.cache_dir) shutil.rmtree(option.cache_dir) + + if not option.save_log: + public_dir(option.temp_dir) + shutil.rmtree(option.temp_dir) -- cgit From a0c083af208cd9f676bb56762b4e27a3174a773d Mon Sep 17 00:00:00 2001 From: Oisin Canty Date: Wed, 12 May 2021 09:26:55 +0000 Subject: Node.js: a shim for overriding "http" and "websocket" modules. Also added stubs for Server.address() This was done to prevent crashes in some popular frameworks like express Supports both CommonJS and the new ES Modules system syntax e.g: app.js: const http = require('http') app.mjs: import http from "http" Usage on Node 14.16.x and higher: { "type": "external", "processes": {"spare": 0}, "working_directory": '/project', "executable": "/usr/bin/env", "arguments": [ "node", "--loader", "unit-http/require_shim.mjs" "--require", "unit-http/require_shim", "app.js" ] } Usage on Node 14.15.x and lower: { "type": "external", "processes": {"spare": 0}, "working_directory": '/project', "executable": "/usr/bin/env", "arguments": [ "node", "--require", "unit-http/require_shim", "app.js" ] } --- test/node/404/app.js | 3 +- test/node/basic/app.js | 3 +- test/node/double_end/app.js | 3 +- test/node/get_header_names/app.js | 3 +- test/node/get_header_type/app.js | 3 +- test/node/get_variables/app.js | 3 +- test/node/has_header/app.js | 3 +- test/node/header_name_case/app.js | 3 +- test/node/header_name_valid/app.js | 3 +- test/node/header_value_object/app.js | 3 +- test/node/mirror/app.js | 3 +- test/node/post_variables/app.js | 3 +- test/node/promise_end/app.js | 3 +- test/node/promise_handler/app.js | 3 +- test/node/remove_header/app.js | 3 +- test/node/require_shim/es_modules_http/app.mjs | 6 +++ .../require_shim/es_modules_http_indirect/app.js | 1 + .../es_modules_http_indirect/module.mjs | 6 +++ .../node/require_shim/es_modules_websocket/app.mjs | 30 +++++++++++++ .../es_modules_websocket_indirect/app.js | 1 + .../es_modules_websocket_indirect/module.mjs | 30 +++++++++++++ .../node/require_shim/transitive_dependency/app.js | 1 + .../transitive_dependency/transitive_http.js | 8 ++++ test/node/require_shim/unit_http/app.js | 4 ++ test/node/set_header_array/app.js | 3 +- test/node/status_message/app.js | 3 +- test/node/update_header/app.js | 3 +- test/node/variables/app.js | 3 +- test/node/websockets/mirror/app.js | 7 +-- test/node/websockets/mirror_fragmentation/app.js | 7 +-- test/node/write_before_write_head/app.js | 3 +- test/node/write_buffer/app.js | 3 +- test/node/write_callback/app.js | 3 +- test/node/write_multiple/app.js | 3 +- test/node/write_return/app.js | 3 +- test/test_node_application.py | 19 ++++++-- test/test_node_es_modules.py | 50 ++++++++++++++++++++++ test/unit/applications/lang/node.py | 21 +++++++-- test/unit/check/node.py | 13 +++++- 39 files changed, 210 insertions(+), 66 deletions(-) mode change 100755 => 100644 test/node/404/app.js mode change 100755 => 100644 test/node/basic/app.js mode change 100755 => 100644 test/node/double_end/app.js mode change 100755 => 100644 test/node/get_header_names/app.js mode change 100755 => 100644 test/node/get_header_type/app.js mode change 100755 => 100644 test/node/get_variables/app.js mode change 100755 => 100644 test/node/has_header/app.js mode change 100755 => 100644 test/node/header_name_case/app.js mode change 100755 => 100644 test/node/header_name_valid/app.js mode change 100755 => 100644 test/node/header_value_object/app.js mode change 100755 => 100644 test/node/mirror/app.js mode change 100755 => 100644 test/node/post_variables/app.js mode change 100755 => 100644 test/node/promise_end/app.js mode change 100755 => 100644 test/node/promise_handler/app.js mode change 100755 => 100644 test/node/remove_header/app.js create mode 100644 test/node/require_shim/es_modules_http/app.mjs create mode 100644 test/node/require_shim/es_modules_http_indirect/app.js create mode 100644 test/node/require_shim/es_modules_http_indirect/module.mjs create mode 100644 test/node/require_shim/es_modules_websocket/app.mjs create mode 100644 test/node/require_shim/es_modules_websocket_indirect/app.js create mode 100644 test/node/require_shim/es_modules_websocket_indirect/module.mjs create mode 100644 test/node/require_shim/transitive_dependency/app.js create mode 100644 test/node/require_shim/transitive_dependency/transitive_http.js create mode 100644 test/node/require_shim/unit_http/app.js mode change 100755 => 100644 test/node/set_header_array/app.js mode change 100755 => 100644 test/node/status_message/app.js mode change 100755 => 100644 test/node/update_header/app.js mode change 100755 => 100644 test/node/variables/app.js mode change 100755 => 100644 test/node/websockets/mirror/app.js mode change 100755 => 100644 test/node/websockets/mirror_fragmentation/app.js mode change 100755 => 100644 test/node/write_before_write_head/app.js mode change 100755 => 100644 test/node/write_buffer/app.js mode change 100755 => 100644 test/node/write_callback/app.js mode change 100755 => 100644 test/node/write_multiple/app.js mode change 100755 => 100644 test/node/write_return/app.js create mode 100644 test/test_node_es_modules.py (limited to 'test') diff --git a/test/node/404/app.js b/test/node/404/app.js old mode 100755 new mode 100644 index 587c432d..ba15c104 --- a/test/node/404/app.js +++ b/test/node/404/app.js @@ -1,7 +1,6 @@ -#!/usr/bin/env node var fs = require('fs'); -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { res.writeHead(404, {}).end(fs.readFileSync('404.html')); }).listen(7080); diff --git a/test/node/basic/app.js b/test/node/basic/app.js old mode 100755 new mode 100644 index 7820c474..9092022c --- a/test/node/basic/app.js +++ b/test/node/basic/app.js @@ -1,6 +1,5 @@ -#!/usr/bin/env node -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { res.writeHead(200, {'Content-Length': 12, 'Content-Type': 'text/plain'}) .end('Hello World\n'); }).listen(7080); diff --git a/test/node/double_end/app.js b/test/node/double_end/app.js old mode 100755 new mode 100644 index 63912097..653e33b1 --- a/test/node/double_end/app.js +++ b/test/node/double_end/app.js @@ -1,5 +1,4 @@ -#!/usr/bin/env node -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { res.end().end(); }).listen(7080); diff --git a/test/node/get_header_names/app.js b/test/node/get_header_names/app.js old mode 100755 new mode 100644 index 4cbccc16..a938b762 --- a/test/node/get_header_names/app.js +++ b/test/node/get_header_names/app.js @@ -1,6 +1,5 @@ -#!/usr/bin/env node -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { res.setHeader('DATE', ['date1', 'date2']); res.setHeader('X-Header', 'blah'); res.setHeader('X-Names', res.getHeaderNames()); diff --git a/test/node/get_header_type/app.js b/test/node/get_header_type/app.js old mode 100755 new mode 100644 index b606f142..6e45b71f --- a/test/node/get_header_type/app.js +++ b/test/node/get_header_type/app.js @@ -1,6 +1,5 @@ -#!/usr/bin/env node -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { res.setHeader('X-Number', 100); res.setHeader('X-Type', typeof(res.getHeader('X-Number'))); res.end(); diff --git a/test/node/get_variables/app.js b/test/node/get_variables/app.js old mode 100755 new mode 100644 index 5c1faf41..cded43d2 --- a/test/node/get_variables/app.js +++ b/test/node/get_variables/app.js @@ -1,6 +1,5 @@ -#!/usr/bin/env node -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { let query = require('url').parse(req.url, true).query; res.setHeader('X-Var-1', query.var1); res.setHeader('X-Var-2', query.var2); diff --git a/test/node/has_header/app.js b/test/node/has_header/app.js old mode 100755 new mode 100644 index eff7f4ff..04b13916 --- a/test/node/has_header/app.js +++ b/test/node/has_header/app.js @@ -1,6 +1,5 @@ -#!/usr/bin/env node -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { res.setHeader('X-Has-Header', res.hasHeader(req.headers['x-header']) + ''); res.end(); }).listen(7080); diff --git a/test/node/header_name_case/app.js b/test/node/header_name_case/app.js old mode 100755 new mode 100644 index 490bd4d5..af157547 --- a/test/node/header_name_case/app.js +++ b/test/node/header_name_case/app.js @@ -1,6 +1,5 @@ -#!/usr/bin/env node -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { res.setHeader('X-Header', '1'); res.setHeader('X-header', '2'); res.setHeader('X-HEADER', '3'); diff --git a/test/node/header_name_valid/app.js b/test/node/header_name_valid/app.js old mode 100755 new mode 100644 index 425f026f..c0c36098 --- a/test/node/header_name_valid/app.js +++ b/test/node/header_name_valid/app.js @@ -1,6 +1,5 @@ -#!/usr/bin/env node -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { res.writeHead(200, {}); res.setHeader('@$', 'test'); res.end(); diff --git a/test/node/header_value_object/app.js b/test/node/header_value_object/app.js old mode 100755 new mode 100644 index ff4e2bb0..bacdc7d5 --- a/test/node/header_value_object/app.js +++ b/test/node/header_value_object/app.js @@ -1,6 +1,5 @@ -#!/usr/bin/env node -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { res.setHeader('X-Header', {}); res.end(); }).listen(7080); diff --git a/test/node/mirror/app.js b/test/node/mirror/app.js old mode 100755 new mode 100644 index 1488917e..bdefe1cd --- a/test/node/mirror/app.js +++ b/test/node/mirror/app.js @@ -1,6 +1,5 @@ -#!/usr/bin/env node -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { let body = ''; req.on('data', chunk => { body += chunk.toString(); diff --git a/test/node/post_variables/app.js b/test/node/post_variables/app.js old mode 100755 new mode 100644 index 928a38cf..12b867cb --- a/test/node/post_variables/app.js +++ b/test/node/post_variables/app.js @@ -1,6 +1,5 @@ -#!/usr/bin/env node -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { let body = ''; req.on('data', chunk => { body += chunk.toString(); diff --git a/test/node/promise_end/app.js b/test/node/promise_end/app.js old mode 100755 new mode 100644 index ed22464c..373c3bc6 --- a/test/node/promise_end/app.js +++ b/test/node/promise_end/app.js @@ -1,8 +1,7 @@ -#!/usr/bin/env node var fs = require('fs'); -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { res.write('blah'); Promise.resolve().then(() => { diff --git a/test/node/promise_handler/app.js b/test/node/promise_handler/app.js old mode 100755 new mode 100644 index 51c3666b..32d7d7b9 --- a/test/node/promise_handler/app.js +++ b/test/node/promise_handler/app.js @@ -1,8 +1,7 @@ -#!/usr/bin/env node var fs = require('fs'); -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { res.end(); if (req.headers['x-write-call']) { diff --git a/test/node/remove_header/app.js b/test/node/remove_header/app.js old mode 100755 new mode 100644 index cd7b80c3..2a591235 --- a/test/node/remove_header/app.js +++ b/test/node/remove_header/app.js @@ -1,6 +1,5 @@ -#!/usr/bin/env node -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { res.setHeader('X-Header', 'test'); res.setHeader('Was-Header', res.hasHeader('X-Header').toString()); diff --git a/test/node/require_shim/es_modules_http/app.mjs b/test/node/require_shim/es_modules_http/app.mjs new file mode 100644 index 00000000..c7bcfe49 --- /dev/null +++ b/test/node/require_shim/es_modules_http/app.mjs @@ -0,0 +1,6 @@ +import http from "http" + +http.createServer(function (req, res) { + res.writeHead(200, {'Content-Length': 12, 'Content-Type': 'text/plain'}) + .end('Hello World\n'); +}).listen(7080); diff --git a/test/node/require_shim/es_modules_http_indirect/app.js b/test/node/require_shim/es_modules_http_indirect/app.js new file mode 100644 index 00000000..535befba --- /dev/null +++ b/test/node/require_shim/es_modules_http_indirect/app.js @@ -0,0 +1 @@ +import("./module.mjs") diff --git a/test/node/require_shim/es_modules_http_indirect/module.mjs b/test/node/require_shim/es_modules_http_indirect/module.mjs new file mode 100644 index 00000000..c7bcfe49 --- /dev/null +++ b/test/node/require_shim/es_modules_http_indirect/module.mjs @@ -0,0 +1,6 @@ +import http from "http" + +http.createServer(function (req, res) { + res.writeHead(200, {'Content-Length': 12, 'Content-Type': 'text/plain'}) + .end('Hello World\n'); +}).listen(7080); diff --git a/test/node/require_shim/es_modules_websocket/app.mjs b/test/node/require_shim/es_modules_websocket/app.mjs new file mode 100644 index 00000000..a71ffa9d --- /dev/null +++ b/test/node/require_shim/es_modules_websocket/app.mjs @@ -0,0 +1,30 @@ +import http from "http" +import websocket from "websocket" + +let server = http.createServer(function() {}); +let webSocketServer = websocket.server; + +server.listen(7080, function() {}); + +var wsServer = new webSocketServer({ + maxReceivedMessageSize: 0x1000000000, + maxReceivedFrameSize: 0x1000000000, + fragmentOutgoingMessages: false, + fragmentationThreshold: 0x1000000000, + httpServer: server, +}); + +wsServer.on('request', function(request) { + var connection = request.accept(null); + + connection.on('message', function(message) { + if (message.type === 'utf8') { + connection.send(message.utf8Data); + } else if (message.type === 'binary') { + connection.send(message.binaryData); + } + + }); + + connection.on('close', function(r) {}); +}); diff --git a/test/node/require_shim/es_modules_websocket_indirect/app.js b/test/node/require_shim/es_modules_websocket_indirect/app.js new file mode 100644 index 00000000..535befba --- /dev/null +++ b/test/node/require_shim/es_modules_websocket_indirect/app.js @@ -0,0 +1 @@ +import("./module.mjs") diff --git a/test/node/require_shim/es_modules_websocket_indirect/module.mjs b/test/node/require_shim/es_modules_websocket_indirect/module.mjs new file mode 100644 index 00000000..a71ffa9d --- /dev/null +++ b/test/node/require_shim/es_modules_websocket_indirect/module.mjs @@ -0,0 +1,30 @@ +import http from "http" +import websocket from "websocket" + +let server = http.createServer(function() {}); +let webSocketServer = websocket.server; + +server.listen(7080, function() {}); + +var wsServer = new webSocketServer({ + maxReceivedMessageSize: 0x1000000000, + maxReceivedFrameSize: 0x1000000000, + fragmentOutgoingMessages: false, + fragmentationThreshold: 0x1000000000, + httpServer: server, +}); + +wsServer.on('request', function(request) { + var connection = request.accept(null); + + connection.on('message', function(message) { + if (message.type === 'utf8') { + connection.send(message.utf8Data); + } else if (message.type === 'binary') { + connection.send(message.binaryData); + } + + }); + + connection.on('close', function(r) {}); +}); diff --git a/test/node/require_shim/transitive_dependency/app.js b/test/node/require_shim/transitive_dependency/app.js new file mode 100644 index 00000000..aaca5216 --- /dev/null +++ b/test/node/require_shim/transitive_dependency/app.js @@ -0,0 +1 @@ +require("./transitive_http") diff --git a/test/node/require_shim/transitive_dependency/transitive_http.js b/test/node/require_shim/transitive_dependency/transitive_http.js new file mode 100644 index 00000000..f1eb98e5 --- /dev/null +++ b/test/node/require_shim/transitive_dependency/transitive_http.js @@ -0,0 +1,8 @@ +const http = require("http"); + +http.createServer(function (req, res) { + res.writeHead(200, {'Content-Length': 12, 'Content-Type': 'text/plain'}) + .end('Hello World\n'); +}).listen(7080); + +module.exports = http; diff --git a/test/node/require_shim/unit_http/app.js b/test/node/require_shim/unit_http/app.js new file mode 100644 index 00000000..9172e44f --- /dev/null +++ b/test/node/require_shim/unit_http/app.js @@ -0,0 +1,4 @@ +require("unit-http").createServer(function (req, res) { + res.writeHead(200, {'Content-Length': 12, 'Content-Type': 'text/plain'}) + .end('Hello World\n'); +}).listen(7080); diff --git a/test/node/set_header_array/app.js b/test/node/set_header_array/app.js old mode 100755 new mode 100644 index faac45c7..965330e2 --- a/test/node/set_header_array/app.js +++ b/test/node/set_header_array/app.js @@ -1,6 +1,5 @@ -#!/usr/bin/env node -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { res.setHeader('Set-Cookie', ['tc=one,two,three', 'tc=four,five,six']); res.end(); }).listen(7080); diff --git a/test/node/status_message/app.js b/test/node/status_message/app.js old mode 100755 new mode 100644 index e8a798dd..ba51d35b --- a/test/node/status_message/app.js +++ b/test/node/status_message/app.js @@ -1,5 +1,4 @@ -#!/usr/bin/env node -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { res.writeHead(200, 'blah', {'Content-Type': 'text/plain'}).end(); }).listen(7080); diff --git a/test/node/update_header/app.js b/test/node/update_header/app.js old mode 100755 new mode 100644 index 0c5cd237..905ac294 --- a/test/node/update_header/app.js +++ b/test/node/update_header/app.js @@ -1,6 +1,5 @@ -#!/usr/bin/env node -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { res.setHeader('X-Header', 'test'); res.setHeader('X-Header', 'new'); res.end(); diff --git a/test/node/variables/app.js b/test/node/variables/app.js old mode 100755 new mode 100644 index d8cdc20c..a569dddd --- a/test/node/variables/app.js +++ b/test/node/variables/app.js @@ -1,6 +1,5 @@ -#!/usr/bin/env node -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { let body = ''; req.on('data', chunk => { body += chunk.toString(); diff --git a/test/node/websockets/mirror/app.js b/test/node/websockets/mirror/app.js old mode 100755 new mode 100644 index 23746465..0443adb2 --- a/test/node/websockets/mirror/app.js +++ b/test/node/websockets/mirror/app.js @@ -1,9 +1,6 @@ -#!/usr/bin/env node -server = require('unit-http').createServer(function() {}); -webSocketServer = require('unit-http/websocket').server; -//server = require('http').createServer(function() {}); -//webSocketServer = require('websocket').server; +server = require('http').createServer(function() {}); +webSocketServer = require('websocket').server; server.listen(7080, function() {}); diff --git a/test/node/websockets/mirror_fragmentation/app.js b/test/node/websockets/mirror_fragmentation/app.js old mode 100755 new mode 100644 index 7024252a..ea580ac2 --- a/test/node/websockets/mirror_fragmentation/app.js +++ b/test/node/websockets/mirror_fragmentation/app.js @@ -1,9 +1,6 @@ -#!/usr/bin/env node -server = require('unit-http').createServer(function() {}); -webSocketServer = require('unit-http/websocket').server; -//server = require('http').createServer(function() {}); -//webSocketServer = require('websocket').server; +server = require('http').createServer(function() {}); +webSocketServer = require('websocket').server; server.listen(7080, function() {}); diff --git a/test/node/write_before_write_head/app.js b/test/node/write_before_write_head/app.js old mode 100755 new mode 100644 index 724b0efb..2293111a --- a/test/node/write_before_write_head/app.js +++ b/test/node/write_before_write_head/app.js @@ -1,6 +1,5 @@ -#!/usr/bin/env node -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { res.write('blah'); res.writeHead(200, {'Content-Type': 'text/plain'}).end(); }).listen(7080); diff --git a/test/node/write_buffer/app.js b/test/node/write_buffer/app.js old mode 100755 new mode 100644 index a7623523..506e8613 --- a/test/node/write_buffer/app.js +++ b/test/node/write_buffer/app.js @@ -1,6 +1,5 @@ -#!/usr/bin/env node -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}) .end(new Buffer([0x62, 0x75, 0x66, 0x66, 0x65, 0x72])); }).listen(7080); diff --git a/test/node/write_callback/app.js b/test/node/write_callback/app.js old mode 100755 new mode 100644 index 3a9e51e8..71eb4116 --- a/test/node/write_callback/app.js +++ b/test/node/write_callback/app.js @@ -1,8 +1,7 @@ -#!/usr/bin/env node var fs = require('fs'); -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); var a = 'world'; res.write('hello', 'utf8', function() { diff --git a/test/node/write_multiple/app.js b/test/node/write_multiple/app.js old mode 100755 new mode 100644 index 3cbb3b86..e9c51ae0 --- a/test/node/write_multiple/app.js +++ b/test/node/write_multiple/app.js @@ -1,6 +1,5 @@ -#!/usr/bin/env node -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain', 'Content-Length': 14}); res.write('write'); res.write('write2'); diff --git a/test/node/write_return/app.js b/test/node/write_return/app.js old mode 100755 new mode 100644 index 82dfbc6e..345b6c4b --- a/test/node/write_return/app.js +++ b/test/node/write_return/app.js @@ -1,6 +1,5 @@ -#!/usr/bin/env node -require('unit-http').createServer(function (req, res) { +require('http').createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}) .end(res.write('body').toString()); }).listen(7080); diff --git a/test/test_node_application.py b/test/test_node_application.py index 52ad72ee..59601ff0 100644 --- a/test/test_node_application.py +++ b/test/test_node_application.py @@ -9,13 +9,26 @@ from unit.utils import waitforfiles class TestNodeApplication(TestApplicationNode): prerequisites = {'modules': {'node': 'all'}} - def test_node_application_basic(self): - self.load('basic') - + def assert_basic_application(self): resp = self.get() assert resp['headers']['Content-Type'] == 'text/plain', 'basic header' assert resp['body'] == 'Hello World\n', 'basic body' + def test_node_application_basic(self): + self.load('basic') + + self.assert_basic_application() + + def test_node_application_require_shim_unit_http(self): + self.load('require_shim/unit_http') + + self.assert_basic_application() + + def test_node_application_require_shim_transitive_dependency(self): + self.load('require_shim/transitive_dependency') + + self.assert_basic_application() + def test_node_application_seq(self): self.load('basic') diff --git a/test/test_node_es_modules.py b/test/test_node_es_modules.py new file mode 100644 index 00000000..ce27e474 --- /dev/null +++ b/test/test_node_es_modules.py @@ -0,0 +1,50 @@ +import pytest + +from distutils.version import LooseVersion +from unit.applications.lang.node import TestApplicationNode +from unit.applications.websockets import TestApplicationWebsocket + + +class TestNodeESModules(TestApplicationNode): + prerequisites = { + 'modules': { + 'node': lambda v: LooseVersion(v) >= LooseVersion("14.16.0") + } + } + + es_modules = True + ws = TestApplicationWebsocket() + + def assert_basic_application(self): + resp = self.get() + assert resp['headers']['Content-Type'] == 'text/plain', 'basic header' + assert resp['body'] == 'Hello World\n', 'basic body' + + def test_node_es_modules_require_shim_http(self): + self.load('require_shim/es_modules_http', name="app.mjs") + + self.assert_basic_application() + + def test_node_es_modules_require_shim_http_indirect(self): + self.load('require_shim/es_modules_http_indirect', name="app.js") + + self.assert_basic_application() + + def test_node_es_modules_require_shim_websockets(self): + self.load('require_shim/es_modules_websocket', name="app.mjs") + + 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() diff --git a/test/unit/applications/lang/node.py b/test/unit/applications/lang/node.py index cc6d06ef..3254f3d4 100644 --- a/test/unit/applications/lang/node.py +++ b/test/unit/applications/lang/node.py @@ -7,15 +7,16 @@ from unit.utils import public_dir class TestApplicationNode(TestApplicationProto): + application_type = "node" + es_modules = False + def prepare_env(self, script): # copy application - shutil.copytree( option.test_dir + '/node/' + script, option.temp_dir + '/node' ) # copy modules - shutil.copytree( option.current_dir + '/node/node_modules', option.temp_dir + '/node/node_modules', @@ -26,6 +27,19 @@ class TestApplicationNode(TestApplicationProto): def load(self, script, name='app.js', **kwargs): self.prepare_env(script) + if self.es_modules: + arguments = [ + "node", + "--loader", + "unit-http/require_shim.mjs", + "--require", + "unit-http/require_shim", + name, + ] + + else: + arguments = ["node", "--require", "unit-http/require_shim", name] + self._load_conf( { "listeners": { @@ -36,7 +50,8 @@ class TestApplicationNode(TestApplicationProto): "type": "external", "processes": {"spare": 0}, "working_directory": option.temp_dir + '/node', - "executable": name, + "executable": '/usr/bin/env', + "arguments": arguments, } }, }, diff --git a/test/unit/check/node.py b/test/unit/check/node.py index 236ba7b5..e053a749 100644 --- a/test/unit/check/node.py +++ b/test/unit/check/node.py @@ -1,6 +1,15 @@ import os +import subprocess def check_node(current_dir): - if os.path.exists(current_dir + '/node/node_modules'): - return True + if not os.path.exists(current_dir + '/node/node_modules'): + return None + + try: + v_bytes = subprocess.check_output(['/usr/bin/env', 'node', '-v']) + + return [str(v_bytes, 'utf-8').lstrip('v').rstrip()] + + except subprocess.CalledProcessError: + return None -- cgit From 25603eae9f8d3c2a6af3c5efb12b4a826776e300 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Wed, 12 May 2021 14:37:25 +0100 Subject: Tests: added test for TLS with IP in SAN. --- test/test_tls.py | 23 +++++++++++++++++++++++ test/unit/applications/tls.py | 9 +++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/test_tls.py b/test/test_tls.py index d4d1900c..3ab6f7d7 100644 --- a/test/test_tls.py +++ b/test/test_tls.py @@ -423,6 +423,29 @@ basicConstraints = critical,CA:TRUE""" }, 'subject alt_names' assert cert['chain'][0]['issuer']['common_name'] == 'root', 'issuer' + def test_tls_certificate_empty_cn_san_ip(self): + self.certificate('root', False) + + self.openssl_conf( + rewrite=True, + alt_names=['example.com', 'www.example.net', 'IP|10.0.0.1'], + ) + + self.req(subject='/') + + self.generate_ca_conf() + self.ca() + + self.set_certificate_req_context() + + assert 'success' in self.certificate_load('localhost', 'localhost') + + cert = self.conf_get('/certificates/localhost') + assert cert['chain'][0]['subject'] == { + 'alt_names': ['example.com', 'www.example.net'] + }, 'subject alt_names' + assert cert['chain'][0]['issuer']['common_name'] == 'root', 'issuer' + @pytest.mark.skip('not yet') def test_tls_reconfigure(self): self.load('empty') diff --git a/test/unit/applications/tls.py b/test/unit/applications/tls.py index 95eeac55..583b618f 100644 --- a/test/unit/applications/tls.py +++ b/test/unit/applications/tls.py @@ -76,9 +76,14 @@ class TestApplicationTLS(TestApplicationProto): # Generates alt_names section with dns names a_names = "[alt_names]\n" for i, k in enumerate(alt_names, 1): - a_names += "DNS.%d = %s\n" % (i, k) + k = k.split('|') - # Generates section for sign request extension + if k[0] == 'IP': + a_names += "IP.%d = %s\n" % (i, k[1]) + else: + a_names += "DNS.%d = %s\n" % (i, k[0]) + + # Generates section for sign request extension a_sec = """req_extensions = myca_req_extensions [ myca_req_extensions ] -- cgit From 1198118b3b987930c508d78d90af909eec1835db Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Mon, 17 May 2021 15:39:15 +0100 Subject: Tests: fixed incorrect "--restart" mode performing. --- test/conftest.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/test/conftest.py b/test/conftest.py index c2781571..5ea4e49d 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -355,7 +355,9 @@ def run(request): fds_diff = waitforfds(lambda: _count_fds(ps['pid']) - ps['fds']) ps['fds'] += fds_diff - assert ps['pid'] == ps_pid, 'same pid %s' % name + if not option.restart: + assert ps['pid'] == ps_pid, 'same pid %s' % name + assert fds_diff <= option.fds_threshold, ( 'descriptors leak %s' % name ) @@ -573,7 +575,7 @@ def _count_fds(pid): ).decode() return len(out.splitlines()) - except (FileNotFoundError, subprocess.CalledProcessError): + except (FileNotFoundError, TypeError, subprocess.CalledProcessError): pass try: @@ -582,7 +584,7 @@ def _count_fds(pid): ).decode() return len(out.splitlines()) - except (FileNotFoundError, subprocess.CalledProcessError): + except (FileNotFoundError, TypeError, subprocess.CalledProcessError): pass return 0 @@ -675,6 +677,6 @@ def pytest_sessionfinish(session): public_dir(option.cache_dir) shutil.rmtree(option.cache_dir) - if not option.save_log: + if not option.save_log and os.path.isdir(option.temp_dir): public_dir(option.temp_dir) shutil.rmtree(option.temp_dir) -- cgit From 2f0cca2e2b48f3f96056bac14e216f1248f8d4a8 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Tue, 18 May 2021 16:35:54 +0100 Subject: Tests: added test to check port release. --- test/test_configuration.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'test') diff --git a/test/test_configuration.py b/test/test_configuration.py index 7feb3adb..880aef6c 100644 --- a/test/test_configuration.py +++ b/test/test_configuration.py @@ -1,5 +1,6 @@ import pytest +import socket from unit.control import TestControl @@ -261,6 +262,33 @@ class TestConfiguration(TestControl): } ), 'explicit ipv6' + def test_listeners_port_release(self): + for i in range(10): + fail = False + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + self.conf( + { + "listeners": {"127.0.0.1:7080": {"pass": "routes"}}, + "routes": [], + } + ) + + resp = self.conf({"listeners": {}, "applications": {}}) + + try: + s.bind(('127.0.0.1', 7080)) + s.listen() + + except OSError: + fail = True + + if fail: + pytest.fail('cannot bind or listen to the address') + + assert 'success' in resp, 'port release' + @pytest.mark.skip('not yet, unsafe') def test_listeners_no_port(self): assert 'error' in self.conf( -- cgit From e50bb120e2a2dfad55d28724133656264ef13dc8 Mon Sep 17 00:00:00 2001 From: Oisin Canty Date: Thu, 20 May 2021 13:03:12 +0000 Subject: Tests: Python targets. --- test/python/lifespan/empty/asgi.py | 16 ++++-- test/python/targets/asgi.py | 54 ++++++++++++++++++++ test/python/targets/wsgi.py | 8 +++ test/test_asgi_lifespan.py | 95 +++++++++++++++++++++++++---------- test/test_asgi_targets.py | 92 +++++++++++++++++++++++++++++++++ test/test_python_targets.py | 51 +++++++++++++++++++ test/unit/applications/lang/python.py | 11 +++- 7 files changed, 295 insertions(+), 32 deletions(-) create mode 100644 test/python/targets/asgi.py create mode 100644 test/python/targets/wsgi.py create mode 100644 test/test_asgi_targets.py create mode 100644 test/test_python_targets.py (limited to 'test') diff --git a/test/python/lifespan/empty/asgi.py b/test/python/lifespan/empty/asgi.py index ea43af13..8ceecc2f 100644 --- a/test/python/lifespan/empty/asgi.py +++ b/test/python/lifespan/empty/asgi.py @@ -1,19 +1,19 @@ import os -async def application(scope, receive, send): +async def handler(prefix, scope, receive, send): if scope['type'] == 'lifespan': - with open('version', 'w+') as f: + with open(prefix + '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') + os.remove(prefix + 'startup') await send({'type': 'lifespan.startup.complete'}) elif message['type'] == 'lifespan.shutdown': - os.remove('shutdown') + os.remove(prefix + 'shutdown') await send({'type': 'lifespan.shutdown.complete'}) return @@ -25,3 +25,11 @@ async def application(scope, receive, send): 'headers': [(b'content-length', b'0'),], } ) + + +async def application(scope, receive, send): + return await handler('', scope, receive, send) + + +async def application2(scope, receive, send): + return await handler('app2_', scope, receive, send) diff --git a/test/python/targets/asgi.py b/test/python/targets/asgi.py new file mode 100644 index 00000000..b51f3964 --- /dev/null +++ b/test/python/targets/asgi.py @@ -0,0 +1,54 @@ +async def application_201(scope, receive, send): + assert scope['type'] == 'http' + + await send( + { + 'type': 'http.response.start', + 'status': 201, + 'headers': [(b'content-length', b'0')], + } + ) + + +async def application_200(scope, receive, send): + assert scope['type'] == 'http' + + await send( + { + 'type': 'http.response.start', + 'status': 200, + 'headers': [(b'content-length', b'0')], + } + ) + + +def legacy_application_200(scope): + assert scope['type'] == 'http' + + return legacy_app_http_200 + + +async def legacy_app_http_200(receive, send): + await send( + { + 'type': 'http.response.start', + 'status': 200, + 'headers': [(b'content-length', b'0')], + } + ) + + +def legacy_application_201(scope, receive=None, send=None): + assert scope['type'] == 'http' + + return legacy_app_http_201 + + +async def legacy_app_http_201(receive, send): + await send( + { + 'type': 'http.response.start', + 'status': 201, + 'headers': [(b'content-length', b'0')], + } + ) diff --git a/test/python/targets/wsgi.py b/test/python/targets/wsgi.py new file mode 100644 index 00000000..fa17ab87 --- /dev/null +++ b/test/python/targets/wsgi.py @@ -0,0 +1,8 @@ +def wsgi_target_a(env, start_response): + start_response('200', [('Content-Length', '1')]) + return [b'1'] + + +def wsgi_target_b(env, start_response): + start_response('200', [('Content-Length', '1')]) + return [b'2'] diff --git a/test/test_asgi_lifespan.py b/test/test_asgi_lifespan.py index 43286e22..90866ec3 100644 --- a/test/test_asgi_lifespan.py +++ b/test/test_asgi_lifespan.py @@ -14,45 +14,88 @@ class TestASGILifespan(TestApplicationPython): } load_module = 'asgi' - def test_asgi_lifespan(self): - self.load('lifespan/empty') + def setup_cookies(self, prefix): + base_dir = option.test_dir + '/python/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(base_dir, 0o777) - os.chmod(option.test_dir + '/python/lifespan/empty', 0o777) + for name in ['startup', 'shutdown', 'version']: + path = option.test_dir + '/python/lifespan/empty/' + prefix + name + open(path, 'a').close() + os.chmod(path, 0o777) - open(startup_path, 'a').close() - os.chmod(startup_path, 0o777) + def assert_cookies(self, prefix): + for name in ['startup', 'shutdown']: + path = option.test_dir + '/python/lifespan/empty/' + prefix + name + exists = os.path.isfile(path) + if exists: + os.remove(path) - open(shutdown_path, 'a').close() - os.chmod(shutdown_path, 0o777) + assert not exists, name - open(version_path, 'a').close() - os.chmod(version_path, 0o777) + path = option.test_dir + '/python/lifespan/empty/' + prefix + 'version' - assert self.get()['status'] == 204 + with open(path, 'r') as f: + version = f.read() - unit_stop() + os.remove(path) - is_startup = os.path.isfile(startup_path) - is_shutdown = os.path.isfile(shutdown_path) + assert version == '3.0 2.0', 'version' - if is_startup: - os.remove(startup_path) + def test_asgi_lifespan(self): + self.load('lifespan/empty') - if is_shutdown: - os.remove(shutdown_path) + self.setup_cookies('') - with open(version_path, 'r') as f: - version = f.read() + assert self.get()['status'] == 204 - os.remove(version_path) + unit_stop() - assert not is_startup, 'startup' - assert not is_shutdown, 'shutdown' - assert version == '3.0 2.0', 'version' + self.assert_cookies('') + + def test_asgi_lifespan_targets(self): + 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"}, + }, + ], + "applications": { + "targets": { + "type": "python", + "processes": {"spare": 0}, + "working_directory": option.test_dir + + "/python/lifespan/empty", + "path": option.test_dir + '/python/lifespan/empty', + "targets": { + "1": {"module": "asgi", "callable": "application"}, + "2": { + "module": "asgi", + "callable": "application2", + }, + }, + } + }, + } + ) + + self.setup_cookies('') + self.setup_cookies('app2_') + + assert self.get(url="/1")['status'] == 204 + assert self.get(url="/2")['status'] == 204 + + unit_stop() + + self.assert_cookies('') + self.assert_cookies('app2_') def test_asgi_lifespan_failed(self): self.load('lifespan/failed') diff --git a/test/test_asgi_targets.py b/test/test_asgi_targets.py new file mode 100644 index 00000000..a0eb1f84 --- /dev/null +++ b/test/test_asgi_targets.py @@ -0,0 +1,92 @@ +from distutils.version import LooseVersion + +import pytest + +from unit.applications.lang.python import TestApplicationPython +from unit.option import option + + +class TestASGITargets(TestApplicationPython): + prerequisites = { + 'modules': {'python': lambda v: LooseVersion(v) >= LooseVersion('3.5')} + } + load_module = 'asgi' + + @pytest.fixture(autouse=True) + def setup_method_fixture(self): + 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"}, + }, + ], + "applications": { + "targets": { + "type": "python", + "processes": {"spare": 0}, + "working_directory": option.test_dir + + "/python/targets/", + "path": option.test_dir + '/python/targets/', + "protocol": "asgi", + "targets": { + "1": { + "module": "asgi", + "callable": "application_200", + }, + "2": { + "module": "asgi", + "callable": "application_201", + }, + }, + } + }, + } + ) + + def conf_targets(self, targets): + assert 'success' in self.conf(targets, 'applications/targets/targets') + + def test_asgi_targets(self): + assert self.get(url='/1')['status'] == 200 + assert self.get(url='/2')['status'] == 201 + + def test_asgi_targets_legacy(self): + self.conf_targets( + { + "1": {"module": "asgi", "callable": "legacy_application_200"}, + "2": {"module": "asgi", "callable": "legacy_application_201"}, + } + ) + + assert self.get(url='/1')['status'] == 200 + assert self.get(url='/2')['status'] == 201 + + def test_asgi_targets_mix(self): + self.conf_targets( + { + "1": {"module": "asgi", "callable": "application_200"}, + "2": {"module": "asgi", "callable": "legacy_application_201"}, + } + ) + + assert self.get(url='/1')['status'] == 200 + assert self.get(url='/2')['status'] == 201 + + def test_asgi_targets_broken(self, skip_alert): + skip_alert(r'Python failed to get "blah" from module') + + self.conf_targets( + { + "1": {"module": "asgi", "callable": "application_200"}, + "2": {"module": "asgi", "callable": "blah"}, + } + ) + + assert self.get(url='/1')['status'] != 200 diff --git a/test/test_python_targets.py b/test/test_python_targets.py new file mode 100644 index 00000000..ca736c0d --- /dev/null +++ b/test/test_python_targets.py @@ -0,0 +1,51 @@ +import pytest + +from unit.applications.lang.python import TestApplicationPython +from unit.option import option + + +class TestPythonTargets(TestApplicationPython): + prerequisites = {'modules': {'python': 'all'}} + + def test_python_targets(self): + 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"}, + }, + ], + "applications": { + "targets": { + "type": "python", + "working_directory": option.test_dir + + "/python/targets/", + "path": option.test_dir + '/python/targets/', + "targets": { + "1": { + "module": "wsgi", + "callable": "wsgi_target_a", + }, + "2": { + "module": "wsgi", + "callable": "wsgi_target_b", + }, + }, + } + }, + } + ) + + resp = self.get(url='/1') + assert resp['status'] == 200 + assert resp['body'] == '1' + + resp = self.get(url='/2') + assert resp['status'] == 200 + assert resp['body'] == '2' diff --git a/test/unit/applications/lang/python.py b/test/unit/applications/lang/python.py index 287d23f0..b399dffd 100644 --- a/test/unit/applications/lang/python.py +++ b/test/unit/applications/lang/python.py @@ -42,8 +42,15 @@ class TestApplicationPython(TestApplicationProto): "module": module, } - for attr in ('callable', 'home', 'limits', 'path', 'protocol', - 'threads'): + for attr in ( + 'callable', + 'home', + 'limits', + 'path', + 'protocol', + 'targets', + 'threads', + ): if attr in kwargs: app[attr] = kwargs.pop(attr) -- cgit From d6439002371d0bc73183c9d3d28df4f62ce0b972 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Mon, 24 May 2021 04:33:42 +0100 Subject: Tests: minor fixes. --- test/test_routing.py | 90 ++++++++++-------------------------------------- test/test_share_mount.py | 12 +++---- 2 files changed, 25 insertions(+), 77 deletions(-) (limited to 'test') diff --git a/test/test_routing.py b/test/test_routing.py index 7392c1ab..eaa0a134 100644 --- a/test/test_routing.py +++ b/test/test_routing.py @@ -1041,83 +1041,31 @@ class TestRouting(TestApplicationProto): } ) + def check_headers(hds): + hds = dict({"Host": "localhost", "Connection": "close"}, **hds) + assert ( + self.get(headers=hds)['status'] == 200 + ), 'headers array match' + + def check_headers_404(hds): + hds = dict({"Host": "localhost", "Connection": "close"}, **hds) + assert ( + self.get(headers=hds)['status'] == 404 + ), 'headers array no match' + 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' - assert ( - self.get( - headers={ - "Host": "localhost", - "x-header2": "bar", - "Connection": "close", - } - )['status'] - == 200 - ), 'match headers array 3' - assert ( - self.get( - headers={ - "Host": "localhost", - "x-header3": "bar", - "Connection": "close", - } - )['status'] - == 200 - ), 'match headers array 4' - assert ( - self.get( - headers={ - "Host": "localhost", - "x-header1": "bar", - "Connection": "close", - } - )['status'] - == 404 - ), 'match headers array 5' - assert ( - self.get( - headers={ - "Host": "localhost", - "x-header1": "bar", - "x-header4": "foo", - "Connection": "close", - } - )['status'] - == 200 - ), 'match headers array 6' + check_headers({"x-header1": "foo123"}) + check_headers({"x-header2": "bar"}) + check_headers({"x-header3": "bar"}) + check_headers_404({"x-header1": "bar"}) + check_headers({"x-header1": "bar", "x-header4": "foo"}) assert 'success' in self.conf_delete( 'routes/0/match/headers/1' ), 'match headers array configure 2' - assert ( - self.get( - headers={ - "Host": "localhost", - "x-header2": "bar", - "Connection": "close", - } - )['status'] - == 404 - ), 'match headers array 7' - assert ( - self.get( - headers={ - "Host": "localhost", - "x-header3": "foo", - "Connection": "close", - } - )['status'] - == 200 - ), 'match headers array 8' + check_headers_404({"x-header2": "bar"}) + check_headers({"x-header3": "foo"}) def test_routes_match_arguments(self): self.route_match({"arguments": {"foo": "bar"}}) diff --git a/test/test_share_mount.py b/test/test_share_mount.py index f46e1279..f22fbe75 100644 --- a/test/test_share_mount.py +++ b/test/test_share_mount.py @@ -70,8 +70,8 @@ class TestShareMount(TestApplicationProto): skip_alert(r'opening.*failed') resp = self.get(url='/mount/') - resp['status'] == 200 - resp['body'] == 'mount' + assert resp['status'] == 200 + assert resp['body'] == 'mount' assert 'success' in self.conf( {"share": temp_dir + "/assets/dir", "traverse_mounts": False}, @@ -86,8 +86,8 @@ class TestShareMount(TestApplicationProto): ), 'configure mount enable' resp = self.get(url='/mount/') - resp['status'] == 200 - resp['body'] == 'mount' + assert resp['status'] == 200 + assert resp['body'] == 'mount' def test_share_mount_two_blocks(self, temp_dir, skip_alert): skip_alert(r'opening.*failed') @@ -128,7 +128,7 @@ class TestShareMount(TestApplicationProto): 'routes/0/action', ), 'configure chroot mount default' - self.get(url='/mount/')['status'] == 200, 'chroot' + assert self.get(url='/mount/')['status'] == 200, 'chroot' assert 'success' in self.conf( { @@ -139,4 +139,4 @@ class TestShareMount(TestApplicationProto): 'routes/0/action', ), 'configure chroot mount disable' - self.get(url='/mount/')['status'] == 403, 'chroot mount' + assert self.get(url='/mount/')['status'] == 403, 'chroot mount' -- cgit From c160ea11e4ece4db52731ac8b83dd09ca2d1ef11 Mon Sep 17 00:00:00 2001 From: Oisin Canty Date: Mon, 24 May 2021 09:01:42 +0000 Subject: Node.js: renamed "require_shim" to "loader". --- test/node/loader/es_modules_http/app.mjs | 6 +++++ test/node/loader/es_modules_http_indirect/app.js | 1 + .../loader/es_modules_http_indirect/module.mjs | 6 +++++ test/node/loader/es_modules_websocket/app.mjs | 30 ++++++++++++++++++++++ .../loader/es_modules_websocket_indirect/app.js | 1 + .../es_modules_websocket_indirect/module.mjs | 30 ++++++++++++++++++++++ test/node/loader/transitive_dependency/app.js | 1 + .../transitive_dependency/transitive_http.js | 8 ++++++ test/node/loader/unit_http/app.js | 4 +++ test/node/require_shim/es_modules_http/app.mjs | 6 ----- .../require_shim/es_modules_http_indirect/app.js | 1 - .../es_modules_http_indirect/module.mjs | 6 ----- .../node/require_shim/es_modules_websocket/app.mjs | 30 ---------------------- .../es_modules_websocket_indirect/app.js | 1 - .../es_modules_websocket_indirect/module.mjs | 30 ---------------------- .../node/require_shim/transitive_dependency/app.js | 1 - .../transitive_dependency/transitive_http.js | 8 ------ test/node/require_shim/unit_http/app.js | 4 --- test/test_node_application.py | 8 +++--- test/test_node_es_modules.py | 12 ++++----- test/unit/applications/lang/node.py | 6 ++--- 21 files changed, 100 insertions(+), 100 deletions(-) create mode 100644 test/node/loader/es_modules_http/app.mjs create mode 100644 test/node/loader/es_modules_http_indirect/app.js create mode 100644 test/node/loader/es_modules_http_indirect/module.mjs create mode 100644 test/node/loader/es_modules_websocket/app.mjs create mode 100644 test/node/loader/es_modules_websocket_indirect/app.js create mode 100644 test/node/loader/es_modules_websocket_indirect/module.mjs create mode 100644 test/node/loader/transitive_dependency/app.js create mode 100644 test/node/loader/transitive_dependency/transitive_http.js create mode 100644 test/node/loader/unit_http/app.js delete mode 100644 test/node/require_shim/es_modules_http/app.mjs delete mode 100644 test/node/require_shim/es_modules_http_indirect/app.js delete mode 100644 test/node/require_shim/es_modules_http_indirect/module.mjs delete mode 100644 test/node/require_shim/es_modules_websocket/app.mjs delete mode 100644 test/node/require_shim/es_modules_websocket_indirect/app.js delete mode 100644 test/node/require_shim/es_modules_websocket_indirect/module.mjs delete mode 100644 test/node/require_shim/transitive_dependency/app.js delete mode 100644 test/node/require_shim/transitive_dependency/transitive_http.js delete mode 100644 test/node/require_shim/unit_http/app.js (limited to 'test') diff --git a/test/node/loader/es_modules_http/app.mjs b/test/node/loader/es_modules_http/app.mjs new file mode 100644 index 00000000..c7bcfe49 --- /dev/null +++ b/test/node/loader/es_modules_http/app.mjs @@ -0,0 +1,6 @@ +import http from "http" + +http.createServer(function (req, res) { + res.writeHead(200, {'Content-Length': 12, 'Content-Type': 'text/plain'}) + .end('Hello World\n'); +}).listen(7080); diff --git a/test/node/loader/es_modules_http_indirect/app.js b/test/node/loader/es_modules_http_indirect/app.js new file mode 100644 index 00000000..535befba --- /dev/null +++ b/test/node/loader/es_modules_http_indirect/app.js @@ -0,0 +1 @@ +import("./module.mjs") diff --git a/test/node/loader/es_modules_http_indirect/module.mjs b/test/node/loader/es_modules_http_indirect/module.mjs new file mode 100644 index 00000000..c7bcfe49 --- /dev/null +++ b/test/node/loader/es_modules_http_indirect/module.mjs @@ -0,0 +1,6 @@ +import http from "http" + +http.createServer(function (req, res) { + res.writeHead(200, {'Content-Length': 12, 'Content-Type': 'text/plain'}) + .end('Hello World\n'); +}).listen(7080); diff --git a/test/node/loader/es_modules_websocket/app.mjs b/test/node/loader/es_modules_websocket/app.mjs new file mode 100644 index 00000000..a71ffa9d --- /dev/null +++ b/test/node/loader/es_modules_websocket/app.mjs @@ -0,0 +1,30 @@ +import http from "http" +import websocket from "websocket" + +let server = http.createServer(function() {}); +let webSocketServer = websocket.server; + +server.listen(7080, function() {}); + +var wsServer = new webSocketServer({ + maxReceivedMessageSize: 0x1000000000, + maxReceivedFrameSize: 0x1000000000, + fragmentOutgoingMessages: false, + fragmentationThreshold: 0x1000000000, + httpServer: server, +}); + +wsServer.on('request', function(request) { + var connection = request.accept(null); + + connection.on('message', function(message) { + if (message.type === 'utf8') { + connection.send(message.utf8Data); + } else if (message.type === 'binary') { + connection.send(message.binaryData); + } + + }); + + connection.on('close', function(r) {}); +}); diff --git a/test/node/loader/es_modules_websocket_indirect/app.js b/test/node/loader/es_modules_websocket_indirect/app.js new file mode 100644 index 00000000..535befba --- /dev/null +++ b/test/node/loader/es_modules_websocket_indirect/app.js @@ -0,0 +1 @@ +import("./module.mjs") diff --git a/test/node/loader/es_modules_websocket_indirect/module.mjs b/test/node/loader/es_modules_websocket_indirect/module.mjs new file mode 100644 index 00000000..a71ffa9d --- /dev/null +++ b/test/node/loader/es_modules_websocket_indirect/module.mjs @@ -0,0 +1,30 @@ +import http from "http" +import websocket from "websocket" + +let server = http.createServer(function() {}); +let webSocketServer = websocket.server; + +server.listen(7080, function() {}); + +var wsServer = new webSocketServer({ + maxReceivedMessageSize: 0x1000000000, + maxReceivedFrameSize: 0x1000000000, + fragmentOutgoingMessages: false, + fragmentationThreshold: 0x1000000000, + httpServer: server, +}); + +wsServer.on('request', function(request) { + var connection = request.accept(null); + + connection.on('message', function(message) { + if (message.type === 'utf8') { + connection.send(message.utf8Data); + } else if (message.type === 'binary') { + connection.send(message.binaryData); + } + + }); + + connection.on('close', function(r) {}); +}); diff --git a/test/node/loader/transitive_dependency/app.js b/test/node/loader/transitive_dependency/app.js new file mode 100644 index 00000000..aaca5216 --- /dev/null +++ b/test/node/loader/transitive_dependency/app.js @@ -0,0 +1 @@ +require("./transitive_http") diff --git a/test/node/loader/transitive_dependency/transitive_http.js b/test/node/loader/transitive_dependency/transitive_http.js new file mode 100644 index 00000000..f1eb98e5 --- /dev/null +++ b/test/node/loader/transitive_dependency/transitive_http.js @@ -0,0 +1,8 @@ +const http = require("http"); + +http.createServer(function (req, res) { + res.writeHead(200, {'Content-Length': 12, 'Content-Type': 'text/plain'}) + .end('Hello World\n'); +}).listen(7080); + +module.exports = http; diff --git a/test/node/loader/unit_http/app.js b/test/node/loader/unit_http/app.js new file mode 100644 index 00000000..9172e44f --- /dev/null +++ b/test/node/loader/unit_http/app.js @@ -0,0 +1,4 @@ +require("unit-http").createServer(function (req, res) { + res.writeHead(200, {'Content-Length': 12, 'Content-Type': 'text/plain'}) + .end('Hello World\n'); +}).listen(7080); diff --git a/test/node/require_shim/es_modules_http/app.mjs b/test/node/require_shim/es_modules_http/app.mjs deleted file mode 100644 index c7bcfe49..00000000 --- a/test/node/require_shim/es_modules_http/app.mjs +++ /dev/null @@ -1,6 +0,0 @@ -import http from "http" - -http.createServer(function (req, res) { - res.writeHead(200, {'Content-Length': 12, 'Content-Type': 'text/plain'}) - .end('Hello World\n'); -}).listen(7080); diff --git a/test/node/require_shim/es_modules_http_indirect/app.js b/test/node/require_shim/es_modules_http_indirect/app.js deleted file mode 100644 index 535befba..00000000 --- a/test/node/require_shim/es_modules_http_indirect/app.js +++ /dev/null @@ -1 +0,0 @@ -import("./module.mjs") diff --git a/test/node/require_shim/es_modules_http_indirect/module.mjs b/test/node/require_shim/es_modules_http_indirect/module.mjs deleted file mode 100644 index c7bcfe49..00000000 --- a/test/node/require_shim/es_modules_http_indirect/module.mjs +++ /dev/null @@ -1,6 +0,0 @@ -import http from "http" - -http.createServer(function (req, res) { - res.writeHead(200, {'Content-Length': 12, 'Content-Type': 'text/plain'}) - .end('Hello World\n'); -}).listen(7080); diff --git a/test/node/require_shim/es_modules_websocket/app.mjs b/test/node/require_shim/es_modules_websocket/app.mjs deleted file mode 100644 index a71ffa9d..00000000 --- a/test/node/require_shim/es_modules_websocket/app.mjs +++ /dev/null @@ -1,30 +0,0 @@ -import http from "http" -import websocket from "websocket" - -let server = http.createServer(function() {}); -let webSocketServer = websocket.server; - -server.listen(7080, function() {}); - -var wsServer = new webSocketServer({ - maxReceivedMessageSize: 0x1000000000, - maxReceivedFrameSize: 0x1000000000, - fragmentOutgoingMessages: false, - fragmentationThreshold: 0x1000000000, - httpServer: server, -}); - -wsServer.on('request', function(request) { - var connection = request.accept(null); - - connection.on('message', function(message) { - if (message.type === 'utf8') { - connection.send(message.utf8Data); - } else if (message.type === 'binary') { - connection.send(message.binaryData); - } - - }); - - connection.on('close', function(r) {}); -}); diff --git a/test/node/require_shim/es_modules_websocket_indirect/app.js b/test/node/require_shim/es_modules_websocket_indirect/app.js deleted file mode 100644 index 535befba..00000000 --- a/test/node/require_shim/es_modules_websocket_indirect/app.js +++ /dev/null @@ -1 +0,0 @@ -import("./module.mjs") diff --git a/test/node/require_shim/es_modules_websocket_indirect/module.mjs b/test/node/require_shim/es_modules_websocket_indirect/module.mjs deleted file mode 100644 index a71ffa9d..00000000 --- a/test/node/require_shim/es_modules_websocket_indirect/module.mjs +++ /dev/null @@ -1,30 +0,0 @@ -import http from "http" -import websocket from "websocket" - -let server = http.createServer(function() {}); -let webSocketServer = websocket.server; - -server.listen(7080, function() {}); - -var wsServer = new webSocketServer({ - maxReceivedMessageSize: 0x1000000000, - maxReceivedFrameSize: 0x1000000000, - fragmentOutgoingMessages: false, - fragmentationThreshold: 0x1000000000, - httpServer: server, -}); - -wsServer.on('request', function(request) { - var connection = request.accept(null); - - connection.on('message', function(message) { - if (message.type === 'utf8') { - connection.send(message.utf8Data); - } else if (message.type === 'binary') { - connection.send(message.binaryData); - } - - }); - - connection.on('close', function(r) {}); -}); diff --git a/test/node/require_shim/transitive_dependency/app.js b/test/node/require_shim/transitive_dependency/app.js deleted file mode 100644 index aaca5216..00000000 --- a/test/node/require_shim/transitive_dependency/app.js +++ /dev/null @@ -1 +0,0 @@ -require("./transitive_http") diff --git a/test/node/require_shim/transitive_dependency/transitive_http.js b/test/node/require_shim/transitive_dependency/transitive_http.js deleted file mode 100644 index f1eb98e5..00000000 --- a/test/node/require_shim/transitive_dependency/transitive_http.js +++ /dev/null @@ -1,8 +0,0 @@ -const http = require("http"); - -http.createServer(function (req, res) { - res.writeHead(200, {'Content-Length': 12, 'Content-Type': 'text/plain'}) - .end('Hello World\n'); -}).listen(7080); - -module.exports = http; diff --git a/test/node/require_shim/unit_http/app.js b/test/node/require_shim/unit_http/app.js deleted file mode 100644 index 9172e44f..00000000 --- a/test/node/require_shim/unit_http/app.js +++ /dev/null @@ -1,4 +0,0 @@ -require("unit-http").createServer(function (req, res) { - res.writeHead(200, {'Content-Length': 12, 'Content-Type': 'text/plain'}) - .end('Hello World\n'); -}).listen(7080); diff --git a/test/test_node_application.py b/test/test_node_application.py index 59601ff0..48ed8d3d 100644 --- a/test/test_node_application.py +++ b/test/test_node_application.py @@ -19,13 +19,13 @@ class TestNodeApplication(TestApplicationNode): self.assert_basic_application() - def test_node_application_require_shim_unit_http(self): - self.load('require_shim/unit_http') + def test_node_application_loader_unit_http(self): + self.load('loader/unit_http') self.assert_basic_application() - def test_node_application_require_shim_transitive_dependency(self): - self.load('require_shim/transitive_dependency') + def test_node_application_loader_transitive_dependency(self): + self.load('loader/transitive_dependency') self.assert_basic_application() diff --git a/test/test_node_es_modules.py b/test/test_node_es_modules.py index ce27e474..0945a967 100644 --- a/test/test_node_es_modules.py +++ b/test/test_node_es_modules.py @@ -20,18 +20,18 @@ class TestNodeESModules(TestApplicationNode): assert resp['headers']['Content-Type'] == 'text/plain', 'basic header' assert resp['body'] == 'Hello World\n', 'basic body' - def test_node_es_modules_require_shim_http(self): - self.load('require_shim/es_modules_http', name="app.mjs") + def test_node_es_modules_loader_http(self): + self.load('loader/es_modules_http', name="app.mjs") self.assert_basic_application() - def test_node_es_modules_require_shim_http_indirect(self): - self.load('require_shim/es_modules_http_indirect', name="app.js") + def test_node_es_modules_loader_http_indirect(self): + self.load('loader/es_modules_http_indirect', name="app.js") self.assert_basic_application() - def test_node_es_modules_require_shim_websockets(self): - self.load('require_shim/es_modules_websocket', name="app.mjs") + def test_node_es_modules_loader_websockets(self): + self.load('loader/es_modules_websocket', name="app.mjs") message = 'blah' diff --git a/test/unit/applications/lang/node.py b/test/unit/applications/lang/node.py index 3254f3d4..5d05c70c 100644 --- a/test/unit/applications/lang/node.py +++ b/test/unit/applications/lang/node.py @@ -31,14 +31,14 @@ class TestApplicationNode(TestApplicationProto): arguments = [ "node", "--loader", - "unit-http/require_shim.mjs", + "unit-http/loader.mjs", "--require", - "unit-http/require_shim", + "unit-http/loader", name, ] else: - arguments = ["node", "--require", "unit-http/require_shim", name] + arguments = ["node", "--require", "unit-http/loader", name] self._load_conf( { -- cgit From 1154ede862824331d24591c717c270e779a2b08c Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Mon, 24 May 2021 05:26:15 +0100 Subject: Tests: test_settings_send_timeout improved. Data length adjusts depending on socket buffer size when it's possible. --- test/python/body_generate/wsgi.py | 6 ++++++ test/test_settings.py | 25 +++++++++++++++++-------- test/unit/utils.py | 11 +++++++++++ 3 files changed, 34 insertions(+), 8 deletions(-) create mode 100644 test/python/body_generate/wsgi.py (limited to 'test') diff --git a/test/python/body_generate/wsgi.py b/test/python/body_generate/wsgi.py new file mode 100644 index 00000000..73462be6 --- /dev/null +++ b/test/python/body_generate/wsgi.py @@ -0,0 +1,6 @@ +def application(env, start_response): + length = env.get('HTTP_X_LENGTH', '10') + bytes = b'X' * int(length) + + start_response('200', [('Content-Length', length)]) + return [bytes] diff --git a/test/test_settings.py b/test/test_settings.py index d129dec9..ef4136e3 100644 --- a/test/test_settings.py +++ b/test/test_settings.py @@ -5,6 +5,7 @@ import time import pytest from unit.applications.lang.python import TestApplicationPython +from unit.utils import sysctl class TestSettings(TestApplicationPython): @@ -147,27 +148,35 @@ Connection: close assert resp['status'] == 200, 'status body read timeout update' def test_settings_send_timeout(self, temp_dir): - self.load('mirror') + self.load('body_generate') + + sysctl_out = sysctl() + values = re.findall( + r'net.core.[rw]mem_(?:max|default).*?(\d+)', sysctl_out + ) + values = [int(v) for v in values] - data_len = 1048576 + data_len = 1048576 if len(values) == 0 else 10 * max(values) self.conf({'http': {'send_timeout': 1}}, 'settings') addr = temp_dir + '/sock' - self.conf({"unix:" + addr: {'application': 'mirror'}}, 'listeners') + self.conf( + {"unix:" + addr: {'application': 'body_generate'}}, 'listeners' + ) sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.connect(addr) - req = """POST / HTTP/1.1 + req = ( + """GET / HTTP/1.1 Host: localhost -Content-Type: text/html -Content-Length: %d +X-Length: %d Connection: close -""" % data_len + ( - 'X' * data_len +""" + % data_len ) sock.sendall(req.encode()) diff --git a/test/unit/utils.py b/test/unit/utils.py index e80fc469..a627e9f5 100644 --- a/test/unit/utils.py +++ b/test/unit/utils.py @@ -61,6 +61,17 @@ def findmnt(): return out +def sysctl(): + try: + out = subprocess.check_output( + ['sysctl', '-a'], stderr=subprocess.STDOUT + ).decode() + except FileNotFoundError: + pytest.skip('requires sysctl') + + return out + + def waitformount(template, wait=50): for i in range(wait): if findmnt().find(template) != -1: -- cgit From 39c0fda24c23b7b5358f473349d04752a70ceecc Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Mon, 24 May 2021 22:28:23 +0100 Subject: Tests: added additional check in tests with timeouts. --- test/test_settings.py | 195 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 119 insertions(+), 76 deletions(-) (limited to 'test') diff --git a/test/test_settings.py b/test/test_settings.py index ef4136e3..49041b62 100644 --- a/test/test_settings.py +++ b/test/test_settings.py @@ -14,33 +14,42 @@ class TestSettings(TestApplicationPython): def test_settings_header_read_timeout(self): self.load('empty') - self.conf({'http': {'header_read_timeout': 2}}, 'settings') - - (resp, sock) = self.http( - b"""GET / HTTP/1.1 + def req(): + (resp, sock) = self.http( + b"""GET / HTTP/1.1 """, - start=True, - read_timeout=1, - raw=True, - ) + start=True, + read_timeout=1, + raw=True, + ) - time.sleep(3) + time.sleep(3) - resp = self.http( - b"""Host: localhost + return self.http( + b"""Host: localhost Connection: close -""", - sock=sock, - raw=True, + """, + sock=sock, + raw=True, + ) + + assert 'success' in self.conf( + {'http': {'header_read_timeout': 2}}, 'settings' ) + assert req()['status'] == 408, 'status header read timeout' - assert resp['status'] == 408, 'status header read timeout' + assert 'success' in self.conf( + {'http': {'header_read_timeout': 7}}, 'settings' + ) + assert req()['status'] == 200, 'status header read timeout 2' def test_settings_header_read_timeout_update(self): self.load('empty') - self.conf({'http': {'header_read_timeout': 4}}, 'settings') + assert 'success' in self.conf( + {'http': {'header_read_timeout': 4}}, 'settings' + ) (resp, sock) = self.http( b"""GET / HTTP/1.1 @@ -91,31 +100,40 @@ Connection: close def test_settings_body_read_timeout(self): self.load('empty') - self.conf({'http': {'body_read_timeout': 2}}, 'settings') - - (resp, sock) = self.http( - b"""POST / HTTP/1.1 + def req(): + (resp, sock) = self.http( + b"""POST / HTTP/1.1 Host: localhost Content-Length: 10 Connection: close """, - start=True, - raw_resp=True, - read_timeout=1, - raw=True, - ) + start=True, + raw_resp=True, + read_timeout=1, + raw=True, + ) - time.sleep(3) + time.sleep(3) - resp = self.http(b"""0123456789""", sock=sock, raw=True) + return self.http(b"""0123456789""", sock=sock, raw=True) - assert resp['status'] == 408, 'status body read timeout' + assert 'success' in self.conf( + {'http': {'body_read_timeout': 2}}, 'settings' + ) + assert req()['status'] == 408, 'status body read timeout' + + assert 'success' in self.conf( + {'http': {'body_read_timeout': 7}}, 'settings' + ) + assert req()['status'] == 200, 'status body read timeout 2' def test_settings_body_read_timeout_update(self): self.load('empty') - self.conf({'http': {'body_read_timeout': 4}}, 'settings') + assert 'success' in self.conf( + {'http': {'body_read_timeout': 4}}, 'settings' + ) (resp, sock) = self.http( b"""POST / HTTP/1.1 @@ -150,6 +168,32 @@ Connection: close def test_settings_send_timeout(self, temp_dir): self.load('body_generate') + def req(addr, data_len): + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.connect(addr) + + req = ( + """GET / HTTP/1.1 +Host: localhost +X-Length: %d +Connection: close + +""" + % data_len + ) + + sock.sendall(req.encode()) + + data = sock.recv(16).decode() + + time.sleep(3) + + data += self.recvall(sock).decode() + + sock.close() + + return data + sysctl_out = sysctl() values = re.findall( r'net.core.[rw]mem_(?:max|default).*?(\d+)', sysctl_out @@ -158,83 +202,80 @@ Connection: close data_len = 1048576 if len(values) == 0 else 10 * max(values) - self.conf({'http': {'send_timeout': 1}}, 'settings') - addr = temp_dir + '/sock' - self.conf( + assert 'success' in self.conf( {"unix:" + addr: {'application': 'body_generate'}}, 'listeners' ) - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - sock.connect(addr) - - req = ( - """GET / HTTP/1.1 -Host: localhost -X-Length: %d -Connection: close - -""" - % data_len + assert 'success' in self.conf( + {'http': {'send_timeout': 1}}, 'settings' ) - sock.sendall(req.encode()) - - data = sock.recv(16).decode() - - time.sleep(3) + data = req(addr, data_len) + assert re.search(r'200 OK', data), 'send timeout status' + assert len(data) < data_len, 'send timeout data ' - data += self.recvall(sock).decode() + self.conf({'http': {'send_timeout': 7}}, 'settings') - sock.close() - - assert re.search(r'200 OK', data), 'status send timeout' - assert len(data) < data_len, 'data send timeout' + data = req(addr, data_len) + assert re.search(r'200 OK', data), 'send timeout status 2' + assert len(data) > data_len, 'send timeout data 2' def test_settings_idle_timeout(self): self.load('empty') - assert self.get()['status'] == 200, 'init' + def req(): + (resp, sock) = self.get( + headers={'Host': 'localhost', 'Connection': 'keep-alive'}, + start=True, + read_timeout=1, + ) - self.conf({'http': {'idle_timeout': 2}}, 'settings') + time.sleep(3) - (resp, sock) = self.get( - headers={'Host': 'localhost', 'Connection': 'keep-alive'}, - start=True, - read_timeout=1, - ) + return self.get(sock=sock) - time.sleep(3) + assert self.get()['status'] == 200, 'init' - resp = self.get( - headers={'Host': 'localhost', 'Connection': 'close'}, sock=sock + assert 'success' in self.conf( + {'http': {'idle_timeout': 2}}, 'settings' ) + assert req()['status'] == 408, 'status idle timeout' - assert resp['status'] == 408, 'status idle timeout' + assert 'success' in self.conf( + {'http': {'idle_timeout': 7}}, 'settings' + ) + assert req()['status'] == 200, 'status idle timeout 2' def test_settings_idle_timeout_2(self): self.load('empty') - assert self.get()['status'] == 200, 'init' + def req(): + _, sock = self.http(b'', start=True, raw=True, no_recv=True) - self.conf({'http': {'idle_timeout': 1}}, 'settings') + time.sleep(3) - _, sock = self.http(b'', start=True, raw=True, no_recv=True) + return self.get(sock=sock) - time.sleep(3) + assert self.get()['status'] == 200, 'init' - assert ( - self.get( - headers={'Host': 'localhost', 'Connection': 'close'}, sock=sock - )['status'] - == 408 - ), 'status idle timeout' + assert 'success' in self.conf( + {'http': {'idle_timeout': 1}}, 'settings' + ) + assert req()['status'] == 408, 'status idle timeout' + + assert 'success' in self.conf( + {'http': {'idle_timeout': 7}}, 'settings' + ) + assert req()['status'] == 200, 'status idle timeout 2' def test_settings_max_body_size(self): self.load('empty') - self.conf({'http': {'max_body_size': 5}}, 'settings') + assert 'success' in self.conf( + {'http': {'max_body_size': 5}}, 'settings' + ) assert self.post(body='01234')['status'] == 200, 'status size' assert self.post(body='012345')['status'] == 413, 'status size max' @@ -242,7 +283,9 @@ Connection: close def test_settings_max_body_size_large(self): self.load('mirror') - self.conf({'http': {'max_body_size': 32 * 1024 * 1024}}, 'settings') + assert 'success' in self.conf( + {'http': {'max_body_size': 32 * 1024 * 1024}}, 'settings' + ) body = '0123456789abcdef' * 4 * 64 * 1024 resp = self.post(body=body, read_buffer_size=1024 * 1024) -- cgit From 155e22da05f01eb51b9dc082e9c8e8bff9b5ec8d Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Tue, 25 May 2021 18:00:59 +0300 Subject: Go: fixing tests for Go 1.16. In Go 1.16, the module-aware mode is enabled by default; to fall back to previous behavior, the GO111MODULE environment variable should be set to 'auto'. Details: https://golang.org/doc/go1.16 --- test/unit/applications/lang/go.py | 1 + test/unit/check/go.py | 1 + 2 files changed, 2 insertions(+) (limited to 'test') diff --git a/test/unit/applications/lang/go.py b/test/unit/applications/lang/go.py index a17b1af4..6be1667b 100644 --- a/test/unit/applications/lang/go.py +++ b/test/unit/applications/lang/go.py @@ -13,6 +13,7 @@ class TestApplicationGo(TestApplicationProto): env = os.environ.copy() env['GOPATH'] = option.current_dir + '/build/go' env['GOCACHE'] = option.cache_dir + '/go' + env['GO111MODULE'] = 'auto' if static: args = [ diff --git a/test/unit/check/go.py b/test/unit/check/go.py index 35b0c2d5..309091c0 100644 --- a/test/unit/check/go.py +++ b/test/unit/check/go.py @@ -8,6 +8,7 @@ def check_go(current_dir, temp_dir, test_dir): env = os.environ.copy() env['GOPATH'] = current_dir + '/build/go' + env['GO111MODULE'] = 'auto' try: process = subprocess.Popen( -- cgit From d67a0c871157454d591fa1d2a8b2d831b32e4040 Mon Sep 17 00:00:00 2001 From: Oisin Canty Date: Wed, 26 May 2021 16:48:11 +0000 Subject: Static: handled unknown MIME types when MIME-filtering active. --- test/test_share_types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/test_share_types.py b/test/test_share_types.py index 98ad106b..b5ed97a0 100644 --- a/test/test_share_types.py +++ b/test/test_share_types.py @@ -128,7 +128,7 @@ class TestShareTypes(TestApplicationProto): { "action": { "share": temp_dir + "/assets", - "types": ["!application/php"], + "types": ["!application/x-httpd-php"], "fallback": {"proxy": "http://127.0.0.1:7081"}, } }, -- cgit From 753ce145f7cfbfffab34d18ff74236f09e471f18 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Wed, 26 May 2021 21:47:12 +0100 Subject: Tests: added TLS test without close notify. --- test/test_tls.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'test') diff --git a/test/test_tls.py b/test/test_tls.py index 3ab6f7d7..0cfeaded 100644 --- a/test/test_tls.py +++ b/test/test_tls.py @@ -2,6 +2,7 @@ import io import re import ssl import subprocess +import time import pytest @@ -501,6 +502,28 @@ basicConstraints = critical,CA:TRUE""" assert resp['body'] == '0123456789', 'keepalive 2' + def test_tls_no_close_notify(self): + self.certificate() + + assert 'success' in self.conf( + { + "listeners": { + "*:7080": { + "pass": "routes", + "tls": {"certificate": "default"}, + } + }, + "routes": [{"action": {"return": 200}}], + "applications": {}, + } + ), 'load application configuration' + + (resp, sock) = self.get_ssl(start=True) + + time.sleep(5) + + sock.close() + @pytest.mark.skip('not yet') def test_tls_keepalive_certificate_remove(self): self.load('empty') -- cgit From f91fe4ce9e9c819f1e86ab1018223e38a34fb07d Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Thu, 27 May 2021 13:30:51 +0100 Subject: Tests: added tests for TLS "conf_commands" option. --- test/test_tls_conf_command.py | 112 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 test/test_tls_conf_command.py (limited to 'test') diff --git a/test/test_tls_conf_command.py b/test/test_tls_conf_command.py new file mode 100644 index 00000000..ccae09ad --- /dev/null +++ b/test/test_tls_conf_command.py @@ -0,0 +1,112 @@ +import ssl + +import pytest + +from unit.applications.tls import TestApplicationTLS + + +class TestTLSConfCommand(TestApplicationTLS): + prerequisites = {'modules': {'openssl': 'any'}} + + @pytest.fixture(autouse=True) + def setup_method_fixture(self, request): + self.certificate() + + assert 'success' in self.conf( + { + "listeners": { + "*:7080": { + "pass": "routes", + "tls": {"certificate": "default"}, + } + }, + "routes": [{"action": {"return": 200}}], + "applications": {}, + } + ), 'load application configuration' + + def test_tls_conf_command(self): + def check_no_connection(): + try: + self.get_ssl() + pytest.fail('Unexpected connection.') + + except (ssl.SSLError, ConnectionRefusedError): + pass + + # Set one conf_commands (disable protocol). + + (resp, sock) = self.get_ssl(start=True) + + shared_ciphers = sock.shared_ciphers() + protocols = list(set(c[1] for c in shared_ciphers)) + protocol = sock.cipher()[1] + + if '/' in protocol: + pytest.skip('Complex protocol format.') + + assert 'success' in self.conf( + { + "certificate": "default", + "conf_commands": {"protocol": '-' + protocol}, + }, + 'listeners/*:7080/tls', + ), 'protocol disabled' + + sock.close() + + if len(protocols) > 1: + (resp, sock) = self.get_ssl(start=True) + + cipher = sock.cipher() + assert cipher[1] != protocol, 'new protocol used' + + shared_ciphers = sock.shared_ciphers() + ciphers = list(set(c for c in shared_ciphers if c[1] == cipher[1])) + + sock.close() + else: + check_no_connection() + pytest.skip('One TLS protocol available only.') + + # Set two conf_commands (disable protocol and cipher). + + assert 'success' in self.conf( + { + "certificate": "default", + "conf_commands": { + "protocol": '-' + protocol, + "cipherstring": cipher[1] + ":!" + cipher[0], + }, + }, + 'listeners/*:7080/tls', + ), 'cipher disabled' + + if len(ciphers) > 1: + (resp, sock) = self.get_ssl(start=True) + + cipher_new = sock.cipher() + assert cipher_new[1] == cipher[1], 'previous protocol used' + assert cipher_new[0] != cipher[0], 'new cipher used' + + sock.close() + + else: + check_no_connection() + + def test_tls_conf_command_invalid(self, skip_alert): + skip_alert(r'SSL_CONF_cmd', r'failed to apply new conf') + + def check_conf_commands(conf_commands): + assert 'error' in self.conf( + {"certificate": "default", "conf_commands": conf_commands}, + 'listeners/*:7080/tls', + ), 'ivalid conf_commands' + + check_conf_commands([]) + check_conf_commands("blah") + check_conf_commands({"": ""}) + check_conf_commands({"blah": ""}) + check_conf_commands({"protocol": {}}) + check_conf_commands({"protocol": "blah"}) + check_conf_commands({"protocol": "TLSv1.2", "blah": ""}) -- cgit