diff options
Diffstat (limited to '')
59 files changed, 871 insertions, 537 deletions
diff --git a/test/conftest.py b/test/conftest.py index 689c857a..904abc32 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -159,9 +159,7 @@ def pytest_generate_tests(metafunc): type + ' ' + available_versions[0] ) elif callable(prereq_version): - generate_tests( - list(filter(prereq_version, available_versions)) - ) + generate_tests(list(filter(prereq_version, available_versions))) else: raise ValueError( @@ -203,9 +201,7 @@ def pytest_sessionstart(session): # discover modules from check option.available['modules']['openssl'] = check_openssl(unit['unitd']) - option.available['modules']['go'] = check_go( - option.current_dir, unit['temp_dir'], option.test_dir - ) + option.available['modules']['go'] = check_go() option.available['modules']['node'] = check_node(option.current_dir) option.available['modules']['regex'] = check_regex(unit['unitd']) @@ -322,9 +318,7 @@ 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: for attempt in range(10): @@ -340,6 +334,10 @@ def run(request): _check_fds(log=log) + # check processes id's and amount + + _check_processes() + # print unit.log in case of error if hasattr(request.node, 'rep_call') and request.node.rep_call.failed: @@ -439,6 +437,16 @@ def unit_stop(): return + # check zombies + + out = subprocess.check_output( + ['ps', 'ax', '-o', 'state', '-o', 'ppid'] + ).decode() + z_ppids = re.findall(r'Z\s*(\d+)', out) + assert unit_instance['pid'] not in z_ppids, 'no zombies' + + # terminate unit + p = unit_instance['process'] if p.poll() is not None: @@ -522,7 +530,7 @@ def _clear_conf(sock, *, log=None): try: certs = json.loads( - http.get(url='/certificates', sock_type='unix', addr=sock,)['body'] + http.get(url='/certificates', sock_type='unix', addr=sock)['body'] ).keys() except json.JSONDecodeError: @@ -530,12 +538,58 @@ def _clear_conf(sock, *, log=None): for cert in certs: resp = http.delete( - url='/certificates/' + cert, sock_type='unix', addr=sock, + url='/certificates/' + cert, + sock_type='unix', + addr=sock, )['body'] assert 'success' in resp, 'remove certificate' +def _check_processes(): + router_pid = _fds_info['router']['pid'] + controller_pid = _fds_info['controller']['pid'] + unit_pid = unit_instance['pid'] + + for i in range(600): + out = ( + subprocess.check_output( + ['ps', '-ax', '-o', 'pid', '-o', 'ppid', '-o', 'command'] + ) + .decode() + .splitlines() + ) + out = [l for l in out if unit_pid in l] + + if len(out) <= 3: + break + + time.sleep(0.1) + + assert len(out) == 3, 'main, router, and controller expected' + + out = [l for l in out if 'unit: main' not in l] + assert len(out) == 2, 'one main' + + out = [ + l + for l in out + if re.search(router_pid + r'\s+' + unit_pid + r'.*unit: router', l) + is None + ] + assert len(out) == 1, 'one router' + + out = [ + l + for l in out + if re.search( + controller_pid + r'\s+' + unit_pid + r'.*unit: controller', l + ) + is None + ] + assert len(out) == 0, 'one controller' + + @print_log_on_assert def _check_fds(*, log=None): def waitforfds(diff): @@ -556,9 +610,7 @@ def _check_fds(*, log=None): ) ps['fds'] += fds_diff - assert ( - fds_diff <= option.fds_threshold - ), 'descriptors leak main process' + assert fds_diff <= option.fds_threshold, 'descriptors leak main process' else: ps['fds'] = _count_fds(unit_instance['pid']) @@ -590,7 +642,8 @@ def _count_fds(pid): try: out = subprocess.check_output( - ['procstat', '-f', pid], stderr=subprocess.STDOUT, + ['procstat', '-f', pid], + stderr=subprocess.STDOUT, ).decode() return len(out.splitlines()) @@ -599,7 +652,8 @@ def _count_fds(pid): try: out = subprocess.check_output( - ['lsof', '-n', '-p', pid], stderr=subprocess.STDOUT, + ['lsof', '-n', '-p', pid], + stderr=subprocess.STDOUT, ).decode() return len(out.splitlines()) diff --git a/test/perl/input_buffered_read/psgi.pl b/test/perl/input_buffered_read/psgi.pl new file mode 100644 index 00000000..4ca699d7 --- /dev/null +++ b/test/perl/input_buffered_read/psgi.pl @@ -0,0 +1,17 @@ +use FileHandle; + +my $app = sub { + my ($environ) = @_; + + $environ->{'psgi.input'}->read(my $body, 1024); + + open my $io, "<", \$body; + + # This makes $io work as FileHandle under 5.8, .10 and .11. + bless $io, 'FileHandle'; + + $environ->{'psgix.input.buffered'} = 1; + $environ->{'psgi.input'} = $io; + + return ['200', ['Content-Length' => length $body], [$body]]; +}; diff --git a/test/perl/input_close/psgi.pl b/test/perl/input_close/psgi.pl new file mode 100644 index 00000000..4a2d9bb9 --- /dev/null +++ b/test/perl/input_close/psgi.pl @@ -0,0 +1,8 @@ +my $app = sub { + my ($environ) = @_; + + $environ->{'psgi.input'}->read(my $body, 1024); + $environ->{'psgi.input'}->close(); + + return ['200', ['Content-Length' => length $body], [$body]]; +}; diff --git a/test/php/opcache/index.php b/test/php/opcache/index.php index de4002bb..cf67c4c2 100644 --- a/test/php/opcache/index.php +++ b/test/php/opcache/index.php @@ -12,7 +12,7 @@ if (function_exists('opcache_is_script_cached')) { opcache_compile_file(__DIR__ . '/test.php'); } } else { - header('X-Cached: -1'); + header('X-OPcache: -1'); } ?> diff --git a/test/php/opcache/preload/chdir.php b/test/php/opcache/preload/chdir.php new file mode 100644 index 00000000..ad75e6ad --- /dev/null +++ b/test/php/opcache/preload/chdir.php @@ -0,0 +1,7 @@ +<?php + +chdir(realpath(__DIR__ . '/..')); + +opcache_compile_file('index.php'); + +?> diff --git a/test/php/opcache/preload/fastcgi_finish_request.php b/test/php/opcache/preload/fastcgi_finish_request.php new file mode 100644 index 00000000..31630cfa --- /dev/null +++ b/test/php/opcache/preload/fastcgi_finish_request.php @@ -0,0 +1,5 @@ +<?php + +fastcgi_finish_request(); + +?> diff --git a/test/python/204_no_content/asgi.py b/test/python/204_no_content/asgi.py index 634facc2..5dbb67d0 100644 --- a/test/python/204_no_content/asgi.py +++ b/test/python/204_no_content/asgi.py @@ -1,8 +1,10 @@ async def application(scope, receive, send): assert scope['type'] == 'http' - await send({ - 'type': 'http.response.start', - 'status': 204, - 'headers': [], - }) + await send( + { + 'type': 'http.response.start', + 'status': 204, + 'headers': [], + } + ) diff --git a/test/ruby/errors_write/config.ru b/test/ruby/errors_write/config.ru index 47619d6b..79ee4d1d 100644 --- a/test/ruby/errors_write/config.ru +++ b/test/ruby/errors_write/config.ru @@ -1,5 +1,7 @@ app = Proc.new do |env| env['rack.errors'].write('Error in application') + env['rack.errors'].flush + env['rack.errors'].close ['200', {'Content-Length' => '0'}, ['']] end diff --git a/test/ruby/input_gets/config.ru b/test/ruby/input_gets/config.ru index 1a6633ab..151fe235 100644 --- a/test/ruby/input_gets/config.ru +++ b/test/ruby/input_gets/config.ru @@ -1,5 +1,6 @@ app = Proc.new do |env| body = env['rack.input'].gets + env['rack.input'].close ['200', { 'Content-Length' => body.length.to_s }, [body]] diff --git a/test/ruby/variables/config.ru b/test/ruby/variables/config.ru index 55d01796..e335e049 100644 --- a/test/ruby/variables/config.ru +++ b/test/ruby/variables/config.ru @@ -8,6 +8,7 @@ app = Proc.new do |env| 'Request-Method' => env['REQUEST_METHOD'], 'Request-Uri' => env['REQUEST_URI'], 'Http-Host' => env['HTTP_HOST'], + 'Script-Name' => env['SCRIPT_NAME'], 'Server-Protocol' => env['SERVER_PROTOCOL'], 'Server-Software' => env['SERVER_SOFTWARE'], 'Custom-Header' => env['HTTP_CUSTOM_HEADER'], diff --git a/test/test_asgi_application.py b/test/test_asgi_application.py index 021aa2b2..60fcffc1 100644 --- a/test/test_asgi_application.py +++ b/test/test_asgi_application.py @@ -1,14 +1,16 @@ import re import time -from distutils.version import LooseVersion import pytest +from packaging import version from unit.applications.lang.python import TestApplicationPython class TestASGIApplication(TestApplicationPython): prerequisites = { - 'modules': {'python': lambda v: LooseVersion(v) >= LooseVersion('3.5')} + 'modules': { + 'python': lambda v: version.parse(v) >= version.parse('3.5') + } } load_module = 'asgi' diff --git a/test/test_asgi_lifespan.py b/test/test_asgi_lifespan.py index 912d0d85..e295f7fa 100644 --- a/test/test_asgi_lifespan.py +++ b/test/test_asgi_lifespan.py @@ -1,14 +1,16 @@ import os -from distutils.version import LooseVersion from conftest import unit_stop +from packaging import version from unit.applications.lang.python import TestApplicationPython from unit.option import option class TestASGILifespan(TestApplicationPython): prerequisites = { - 'modules': {'python': lambda v: LooseVersion(v) >= LooseVersion('3.5')} + 'modules': { + 'python': lambda v: version.parse(v) >= version.parse('3.5') + } } load_module = 'asgi' @@ -67,7 +69,7 @@ class TestASGILifespan(TestApplicationPython): ], "applications": { "targets": { - "type": "python", + "type": self.get_application_type(), "processes": {"spare": 0}, "working_directory": option.test_dir + "/python/lifespan/empty", diff --git a/test/test_asgi_targets.py b/test/test_asgi_targets.py index b9489cd3..c1e345ef 100644 --- a/test/test_asgi_targets.py +++ b/test/test_asgi_targets.py @@ -1,13 +1,14 @@ -from distutils.version import LooseVersion - import pytest +from packaging import version 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')} + 'modules': { + 'python': lambda v: version.parse(v) >= version.parse('3.5') + } } load_module = 'asgi' @@ -28,7 +29,7 @@ class TestASGITargets(TestApplicationPython): ], "applications": { "targets": { - "type": "python", + "type": self.get_application_type(), "processes": {"spare": 0}, "working_directory": option.test_dir + "/python/targets/", diff --git a/test/test_asgi_websockets.py b/test/test_asgi_websockets.py index bad54e22..975be90a 100644 --- a/test/test_asgi_websockets.py +++ b/test/test_asgi_websockets.py @@ -1,8 +1,8 @@ import struct import time -from distutils.version import LooseVersion import pytest +from packaging import version from unit.applications.lang.python import TestApplicationPython from unit.applications.websockets import TestApplicationWebsocket from unit.option import option @@ -10,7 +10,9 @@ from unit.option import option class TestASGIWebsockets(TestApplicationPython): prerequisites = { - 'modules': {'python': lambda v: LooseVersion(v) >= LooseVersion('3.5')} + 'modules': { + 'python': lambda v: version.parse(v) >= version.parse('3.5') + } } load_module = 'asgi' @@ -162,7 +164,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 @@ -940,9 +942,7 @@ 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) @@ -1187,7 +1187,7 @@ class TestASGIWebsockets(TestApplicationPython): _, sock, _ = self.ws.upgrade() - self.ws.frame_write(sock, self.ws.OP_TEXT, 'BAsd7&jh23' * 26 * 2 ** 10) + self.ws.frame_write(sock, self.ws.OP_TEXT, 'BAsd7&jh23' * 26 * 2**10) self.ws.frame_write(sock, self.ws.OP_TEXT, payload) self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close()) @@ -1349,62 +1349,62 @@ class TestASGIWebsockets(TestApplicationPython): def check_message(opcode, f_size): if opcode == self.ws.OP_TEXT: - payload = '*' * 4 * 2 ** 20 + payload = '*' * 4 * 2**20 else: - payload = b'*' * 4 * 2 ** 20 + payload = b'*' * 4 * 2**20 self.ws.message(sock, opcode, payload, fragmention_size=f_size) frame = self.ws.frame_read(sock, read_timeout=5) self.check_frame(frame, True, opcode, payload) - check_payload(op_text, 64 * 2 ** 10) # 9_1_1 - check_payload(op_text, 256 * 2 ** 10) # 9_1_2 - check_payload(op_text, 2 ** 20) # 9_1_3 - check_payload(op_text, 4 * 2 ** 20) # 9_1_4 - check_payload(op_text, 8 * 2 ** 20) # 9_1_5 - check_payload(op_text, 16 * 2 ** 20) # 9_1_6 + check_payload(op_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_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 + check_message(op_binary, 2**10) # 9_4_3 + check_message(op_binary, 4 * 2**10) # 9_4_4 + check_message(op_binary, 16 * 2**10) # 9_4_5 + check_message(op_binary, 64 * 2**10) # 9_4_6 + check_message(op_binary, 256 * 2**10) # 9_4_7 + check_message(op_binary, 2**20) # 9_4_8 + check_message(op_binary, 4 * 2**20) # 9_4_9 + + check_payload(op_text, 2**20, chopsize=64) # 9_5_1 + check_payload(op_text, 2**20, chopsize=128) # 9_5_2 + check_payload(op_text, 2**20, chopsize=256) # 9_5_3 + check_payload(op_text, 2**20, chopsize=512) # 9_5_4 + check_payload(op_text, 2**20, chopsize=1024) # 9_5_5 + check_payload(op_text, 2**20, chopsize=2048) # 9_5_6 + + check_payload(op_binary, 2**20, chopsize=64) # 9_6_1 + check_payload(op_binary, 2**20, chopsize=128) # 9_6_2 + check_payload(op_binary, 2**20, chopsize=256) # 9_6_3 + check_payload(op_binary, 2**20, chopsize=512) # 9_6_4 + check_payload(op_binary, 2**20, chopsize=1024) # 9_6_5 + check_payload(op_binary, 2**20, chopsize=2048) # 9_6_6 self.close_connection(sock) diff --git a/test/test_client_ip.py b/test/test_client_ip.py index 4b2b2fa1..53e52201 100644 --- a/test/test_client_ip.py +++ b/test/test_client_ip.py @@ -7,10 +7,14 @@ class TestClientIP(TestApplicationPython): def client_ip(self, options): assert 'success' in self.conf( { - "127.0.0.1:7081": - {"client_ip": options, "pass": "applications/client_ip"}, - "[::1]:7082": - {"client_ip": options, "pass": "applications/client_ip"}, + "127.0.0.1:7081": { + "client_ip": options, + "pass": "applications/client_ip", + }, + "[::1]:7082": { + "client_ip": options, + "pass": "applications/client_ip", + }, }, 'listeners', ), 'listeners configure' @@ -48,9 +52,7 @@ class TestClientIP(TestApplicationPython): ), 'ipv6 default 2' assert self.get_xff('1.1.1.1') == '1.1.1.1', 'replace' assert self.get_xff('blah') == '127.0.0.1', 'bad header 2' - assert ( - self.get_xff('1.1.1.1', 'ipv6') == '::1' - ), 'bad source ipv6 2' + assert self.get_xff('1.1.1.1', 'ipv6') == '::1', 'bad source ipv6 2' self.client_ip({'header': 'X-Forwarded-For', 'source': '!127.0.0.1'}) @@ -118,10 +120,18 @@ class TestClientIP(TestApplicationPython): def test_settings_client_ip_invalid(self): assert 'error' in self.conf( - {"http": {"client_ip": {'header': 'X-Forwarded-For', 'source': []}}}, + { + "http": { + "client_ip": {'header': 'X-Forwarded-For', 'source': []} + } + }, 'settings', ), 'empty array source' assert 'error' in self.conf( - {"http":{"client_ip": {'header': 'X-Forwarded-For', 'source': 'a'}}}, + { + "http": { + "client_ip": {'header': 'X-Forwarded-For', 'source': 'a'} + } + }, 'settings', ), 'empty source invalid' diff --git a/test/test_go_application.py b/test/test_go_application.py index 94da1aee..c8cf3e53 100644 --- a/test/test_go_application.py +++ b/test/test_go_application.py @@ -1,7 +1,6 @@ import re import pytest - from unit.applications.lang.go import TestApplicationGo @@ -158,9 +157,7 @@ class TestGoApplication(TestApplicationGo): 'applications/command_line_arguments/arguments', ) - assert ( - self.get()['body'] == arg1 + ',' + arg2 + ',' + arg3 - ), 'arguments' + assert self.get()['body'] == arg1 + ',' + arg2 + ',' + arg3, 'arguments' def test_go_application_command_line_arguments_change(self): self.load('command_line_arguments') @@ -177,6 +174,4 @@ class TestGoApplication(TestApplicationGo): assert 'success' in self.conf('[]', args_path) - assert ( - self.get()['headers']['Content-Length'] == '0' - ), 'arguments empty' + assert self.get()['headers']['Content-Length'] == '0', 'arguments empty' diff --git a/test/test_go_isolation.py b/test/test_go_isolation.py index 72988a34..c3f92679 100644 --- a/test/test_go_isolation.py +++ b/test/test_go_isolation.py @@ -167,9 +167,7 @@ class TestGoIsolation(TestApplicationGo): user='nobody', isolation={ 'namespaces': {'credential': True}, - 'uidmap': [ - {'container': 0, 'host': 0, 'size': nobody_uid + 1} - ], + 'uidmap': [{'container': 0, 'host': 0, 'size': nobody_uid + 1}], }, ) diff --git a/test/test_http_header.py b/test/test_http_header.py index ca355eb7..6773c44f 100644 --- a/test/test_http_header.py +++ b/test/test_http_header.py @@ -213,7 +213,7 @@ Connection: close self.post( headers={ 'Host': 'localhost', - 'Content-Length': str(2 ** 64), + 'Content-Length': str(2**64), 'Connection': 'close', }, body='X' * 1000, @@ -325,9 +325,7 @@ Connection: close def test_http_header_host_port_empty(self): self.load('host') - resp = self.get( - headers={'Host': 'exmaple.com:', 'Connection': 'close'} - ) + resp = self.get(headers={'Host': 'exmaple.com:', 'Connection': 'close'}) assert resp['status'] == 200, 'Host port empty status' assert ( @@ -376,9 +374,7 @@ Connection: close def test_http_header_host_trailing_period_2(self): self.load('host') - resp = self.get( - headers={'Host': 'EXAMPLE.COM.', 'Connection': 'close'} - ) + resp = self.get(headers={'Host': 'EXAMPLE.COM.', 'Connection': 'close'}) assert resp['status'] == 200, 'Host trailing period 2 status' assert ( @@ -453,14 +449,16 @@ Connection: close assert 'CUSTOM' not in resp['headers']['All-Headers'] assert 'success' in self.conf( - {'http': {'discard_unsafe_fields': False}}, 'settings', + {'http': {'discard_unsafe_fields': False}}, + 'settings', ) resp = check_status("!#$%&'*+.^`|~Custom_Header") assert 'CUSTOM' in resp['headers']['All-Headers'] assert 'success' in self.conf( - {'http': {'discard_unsafe_fields': True}}, 'settings', + {'http': {'discard_unsafe_fields': True}}, + 'settings', ) resp = check_status("!Custom-Header") diff --git a/test/test_java_application.py b/test/test_java_application.py index 3fd5c26e..adcb4eca 100644 --- a/test/test_java_application.py +++ b/test/test_java_application.py @@ -22,7 +22,7 @@ class TestJavaApplication(TestApplicationJava): "listeners": {"*:7080": {"pass": "applications/app"}}, "applications": { "app": { - "type": "java", + "type": self.get_application_type(), "processes": 1, "working_directory": option.test_dir + "/java/empty", "webapp": temp_dir + "/java", @@ -173,9 +173,7 @@ class TestJavaApplication(TestApplicationJava): } ) - assert ( - resp['headers']['X-Session-Id'] == session_id - ), 'session active 2' + assert resp['headers']['X-Session-Id'] == session_id, 'session active 2' time.sleep(2) @@ -187,9 +185,7 @@ class TestJavaApplication(TestApplicationJava): } ) - assert ( - resp['headers']['X-Session-Id'] == session_id - ), 'session active 3' + assert resp['headers']['X-Session-Id'] == session_id, 'session active 3' def test_java_application_session_inactive(self): self.load('session_inactive') @@ -213,9 +209,7 @@ class TestJavaApplication(TestApplicationJava): } ) - assert ( - resp['headers']['X-Session-Id'] != session_id - ), 'session inactive' + assert resp['headers']['X-Session-Id'] != session_id, 'session inactive' def test_java_application_session_invalidate(self): self.load('session_invalidate') @@ -391,9 +385,7 @@ class TestJavaApplication(TestApplicationJava): assert ( headers['X-Content-Type'] == 'text/plain;charset=utf-8' ), '#1 response Content-Type' - assert ( - headers['X-Character-Encoding'] == 'utf-8' - ), '#1 response charset' + assert headers['X-Character-Encoding'] == 'utf-8', '#1 response charset' headers = self.get(url='/2')['headers'] @@ -445,15 +437,11 @@ class TestJavaApplication(TestApplicationJava): headers = self.get(url='/6')['headers'] - assert ( - 'Content-Type' in headers - ) == False, '#6 no Content-Type header' + assert ('Content-Type' in headers) == False, '#6 no Content-Type header' assert ( 'X-Content-Type' in headers ) == False, '#6 no response Content-Type' - assert ( - headers['X-Character-Encoding'] == 'utf-8' - ), '#6 response charset' + assert headers['X-Character-Encoding'] == 'utf-8', '#6 response charset' headers = self.get(url='/7')['headers'] @@ -463,9 +451,7 @@ class TestJavaApplication(TestApplicationJava): assert ( headers['X-Content-Type'] == 'text/plain;charset=utf-8' ), '#7 response Content-Type' - assert ( - headers['X-Character-Encoding'] == 'utf-8' - ), '#7 response charset' + assert headers['X-Character-Encoding'] == 'utf-8', '#7 response charset' headers = self.get(url='/8')['headers'] @@ -475,9 +461,7 @@ class TestJavaApplication(TestApplicationJava): assert ( headers['X-Content-Type'] == 'text/html;charset=utf-8' ), '#8 response Content-Type' - assert ( - headers['X-Character-Encoding'] == 'utf-8' - ), '#8 response charset' + assert headers['X-Character-Encoding'] == 'utf-8', '#8 response charset' def test_java_application_welcome_files(self): self.load('welcome_files') @@ -490,9 +474,7 @@ class TestJavaApplication(TestApplicationJava): resp = self.get(url='/dir1/') - assert ( - 'This is index.txt.' in resp['body'] - ) == True, 'dir1 index body' + assert ('This is index.txt.' in resp['body']) == True, 'dir1 index body' assert resp['headers']['X-TXT-Filter'] == '1', 'TXT Filter header' headers = self.get(url='/dir2/')['headers'] @@ -655,9 +637,7 @@ class TestJavaApplication(TestApplicationJava): assert ( headers['X-FORWARD-Id'] == 'data' ), 'forward request servlet mapping' - assert ( - headers['X-FORWARD-Request-URI'] == '/fwd' - ), 'forward request uri' + assert headers['X-FORWARD-Request-URI'] == '/fwd', 'forward request uri' assert ( headers['X-FORWARD-Servlet-Path'] == '/fwd' ), 'forward request servlet path' @@ -1003,9 +983,7 @@ class TestJavaApplication(TestApplicationJava): ) assert resp['status'] == 200, 'multipart status' - assert re.search( - r'sample\.txt created', resp['body'] - ), 'multipart body' + assert re.search(r'sample\.txt created', resp['body']), 'multipart body' assert ( self.search_in_log( r'^Data from sample file$', name=reldst + '/sample.txt' diff --git a/test/test_java_isolation_rootfs.py b/test/test_java_isolation_rootfs.py index eac86a0c..3c6a45a3 100644 --- a/test/test_java_isolation_rootfs.py +++ b/test/test_java_isolation_rootfs.py @@ -11,7 +11,7 @@ class TestJavaIsolationRootfs(TestApplicationJava): def setup_method(self, is_su): if not is_su: - return + pytest.skip('require root') os.makedirs(option.temp_dir + '/jars') os.makedirs(option.temp_dir + '/tmp') @@ -61,7 +61,8 @@ class TestJavaIsolationRootfs(TestApplicationJava): self.load('empty_war', isolation=isolation) assert 'success' in self.conf( - '"/"', '/config/applications/empty_war/working_directory', + '"/"', + '/config/applications/empty_war/working_directory', ) assert 'success' in self.conf( diff --git a/test/test_java_websockets.py b/test/test_java_websockets.py index a80d3bf3..362c8619 100644 --- a/test/test_java_websockets.py +++ b/test/test_java_websockets.py @@ -869,9 +869,7 @@ 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) @@ -1116,7 +1114,7 @@ class TestJavaWebsockets(TestApplicationJava): _, sock, _ = self.ws.upgrade() - self.ws.frame_write(sock, self.ws.OP_TEXT, 'BAsd7&jh23' * 26 * 2 ** 10) + self.ws.frame_write(sock, self.ws.OP_TEXT, 'BAsd7&jh23' * 26 * 2**10) self.ws.frame_write(sock, self.ws.OP_TEXT, payload) self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close()) @@ -1278,62 +1276,62 @@ class TestJavaWebsockets(TestApplicationJava): def check_message(opcode, f_size): if opcode == self.ws.OP_TEXT: - payload = '*' * 4 * 2 ** 20 + payload = '*' * 4 * 2**20 else: - payload = b'*' * 4 * 2 ** 20 + payload = b'*' * 4 * 2**20 self.ws.message(sock, opcode, payload, fragmention_size=f_size) frame = self.ws.frame_read(sock, read_timeout=5) self.check_frame(frame, True, opcode, payload) - check_payload(op_text, 64 * 2 ** 10) # 9_1_1 - check_payload(op_text, 256 * 2 ** 10) # 9_1_2 - check_payload(op_text, 2 ** 20) # 9_1_3 - check_payload(op_text, 4 * 2 ** 20) # 9_1_4 - check_payload(op_text, 8 * 2 ** 20) # 9_1_5 - check_payload(op_text, 16 * 2 ** 20) # 9_1_6 + check_payload(op_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_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 + check_message(op_binary, 2**10) # 9_4_3 + check_message(op_binary, 4 * 2**10) # 9_4_4 + check_message(op_binary, 16 * 2**10) # 9_4_5 + check_message(op_binary, 64 * 2**10) # 9_4_6 + check_message(op_binary, 256 * 2**10) # 9_4_7 + check_message(op_binary, 2**20) # 9_4_8 + check_message(op_binary, 4 * 2**20) # 9_4_9 + + check_payload(op_text, 2**20, chopsize=64) # 9_5_1 + check_payload(op_text, 2**20, chopsize=128) # 9_5_2 + check_payload(op_text, 2**20, chopsize=256) # 9_5_3 + check_payload(op_text, 2**20, chopsize=512) # 9_5_4 + check_payload(op_text, 2**20, chopsize=1024) # 9_5_5 + check_payload(op_text, 2**20, chopsize=2048) # 9_5_6 + + check_payload(op_binary, 2**20, chopsize=64) # 9_6_1 + check_payload(op_binary, 2**20, chopsize=128) # 9_6_2 + check_payload(op_binary, 2**20, chopsize=256) # 9_6_3 + check_payload(op_binary, 2**20, chopsize=512) # 9_6_4 + check_payload(op_binary, 2**20, chopsize=1024) # 9_6_5 + check_payload(op_binary, 2**20, chopsize=2048) # 9_6_6 self.close_connection(sock) diff --git a/test/test_node_application.py b/test/test_node_application.py index 62a09c43..fc722582 100644 --- a/test/test_node_application.py +++ b/test/test_node_application.py @@ -218,9 +218,7 @@ 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_es_modules.py b/test/test_node_es_modules.py index 12788fa4..8a9cb181 100644 --- a/test/test_node_es_modules.py +++ b/test/test_node_es_modules.py @@ -1,5 +1,4 @@ -from distutils.version import LooseVersion - +from packaging import version from unit.applications.lang.node import TestApplicationNode from unit.applications.websockets import TestApplicationWebsocket @@ -7,7 +6,7 @@ from unit.applications.websockets import TestApplicationWebsocket class TestNodeESModules(TestApplicationNode): prerequisites = { 'modules': { - 'node': lambda v: LooseVersion(v) >= LooseVersion("14.16.0") + 'node': lambda v: version.parse(v) >= version.parse('14.16.0') } } diff --git a/test/test_node_websockets.py b/test/test_node_websockets.py index e4c8a05e..1f9a2e6b 100644 --- a/test/test_node_websockets.py +++ b/test/test_node_websockets.py @@ -888,9 +888,7 @@ 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) @@ -1135,7 +1133,7 @@ class TestNodeWebsockets(TestApplicationNode): _, sock, _ = self.ws.upgrade() - self.ws.frame_write(sock, self.ws.OP_TEXT, 'BAsd7&jh23' * 26 * 2 ** 10) + self.ws.frame_write(sock, self.ws.OP_TEXT, 'BAsd7&jh23' * 26 * 2**10) self.ws.frame_write(sock, self.ws.OP_TEXT, payload) self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close()) @@ -1297,62 +1295,62 @@ class TestNodeWebsockets(TestApplicationNode): def check_message(opcode, f_size): if opcode == self.ws.OP_TEXT: - payload = '*' * 4 * 2 ** 20 + payload = '*' * 4 * 2**20 else: - payload = b'*' * 4 * 2 ** 20 + payload = b'*' * 4 * 2**20 self.ws.message(sock, opcode, payload, fragmention_size=f_size) frame = self.ws.frame_read(sock, read_timeout=5) self.check_frame(frame, True, opcode, payload) - check_payload(op_text, 64 * 2 ** 10) # 9_1_1 - check_payload(op_text, 256 * 2 ** 10) # 9_1_2 - check_payload(op_text, 2 ** 20) # 9_1_3 - check_payload(op_text, 4 * 2 ** 20) # 9_1_4 - check_payload(op_text, 8 * 2 ** 20) # 9_1_5 - check_payload(op_text, 16 * 2 ** 20) # 9_1_6 + check_payload(op_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_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 + check_message(op_binary, 2**10) # 9_4_3 + check_message(op_binary, 4 * 2**10) # 9_4_4 + check_message(op_binary, 16 * 2**10) # 9_4_5 + check_message(op_binary, 64 * 2**10) # 9_4_6 + check_message(op_binary, 256 * 2**10) # 9_4_7 + check_message(op_binary, 2**20) # 9_4_8 + check_message(op_binary, 4 * 2**20) # 9_4_9 + + check_payload(op_text, 2**20, chopsize=64) # 9_5_1 + check_payload(op_text, 2**20, chopsize=128) # 9_5_2 + check_payload(op_text, 2**20, chopsize=256) # 9_5_3 + check_payload(op_text, 2**20, chopsize=512) # 9_5_4 + check_payload(op_text, 2**20, chopsize=1024) # 9_5_5 + check_payload(op_text, 2**20, chopsize=2048) # 9_5_6 + + check_payload(op_binary, 2**20, chopsize=64) # 9_6_1 + check_payload(op_binary, 2**20, chopsize=128) # 9_6_2 + check_payload(op_binary, 2**20, chopsize=256) # 9_6_3 + check_payload(op_binary, 2**20, chopsize=512) # 9_6_4 + check_payload(op_binary, 2**20, chopsize=1024) # 9_6_5 + check_payload(op_binary, 2**20, chopsize=2048) # 9_6_6 self.close_connection(sock) diff --git a/test/test_perl_application.py b/test/test_perl_application.py index dfd8be6c..0d1d7906 100644 --- a/test/test_perl_application.py +++ b/test/test_perl_application.py @@ -100,6 +100,22 @@ class TestPerlApplication(TestApplicationPerl): self.post(body='0123456789')['body'] == '0123456789' ), 'input read parts' + def test_perl_application_input_buffered_read(self): + self.load('input_buffered_read') + + assert self.post(body='012345')['body'] == '012345', 'buffered read #1' + assert ( + self.post(body='9876543210')['body'] == '9876543210' + ), 'buffered read #2' + + def test_perl_application_input_close(self): + self.load('input_close') + + assert self.post(body='012345')['body'] == '012345', 'input close #1' + assert ( + self.post(body='9876543210')['body'] == '9876543210' + ), 'input close #2' + @pytest.mark.skip('not yet') def test_perl_application_input_read_offset(self): self.load('input_read_offset') @@ -118,8 +134,7 @@ class TestPerlApplication(TestApplicationPerl): assert self.get()['body'] == '1', 'errors result' assert ( - self.wait_for_record(r'\[error\].+Error in application') - is not None + self.wait_for_record(r'\[error\].+Error in application') is not None ), 'errors print' def test_perl_application_header_equal_names(self): diff --git a/test/test_php_application.py b/test/test_php_application.py index d9c16a6d..606ac723 100644 --- a/test/test_php_application.py +++ b/test/test_php_application.py @@ -1,3 +1,4 @@ +import getpass import os import re import shutil @@ -18,18 +19,43 @@ class TestPHPApplication(TestApplicationPHP): assert re.search(r'time: \d+', body), 'disable_functions before time' assert re.search(r'exec: \/\w+', body), 'disable_functions before exec' + def check_opcache(self): + resp = self.get() + assert resp['status'] == 200, 'status' + + headers = resp['headers'] + if 'X-OPcache' in headers and headers['X-OPcache'] == '-1': + pytest.skip('opcache is not supported') + + return resp + def set_opcache(self, app, val): assert 'success' in self.conf( {"admin": {"opcache.enable": val, "opcache.enable_cli": val}}, 'applications/' + app + '/options', ) - opcache = self.get()['headers']['X-OPcache'] - - if not opcache or opcache == '-1': - pytest.skip('opcache is not supported') + r = self.check_opcache() + assert r['headers']['X-OPcache'] == val, 'opcache value' + + def set_preload(self, preload): + with open(option.temp_dir + '/php.ini', 'w') as f: + f.write( + """opcache.preload = %(test_dir)s/php/opcache/preload\ +/%(preload)s +opcache.preload_user = %(user)s +""" + % { + 'test_dir': option.test_dir, + 'preload': preload, + 'user': option.user or getpass.getuser(), + } + ) - assert opcache == val, 'opcache value' + assert 'success' in self.conf( + {"file": option.temp_dir + "/php.ini"}, + 'applications/opcache/options', + ) def test_php_application_variables(self): self.load('variables') @@ -294,20 +320,28 @@ class TestPHPApplication(TestApplicationPHP): self.load('ini_precision') assert 'success' in self.conf( - {"file": "php.ini", "admin": {"precision": "5"}}, + {"file": "ini/php.ini", "admin": {"precision": "5"}}, 'applications/ini_precision/options', ) + assert ( + self.get()['headers']['X-File'] + == option.test_dir + '/php/ini_precision/ini/php.ini' + ), 'ini file' assert self.get()['headers']['X-Precision'] == '5', 'ini value admin' def test_php_application_ini_user(self): self.load('ini_precision') assert 'success' in self.conf( - {"file": "php.ini", "user": {"precision": "5"}}, + {"file": "ini/php.ini", "user": {"precision": "5"}}, 'applications/ini_precision/options', ) + assert ( + self.get()['headers']['X-File'] + == option.test_dir + '/php/ini_precision/ini/php.ini' + ), 'ini file' assert self.get()['headers']['X-Precision'] == '5', 'ini value user' def test_php_application_ini_user_2(self): @@ -385,9 +419,7 @@ class TestPHPApplication(TestApplicationPHP): body = self.get()['body'] - assert not re.search( - r'time: \d+', body - ), 'disable_functions comma time' + assert not re.search(r'time: \d+', body), 'disable_functions comma time' assert not re.search( r'exec: \/\w+', body ), 'disable_functions comma exec' @@ -464,9 +496,7 @@ class TestPHPApplication(TestApplicationPHP): body = self.get()['body'] - assert not re.search( - r'time: \d+', body - ), 'disable_functions space time' + assert not re.search(r'time: \d+', body), 'disable_functions space time' assert not re.search( r'exec: \/\w+', body ), 'disable_functions space exec' @@ -566,7 +596,7 @@ class TestPHPApplication(TestApplicationPHP): "listeners": {"*:7080": {"pass": "applications/script"}}, "applications": { "script": { - "type": "php", + "type": self.get_application_type(), "processes": {"spare": 0}, "root": option.test_dir + "/php/script", "script": "phpinfo.php", @@ -586,7 +616,7 @@ class TestPHPApplication(TestApplicationPHP): "listeners": {"*:7080": {"pass": "applications/phpinfo"}}, "applications": { "phpinfo": { - "type": "php", + "type": self.get_application_type(), "processes": {"spare": 0}, "root": option.test_dir + "/php/phpinfo", } @@ -613,7 +643,7 @@ class TestPHPApplication(TestApplicationPHP): "listeners": {"*:7080": {"pass": "applications/phpinfo"}}, "applications": { "phpinfo": { - "type": "php", + "type": self.get_application_type(), "processes": {"spare": 0}, "root": new_root, "working_directory": new_root, @@ -637,7 +667,8 @@ class TestPHPApplication(TestApplicationPHP): assert resp['body'] == script_cwd, 'default cwd' assert 'success' in self.conf( - '"' + option.test_dir + '"', 'applications/cwd/working_directory', + '"' + option.test_dir + '"', + 'applications/cwd/working_directory', ) resp = self.get() @@ -717,16 +748,31 @@ class TestPHPApplication(TestApplicationPHP): def test_php_application_shared_opcache(self): self.load('opcache', limits={'requests': 1}) - r = self.get() - cached = r['headers']['X-Cached'] - if cached == '-1': - pytest.skip('opcache is not supported') - + r = self.check_opcache() pid = r['headers']['X-Pid'] - - assert cached == '0', 'not cached' + assert r['headers']['X-Cached'] == '0', 'not cached' r = self.get() assert r['headers']['X-Pid'] != pid, 'new instance' assert r['headers']['X-Cached'] == '1', 'cached' + + def test_php_application_opcache_preload_chdir(self, temp_dir): + self.load('opcache') + + self.check_opcache() + + self.set_preload('chdir.php') + + assert self.get()['headers']['X-Cached'] == '0', 'not cached' + assert self.get()['headers']['X-Cached'] == '1', 'cached' + + def test_php_application_opcache_preload_ffr(self, temp_dir): + self.load('opcache') + + self.check_opcache() + + self.set_preload('fastcgi_finish_request.php') + + assert self.get()['headers']['X-Cached'] == '0', 'not cached' + assert self.get()['headers']['X-Cached'] == '1', 'cached' diff --git a/test/test_php_targets.py b/test/test_php_targets.py index 76326131..918c5fda 100644 --- a/test/test_php_targets.py +++ b/test/test_php_targets.py @@ -22,7 +22,7 @@ class TestPHPTargets(TestApplicationPHP): ], "applications": { "targets": { - "type": "php", + "type": self.get_application_type(), "processes": {"spare": 0}, "targets": { "1": { @@ -66,7 +66,7 @@ class TestPHPTargets(TestApplicationPHP): }, "applications": { "targets": { - "type": "php", + "type": self.get_application_type(), "processes": {"spare": 0}, "targets": { "default": { diff --git a/test/test_proxy.py b/test/test_proxy.py index 553cb07c..68ae2394 100644 --- a/test/test_proxy.py +++ b/test/test_proxy.py @@ -72,15 +72,14 @@ Content-Length: 10 "routes": [{"action": {"proxy": "http://127.0.0.1:7081"}}], "applications": { "mirror": { - "type": "python", + "type": self.get_application_type(), "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", }, "custom_header": { - "type": "python", + "type": self.get_application_type(), "processes": {"spare": 0}, "path": option.test_dir + "/python/custom_header", "working_directory": option.test_dir @@ -88,7 +87,7 @@ Content-Length: 10 "module": "wsgi", }, "delayed": { - "type": "python", + "type": self.get_application_type(), "processes": {"spare": 0}, "path": option.test_dir + "/python/delayed", "working_directory": option.test_dir @@ -123,11 +122,10 @@ Content-Length: 10 }, "applications": { "mirror": { - "type": "python", + "type": self.get_application_type(), "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", } }, @@ -499,11 +497,10 @@ Content-Length: 10 "routes": [{"action": {"proxy": "http://127.0.0.1:7082"}}], "applications": { "mirror": { - "type": "python", + "type": self.get_application_type(), "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_proxy_chunked.py b/test/test_proxy_chunked.py index 73d94332..f024eaf5 100644 --- a/test/test_proxy_chunked.py +++ b/test/test_proxy_chunked.py @@ -90,12 +90,13 @@ class TestProxyChunked(TestApplicationPython): assert 'success' in self.conf( { - "listeners": {"*:7080": {"pass": "routes"},}, + "listeners": { + "*:7080": {"pass": "routes"}, + }, "routes": [ { "action": { - "proxy": "http://127.0.0.1:" - + str(self.SERVER_PORT) + "proxy": "http://127.0.0.1:" + str(self.SERVER_PORT) } } ], @@ -166,9 +167,7 @@ class TestProxyChunked(TestApplicationPython): assert ( self.get_http10( - body=self.chunks( - [('1', hex(i % 16)[2:]) for i in range(4096)] - ), + body=self.chunks([('1', hex(i % 16)[2:]) for i in range(4096)]), )['body'] == part * 256 ) @@ -210,8 +209,7 @@ class TestProxyChunked(TestApplicationPython): assert resp['body'][-5:] != '0\r\n\r\n', 'no zero chunk' assert ( - self.get_http10(body='\r\n\r\n80000000\r\nA X 100')['status'] - == 200 + self.get_http10(body='\r\n\r\n80000000\r\nA X 100')['status'] == 200 ) assert ( self.get_http10(body='\r\n\r\n10000000000000000\r\nA X 100')[ diff --git a/test/test_python_application.py b/test/test_python_application.py index 7bd43664..befbd4d8 100644 --- a/test/test_python_application.py +++ b/test/test_python_application.py @@ -293,36 +293,6 @@ custom-header: BLAH assert resp == {}, 'reconfigure 2 keep-alive 3' - def test_python_keepalive_reconfigure_3(self): - self.load('empty') - - assert self.get()['status'] == 200, 'init' - - (_, sock) = self.http( - b"""GET / HTTP/1.1 -""", - start=True, - raw=True, - no_recv=True, - ) - - assert self.get()['status'] == 200 - - assert 'success' in self.conf( - {"listeners": {}, "applications": {}} - ), 'reconfigure 3 clear configuration' - - resp = self.http( - b"""Host: localhost -Connection: close - -""", - sock=sock, - raw=True, - ) - - assert resp['status'] == 200, 'reconfigure 3' - def test_python_atexit(self): self.load('atexit') @@ -735,9 +705,7 @@ last line: 987654321 'nobody uid user=nobody group=%s' % group ) - assert obj['GID'] == group_id, ( - 'nobody gid user=nobody group=%s' % group - ) + assert obj['GID'] == group_id, 'nobody gid user=nobody group=%s' % group self.load('user_group', group=group) diff --git a/test/test_python_isolation.py b/test/test_python_isolation.py index 53d28285..8cef6812 100644 --- a/test/test_python_isolation.py +++ b/test/test_python_isolation.py @@ -56,9 +56,7 @@ class TestPythonIsolation(TestApplicationPython): ret = self.getjson(url='/?path=/app/python/ns_inspect') - assert ( - ret['body']['FileExists'] == True - ), 'application exists in rootfs' + assert ret['body']['FileExists'] == True, 'application exists in rootfs' def test_python_isolation_rootfs_no_language_deps(self, is_su, temp_dir): if not is_su: @@ -93,8 +91,7 @@ class TestPythonIsolation(TestApplicationPython): self.load('ns_inspect', isolation=isolation) assert ( - self.getjson(url='/?path=/proc/self')['body']['FileExists'] - == False + self.getjson(url='/?path=/proc/self')['body']['FileExists'] == False ), 'no /proc/self' isolation['automount']['procfs'] = True diff --git a/test/test_python_isolation_chroot.py b/test/test_python_isolation_chroot.py index 1554fb72..8e5b5fce 100644 --- a/test/test_python_isolation_chroot.py +++ b/test/test_python_isolation_chroot.py @@ -35,6 +35,4 @@ class TestPythonIsolation(TestApplicationPython): ret = self.getjson(url='/?path=/app/python/ns_inspect') - assert ( - ret['body']['FileExists'] == True - ), 'application exists in rootfs' + assert ret['body']['FileExists'] == True, 'application exists in rootfs' diff --git a/test/test_python_targets.py b/test/test_python_targets.py index e5dca870..8e9ecb87 100644 --- a/test/test_python_targets.py +++ b/test/test_python_targets.py @@ -21,7 +21,7 @@ class TestPythonTargets(TestApplicationPython): ], "applications": { "targets": { - "type": "python", + "type": self.get_application_type(), "working_directory": option.test_dir + "/python/targets/", "path": option.test_dir + '/python/targets/', diff --git a/test/test_reconfigure.py b/test/test_reconfigure.py new file mode 100644 index 00000000..ab05a1c8 --- /dev/null +++ b/test/test_reconfigure.py @@ -0,0 +1,53 @@ +import time + +import pytest +from unit.applications.proto import TestApplicationProto + + +class TestReconfigure(TestApplicationProto): + prerequisites = {} + + @pytest.fixture(autouse=True) + def setup_method_fixture(self): + assert 'success' in self.conf( + { + "listeners": {"*:7080": {"pass": "routes"}}, + "routes": [{"action": {"return": 200}}], + "applications": {}, + } + ) + + def clear_conf(self): + assert 'success' in self.conf({"listeners": {}, "applications": {}}) + + def test_reconfigure(self): + (_, sock) = self.http( + b"""GET / HTTP/1.1 +""", + start=True, + raw=True, + no_recv=True, + ) + + self.clear_conf() + + resp = self.http( + b"""Host: localhost +Connection: close + +""", + sock=sock, + raw=True, + ) + assert resp['status'] == 200, 'finish request' + + def test_reconfigure_2(self): + (_, sock) = self.http(b'', raw=True, start=True, no_recv=True) + + # Waiting for connection completion. + # Delay should be more than TCP_DEFER_ACCEPT. + time.sleep(1.5) + + self.clear_conf() + + assert self.get(sock=sock)['status'] == 408, 'request timeout' diff --git a/test/test_reconfigure_tls.py b/test/test_reconfigure_tls.py new file mode 100644 index 00000000..0f92a419 --- /dev/null +++ b/test/test_reconfigure_tls.py @@ -0,0 +1,105 @@ +import socket +import ssl +import time + +import pytest +from unit.applications.tls import TestApplicationTLS + + +class TestReconfigureTLS(TestApplicationTLS): + prerequisites = {'modules': {'openssl': 'any'}} + + @pytest.fixture(autouse=True) + def setup_method_fixture(self): + if 'HAS_TLSv1_2' not in dir(ssl) or not ssl.HAS_TLSv1_2: + pytest.skip('OpenSSL too old') + + self.certificate() + + assert 'success' in self.conf( + { + "listeners": { + "*:7080": { + "pass": "routes", + "tls": {"certificate": "default"}, + } + }, + "routes": [{"action": {"return": 200}}], + "applications": {}, + } + ), 'load application configuration' + + def create_socket(self): + ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + ctx.check_hostname = False + ctx.verify_mode = ssl.CERT_NONE + + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + ssl_sock = ctx.wrap_socket( + s, server_hostname='localhost', do_handshake_on_connect=False + ) + ssl_sock.connect(('127.0.0.1', 7080)) + + return ssl_sock + + def clear_conf(self): + assert 'success' in self.conf({"listeners": {}, "applications": {}}) + + @pytest.mark.skip('not yet') + def test_reconfigure_tls_switch(self): + assert 'success' in self.conf_delete('listeners/*:7080/tls') + + (_, sock) = self.get( + headers={'Host': 'localhost', 'Connection': 'keep-alive'}, + start=True, + read_timeout=1, + ) + + assert 'success' in self.conf( + {"pass": "routes", "tls": {"certificate": "default"}}, + 'listeners/*:7080', + ) + + assert self.get(sock=sock)['status'] == 200, 'reconfigure' + assert self.get_ssl()['status'] == 200, 'reconfigure tls' + + def test_reconfigure_tls(self): + ssl_sock = self.create_socket() + + ssl_sock.sendall("""GET / HTTP/1.1\r\n""".encode()) + + self.clear_conf() + + ssl_sock.sendall( + """Host: localhost\r\nConnection: close\r\n\r\n""".encode() + ) + + assert ( + self.recvall(ssl_sock).decode().startswith('HTTP/1.1 200 OK') + ), 'finish request' + + def test_reconfigure_tls_2(self): + ssl_sock = self.create_socket() + + # Waiting for connection completion. + # Delay should be more than TCP_DEFER_ACCEPT. + time.sleep(1.5) + + self.clear_conf() + + try: + ssl_sock.do_handshake() + except ssl.SSLError: + ssl_sock.close() + success = True + + if not success: + pytest.fail('Connection is not closed.') + + def test_reconfigure_tls_3(self): + ssl_sock = self.create_socket() + ssl_sock.do_handshake() + + self.clear_conf() + + assert self.get(sock=ssl_sock)['status'] == 408, 'request timeout' diff --git a/test/test_respawn.py b/test/test_respawn.py index 5a5d6126..19d97d37 100644 --- a/test/test_respawn.py +++ b/test/test_respawn.py @@ -82,8 +82,7 @@ class TestRespawn(TestApplicationPython): skip_alert(r'process %s exited on signal 9' % pid) assert ( - self.wait_for_process(self.PATTERN_CONTROLLER, unit_pid) - is not None + self.wait_for_process(self.PATTERN_CONTROLLER, unit_pid) is not None ) assert self.get()['status'] == 200 diff --git a/test/test_return.py b/test/test_return.py index 2f7b7ae4..82bf1e64 100644 --- a/test/test_return.py +++ b/test/test_return.py @@ -83,7 +83,7 @@ Connection: close assert resp['body'] == '' def test_return_location(self): - reserved = ":/?#[]@!$&'()*+,;=" + reserved = ":/?#[]@!&'()*+,;=" unreserved = ( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" "0123456789-._~" @@ -107,15 +107,15 @@ Connection: close check_location(reserved) # After first "?" all other "?" encoded. - check_location("/?" + reserved, "/?:/%3F#[]@!$&'()*+,;=") + check_location("/?" + reserved, "/?:/%3F#[]@!&'()*+,;=") check_location("???", "?%3F%3F") # After first "#" all other "?" or "#" encoded. - check_location("/#" + reserved, "/#:/%3F%23[]@!$&'()*+,;=") + check_location("/#" + reserved, "/#:/%3F%23[]@!&'()*+,;=") check_location("##?#?", "#%23%3F%23%3F") # After first "?" next "#" not encoded. - check_location("/?#" + reserved, "/?#:/%3F%23[]@!$&'()*+,;=") + check_location("/?#" + reserved, "/?#:/%3F%23[]@!&'()*+,;=") check_location("??##", "?%3F#%23") check_location("/?##?", "/?#%23%3F") @@ -161,6 +161,38 @@ Connection: close ), 'location method not allowed' assert self.get()['headers']['Location'] == 'blah' + assert 'success' in self.conf( + '"https://${host}${uri}"', 'routes/0/action/location' + ), 'location with variables' + assert self.get()['headers']['Location'] == 'https://localhost/' + + assert 'success' in self.conf( + '"/#$host"', 'routes/0/action/location' + ), 'location with encoding and a variable' + assert self.get()['headers']['Location'] == '/#localhost' + + assert ( + self.get(headers={"Host": "#foo?bar", "Connection": "close"})[ + 'headers' + ]['Location'] + == "/#%23foo%3Fbar" + ), 'location with a variable with encoding' + + assert 'success' in self.conf( + '""', 'routes/0/action/location' + ), 'location empty' + assert self.get()['headers']['Location'] == '' + + assert 'success' in self.conf( + '"${host}"', 'routes/0/action/location' + ), 'location empty with variable' + assert ( + self.get(headers={"Host": "", "Connection": "close"})['headers'][ + 'Location' + ] + == "" + ), 'location with empty variable' + def test_return_invalid(self): def check_error(conf): assert 'error' in self.conf(conf, 'routes/0/action') @@ -171,6 +203,8 @@ Connection: close check_error({"return": 1000}) check_error({"return": -1}) check_error({"return": 200, "share": "/blah"}) + check_error({"return": 200, "location": "$hos"}) + check_error({"return": 200, "location": "$hostblah"}) assert 'error' in self.conf( '001', 'routes/0/action/return' diff --git a/test/test_routing.py b/test/test_routing.py index 167d2640..fda429a4 100644 --- a/test/test_routing.py +++ b/test/test_routing.py @@ -1,10 +1,10 @@ # -*- coding: utf-8 -*- import pytest -from unit.applications.proto import TestApplicationProto +from unit.applications.lang.python import TestApplicationPython from unit.option import option -class TestRouting(TestApplicationProto): +class TestRouting(TestApplicationPython): prerequisites = {'modules': {'python': 'any'}} def setup_method(self): @@ -12,7 +12,10 @@ class TestRouting(TestApplicationProto): { "listeners": {"*:7080": {"pass": "routes"}}, "routes": [ - {"match": {"method": "GET"}, "action": {"return": 200},} + { + "match": {"method": "GET"}, + "action": {"return": 200}, + } ], "applications": {}, } @@ -289,7 +292,7 @@ class TestRouting(TestApplicationProto): "listeners": {"*:7080": {"pass": "applications/" + path}}, "applications": { name: { - "type": "python", + "type": self.get_application_type(), "processes": {"spare": 0}, "path": option.test_dir + '/python/empty', "working_directory": option.test_dir @@ -313,7 +316,7 @@ class TestRouting(TestApplicationProto): "listeners": {"*:7080": {"pass": "applications/" + path}}, "applications": { name: { - "type": "python", + "type": self.get_application_type(), "processes": {"spare": 0}, "path": option.test_dir + '/python/empty', "working_directory": option.test_dir @@ -333,7 +336,7 @@ class TestRouting(TestApplicationProto): "listeners": {"*:7081": {"pass": "applications/empty"}}, "applications": { "empty": { - "type": "python", + "type": self.get_application_type(), "processes": {"spare": 0}, "path": option.test_dir + '/python/empty', "working_directory": option.test_dir + '/python/empty', @@ -387,7 +390,7 @@ class TestRouting(TestApplicationProto): { "applications": { "app": { - "type": "python", + "type": self.get_application_type(), "processes": {"spare": 0}, "path": "/app", "module": "wsgi", @@ -430,7 +433,7 @@ class TestRouting(TestApplicationProto): { "applications": { "app": { - "type": "python", + "type": self.get_application_type(), "processes": {"spare": 0}, "path": "/app", "module": "wsgi", @@ -476,7 +479,7 @@ class TestRouting(TestApplicationProto): "routes": [{"action": {"proxy": "http://127.0.0.1:7081"}}], "applications": { "app": { - "type": "python", + "type": self.get_application_type(), "processes": {"spare": 0}, "path": "/app", "module": "wsgi", @@ -490,11 +493,15 @@ class TestRouting(TestApplicationProto): 'routes/0/action', ), 'proxy share' assert 'error' in self.conf( - {"proxy": "http://127.0.0.1:7081", "pass": "applications/app",}, + { + "proxy": "http://127.0.0.1:7081", + "pass": "applications/app", + }, '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): @@ -693,7 +700,8 @@ class TestRouting(TestApplicationProto): assert self.post()['status'] == 404, 'routes edit POST' assert 'success' in self.conf_post( - {"match": {"method": "POST"}, "action": {"return": 200}}, 'routes', + {"match": {"method": "POST"}, "action": {"return": 200}}, + 'routes', ), 'routes edit configure 2' assert 'GET' == self.conf_get( 'routes/0/match/method' @@ -733,7 +741,8 @@ class TestRouting(TestApplicationProto): assert self.post()['status'] == 404, 'routes edit POST 5' assert 'success' in self.conf_post( - {"match": {"method": "POST"}, "action": {"return": 200}}, 'routes', + {"match": {"method": "POST"}, "action": {"return": 200}}, + 'routes', ), 'routes edit configure 6' assert self.get()['status'] == 404, 'routes edit GET 6' @@ -1042,9 +1051,7 @@ class TestRouting(TestApplicationProto): def check_headers(hds): hds = dict({"Host": "localhost", "Connection": "close"}, **hds) - assert ( - self.get(headers=hds)['status'] == 200 - ), 'headers array match' + assert self.get(headers=hds)['status'] == 200, 'headers array match' def check_headers_404(hds): hds = dict({"Host": "localhost", "Connection": "close"}, **hds) @@ -1262,9 +1269,7 @@ class TestRouting(TestApplicationProto): self.get(url='/?foo=bar&blah=test')['status'] == 200 ), 'multiple 2' assert self.get(url='/?foo=bar&blah')['status'] == 404, 'multiple 3' - assert ( - self.get(url='/?foo=bar&blah=tes')['status'] == 404 - ), 'multiple 4' + assert self.get(url='/?foo=bar&blah=tes')['status'] == 404, 'multiple 4' assert ( self.get(url='/?foo=b%61r&bl%61h=t%65st')['status'] == 200 ), 'multiple 5' @@ -1494,9 +1499,7 @@ class TestRouting(TestApplicationProto): sock, port = sock_port() sock2, port2 = sock_port() - self.route_match( - {"source": "127.0.0.1:" + str(port) + "-" + str(port)} - ) + self.route_match({"source": "127.0.0.1:" + str(port) + "-" + str(port)}) assert self.get(sock=sock)['status'] == 200, 'range single' assert self.get(sock=sock2)['status'] == 404, 'range single 2' @@ -1544,7 +1547,10 @@ class TestRouting(TestApplicationProto): def test_routes_source_addr(self): assert 'success' in self.conf( - {"*:7080": {"pass": "routes"}, "[::1]:7081": {"pass": "routes"},}, + { + "*:7080": {"pass": "routes"}, + "[::1]:7081": {"pass": "routes"}, + }, 'listeners', ), 'source listeners configure' @@ -1650,7 +1656,10 @@ class TestRouting(TestApplicationProto): def test_routes_source_cidr(self): assert 'success' in self.conf( - {"*:7080": {"pass": "routes"}, "[::1]:7081": {"pass": "routes"},}, + { + "*:7080": {"pass": "routes"}, + "[::1]:7081": {"pass": "routes"}, + }, 'listeners', ), 'source listeners configure' diff --git a/test/test_ruby_application.py b/test/test_ruby_application.py index ed0200d9..95c75d47 100644 --- a/test/test_ruby_application.py +++ b/test/test_ruby_application.py @@ -44,6 +44,7 @@ class TestRubyApplication(TestApplicationRuby): 'Request-Method': 'POST', 'Request-Uri': '/', 'Http-Host': 'localhost', + 'Script-Name': 'config.ru', 'Server-Protocol': 'HTTP/1.1', 'Custom-Header': 'blah', 'Rack-Version': '13', @@ -172,17 +173,16 @@ class TestRubyApplication(TestApplicationRuby): def test_ruby_application_errors_puts(self): self.load('errors_puts') - self.get() + assert self.get()['status'] == 200 assert ( - self.wait_for_record(r'\[error\].+Error in application') - is not None + self.wait_for_record(r'\[error\].+Error in application') is not None ), 'errors puts' def test_ruby_application_errors_puts_int(self): self.load('errors_puts_int') - self.get() + assert self.get()['status'] == 200 assert ( self.wait_for_record(r'\[error\].+1234567890') is not None @@ -191,11 +191,9 @@ class TestRubyApplication(TestApplicationRuby): def test_ruby_application_errors_write(self): self.load('errors_write') - self.get() - + assert self.get()['status'] == 200 assert ( - self.wait_for_record(r'\[error\].+Error in application') - is not None + self.wait_for_record(r'\[error\].+Error in application') is not None ), 'errors write' def test_ruby_application_errors_write_to_s_custom(self): @@ -206,8 +204,7 @@ class TestRubyApplication(TestApplicationRuby): def test_ruby_application_errors_write_int(self): self.load('errors_write_int') - self.get() - + assert self.get()['status'] == 200 assert ( self.wait_for_record(r'\[error\].+1234567890') is not None ), 'errors write int' @@ -215,7 +212,7 @@ class TestRubyApplication(TestApplicationRuby): def test_ruby_application_at_exit(self): self.load('at_exit') - self.get() + assert self.get()['status'] == 200 assert 'success' in self.conf({"listeners": {}, "applications": {}}) @@ -229,7 +226,8 @@ class TestRubyApplication(TestApplicationRuby): try: locales = ( subprocess.check_output( - ['locale', '-a'], stderr=subprocess.STDOUT, + ['locale', '-a'], + stderr=subprocess.STDOUT, ) .decode() .split('\n') diff --git a/test/test_ruby_hooks.py b/test/test_ruby_hooks.py index 20980ad7..b4a79ebb 100644 --- a/test/test_ruby_hooks.py +++ b/test/test_ruby_hooks.py @@ -81,7 +81,10 @@ class TestRubyHooks(TestApplicationRuby): threads = 1 self.load( - 'hooks', processes=processes, threads=threads, hooks='multiple.rb', + 'hooks', + processes=processes, + threads=threads, + hooks='multiple.rb', ) hooked = self._wait_cookie('worker_boot.*', processes) diff --git a/test/test_ruby_isolation.py b/test/test_ruby_isolation.py index 940427f1..ea208523 100644 --- a/test/test_ruby_isolation.py +++ b/test/test_ruby_isolation.py @@ -34,11 +34,13 @@ class TestRubyIsolation(TestApplicationRuby): self.load('status_int', isolation=isolation) assert 'success' in self.conf( - '"/ruby/status_int/config.ru"', 'applications/status_int/script', + '"/ruby/status_int/config.ru"', + 'applications/status_int/script', ) assert 'success' in self.conf( - '"/ruby/status_int"', 'applications/status_int/working_directory', + '"/ruby/status_int"', + 'applications/status_int/working_directory', ) assert self.get()['status'] == 200, 'status int' diff --git a/test/test_settings.py b/test/test_settings.py index a16e35e8..ea3cfb99 100644 --- a/test/test_settings.py +++ b/test/test_settings.py @@ -207,9 +207,7 @@ Connection: close {"unix:" + addr: {'application': 'body_generate'}}, 'listeners' ) - assert 'success' in self.conf( - {'http': {'send_timeout': 1}}, 'settings' - ) + assert 'success' in self.conf({'http': {'send_timeout': 1}}, 'settings') data = req(addr, data_len) assert re.search(r'200 OK', data), 'send timeout status' @@ -237,14 +235,10 @@ Connection: close assert self.get()['status'] == 200, 'init' - assert 'success' in self.conf( - {'http': {'idle_timeout': 2}}, 'settings' - ) + assert 'success' in self.conf({'http': {'idle_timeout': 2}}, 'settings') assert req()['status'] == 408, 'status idle timeout' - assert 'success' in self.conf( - {'http': {'idle_timeout': 7}}, 'settings' - ) + 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): @@ -259,14 +253,10 @@ Connection: close assert self.get()['status'] == 200, 'init' - assert 'success' in self.conf( - {'http': {'idle_timeout': 1}}, 'settings' - ) + 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 'success' in self.conf({'http': {'idle_timeout': 7}}, 'settings') assert req()['status'] == 200, 'status idle timeout 2' def test_settings_max_body_size(self): diff --git a/test/test_static.py b/test/test_static.py index 80f4c610..b9c78fdd 100644 --- a/test/test_static.py +++ b/test/test_static.py @@ -3,7 +3,8 @@ import shutil import socket import pytest -from conftest import unit_run, unit_stop +from conftest import unit_run +from conftest import unit_stop from unit.applications.proto import TestApplicationProto from unit.option import option from unit.utils import waitforfiles @@ -86,6 +87,22 @@ class TestStatic(TestApplicationProto): assert self.get(url='/')['body'] == '0123456789', 'before 1.26.0 2' def test_static_index(self): + def set_index(index): + assert 'success' in self.conf( + {"share": option.temp_dir + "/assets$uri", "index": index}, + 'routes/0/action', + ), 'configure index' + + set_index('README') + assert self.get()['body'] == 'readme', 'index' + + self.conf_delete('routes/0/action/index') + assert self.get()['body'] == '0123456789', 'delete index' + + set_index('') + assert self.get()['status'] == 404, 'index empty' + + def test_static_index_default(self): assert self.get(url='/index.html')['body'] == '0123456789', 'index' assert self.get(url='/')['body'] == '0123456789', 'index 2' assert self.get(url='//')['body'] == '0123456789', 'index 3' @@ -101,6 +118,18 @@ class TestStatic(TestApplicationProto): resp['headers']['Content-Type'] == 'text/html' ), 'index not found 2 Content-Type' + def test_static_index_invalid(self, skip_alert): + skip_alert(r'failed to apply new conf') + + def check_index(index): + assert 'error' in self.conf( + {"share": option.temp_dir + "/assets$uri", "index": index}, + 'routes/0/action', + ) + + check_index({}) + check_index(['index.html', '$blah']) + def test_static_large_file(self, temp_dir): file_size = 32 * 1024 * 1024 with open(temp_dir + '/assets/large', 'wb') as f: @@ -132,7 +161,8 @@ 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' @@ -153,9 +183,7 @@ class TestStatic(TestApplicationProto): assert ( self.get(url='/ di r %2Ffi le')['body'] == 'blah' ), 'slash encoded' - assert ( - self.get(url='/ di r /fi%20le')['body'] == 'blah' - ), 'file encoded' + assert self.get(url='/ di r /fi%20le')['body'] == 'blah', 'file encoded' assert ( self.get(url='/%20di%20r%20%2Ffi%20le')['body'] == 'blah' ), 'encoded' @@ -194,7 +222,8 @@ 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 ( @@ -265,13 +294,14 @@ class TestStatic(TestApplicationProto): self.get(url='/')['headers']['Content-Type'] == 'text/plain' ), 'mime_types index default' assert ( - self.get(url='/dir/file')['headers']['Content-Type'] - == 'text/plain' + self.get(url='/dir/file')['headers']['Content-Type'] == 'text/plain' ), 'mime_types file in dir' def test_static_mime_types_partial_match(self): assert 'success' in self.conf( - {"text/x-blah": ["ile", "fil", "f", "e", ".file"],}, + { + "text/x-blah": ["ile", "fil", "f", "e", ".file"], + }, 'settings/http/static/mime_types', ), 'configure mime_types' assert 'Content-Type' not in self.get(url='/dir/file'), 'partial match' @@ -312,16 +342,14 @@ class TestStatic(TestApplicationProto): '"file"', 'settings/http/static/mime_types/text%2Fplain' ), 'mime_types add array element' assert ( - self.get(url='/dir/file')['headers']['Content-Type'] - == 'text/plain' + self.get(url='/dir/file')['headers']['Content-Type'] == 'text/plain' ), 'mime_types reverted' assert 'success' in self.conf( '"file"', 'settings/http/static/mime_types/text%2Fplain' ), 'configure mime_types update' assert ( - self.get(url='/dir/file')['headers']['Content-Type'] - == 'text/plain' + self.get(url='/dir/file')['headers']['Content-Type'] == 'text/plain' ), 'mime_types updated' assert ( 'Content-Type' not in self.get(url='/log.log')['headers'] @@ -345,7 +373,10 @@ class TestStatic(TestApplicationProto): 'settings/http/static/mime_types', ), 'mime_types same extensions array' assert 'error' in self.conf( - {"text/x-code": [".h", ".c", "readme"], "text/plain": "README",}, + { + "text/x-code": [".h", ".c", "readme"], + "text/plain": "README", + }, 'settings/http/static/mime_types', ), 'mime_types same extensions case insensitive' diff --git a/test/test_static_chroot.py b/test/test_static_chroot.py index 62288807..b896a9b9 100644 --- a/test/test_static_chroot.py +++ b/test/test_static_chroot.py @@ -26,13 +26,14 @@ class TestStaticChroot(TestApplicationProto): def update_action(self, share, chroot): return self.conf( - {"share": share, "chroot": chroot}, 'routes/0/action', + {"share": share, "chroot": chroot}, + 'routes/0/action', ) def get_custom(self, uri, host): - return self.get( - url=uri, headers={'Host': host, 'Connection': 'close'} - )['status'] + return self.get(url=uri, headers={'Host': host, 'Connection': 'close'})[ + 'status' + ] def test_static_chroot(self, temp_dir): assert self.get(url='/dir/file')['status'] == 200, 'default chroot' @@ -101,7 +102,8 @@ class TestStaticChroot(TestApplicationProto): ), 'chroot empty absolute' assert 'success' in self.conf( - {"share": ".$uri", "chroot": ""}, 'routes/0/action', + {"share": ".$uri", "chroot": ""}, + 'routes/0/action', ), 'configure chroot empty relative' assert ( @@ -120,13 +122,15 @@ class TestStaticChroot(TestApplicationProto): assert self.get(url='/dir/file')['status'] == 403, 'relative chroot' assert 'success' in self.conf( - {"share": ".$uri"}, 'routes/0/action', + {"share": ".$uri"}, + 'routes/0/action', ), 'configure relative share' assert self.get(url=self.test_path)['status'] == 200, 'relative share' assert 'success' in self.conf( - {"share": ".$uri", "chroot": "."}, 'routes/0/action', + {"share": ".$uri", "chroot": "."}, + 'routes/0/action', ), 'configure relative' assert self.get(url=self.test_path)['status'] == 200, 'relative' @@ -208,13 +212,16 @@ class TestStaticChroot(TestApplicationProto): def test_static_chroot_invalid(self, temp_dir): assert 'error' in self.conf( - {"share": temp_dir, "chroot": True}, 'routes/0/action', + {"share": temp_dir, "chroot": True}, + 'routes/0/action', ), 'configure chroot error' assert 'error' in self.conf( - {"share": temp_dir, "symlinks": "True"}, 'routes/0/action', + {"share": temp_dir, "symlinks": "True"}, + 'routes/0/action', ), 'configure symlink error' assert 'error' in self.conf( - {"share": temp_dir, "mount": "True"}, 'routes/0/action', + {"share": temp_dir, "mount": "True"}, + 'routes/0/action', ), 'configure mount error' assert 'error' in self.update_action( diff --git a/test/test_static_fallback.py b/test/test_static_fallback.py index 71b268c8..1f1a1df7 100644 --- a/test/test_static_fallback.py +++ b/test/test_static_fallback.py @@ -82,7 +82,10 @@ class TestStaticFallback(TestApplicationProto): def test_static_fallback_share(self, temp_dir): self.action_update( - {"share": "/blah", "fallback": {"share": temp_dir + "/assets$uri"},} + { + "share": "/blah", + "fallback": {"share": temp_dir + "/assets$uri"}, + } ) resp = self.get() diff --git a/test/test_static_mount.py b/test/test_static_mount.py index 82eda956..91cf836c 100644 --- a/test/test_static_mount.py +++ b/test/test_static_mount.py @@ -41,9 +41,7 @@ class TestStaticMount(TestApplicationProto): self._load_conf( { "listeners": {"*:7080": {"pass": "routes"}}, - "routes": [ - {"action": {"share": temp_dir + "/assets/dir$uri"}} - ], + "routes": [{"action": {"share": temp_dir + "/assets/dir$uri"}}], } ) diff --git a/test/test_static_types.py b/test/test_static_types.py index 18564a21..0e86517b 100644 --- a/test/test_static_types.py +++ b/test/test_static_types.py @@ -85,7 +85,10 @@ class TestStaticTypes(TestApplicationProto): def test_static_types_regex(self, temp_dir): self.action_update( - {"share": temp_dir + "/assets$uri", "types": ["~text/(html|plain)"]} + { + "share": temp_dir + "/assets$uri", + "types": ["~text/(html|plain)"], + } ) assert self.get(url='/file.php')['status'] == 403, 'regex fail' self.check_body('/file.html', '.html') diff --git a/test/test_tls.py b/test/test_tls.py index 01336765..56ee8298 100644 --- a/test/test_tls.py +++ b/test/test_tls.py @@ -175,11 +175,13 @@ basicConstraints = critical,CA:TRUE""" self.add_tls() - cert_old = self.get_server_certificate() + cert_old = ssl.get_server_certificate(('127.0.0.1', 7080)) self.certificate() - assert cert_old != self.get_server_certificate(), 'update certificate' + assert cert_old != ssl.get_server_certificate( + ('127.0.0.1', 7080) + ), 'update certificate' @pytest.mark.skip('not yet') def test_tls_certificate_key_incorrect(self): @@ -200,11 +202,13 @@ basicConstraints = critical,CA:TRUE""" self.add_tls() - cert_old = self.get_server_certificate() + cert_old = ssl.get_server_certificate(('127.0.0.1', 7080)) self.add_tls(cert='new') - assert cert_old != self.get_server_certificate(), 'change certificate' + assert cert_old != ssl.get_server_certificate( + ('127.0.0.1', 7080) + ), 'change certificate' def test_tls_certificate_key_rsa(self): self.load('empty') @@ -354,9 +358,7 @@ basicConstraints = critical,CA:TRUE""" self.add_tls(cert='int') - assert ( - self.get_ssl()['status'] == 200 - ), 'certificate chain intermediate' + assert self.get_ssl()['status'] == 200, 'certificate chain intermediate' # intermediate server @@ -385,6 +387,51 @@ basicConstraints = critical,CA:TRUE""" self.get_ssl()['status'] == 200 ), 'certificate chain intermediate server' + def test_tls_certificate_chain_long(self, temp_dir): + self.load('empty') + + self.generate_ca_conf() + + # Minimum chain length is 3. + chain_length = 10 + + for i in range(chain_length): + if i == 0: + self.certificate('root', False) + elif i == chain_length - 1: + self.req('end') + else: + self.req('int{}'.format(i)) + + for i in range(chain_length - 1): + if i == 0: + self.ca(cert='root', out='int1') + elif i == chain_length - 2: + self.ca(cert='int{}'.format(chain_length - 2), out='end') + else: + self.ca(cert='int{}'.format(i), out='int{}'.format(i + 1)) + + for i in range(chain_length - 1, 0, -1): + path = temp_dir + ( + '/end.crt' if i == chain_length - 1 else '/int{}.crt'.format(i) + ) + + with open(temp_dir + '/all.crt', 'a') as chain, open(path) as cert: + chain.write(cert.read()) + + self.set_certificate_req_context() + + assert 'success' in self.certificate_load( + 'all', 'end' + ), 'certificate chain upload' + + chain = self.conf_get('/certificates/all/chain') + assert len(chain) == chain_length - 1, 'certificate chain length' + + self.add_tls(cert='all') + + assert self.get_ssl()['status'] == 200, 'certificate chain long' + def test_tls_certificate_empty_cn(self, temp_dir): self.certificate('root', False) @@ -446,27 +493,6 @@ basicConstraints = critical,CA:TRUE""" }, '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') - - assert self.get()['status'] == 200, 'init' - - self.certificate() - - (resp, sock) = self.get( - headers={'Host': 'localhost', 'Connection': 'keep-alive'}, - start=True, - read_timeout=1, - ) - - assert resp['status'] == 200, 'initial status' - - self.add_tls() - - assert self.get(sock=sock)['status'] == 200, 'reconfigure status' - assert self.get_ssl()['status'] == 200, 'reconfigure tls status' - def test_tls_keepalive(self): self.load('mirror') diff --git a/test/test_tls_sni.py b/test/test_tls_sni.py index d5f205cf..dbd5d900 100644 --- a/test/test_tls_sni.py +++ b/test/test_tls_sni.py @@ -178,7 +178,8 @@ basicConstraints = critical,CA:TRUE""" self.add_tls(["localhost.com", "example.com"]) resp, sock = self.get_ssl( - headers={'Content-Length': '0', 'Connection': 'close'}, start=True, + headers={'Content-Length': '0', 'Connection': 'close'}, + start=True, ) assert resp['status'] == 200 assert ( @@ -272,9 +273,7 @@ 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_tls_tickets.py b/test/test_tls_tickets.py index 6899eaa1..5399fae7 100644 --- a/test/test_tls_tickets.py +++ b/test/test_tls_tickets.py @@ -17,9 +17,7 @@ class TestTLSTicket(TestApplicationTLS): prerequisites = {'modules': {'openssl': 'any'}} ticket = 'U1oDTh11mMxODuw12gS0EXX1E/PkZG13cJNQ6m5+6BGlfPTjNlIEw7PSVU3X1gTE' - ticket2 = ( - '5AV0DSYIYbZWZQB7fCnTHZmMxtotb/aXjam+n2XS79lTvX3Tq9xGqpC8XKNEF2lt' - ) + ticket2 = '5AV0DSYIYbZWZQB7fCnTHZmMxtotb/aXjam+n2XS79lTvX3Tq9xGqpC8XKNEF2lt' ticket80 = '6Pfil8lv/k8zf8MndPpfXaO5EAV6dhME6zs6CfUyq2yziynQwSywtKQMqHGnJ2HR\ 49TZXi/Y4/8RSIO7QPsU51/HLR1gWIMhVM2m9yh93Bw=' @@ -182,7 +180,8 @@ class TestTLSTicket(TestApplicationTLS): def test_tls_ticket_invalid(self): def check_tickets(tickets): assert 'error' in self.conf( - {"tickets": tickets}, 'listeners/*:7080/tls/session', + {"tickets": tickets}, + 'listeners/*:7080/tls/session', ) check_tickets({}) diff --git a/test/test_upstreams_rr.py b/test/test_upstreams_rr.py index 163eb646..dd64e1d9 100644 --- a/test/test_upstreams_rr.py +++ b/test/test_upstreams_rr.py @@ -274,7 +274,7 @@ Connection: close ], "applications": { "delayed": { - "type": "python", + "type": self.get_application_type(), "processes": {"spare": 0}, "path": option.test_dir + "/python/delayed", "working_directory": option.test_dir @@ -342,7 +342,8 @@ Connection: close assert self.get()['body'] == '' assert 'success' in self.conf( - {"127.0.0.1:7083": {"weight": 2}}, 'upstreams/one/servers', + {"127.0.0.1:7083": {"weight": 2}}, + 'upstreams/one/servers', ), 'active req new server' assert 'success' in self.conf_delete( 'upstreams/one/servers/127.0.0.1:7083' diff --git a/test/test_usr1.py b/test/test_usr1.py index 9a12b747..3d190935 100644 --- a/test/test_usr1.py +++ b/test/test_usr1.py @@ -59,9 +59,7 @@ class TestUSR1(TestApplicationPython): body = 'body_for_a_log_new\n' assert self.post(body=body)['status'] == 200 - assert ( - self.wait_for_record(body, log_new) is not None - ), 'rename new' + assert self.wait_for_record(body, log_new) is not None, 'rename new' assert not os.path.isfile(log_path), 'rename old' os.kill(unit_pid, signal.SIGUSR1) diff --git a/test/test_variables.py b/test/test_variables.py index d8547b7b..71553685 100644 --- a/test/test_variables.py +++ b/test/test_variables.py @@ -17,6 +17,7 @@ class TestVariables(TestApplicationProto): "5GET": [{"action": {"return": 206}}], "GETGET": [{"action": {"return": 207}}], "localhost": [{"action": {"return": 208}}], + "9?q#a": [{"action": {"return": 209}}], }, }, ), 'configure routes' @@ -28,6 +29,14 @@ class TestVariables(TestApplicationProto): assert self.get()['status'] == 201, 'method GET' assert self.post()['status'] == 202, 'method POST' + def test_variables_request_uri(self): + self.conf_routes("\"routes$request_uri\"") + + assert self.get(url='/3')['status'] == 203, 'request_uri' + assert self.get(url='/4*')['status'] == 204, 'request_uri 2' + assert self.get(url='/4%2A')['status'] == 204, 'request_uri 3' + assert self.get(url='/9?q#a')['status'] == 209, 'request_uri query' + def test_variables_uri(self): self.conf_routes("\"routes$uri\"") @@ -103,20 +112,16 @@ class TestVariables(TestApplicationProto): def test_variables_empty(self): def update_pass(prefix): assert 'success' in self.conf( - { - "listeners": { - "*:7080": {"pass": prefix + "/$method"}, - }, - }, + {"listeners": {"*:7080": {"pass": prefix + "/$method"}}}, ), 'variables empty' - update_pass("routes"); + update_pass("routes") assert self.get(url='/1')['status'] == 404 - update_pass("upstreams"); + update_pass("upstreams") assert self.get(url='/2')['status'] == 404 - update_pass("applications"); + update_pass("applications") assert self.get(url='/3')['status'] == 404 def test_variables_invalid(self): diff --git a/test/unit/applications/lang/go.py b/test/unit/applications/lang/go.py index 367059e6..04af26e1 100644 --- a/test/unit/applications/lang/go.py +++ b/test/unit/applications/lang/go.py @@ -1,4 +1,5 @@ import os +import shutil import subprocess from unit.applications.proto import TestApplicationProto @@ -6,14 +7,25 @@ from unit.option import option class TestApplicationGo(TestApplicationProto): - def prepare_env(self, script, name, static=False): - if not os.path.exists(option.temp_dir + '/go'): - os.mkdir(option.temp_dir + '/go') + @staticmethod + def prepare_env(script, name='app', static=False): + temp_dir = option.temp_dir + '/go/' + + if not os.path.exists(temp_dir): + os.mkdir(temp_dir) + + cache_dir = option.cache_dir + '/go-build' + + if not os.path.exists(cache_dir): + os.mkdir(cache_dir) env = os.environ.copy() env['GOPATH'] = option.current_dir + '/build/go' - env['GOCACHE'] = option.cache_dir + '/go' - env['GO111MODULE'] = 'auto' + env['GOCACHE'] = cache_dir + + shutil.copy2( + option.test_dir + '/go/' + script + '/' + name + '.go', temp_dir + ) if static: args = [ @@ -24,23 +36,33 @@ class TestApplicationGo(TestApplicationProto): '-ldflags', '-extldflags "-static"', '-o', - option.temp_dir + '/go/' + name, - option.test_dir + '/go/' + script + '/' + name + '.go', + temp_dir + name, + temp_dir + name + '.go', ] else: args = [ 'go', 'build', '-o', - option.temp_dir + '/go/' + name, - option.test_dir + '/go/' + script + '/' + name + '.go', + temp_dir + name, + temp_dir + name + '.go', ] + replace_path = option.current_dir + '/build/go/src/unit.nginx.org/go' + + with open(temp_dir + 'go.mod', 'w') as f: + f.write( + f"""module test/app +require unit.nginx.org/go v0.0.0 +replace unit.nginx.org/go => {replace_path} +""" + ) + if option.detailed: print("\n$ GOPATH=" + env['GOPATH'] + " " + " ".join(args)) try: - process = subprocess.run(args, env=env) + process = subprocess.run(args, env=env, cwd=temp_dir) except KeyboardInterrupt: raise @@ -61,7 +83,7 @@ class TestApplicationGo(TestApplicationProto): executable = "/go/" + name static_build = True - self.prepare_env(script, name, static=static_build) + TestApplicationGo.prepare_env(script, name, static=static_build) conf = { "listeners": {"*:7080": {"pass": "applications/" + script}}, diff --git a/test/unit/applications/tls.py b/test/unit/applications/tls.py index c7254235..93400328 100644 --- a/test/unit/applications/tls.py +++ b/test/unit/applications/tls.py @@ -52,21 +52,6 @@ class TestApplicationTLS(TestApplicationProto): def post_ssl(self, **kwargs): return self.post(wrapper=self.context.wrap_socket, **kwargs) - def get_server_certificate(self, addr=('127.0.0.1', 7080)): - - ssl_list = dir(ssl) - - if 'PROTOCOL_TLS' in ssl_list: - ssl_version = ssl.PROTOCOL_TLS - - elif 'PROTOCOL_TLSv1_2' in ssl_list: - ssl_version = ssl.PROTOCOL_TLSv1_2 - - else: - ssl_version = ssl.PROTOCOL_TLSv1_1 - - return ssl.get_server_certificate(addr, ssl_version=ssl_version) - def openssl_conf(self, rewrite=False, alt_names=[]): conf_path = option.temp_dir + '/openssl.conf' diff --git a/test/unit/applications/websockets.py b/test/unit/applications/websockets.py index aa83339c..d647ce9b 100644 --- a/test/unit/applications/websockets.py +++ b/test/unit/applications/websockets.py @@ -43,7 +43,11 @@ 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: @@ -218,9 +222,7 @@ class TestApplicationWebsocket(TestApplicationProto): while pos < message_len: end = min(pos + fragmention_size, message_len) fin = end == message_len - self.frame_write( - sock, op_code, message[pos:end], fin=fin, **kwargs - ) + self.frame_write(sock, op_code, message[pos:end], fin=fin, **kwargs) op_code = self.OP_CONT pos = end diff --git a/test/unit/check/go.py b/test/unit/check/go.py index cc17f0fe..3d9d13e7 100644 --- a/test/unit/check/go.py +++ b/test/unit/check/go.py @@ -1,34 +1,8 @@ -import os -import subprocess +from unit.applications.lang.go import TestApplicationGo -def check_go(current_dir, temp_dir, test_dir): - if not os.path.exists(temp_dir + '/go'): - os.mkdir(temp_dir + '/go') +def check_go(): + process = TestApplicationGo.prepare_env('empty') - env = os.environ.copy() - env['GOPATH'] = current_dir + '/build/go' - env['GO111MODULE'] = 'auto' - - try: - process = subprocess.run( - [ - 'go', - 'build', - '-o', - temp_dir + '/go/app', - test_dir + '/go/empty/app.go', - ], - env=env, - stderr=subprocess.STDOUT, - stdout=subprocess.PIPE, - ) - - if process.returncode == 0: - return True - - except KeyboardInterrupt: - raise - - except subprocess.CalledProcessError: - return None + if process != None and process.returncode == 0: + return True diff --git a/test/unit/control.py b/test/unit/control.py index 3008a64b..99436ca0 100644 --- a/test/unit/control.py +++ b/test/unit/control.py @@ -30,10 +30,6 @@ def args_handler(conf_func): class TestControl(TestHTTP): - - # TODO socket reuse - # TODO http client - @args_handler def conf(self, conf, url): return self.put(**self._get_args(url, conf))['body'] diff --git a/test/unit/http.py b/test/unit/http.py index dcfcd232..b4a1a17b 100644 --- a/test/unit/http.py +++ b/test/unit/http.py @@ -328,9 +328,7 @@ 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() |