summaryrefslogtreecommitdiffhomepage
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/conftest.py28
-rw-r--r--test/python/prefix/asgi.py15
-rw-r--r--test/python/prefix/wsgi.py10
-rw-r--r--test/python/targets/asgi.py17
-rw-r--r--test/python/targets/wsgi.py9
-rw-r--r--test/test_access_log.py22
-rw-r--r--test/test_asgi_application.py43
-rw-r--r--test/test_asgi_targets.py45
-rw-r--r--test/test_configuration.py86
-rw-r--r--test/test_java_application.py20
-rw-r--r--test/test_njs.py90
-rw-r--r--test/test_perl_application.py3
-rw-r--r--test/test_php_application.py44
-rw-r--r--test/test_proxy.py25
-rw-r--r--test/test_python_application.py41
-rw-r--r--test/test_python_isolation.py136
-rw-r--r--test/test_python_targets.py52
-rw-r--r--test/test_reconfigure.py5
-rw-r--r--test/test_routing.py16
-rw-r--r--test/test_ruby_application.py3
-rw-r--r--test/test_settings.py68
-rw-r--r--test/test_static.py50
-rw-r--r--test/test_status.py99
-rw-r--r--test/test_upstreams_rr.py8
-rw-r--r--test/test_variables.py492
-rw-r--r--test/unit/applications/lang/go.py6
-rw-r--r--test/unit/applications/lang/java.py2
-rw-r--r--test/unit/applications/lang/python.py1
-rw-r--r--test/unit/applications/websockets.py3
-rw-r--r--test/unit/check/go.py4
-rw-r--r--test/unit/check/njs.py6
-rw-r--r--test/unit/check/regex.py9
-rw-r--r--test/unit/check/tls.py13
-rw-r--r--test/unit/http.py7
-rw-r--r--test/unit/utils.py21
35 files changed, 1096 insertions, 403 deletions
diff --git a/test/conftest.py b/test/conftest.py
index 18851baa..4a1aa7cc 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -17,6 +17,7 @@ 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.njs import check_njs
from unit.check.node import check_node
from unit.check.regex import check_regex
from unit.check.tls import check_openssl
@@ -25,8 +26,10 @@ from unit.http import TestHTTP
from unit.log import Log
from unit.option import option
from unit.status import Status
+from unit.utils import check_findmnt
from unit.utils import public_dir
from unit.utils import waitforfiles
+from unit.utils import waitforunmount
def pytest_addoption(parser):
@@ -86,6 +89,7 @@ _fds_info = {
},
}
http = TestHTTP()
+is_findmnt = check_findmnt()
def pytest_configure(config):
@@ -176,6 +180,9 @@ def pytest_sessionstart(session):
option.available = {'modules': {}, 'features': {}}
unit = unit_run()
+ output_version = subprocess.check_output(
+ [unit['unitd'], '--version'], stderr=subprocess.STDOUT
+ ).decode()
# read unit.log
@@ -202,10 +209,11 @@ def pytest_sessionstart(session):
# discover modules from check
- option.available['modules']['openssl'] = check_openssl(unit['unitd'])
option.available['modules']['go'] = check_go()
+ option.available['modules']['njs'] = check_njs(output_version)
option.available['modules']['node'] = check_node(option.current_dir)
- option.available['modules']['regex'] = check_regex(unit['unitd'])
+ option.available['modules']['openssl'] = check_openssl(output_version)
+ option.available['modules']['regex'] = check_regex(output_version)
# remove None values
@@ -310,6 +318,9 @@ def run(request):
if not option.restart:
_clear_conf(unit['temp_dir'] + '/control.unit.sock', log=log)
+ if is_findmnt and not waitforunmount(unit['temp_dir'], timeout=600):
+ exit('Could not unmount some filesystems in tmp dir.')
+
for item in os.listdir(unit['temp_dir']):
if item not in [
'control.unit.sock',
@@ -480,14 +491,15 @@ def _check_alerts(*, log=None):
log = f.read()
found = False
-
alerts = re.findall(r'.+\[alert\].+', log)
if alerts:
- print('\nAll alerts/sanitizer errors found in log:')
- [print(alert) for alert in alerts]
found = True
+ if option.detailed:
+ print('\nAll alerts/sanitizer errors found in log:')
+ [print(alert) for alert in alerts]
+
if option.skip_alerts:
for skip in option.skip_alerts:
alerts = [al for al in alerts if re.search(skip, al) is None]
@@ -499,7 +511,7 @@ def _check_alerts(*, log=None):
assert not sanitizer_errors, 'sanitizer error(s)'
- if found:
+ if found and option.detailed:
print('skipped.')
@@ -571,6 +583,10 @@ def _check_processes():
time.sleep(0.1)
+ if option.restart:
+ assert len(out) == 0, 'all termimated'
+ return
+
assert len(out) == 3, 'main, router, and controller expected'
out = [l for l in out if 'unit: main' not in l]
diff --git a/test/python/prefix/asgi.py b/test/python/prefix/asgi.py
new file mode 100644
index 00000000..234f084f
--- /dev/null
+++ b/test/python/prefix/asgi.py
@@ -0,0 +1,15 @@
+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'prefix', scope.get('root_path', 'NULL').encode()),
+ ],
+ }
+ )
+
+ await send({'type': 'http.response.body', 'body': b''})
diff --git a/test/python/prefix/wsgi.py b/test/python/prefix/wsgi.py
new file mode 100644
index 00000000..83b58c9a
--- /dev/null
+++ b/test/python/prefix/wsgi.py
@@ -0,0 +1,10 @@
+def application(environ, start_response):
+ start_response(
+ '200',
+ [
+ ('Content-Length', '0'),
+ ('Script-Name', environ.get('SCRIPT_NAME', 'NULL')),
+ ('Path-Info', environ['PATH_INFO']),
+ ],
+ )
+ return []
diff --git a/test/python/targets/asgi.py b/test/python/targets/asgi.py
index b51f3964..749ec5b1 100644
--- a/test/python/targets/asgi.py
+++ b/test/python/targets/asgi.py
@@ -22,6 +22,23 @@ async def application_200(scope, receive, send):
)
+async def application_prefix(scope, receive, send):
+ assert scope['type'] == 'http'
+
+ await send(
+ {
+ 'type': 'http.response.start',
+ 'status': 200,
+ 'headers': [
+ (b'content-length', b'0'),
+ (b'prefix', scope.get('root_path', 'NULL').encode()),
+ ],
+ }
+ )
+
+ await send({'type': 'http.response.body', 'body': b''})
+
+
def legacy_application_200(scope):
assert scope['type'] == 'http'
diff --git a/test/python/targets/wsgi.py b/test/python/targets/wsgi.py
index fa17ab87..3f3d4b27 100644
--- a/test/python/targets/wsgi.py
+++ b/test/python/targets/wsgi.py
@@ -6,3 +6,12 @@ def wsgi_target_a(env, start_response):
def wsgi_target_b(env, start_response):
start_response('200', [('Content-Length', '1')])
return [b'2']
+
+
+def wsgi_target_prefix(env, start_response):
+ data = u'%s %s' % (
+ env.get('SCRIPT_NAME', 'No Script Name'),
+ env['PATH_INFO'],
+ )
+ start_response('200', [('Content-Length', '%d' % len(data))])
+ return [data.encode('utf-8')]
diff --git a/test/test_access_log.py b/test/test_access_log.py
index b1d89343..a072858b 100644
--- a/test/test_access_log.py
+++ b/test/test_access_log.py
@@ -280,28 +280,6 @@ Connection: close
def test_access_log_variables(self):
self.load('mirror')
- # $time_local
-
- self.set_format('$uri $time_local $uri')
- assert self.get(url='/time_local')['status'] == 200
- assert self.wait_for_record('/time_local') is not None, 'time log'
- date = self.search_in_log(
- r'^\/time_local (.*) \/time_local$', 'access.log'
- )[1]
- assert (
- abs(
- self.date_to_sec_epoch(date, '%d/%b/%Y:%X %z')
- - time.mktime(time.localtime())
- )
- < 5
- ), '$time_local'
-
- # $request_line
-
- self.set_format('$request_line')
- assert self.get(url='/r_line')['status'] == 200
- assert self.wait_for_record(r'^GET \/r_line HTTP\/1\.1$') is not None
-
# $body_bytes_sent
self.set_format('$uri $body_bytes_sent')
diff --git a/test/test_asgi_application.py b/test/test_asgi_application.py
index 34dfe18e..121a2fbc 100644
--- a/test/test_asgi_application.py
+++ b/test/test_asgi_application.py
@@ -79,6 +79,43 @@ custom-header: BLAH
resp['headers']['query-string'] == 'var1=val1&var2=val2'
), 'query-string header'
+ def test_asgi_application_prefix(self):
+ self.load('prefix', prefix='/api/rest')
+
+ def set_prefix(prefix):
+ self.conf('"' + prefix + '"', 'applications/prefix/prefix')
+
+ def check_prefix(url, prefix):
+ resp = self.get(url=url)
+ assert resp['status'] == 200
+ assert resp['headers']['prefix'] == prefix
+
+ check_prefix('/ap', 'NULL')
+ check_prefix('/api', 'NULL')
+ check_prefix('/api/', 'NULL')
+ check_prefix('/api/res', 'NULL')
+ check_prefix('/api/restful', 'NULL')
+ check_prefix('/api/rest', '/api/rest')
+ check_prefix('/api/rest/', '/api/rest')
+ check_prefix('/api/rest/get', '/api/rest')
+ check_prefix('/api/rest/get/blah', '/api/rest')
+
+ set_prefix('/api/rest/')
+ check_prefix('/api/rest', '/api/rest')
+ check_prefix('/api/restful', 'NULL')
+ check_prefix('/api/rest/', '/api/rest')
+ check_prefix('/api/rest/blah', '/api/rest')
+
+ set_prefix('/app')
+ check_prefix('/ap', 'NULL')
+ check_prefix('/app', '/app')
+ check_prefix('/app/', '/app')
+ check_prefix('/application/', 'NULL')
+
+ set_prefix('/')
+ check_prefix('/', 'NULL')
+ check_prefix('/app', 'NULL')
+
def test_asgi_application_query_string_space(self):
self.load('query_string')
@@ -277,10 +314,9 @@ custom-header: BLAH
assert self.get()['status'] == 200, 'init'
- (_, sock) = self.http(
+ sock = self.http(
b"""GET / HTTP/1.1
""",
- start=True,
raw=True,
no_recv=True,
)
@@ -358,14 +394,13 @@ Connection: close
socks = []
for i in range(2):
- (_, sock) = self.get(
+ sock = self.get(
headers={
'Host': 'localhost',
'X-Delay': '3',
'Connection': 'close',
},
no_recv=True,
- start=True,
)
socks.append(sock)
diff --git a/test/test_asgi_targets.py b/test/test_asgi_targets.py
index c1e345ef..84d7b3b0 100644
--- a/test/test_asgi_targets.py
+++ b/test/test_asgi_targets.py
@@ -90,3 +90,48 @@ class TestASGITargets(TestApplicationPython):
)
assert self.get(url='/1')['status'] != 200
+
+ def test_asgi_targets_prefix(self):
+ self.conf_targets(
+ {
+ "1": {
+ "module": "asgi",
+ "callable": "application_prefix",
+ "prefix": "/1/",
+ },
+ "2": {
+ "module": "asgi",
+ "callable": "application_prefix",
+ "prefix": "/api",
+ },
+ }
+ )
+ self.conf(
+ [
+ {
+ "match": {"uri": "/1*"},
+ "action": {"pass": "applications/targets/1"},
+ },
+ {
+ "match": {"uri": "*"},
+ "action": {"pass": "applications/targets/2"},
+ },
+ ],
+ "routes",
+ )
+
+ def check_prefix(url, prefix):
+ resp = self.get(url=url)
+ assert resp['status'] == 200
+ assert resp['headers']['prefix'] == prefix
+
+ check_prefix('/1', '/1')
+ check_prefix('/11', 'NULL')
+ check_prefix('/1/', '/1')
+ check_prefix('/', 'NULL')
+ check_prefix('/ap', 'NULL')
+ check_prefix('/api', '/api')
+ check_prefix('/api/', '/api')
+ check_prefix('/api/test/', '/api')
+ check_prefix('/apis', 'NULL')
+ check_prefix('/apis/', 'NULL')
diff --git a/test/test_configuration.py b/test/test_configuration.py
index 7c612db0..9c27222c 100644
--- a/test/test_configuration.py
+++ b/test/test_configuration.py
@@ -318,6 +318,92 @@ class TestConfiguration(TestControl):
assert 'success' in self.conf(conf)
+ def test_json_application_python_prefix(self):
+ conf = {
+ "applications": {
+ "sub-app": {
+ "type": "python",
+ "processes": {"spare": 0},
+ "path": "/app",
+ "module": "wsgi",
+ "prefix": "/app",
+ }
+ },
+ "listeners": {"*:7080": {"pass": "routes"}},
+ "routes": [
+ {
+ "match": {"uri": "/app/*"},
+ "action": {"pass": "applications/sub-app"},
+ }
+ ],
+ }
+
+ assert 'success' in self.conf(conf)
+
+ def test_json_application_prefix_target(self):
+ conf = {
+ "applications": {
+ "sub-app": {
+ "type": "python",
+ "processes": {"spare": 0},
+ "path": "/app",
+ "targets": {
+ "foo": {"module": "foo.wsgi", "prefix": "/app"},
+ "bar": {
+ "module": "bar.wsgi",
+ "callable": "bar",
+ "prefix": "/api",
+ },
+ },
+ }
+ },
+ "listeners": {"*:7080": {"pass": "routes"}},
+ "routes": [
+ {
+ "match": {"uri": "/app/*"},
+ "action": {"pass": "applications/sub-app/foo"},
+ },
+ {
+ "match": {"uri": "/api/*"},
+ "action": {"pass": "applications/sub-app/bar"},
+ },
+ ],
+ }
+
+ assert 'success' in self.conf(conf)
+
+ def test_json_application_invalid_python_prefix(self):
+ conf = {
+ "applications": {
+ "sub-app": {
+ "type": "python",
+ "processes": {"spare": 0},
+ "path": "/app",
+ "module": "wsgi",
+ "prefix": "app",
+ }
+ },
+ "listeners": {"*:7080": {"pass": "applications/sub-app"}},
+ }
+
+ assert 'error' in self.conf(conf)
+
+ def test_json_application_empty_python_prefix(self):
+ conf = {
+ "applications": {
+ "sub-app": {
+ "type": "python",
+ "processes": {"spare": 0},
+ "path": "/app",
+ "module": "wsgi",
+ "prefix": "",
+ }
+ },
+ "listeners": {"*:7080": {"pass": "applications/sub-app"}},
+ }
+
+ assert 'error' in self.conf(conf)
+
def test_json_application_many2(self):
conf = {
"applications": {
diff --git a/test/test_java_application.py b/test/test_java_application.py
index adcb4eca..b825d925 100644
--- a/test/test_java_application.py
+++ b/test/test_java_application.py
@@ -71,6 +71,11 @@ class TestJavaApplication(TestApplicationJava):
def test_java_application_get_variables(self):
self.load('get_params')
+ def check_header(header, expect):
+ values = header.split(' ')[:-1]
+ assert len(values) == len(expect)
+ assert set(values) == set(expect)
+
headers = self.get(url='/?var1=val1&var2=&var4=val4&var4=foo')[
'headers'
]
@@ -79,13 +84,11 @@ class TestJavaApplication(TestApplicationJava):
assert headers['X-Var-2'] == 'true', 'GET variables 2'
assert headers['X-Var-3'] == 'false', 'GET variables 3'
- assert (
- headers['X-Param-Names'] == 'var4 var2 var1 '
- ), 'getParameterNames'
- assert headers['X-Param-Values'] == 'val4 foo ', 'getParameterValues'
- assert (
- headers['X-Param-Map'] == 'var2= var1=val1 var4=val4,foo '
- ), 'getParameterMap'
+ check_header(headers['X-Param-Names'], ['var4', 'var2', 'var1'])
+ check_header(headers['X-Param-Values'], ['val4', 'foo'])
+ check_header(
+ headers['X-Param-Map'], ['var2=', 'var1=val1', 'var4=val4,foo']
+ )
def test_java_application_post_variables(self):
self.load('post_params')
@@ -1001,14 +1004,13 @@ class TestJavaApplication(TestApplicationJava):
socks = []
for i in range(4):
- (_, sock) = self.get(
+ sock = self.get(
headers={
'Host': 'localhost',
'X-Delay': '2',
'Connection': 'close',
},
no_recv=True,
- start=True,
)
socks.append(sock)
diff --git a/test/test_njs.py b/test/test_njs.py
new file mode 100644
index 00000000..2cbded5b
--- /dev/null
+++ b/test/test_njs.py
@@ -0,0 +1,90 @@
+import os
+
+from unit.applications.proto import TestApplicationProto
+from unit.option import option
+
+
+class TestNJS(TestApplicationProto):
+ prerequisites = {'modules': {'njs': 'any'}}
+
+ def setup_method(self):
+ os.makedirs(option.temp_dir + '/assets')
+ open(option.temp_dir + '/assets/index.html', 'a')
+ open(option.temp_dir + '/assets/localhost', 'a')
+ open(option.temp_dir + '/assets/`string`', 'a')
+ open(option.temp_dir + '/assets/`backtick', 'a')
+ open(option.temp_dir + '/assets/l1\nl2', 'a')
+ open(option.temp_dir + '/assets/127.0.0.1', 'a')
+
+ assert 'success' in self.conf(
+ {
+ "listeners": {"*:7080": {"pass": "routes"}},
+ "routes": [
+ {"action": {"share": option.temp_dir + "/assets$uri"}}
+ ],
+ }
+ )
+
+ def set_share(self, share):
+ assert 'success' in self.conf(share, 'routes/0/action/share')
+
+ def test_njs_template_string(self, temp_dir):
+ self.set_share('"`' + temp_dir + '/assets/index.html`"')
+ assert self.get()['status'] == 200, 'string'
+
+ self.set_share('"' + temp_dir + '/assets/`string`"')
+ assert self.get()['status'] == 200, 'string 2'
+
+ self.set_share('"`' + temp_dir + '/assets/\\\\`backtick`"')
+ assert self.get()['status'] == 200, 'escape'
+
+ self.set_share('"`' + temp_dir + '/assets/l1\\nl2`"')
+ assert self.get()['status'] == 200, 'multiline'
+
+ def test_njs_template_expression(self, temp_dir):
+ def check_expression(expression):
+ self.set_share(expression)
+ assert self.get()['status'] == 200
+
+ check_expression('"`' + temp_dir + '/assets${uri}`"')
+ check_expression('"`' + temp_dir + '/assets${uri}${host}`"')
+ check_expression('"`' + temp_dir + '/assets${uri + host}`"')
+ check_expression('"`' + temp_dir + '/assets${uri + `${host}`}`"')
+
+ def test_njs_variables(self, temp_dir):
+ self.set_share('"`' + temp_dir + '/assets/${host}`"')
+ assert self.get()['status'] == 200, 'host'
+
+ self.set_share('"`' + temp_dir + '/assets/${remoteAddr}`"')
+ assert self.get()['status'] == 200, 'remoteAddr'
+
+ self.set_share('"`' + temp_dir + '/assets/${headers.Host}`"')
+ assert self.get()['status'] == 200, 'headers'
+
+ self.set_share('"`' + temp_dir + '/assets/${cookies.foo}`"')
+ assert (
+ self.get(
+ headers={'Cookie': 'foo=localhost', 'Connection': 'close'}
+ )['status']
+ == 200
+ ), 'cookies'
+
+ self.set_share('"`' + temp_dir + '/assets/${args.foo}`"')
+ assert self.get(url='/?foo=localhost')['status'] == 200, 'args'
+
+ def test_njs_invalid(self, temp_dir, skip_alert):
+ skip_alert(r'js exception:')
+
+ def check_invalid(template):
+ assert 'error' in self.conf(template, 'routes/0/action/share')
+
+ check_invalid('"`a"')
+ check_invalid('"`a``"')
+ check_invalid('"`a`/"')
+
+ def check_invalid_resolve(template):
+ assert 'success' in self.conf(template, 'routes/0/action/share')
+ assert self.get()['status'] == 500
+
+ check_invalid_resolve('"`${a}`"')
+ check_invalid_resolve('"`${uri.a.a}`"')
diff --git a/test/test_perl_application.py b/test/test_perl_application.py
index 0d1d7906..fe2db72e 100644
--- a/test/test_perl_application.py
+++ b/test/test_perl_application.py
@@ -259,14 +259,13 @@ class TestPerlApplication(TestApplicationPerl):
socks = []
for i in range(4):
- (_, sock) = self.get(
+ sock = self.get(
headers={
'Host': 'localhost',
'X-Delay': '2',
'Connection': 'close',
},
no_recv=True,
- start=True,
)
socks.append(sock)
diff --git a/test/test_php_application.py b/test/test_php_application.py
index f1dcc995..f442f551 100644
--- a/test/test_php_application.py
+++ b/test/test_php_application.py
@@ -4,6 +4,7 @@ import re
import shutil
import signal
import time
+from pathlib import Path
import pytest
from unit.applications.lang.php import TestApplicationPHP
@@ -620,6 +621,49 @@ opcache.preload_user = %(user)s
assert resp['status'] == 200, 'status'
assert resp['body'] != '', 'body not empty'
+ def test_php_application_trailing_slash(self, temp_dir):
+ new_root = temp_dir + "/php-root"
+ os.makedirs(new_root + '/path')
+
+ Path(new_root + '/path/index.php').write_text('<?php echo "OK\n"; ?>')
+
+ addr = temp_dir + '/sock'
+
+ assert 'success' in self.conf(
+ {
+ "listeners": {
+ "*:7080": {"pass": "applications/php-path"},
+ "unix:" + addr: {"pass": "applications/php-path"},
+ },
+ "applications": {
+ "php-path": {
+ "type": self.get_application_type(),
+ "processes": {"spare": 0},
+ "root": new_root,
+ }
+ },
+ }
+ ), 'configure trailing slash'
+
+ assert self.get(url='/path/')['status'] == 200, 'uri with trailing /'
+
+ resp = self.get(url='/path?q=a')
+ assert resp['status'] == 301, 'uri without trailing /'
+ assert (
+ resp['headers']['Location'] == 'http://localhost:7080/path/?q=a'
+ ), 'Location with query string'
+
+ resp = self.get(
+ sock_type='unix',
+ addr=addr,
+ url='/path',
+ headers={'Host': 'foo', 'Connection': 'close'},
+ )
+ assert resp['status'] == 301, 'uri without trailing /'
+ assert (
+ resp['headers']['Location'] == 'http://foo/path/'
+ ), 'Location with custom Host over UDS'
+
def test_php_application_extension_check(self, temp_dir):
self.load('phpinfo')
diff --git a/test/test_proxy.py b/test/test_proxy.py
index b0d471e4..ede91fd6 100644
--- a/test/test_proxy.py
+++ b/test/test_proxy.py
@@ -185,9 +185,8 @@ Content-Length: 10
socks = []
for i in range(10):
- _, sock = self.post_http10(
+ sock = self.post_http10(
body=payload + str(i),
- start=True,
no_recv=True,
read_buffer_size=buff_size,
)
@@ -248,9 +247,7 @@ Content-Length: 10
), 'custom header 5'
def test_proxy_fragmented(self):
- _, sock = self.http(
- b"""GET / HTT""", raw=True, start=True, no_recv=True
- )
+ sock = self.http(b"""GET / HTT""", raw=True, no_recv=True)
time.sleep(1)
@@ -266,9 +263,7 @@ Content-Length: 10
sock.close()
def test_proxy_fragmented_close(self):
- _, sock = self.http(
- b"""GET / HTT""", raw=True, start=True, no_recv=True
- )
+ sock = self.http(b"""GET / HTT""", raw=True, no_recv=True)
time.sleep(1)
@@ -277,9 +272,7 @@ Content-Length: 10
sock.close()
def test_proxy_fragmented_body(self):
- _, sock = self.http(
- b"""GET / HTT""", raw=True, start=True, no_recv=True
- )
+ sock = self.http(b"""GET / HTT""", raw=True, no_recv=True)
time.sleep(1)
@@ -306,9 +299,7 @@ Content-Length: 10
assert resp['body'] == "X" * 30000, 'body'
def test_proxy_fragmented_body_close(self):
- _, sock = self.http(
- b"""GET / HTT""", raw=True, start=True, no_recv=True
- )
+ sock = self.http(b"""GET / HTT""", raw=True, no_recv=True)
time.sleep(1)
@@ -398,7 +389,7 @@ Content-Length: 10
{"pass": "applications/delayed"}, 'listeners/*:7081'
), 'delayed configure'
- _, sock = self.post_http10(
+ sock = self.post_http10(
headers={
'Host': 'localhost',
'Content-Length': '10000',
@@ -406,14 +397,13 @@ Content-Length: 10
'X-Delay': '1',
},
body='0123456789' * 1000,
- start=True,
no_recv=True,
)
assert re.search('200 OK', sock.recv(100).decode()), 'first'
sock.close()
- _, sock = self.post_http10(
+ sock = self.post_http10(
headers={
'Host': 'localhost',
'Content-Length': '10000',
@@ -421,7 +411,6 @@ Content-Length: 10
'X-Delay': '1',
},
body='0123456789' * 1000,
- start=True,
no_recv=True,
)
diff --git a/test/test_python_application.py b/test/test_python_application.py
index 2ea9a22e..c9483b6a 100644
--- a/test/test_python_application.py
+++ b/test/test_python_application.py
@@ -94,6 +94,44 @@ custom-header: BLAH
resp['headers']['Query-String'] == ' var1= val1 & var2=val2'
), 'Query-String space 4'
+ def test_python_application_prefix(self):
+ self.load('prefix', prefix='/api/rest')
+
+ def set_prefix(prefix):
+ self.conf('"' + prefix + '"', 'applications/prefix/prefix')
+
+ def check_prefix(url, script_name, path_info):
+ resp = self.get(url=url)
+ assert resp['status'] == 200
+ assert resp['headers']['Script-Name'] == script_name
+ assert resp['headers']['Path-Info'] == path_info
+
+ check_prefix('/ap', 'NULL', '/ap')
+ check_prefix('/api', 'NULL', '/api')
+ check_prefix('/api/', 'NULL', '/api/')
+ check_prefix('/api/res', 'NULL', '/api/res')
+ check_prefix('/api/restful', 'NULL', '/api/restful')
+ check_prefix('/api/rest', '/api/rest', '')
+ check_prefix('/api/rest/', '/api/rest', '/')
+ check_prefix('/api/rest/get', '/api/rest', '/get')
+ check_prefix('/api/rest/get/blah', '/api/rest', '/get/blah')
+
+ set_prefix('/api/rest/')
+ check_prefix('/api/rest', '/api/rest', '')
+ check_prefix('/api/restful', 'NULL', '/api/restful')
+ check_prefix('/api/rest/', '/api/rest', '/')
+ check_prefix('/api/rest/blah', '/api/rest', '/blah')
+
+ set_prefix('/app')
+ check_prefix('/ap', 'NULL', '/ap')
+ check_prefix('/app', '/app', '')
+ check_prefix('/app/', '/app', '/')
+ check_prefix('/application/', 'NULL', '/application/')
+
+ set_prefix('/')
+ check_prefix('/', 'NULL', '/')
+ check_prefix('/app', 'NULL', '/app')
+
def test_python_application_query_string_empty(self):
self.load('query_string')
@@ -765,14 +803,13 @@ last line: 987654321
socks = []
for i in range(4):
- (_, sock) = self.get(
+ sock = self.get(
headers={
'Host': 'localhost',
'X-Delay': '2',
'Connection': 'close',
},
no_recv=True,
- start=True,
)
socks.append(sock)
diff --git a/test/test_python_isolation.py b/test/test_python_isolation.py
index 8cef6812..6d4ffaf3 100644
--- a/test/test_python_isolation.py
+++ b/test/test_python_isolation.py
@@ -1,3 +1,8 @@
+import os
+import re
+import subprocess
+from pathlib import Path
+
import pytest
from unit.applications.lang.python import TestApplicationPython
from unit.option import option
@@ -9,6 +14,23 @@ from unit.utils import waitforunmount
class TestPythonIsolation(TestApplicationPython):
prerequisites = {'modules': {'python': 'any'}, 'features': ['isolation']}
+ def get_cgroup(self, app_name):
+ output = subprocess.check_output(
+ ['ps', 'ax', '-o', 'pid', '-o', 'cmd']
+ ).decode()
+
+ pid = re.search(
+ r'(\d+)\s*unit: "' + app_name + '" application', output
+ ).group(1)
+
+ cgroup = '/proc/' + pid + '/cgroup'
+
+ if not os.path.isfile(cgroup):
+ pytest.skip('no cgroup at ' + cgroup)
+
+ with open(cgroup, 'r') as f:
+ return f.read().rstrip()
+
def test_python_isolation_rootfs(self, is_su, temp_dir):
isolation_features = option.available['features']['isolation'].keys()
@@ -63,24 +85,25 @@ class TestPythonIsolation(TestApplicationPython):
pytest.skip('requires root')
isolation = {'rootfs': temp_dir, 'automount': {'language_deps': False}}
-
self.load('empty', isolation=isolation)
- assert findmnt().find(temp_dir) == -1
+ python_path = temp_dir + '/usr'
+
+ assert findmnt().find(python_path) == -1
assert self.get()['status'] != 200, 'disabled language_deps'
- assert findmnt().find(temp_dir) == -1
+ assert findmnt().find(python_path) == -1
isolation['automount']['language_deps'] = True
self.load('empty', isolation=isolation)
- assert findmnt().find(temp_dir) == -1
+ assert findmnt().find(python_path) == -1
assert self.get()['status'] == 200, 'enabled language_deps'
- assert waitformount(temp_dir), 'language_deps mount'
+ assert waitformount(python_path), 'language_deps mount'
self.conf({"listeners": {}, "applications": {}})
- assert waitforunmount(temp_dir), 'language_deps unmount'
+ assert waitforunmount(python_path), 'language_deps unmount'
def test_python_isolation_procfs(self, is_su, temp_dir):
if not is_su:
@@ -101,3 +124,104 @@ class TestPythonIsolation(TestApplicationPython):
assert (
self.getjson(url='/?path=/proc/self')['body']['FileExists'] == True
), '/proc/self'
+
+ def test_python_isolation_cgroup(self, is_su, temp_dir):
+ if not is_su:
+ pytest.skip('requires root')
+
+ if not 'cgroup' in option.available['features']['isolation']:
+ pytest.skip('cgroup is not supported')
+
+ def set_cgroup_path(path):
+ isolation = {'cgroup': {'path': path}}
+ self.load('empty', processes=1, isolation=isolation)
+
+ set_cgroup_path('scope/python')
+
+ cgroup_rel = Path(self.get_cgroup('empty'))
+ assert cgroup_rel.parts[-2:] == ('scope', 'python'), 'cgroup rel'
+
+ set_cgroup_path('/scope2/python')
+
+ cgroup_abs = Path(self.get_cgroup('empty'))
+ assert cgroup_abs.parts[-2:] == ('scope2', 'python'), 'cgroup abs'
+
+ assert len(cgroup_rel.parts) >= len(cgroup_abs.parts)
+
+ def test_python_isolation_cgroup_two(self, is_su, temp_dir):
+ if not is_su:
+ pytest.skip('requires root')
+
+ if not 'cgroup' in option.available['features']['isolation']:
+ pytest.skip('cgroup is not supported')
+
+ def set_two_cgroup_path(path, path2):
+ script_path = option.test_dir + '/python/empty'
+
+ assert 'success' in self.conf(
+ {
+ "listeners": {
+ "*:7080": {"pass": "applications/one"},
+ "*:7081": {"pass": "applications/two"},
+ },
+ "applications": {
+ "one": {
+ "type": "python",
+ "processes": 1,
+ "path": script_path,
+ "working_directory": script_path,
+ "module": "wsgi",
+ "isolation": {
+ 'cgroup': {'path': path},
+ },
+ },
+ "two": {
+ "type": "python",
+ "processes": 1,
+ "path": script_path,
+ "working_directory": script_path,
+ "module": "wsgi",
+ "isolation": {
+ 'cgroup': {'path': path2},
+ },
+ },
+ },
+ }
+ )
+
+ set_two_cgroup_path('/scope/python', '/scope/python')
+ assert self.get_cgroup('one') == self.get_cgroup('two')
+
+ set_two_cgroup_path('/scope/python', '/scope2/python')
+ assert self.get_cgroup('one') != self.get_cgroup('two')
+
+ def test_python_isolation_cgroup_invalid(self, is_su):
+ if not is_su:
+ pytest.skip('requires root')
+
+ if not 'cgroup' in option.available['features']['isolation']:
+ pytest.skip('cgroup is not supported')
+
+ def check_invalid(path):
+ script_path = option.test_dir + '/python/empty'
+ assert 'error' in self.conf(
+ {
+ "listeners": {"*:7080": {"pass": "applications/empty"}},
+ "applications": {
+ "empty": {
+ "type": "python",
+ "processes": {"spare": 0},
+ "path": script_path,
+ "working_directory": script_path,
+ "module": "wsgi",
+ "isolation": {
+ 'cgroup': {'path': path},
+ },
+ }
+ },
+ }
+ )
+
+ check_invalid('')
+ check_invalid('../scope')
+ check_invalid('scope/../python')
diff --git a/test/test_python_targets.py b/test/test_python_targets.py
index 8e9ecb87..ae271b5f 100644
--- a/test/test_python_targets.py
+++ b/test/test_python_targets.py
@@ -47,3 +47,55 @@ class TestPythonTargets(TestApplicationPython):
resp = self.get(url='/2')
assert resp['status'] == 200
assert resp['body'] == '2'
+
+ def test_python_targets_prefix(self):
+ assert 'success' in self.conf(
+ {
+ "listeners": {"*:7080": {"pass": "routes"}},
+ "routes": [
+ {
+ "match": {"uri": ["/app*"]},
+ "action": {"pass": "applications/targets/app"},
+ },
+ {
+ "match": {"uri": "*"},
+ "action": {"pass": "applications/targets/catchall"},
+ },
+ ],
+ "applications": {
+ "targets": {
+ "type": "python",
+ "working_directory": option.test_dir
+ + "/python/targets/",
+ "path": option.test_dir + '/python/targets/',
+ "protocol": "wsgi",
+ "targets": {
+ "app": {
+ "module": "wsgi",
+ "callable": "wsgi_target_prefix",
+ "prefix": "/app/",
+ },
+ "catchall": {
+ "module": "wsgi",
+ "callable": "wsgi_target_prefix",
+ "prefix": "/api",
+ },
+ },
+ }
+ },
+ }
+ )
+
+ def check_prefix(url, body):
+ resp = self.get(url=url)
+ assert resp['status'] == 200
+ assert resp['body'] == body
+
+ check_prefix('/app', '/app ')
+ check_prefix('/app/', '/app /')
+ check_prefix('/app/rest/user/', '/app /rest/user/')
+ check_prefix('/catchall', 'No Script Name /catchall')
+ check_prefix('/api', '/api ')
+ check_prefix('/api/', '/api /')
+ check_prefix('/apis', 'No Script Name /apis')
+ check_prefix('/api/users/', '/api /users/')
diff --git a/test/test_reconfigure.py b/test/test_reconfigure.py
index ab05a1c8..feb027aa 100644
--- a/test/test_reconfigure.py
+++ b/test/test_reconfigure.py
@@ -21,10 +21,9 @@ class TestReconfigure(TestApplicationProto):
assert 'success' in self.conf({"listeners": {}, "applications": {}})
def test_reconfigure(self):
- (_, sock) = self.http(
+ sock = self.http(
b"""GET / HTTP/1.1
""",
- start=True,
raw=True,
no_recv=True,
)
@@ -42,7 +41,7 @@ Connection: close
assert resp['status'] == 200, 'finish request'
def test_reconfigure_2(self):
- (_, sock) = self.http(b'', raw=True, start=True, no_recv=True)
+ sock = self.http(b'', raw=True, no_recv=True)
# Waiting for connection completion.
# Delay should be more than TCP_DEFER_ACCEPT.
diff --git a/test/test_routing.py b/test/test_routing.py
index 3649b37c..9e872061 100644
--- a/test/test_routing.py
+++ b/test/test_routing.py
@@ -1401,6 +1401,20 @@ class TestRouting(TestApplicationPython):
self.route_match_invalid({"cookies": ["var"]})
self.route_match_invalid({"cookies": [{"foo": {}}]})
+ def test_routes_match_cookies_complex(self):
+ self.route_match({"cookies": {"foo": "bar=baz"}})
+ self.cookie('foo=bar=baz', 200)
+ self.cookie(' foo=bar=baz ', 200)
+ self.cookie('=foo=bar=baz', 404)
+
+ self.route_match({"cookies": {"foo": ""}})
+ self.cookie('foo=', 200)
+ self.cookie('foo=;', 200)
+ self.cookie(' foo=;', 200)
+ self.cookie('foo', 404)
+ self.cookie('', 404)
+ self.cookie('=', 404)
+
def test_routes_match_cookies_multiple(self):
self.route_match({"cookies": {"foo": "bar", "blah": "blah"}})
@@ -1471,7 +1485,7 @@ class TestRouting(TestApplicationPython):
def test_routes_source_port(self):
def sock_port():
- _, sock = self.http(b'', start=True, raw=True, no_recv=True)
+ sock = self.http(b'', raw=True, no_recv=True)
port = sock.getsockname()[1]
return (sock, port)
diff --git a/test/test_ruby_application.py b/test/test_ruby_application.py
index 83af39be..068b587b 100644
--- a/test/test_ruby_application.py
+++ b/test/test_ruby_application.py
@@ -388,14 +388,13 @@ class TestRubyApplication(TestApplicationRuby):
socks = []
for i in range(4):
- (_, sock) = self.get(
+ sock = self.get(
headers={
'Host': 'localhost',
'X-Delay': '2',
'Connection': 'close',
},
no_recv=True,
- start=True,
)
socks.append(sock)
diff --git a/test/test_settings.py b/test/test_settings.py
index ea3cfb99..ad8929f8 100644
--- a/test/test_settings.py
+++ b/test/test_settings.py
@@ -10,6 +10,66 @@ from unit.utils import sysctl
class TestSettings(TestApplicationPython):
prerequisites = {'modules': {'python': 'any'}}
+ def test_settings_large_header_buffer_size(self):
+ self.load('empty')
+
+ def set_buffer_size(size):
+ assert 'success' in self.conf(
+ {'http': {'large_header_buffer_size': size}},
+ 'settings',
+ )
+
+ def header_value(size, expect=200):
+ headers = {'Host': 'a' * (size - 1), 'Connection': 'close'}
+ assert self.get(headers=headers)['status'] == expect
+
+ set_buffer_size(4096)
+ header_value(4096)
+ header_value(4097, 431)
+
+ set_buffer_size(16384)
+ header_value(16384)
+ header_value(16385, 431)
+
+ def test_settings_large_header_buffers(self):
+ self.load('empty')
+
+ def set_buffers(buffers):
+ assert 'success' in self.conf(
+ {'http': {'large_header_buffers': buffers}},
+ 'settings',
+ )
+
+ def big_headers(headers_num, expect=200):
+ headers = {'Host': 'localhost', 'Connection': 'close'}
+
+ for i in range(headers_num):
+ headers['Custom-header-' + str(i)] = 'a' * 8000
+
+ assert self.get(headers=headers)['status'] == expect
+
+ set_buffers(1)
+ big_headers(1)
+ big_headers(2, 431)
+
+ set_buffers(2)
+ big_headers(2)
+ big_headers(3, 431)
+
+ set_buffers(8)
+ big_headers(8)
+ big_headers(9, 431)
+
+ @pytest.mark.skip('not yet')
+ def test_settings_large_header_buffer_invalid(self):
+ def check_error(conf):
+ assert 'error' in self.conf({'http': conf}, 'settings')
+
+ check_error({'large_header_buffer_size': -1})
+ check_error({'large_header_buffer_size': 0})
+ check_error({'large_header_buffers': -1})
+ check_error({'large_header_buffers': 0})
+
def test_settings_header_read_timeout(self):
self.load('empty')
@@ -50,20 +110,18 @@ Connection: close
{'http': {'header_read_timeout': 4}}, 'settings'
)
- (resp, sock) = self.http(
+ sock = self.http(
b"""GET / HTTP/1.1
""",
- start=True,
raw=True,
no_recv=True,
)
time.sleep(2)
- (resp, sock) = self.http(
+ sock = self.http(
b"""Host: localhost
""",
- start=True,
sock=sock,
raw=True,
no_recv=True,
@@ -245,7 +303,7 @@ Connection: close
self.load('empty')
def req():
- _, sock = self.http(b'', start=True, raw=True, no_recv=True)
+ sock = self.http(b'', raw=True, no_recv=True)
time.sleep(3)
diff --git a/test/test_static.py b/test/test_static.py
index b9c78fdd..9013b5c0 100644
--- a/test/test_static.py
+++ b/test/test_static.py
@@ -1,10 +1,7 @@
import os
-import shutil
import socket
import pytest
-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
@@ -43,49 +40,6 @@ class TestStatic(TestApplicationProto):
}
)
- def test_static_migration(self, skip_fds_check, temp_dir):
- skip_fds_check(True, True, True)
-
- def set_conf_version(path, version):
- with open(path, 'w+') as f:
- f.write(str(version))
-
- with open(temp_dir + '/state/version', 'r') as f:
- assert int(f.read().rstrip()) > 12500, 'current version'
-
- assert 'success' in self.conf(
- {"share": temp_dir + "/assets"}, 'routes/0/action'
- ), 'configure migration 12500'
-
- shutil.copytree(temp_dir + '/state', temp_dir + '/state_copy_12500')
- set_conf_version(temp_dir + '/state_copy_12500/version', 12500)
-
- assert 'success' in self.conf(
- {"share": temp_dir + "/assets$uri"}, 'routes/0/action'
- ), 'configure migration 12600'
- shutil.copytree(temp_dir + '/state', temp_dir + '/state_copy_12600')
- set_conf_version(temp_dir + '/state_copy_12600/version', 12600)
-
- assert 'success' in self.conf(
- {"share": temp_dir + "/assets"}, 'routes/0/action'
- ), 'configure migration no version'
- shutil.copytree(
- temp_dir + '/state', temp_dir + '/state_copy_no_version'
- )
- os.remove(temp_dir + '/state_copy_no_version/version')
-
- unit_stop()
- unit_run(temp_dir + '/state_copy_12500')
- assert self.get(url='/')['body'] == '0123456789', 'before 1.26.0'
-
- unit_stop()
- unit_run(temp_dir + '/state_copy_12600')
- assert self.get(url='/')['body'] == '0123456789', 'after 1.26.0'
-
- unit_stop()
- unit_run(temp_dir + '/state_copy_no_version')
- 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(
@@ -262,8 +216,8 @@ class TestStatic(TestApplicationProto):
assert self.get(url='/../assets/')['status'] == 400, 'path invalid 5'
def test_static_two_clients(self):
- _, sock = self.get(url='/', start=True, no_recv=True)
- _, sock2 = self.get(url='/', start=True, no_recv=True)
+ sock = self.get(no_recv=True)
+ sock2 = self.get(no_recv=True)
assert sock.recv(1) == b'H', 'client 1'
assert sock2.recv(1) == b'H', 'client 2'
diff --git a/test/test_status.py b/test/test_status.py
index 214072d4..6c733474 100644
--- a/test/test_status.py
+++ b/test/test_status.py
@@ -9,6 +9,23 @@ from unit.status import Status
class TestStatus(TestApplicationPython):
prerequisites = {'modules': {'python': 'any'}}
+ def check_connections(self, accepted, active, idle, closed):
+ Status.get('/connections') == {
+ 'accepted': accepted,
+ 'active': active,
+ 'idle': idle,
+ 'closed': closed,
+ }
+
+ def app_default(self, name="empty", module="wsgi"):
+ return {
+ "type": self.get_application_type(),
+ "processes": {"spare": 0},
+ "path": option.test_dir + "/python/" + name,
+ "working_directory": option.test_dir + "/python/" + name,
+ "module": module,
+ }
+
def test_status(self):
assert 'error' in self.conf_delete('/status'), 'DELETE method'
@@ -24,13 +41,7 @@ class TestStatus(TestApplicationPython):
},
"routes": [{"action": {"return": 200}}],
"applications": {
- "empty": {
- "type": self.get_application_type(),
- "processes": {"spare": 0},
- "path": option.test_dir + '/python/empty',
- "working_directory": option.test_dir + '/python/empty',
- "module": "wsgi",
- },
+ "empty": self.app_default(),
"blah": {
"type": self.get_application_type(),
"processes": {"spare": 0},
@@ -70,7 +81,7 @@ Connection: close
)
assert Status.get('/requests/total') == 6, 'pipeline'
- (_, sock) = self.get(port=7081, no_recv=True, start=True)
+ sock = self.get(port=7081, no_recv=True)
time.sleep(1)
@@ -79,14 +90,6 @@ Connection: close
sock.close()
def test_status_connections(self):
- def check_connections(accepted, active, idle, closed):
- Status.get('/connections') == {
- 'accepted': accepted,
- 'active': active,
- 'idle': idle,
- 'closed': closed,
- }
-
assert 'success' in self.conf(
{
"listeners": {
@@ -95,14 +98,7 @@ Connection: close
},
"routes": [{"action": {"return": 200}}],
"applications": {
- "delayed": {
- "type": self.get_application_type(),
- "processes": {"spare": 0},
- "path": option.test_dir + "/python/delayed",
- "working_directory": option.test_dir
- + "/python/delayed",
- "module": "wsgi",
- },
+ "delayed": self.app_default("delayed"),
},
},
)
@@ -112,15 +108,15 @@ Connection: close
# accepted, closed
assert self.get()['status'] == 200
- check_connections(1, 0, 0, 1)
+ self.check_connections(1, 0, 0, 1)
# idle
- _, sock = self.http(b'', start=True, raw=True, no_recv=True)
- check_connections(2, 0, 1, 1)
+ sock = self.http(b'', raw=True, no_recv=True)
+ self.check_connections(2, 0, 1, 1)
self.get(sock=sock)
- check_connections(2, 0, 0, 2)
+ self.check_connections(2, 0, 0, 2)
# active
@@ -134,10 +130,10 @@ Connection: close
start=True,
read_timeout=1,
)
- check_connections(3, 1, 0, 2)
+ self.check_connections(3, 1, 0, 2)
self.get(sock=sock)
- check_connections(3, 0, 0, 3)
+ self.check_connections(3, 0, 0, 3)
def test_status_applications(self):
def check_applications(expert):
@@ -192,22 +188,8 @@ Connection: close
},
"routes": [],
"applications": {
- "restart": {
- "type": self.get_application_type(),
- "processes": {"spare": 0},
- "path": option.test_dir + "/python/restart",
- "working_directory": option.test_dir
- + "/python/restart",
- "module": "longstart",
- },
- "delayed": {
- "type": self.get_application_type(),
- "processes": {"spare": 0},
- "path": option.test_dir + "/python/delayed",
- "working_directory": option.test_dir
- + "/python/delayed",
- "module": "wsgi",
- },
+ "restart": self.app_default("restart", "longstart"),
+ "delayed": self.app_default("delayed"),
},
},
)
@@ -221,3 +203,28 @@ Connection: close
check_application('restart', 0, 1, 0, 1)
check_application('delayed', 0, 0, 0, 0)
+
+ def test_status_proxy(self):
+ assert 'success' in self.conf(
+ {
+ "listeners": {
+ "*:7080": {"pass": "routes"},
+ "*:7081": {"pass": "applications/empty"},
+ },
+ "routes": [
+ {
+ "match": {"uri": "/"},
+ "action": {"proxy": "http://127.0.0.1:7081"},
+ }
+ ],
+ "applications": {
+ "empty": self.app_default(),
+ },
+ },
+ )
+
+ Status.init()
+
+ assert self.get()['status'] == 200
+ self.check_connections(2, 0, 0, 2)
+ assert Status.get('/requests/total') == 2, 'proxy'
diff --git a/test/test_upstreams_rr.py b/test/test_upstreams_rr.py
index dd64e1d9..71af3f5d 100644
--- a/test/test_upstreams_rr.py
+++ b/test/test_upstreams_rr.py
@@ -290,14 +290,13 @@ Connection: close
socks = []
for i in range(req):
delay = 1 if i % 5 == 0 else 0
- _, sock = self.get(
+ sock = self.get(
headers={
'Host': 'localhost',
'Content-Length': '0',
'X-Delay': str(delay),
'Connection': 'close',
},
- start=True,
no_recv=True,
)
socks.append(sock)
@@ -320,17 +319,16 @@ Connection: close
socks2 = []
for _ in range(conns):
- _, sock = self.get(start=True, no_recv=True)
+ sock = self.get(no_recv=True)
socks.append(sock)
- _, sock2 = self.http(
+ sock2 = self.http(
b"""POST / HTTP/1.1
Host: localhost
Content-Length: 10
Connection: close
""",
- start=True,
no_recv=True,
raw=True,
)
diff --git a/test/test_variables.py b/test/test_variables.py
index 2ddfdc0a..ecce5e6d 100644
--- a/test/test_variables.py
+++ b/test/test_variables.py
@@ -1,4 +1,8 @@
+import re
+import time
+
from unit.applications.proto import TestApplicationProto
+from unit.option import option
class TestVariables(TestApplicationProto):
@@ -7,79 +11,194 @@ class TestVariables(TestApplicationProto):
def setup_method(self):
assert 'success' in self.conf(
{
- "listeners": {"*:7080": {"pass": "routes/$method"}},
- "routes": {
- "GET": [{"action": {"return": 201}}],
- "POST": [{"action": {"return": 202}}],
- "3": [{"action": {"return": 203}}],
- "4*": [{"action": {"return": 204}}],
- "blahGET}": [{"action": {"return": 205}}],
- "5GET": [{"action": {"return": 206}}],
- "GETGET": [{"action": {"return": 207}}],
- "localhost": [{"action": {"return": 208}}],
- "9?q#a": [{"action": {"return": 209}}],
- "blah": [{"action": {"return": 210}}],
- "127.0.0.1": [{"action": {"return": 211}}],
- "::1": [{"action": {"return": 212}}],
- "referer-value": [{"action": {"return": 213}}],
- "MSIE": [{"action": {"return": 214}}],
- },
+ "listeners": {"*:7080": {"pass": "routes"}},
+ "routes": [{"action": {"return": 200}}],
},
), 'configure routes'
- def conf_routes(self, routes):
- assert 'success' in self.conf(routes, 'listeners/*:7080/pass')
+ def set_format(self, format):
+ assert 'success' in self.conf(
+ {
+ 'path': option.temp_dir + '/access.log',
+ 'format': format,
+ },
+ 'access_log',
+ ), 'access_log format'
+
+ def wait_for_record(self, pattern, name='access.log'):
+ return super().wait_for_record(pattern, name)
+
+ def search_in_log(self, pattern, name='access.log'):
+ return super().search_in_log(pattern, name)
+
+ def test_variables_dollar(self):
+ assert 'success' in self.conf("301", 'routes/0/action/return')
+
+ def check_dollar(location, expect):
+ assert 'success' in self.conf(
+ '"' + location + '"',
+ 'routes/0/action/location',
+ )
+ assert self.get()['headers']['Location'] == expect
+
+ check_dollar(
+ 'https://${host}${uri}path${dollar}dollar',
+ 'https://localhost/path$dollar',
+ )
+ check_dollar('path$dollar${dollar}', 'path$$')
+
+ def test_variables_request_time(self):
+ self.set_format('$uri $request_time')
+
+ sock = self.http(b'', raw=True, no_recv=True)
+
+ time.sleep(1)
+
+ assert self.get(url='/r_time_1', sock=sock)['status'] == 200
+ assert self.wait_for_record(r'\/r_time_1 0\.\d{3}') is not None
+
+ sock = self.http(
+ b"""G""",
+ no_recv=True,
+ raw=True,
+ )
+
+ time.sleep(2)
+
+ self.http(
+ b"""ET /r_time_2 HTTP/1.1
+Host: localhost
+Connection: close
+
+""",
+ sock=sock,
+ raw=True,
+ )
+ assert self.wait_for_record(r'\/r_time_2 [1-9]\.\d{3}') is not None
def test_variables_method(self):
- assert self.get()['status'] == 201, 'method GET'
- assert self.post()['status'] == 202, 'method POST'
+ self.set_format('$method')
+
+ reg = r'^GET$'
+ assert self.search_in_log(reg) is None
+ assert self.get()['status'] == 200
+ assert self.wait_for_record(reg) is not None, 'method GET'
+
+ reg = r'^POST$'
+ assert self.search_in_log(reg) is None
+ assert self.post()['status'] == 200
+ assert self.wait_for_record(reg) is not None, 'method POST'
def test_variables_request_uri(self):
- self.conf_routes("\"routes$request_uri\"")
+ self.set_format('$request_uri')
+
+ def check_request_uri(req_uri):
+ reg = r'^' + re.escape(req_uri) + r'$'
+
+ assert self.search_in_log(reg) is None
+ assert self.get(url=req_uri)['status'] == 200
+ assert self.wait_for_record(reg) is not None
- 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'
+ check_request_uri('/3')
+ check_request_uri('/4*')
+ check_request_uri('/4%2A')
+ check_request_uri('/9?q#a')
def test_variables_uri(self):
- self.conf_routes("\"routes$uri\"")
+ self.set_format('$uri')
- assert self.get(url='/3')['status'] == 203, 'uri'
- assert self.get(url='/4*')['status'] == 204, 'uri 2'
- assert self.get(url='/4%2A')['status'] == 204, 'uri 3'
+ def check_uri(uri, expect=None):
+ expect = uri if expect is None else expect
+ reg = r'^' + re.escape(expect) + r'$'
+
+ assert self.search_in_log(reg) is None
+ assert self.get(url=uri)['status'] == 200
+ assert self.wait_for_record(reg) is not None
+
+ check_uri('/3')
+ check_uri('/4*')
+ check_uri('/5%2A', '/5*')
+ check_uri('/9?q#a', '/9')
def test_variables_host(self):
- self.conf_routes("\"routes/$host\"")
+ self.set_format('$host')
+
+ def check_host(host, expect=None):
+ expect = host if expect is None else expect
+ reg = r'^' + re.escape(expect) + r'$'
- def check_host(host, status=208):
+ assert self.search_in_log(reg) is None
assert (
self.get(headers={'Host': host, 'Connection': 'close'})[
'status'
]
- == status
+ == 200
)
+ assert self.wait_for_record(reg) is not None
check_host('localhost')
- check_host('localhost.')
- check_host('localhost:7080')
- check_host('.localhost', 404)
- check_host('www.localhost', 404)
- check_host('localhost1', 404)
+ check_host('localhost1.', 'localhost1')
+ check_host('localhost2:7080', 'localhost2')
+ check_host('.localhost')
+ check_host('www.localhost')
def test_variables_remote_addr(self):
- self.conf_routes("\"routes/$remote_addr\"")
- assert self.get()['status'] == 211
+ self.set_format('$remote_addr')
+
+ assert self.get()['status'] == 200
+ assert self.wait_for_record(r'^127\.0\.0\.1$') is not None
assert 'success' in self.conf(
- {"[::1]:7080": {"pass": "routes/$remote_addr"}}, 'listeners'
+ {"[::1]:7080": {"pass": "routes"}}, 'listeners'
)
- assert self.get(sock_type='ipv6')['status'] == 212
+
+ reg = r'^::1$'
+ assert self.search_in_log(reg) is None
+ assert self.get(sock_type='ipv6')['status'] == 200
+ assert self.wait_for_record(reg) is not None
+
+ def test_variables_time_local(self):
+ self.set_format('$uri $time_local $uri')
+
+ assert self.search_in_log(r'/time_local') is None
+ assert self.get(url='/time_local')['status'] == 200
+ assert self.wait_for_record(r'/time_local') is not None, 'time log'
+ date = self.search_in_log(
+ r'^\/time_local (.*) \/time_local$', 'access.log'
+ )[1]
+ assert (
+ abs(
+ self.date_to_sec_epoch(date, '%d/%b/%Y:%X %z')
+ - time.mktime(time.localtime())
+ )
+ < 5
+ ), '$time_local'
+
+ def test_variables_request_line(self):
+ self.set_format('$request_line')
+
+ reg = r'^GET \/r_line HTTP\/1\.1$'
+ assert self.search_in_log(reg) is None
+ assert self.get(url='/r_line')['status'] == 200
+ assert self.wait_for_record(reg) is not None
+
+ def test_variables_status(self):
+ self.set_format('$status')
+
+ assert 'success' in self.conf("418", 'routes/0/action/return')
+
+ reg = r'^418$'
+ assert self.search_in_log(reg) is None
+ assert self.get()['status'] == 418
+ assert self.wait_for_record(reg) is not None
def test_variables_header_referer(self):
- self.conf_routes("\"routes/$header_referer\"")
+ self.set_format('$method $header_referer')
+
+ def check_referer(referer):
+ reg = r'^GET ' + re.escape(referer) + r'$'
- def check_referer(referer, status=213):
+ assert self.search_in_log(reg) is None
assert (
self.get(
headers={
@@ -88,17 +207,21 @@ class TestVariables(TestApplicationProto):
'Referer': referer,
}
)['status']
- == status
+ == 200
)
+ assert self.wait_for_record(reg) is not None
check_referer('referer-value')
- check_referer('', 404)
- check_referer('no', 404)
+ check_referer('')
+ check_referer('no')
def test_variables_header_user_agent(self):
- self.conf_routes("\"routes/$header_user_agent\"")
+ self.set_format('$method $header_user_agent')
- def check_user_agent(user_agent, status=214):
+ def check_user_agent(user_agent):
+ reg = r'^GET ' + re.escape(user_agent) + r'$'
+
+ assert self.search_in_log(reg) is None
assert (
self.get(
headers={
@@ -107,152 +230,112 @@ class TestVariables(TestApplicationProto):
'User-Agent': user_agent,
}
)['status']
- == status
+ == 200
)
+ assert self.wait_for_record(reg) is not None
check_user_agent('MSIE')
- check_user_agent('', 404)
- check_user_agent('no', 404)
-
- def test_variables_dollar(self):
- assert 'success' in self.conf(
- {
- "listeners": {"*:7080": {"pass": "routes"}},
- "routes": [{"action": {"return": 301}}],
- }
- )
-
- def check_dollar(location, expect):
- assert 'success' in self.conf(
- '"' + location + '"',
- 'routes/0/action/location',
- )
- assert self.get()['headers']['Location'] == expect
-
- check_dollar(
- 'https://${host}${uri}path${dollar}dollar',
- 'https://localhost/path$dollar',
- )
- check_dollar('path$dollar${dollar}', 'path$$')
+ check_user_agent('')
+ check_user_agent('no')
def test_variables_many(self):
- self.conf_routes("\"routes$uri$method\"")
- assert self.get(url='/5')['status'] == 206, 'many'
-
- self.conf_routes("\"routes${uri}${method}\"")
- assert self.get(url='/5')['status'] == 206, 'many 2'
-
- self.conf_routes("\"routes${uri}$method\"")
- assert self.get(url='/5')['status'] == 206, 'many 3'
+ def check_vars(uri, expect):
+ reg = r'^' + re.escape(expect) + r'$'
- self.conf_routes("\"routes/$method$method\"")
- assert self.get()['status'] == 207, 'many 4'
+ assert self.search_in_log(reg) is None
+ assert self.get(url=uri)['status'] == 200
+ assert self.wait_for_record(reg) is not None
- self.conf_routes("\"routes/$method$uri\"")
- assert self.get()['status'] == 404, 'no route'
- assert self.get(url='/blah')['status'] == 404, 'no route 2'
+ self.set_format('$uri$method')
+ check_vars('/1', '/1GET')
- def test_variables_replace(self):
- assert self.get()['status'] == 201
+ self.set_format('${uri}${method}')
+ check_vars('/2', '/2GET')
- self.conf_routes("\"routes$uri\"")
- assert self.get(url='/3')['status'] == 203
+ self.set_format('${uri}$method')
+ check_vars('/3', '/3GET')
- self.conf_routes("\"routes/${method}\"")
- assert self.post()['status'] == 202
-
- self.conf_routes("\"routes${uri}\"")
- assert self.get(url='/4*')['status'] == 204
-
- self.conf_routes("\"routes/blah$method}\"")
- assert self.get()['status'] == 205
-
- def test_variables_upstream(self):
- assert 'success' in self.conf(
- {
- "listeners": {
- "*:7080": {"pass": "upstreams$uri"},
- "*:7081": {"pass": "routes/one"},
- },
- "upstreams": {"1": {"servers": {"127.0.0.1:7081": {}}}},
- "routes": {"one": [{"action": {"return": 200}}]},
- },
- ), 'upstreams initial configuration'
-
- assert self.get(url='/1')['status'] == 200
- assert self.get(url='/2')['status'] == 404
-
- def test_variables_empty(self):
- def update_pass(prefix):
- assert 'success' in self.conf(
- {"listeners": {"*:7080": {"pass": prefix + "/$method"}}},
- ), 'variables empty'
-
- update_pass("routes")
- assert self.get(url='/1')['status'] == 404
-
- update_pass("upstreams")
- assert self.get(url='/2')['status'] == 404
-
- update_pass("applications")
- assert self.get(url='/3')['status'] == 404
+ self.set_format('$method$method')
+ check_vars('/', 'GETGET')
def test_variables_dynamic(self):
- self.conf_routes("\"routes/$header_foo$arg_foo$cookie_foo\"")
+ self.set_format('$header_foo$cookie_foo$arg_foo')
+
+ assert (
+ self.get(
+ url='/?foo=h',
+ headers={'Foo': 'b', 'Cookie': 'foo=la', 'Connection': 'close'},
+ )['status']
+ == 200
+ )
+ assert self.wait_for_record(r'^blah$') is not None
- self.get(
- url='/?foo=h',
- headers={'Foo': 'b', 'Cookie': 'foo=la', 'Connection': 'close'},
- )['status'] = 210
+ def test_variables_dynamic_arguments(self):
+ def check_arg(url, expect=None):
+ expect = url if expect is None else expect
+ reg = r'^' + re.escape(expect) + r'$'
+
+ assert self.search_in_log(reg) is None
+ assert self.get(url=url)['status'] == 200
+ assert self.wait_for_record(reg) is not None
+
+ def check_no_arg(url):
+ assert self.get(url=url)['status'] == 200
+ assert self.search_in_log(r'^0$') is None
+
+ self.set_format('$arg_foo_bar')
+ check_arg('/?foo_bar=1', '1')
+ check_arg('/?foo_b%61r=2', '2')
+ check_arg('/?bar&foo_bar=3&foo', '3')
+ check_arg('/?foo_bar=l&foo_bar=4', '4')
+ check_no_arg('/')
+ check_no_arg('/?foo_bar=')
+ check_no_arg('/?Foo_bar=0')
+ check_no_arg('/?foo-bar=0')
+ check_no_arg('/?foo_bar=0&foo_bar=l')
+
+ self.set_format('$arg_foo_b%61r')
+ check_no_arg('/?foo_b=0')
+ check_no_arg('/?foo_bar=0')
+
+ self.set_format('$arg_f!~')
+ check_no_arg('/?f=0')
+ check_no_arg('/?f!~=0')
def test_variables_dynamic_headers(self):
- def check_header(header, status=210):
+ def check_header(header, value):
+ reg = r'^' + value + r'$'
+
+ assert self.search_in_log(reg) is None
assert (
- self.get(headers={header: "blah", 'Connection': 'close'})[
+ self.get(headers={header: value, 'Connection': 'close'})[
'status'
]
- == status
+ == 200
)
+ assert self.wait_for_record(reg) is not None
- self.conf_routes("\"routes/$header_foo_bar\"")
- check_header('foo-bar')
- check_header('Foo-Bar')
- check_header('foo_bar', 404)
- check_header('Foo', 404)
- check_header('Bar', 404)
- check_header('foobar', 404)
-
- self.conf_routes("\"routes/$header_Foo_Bar\"")
- check_header('Foo-Bar')
- check_header('foo-bar')
- check_header('foo_bar', 404)
- check_header('foobar', 404)
+ def check_no_header(header):
+ assert (
+ self.get(headers={header: '0', 'Connection': 'close'})['status']
+ == 200
+ )
+ assert self.search_in_log(r'^0$') is None
- self.conf_routes("\"routes/$header_foo-bar\"")
- check_header('foo_bar', 404)
+ self.set_format('$header_foo_bar')
+ check_header('foo-bar', '1')
+ check_header('Foo-Bar', '2')
+ check_no_header('foo_bar')
+ check_no_header('foobar')
- def test_variables_dynamic_arguments(self):
- self.conf_routes("\"routes/$arg_foo_bar\"")
- assert self.get(url='/?foo_bar=blah')['status'] == 210
- assert self.get(url='/?foo_b%61r=blah')['status'] == 210
- assert self.get(url='/?bar&foo_bar=blah&foo')['status'] == 210
- assert self.get(url='/?Foo_bar=blah')['status'] == 404
- assert self.get(url='/?foo-bar=blah')['status'] == 404
- assert self.get()['status'] == 404
- assert self.get(url='/?foo_bar=')['status'] == 404
- assert self.get(url='/?foo_bar=l&foo_bar=blah')['status'] == 210
- assert self.get(url='/?foo_bar=blah&foo_bar=l')['status'] == 404
-
- self.conf_routes("\"routes/$arg_foo_b%61r\"")
- assert self.get(url='/?foo_b=blah')['status'] == 404
- assert self.get(url='/?foo_bar=blah')['status'] == 404
-
- self.conf_routes("\"routes/$arg_f!~\"")
- assert self.get(url='/?f=blah')['status'] == 404
- assert self.get(url='/?f!~=blah')['status'] == 404
+ self.set_format('$header_Foo_Bar')
+ check_header('Foo-Bar', '4')
+ check_header('foo-bar', '5')
+ check_no_header('foo_bar')
+ check_no_header('foobar')
def test_variables_dynamic_cookies(self):
- def check_cookie(cookie, status=210):
+ def check_no_cookie(cookie):
assert (
self.get(
headers={
@@ -261,33 +344,48 @@ class TestVariables(TestApplicationProto):
'Connection': 'close',
},
)['status']
- == status
- ), 'match cookie'
+ == 200
+ )
+ assert self.search_in_log(r'^0$') is None
+
+ self.set_format('$cookie_foo_bar')
+
+ reg = r'^1$'
+ assert self.search_in_log(reg) is None
+ self.get(
+ headers={
+ 'Host': 'localhost',
+ 'Cookie': 'foo_bar=1',
+ 'Connection': 'close',
+ },
+ )['status'] == 200
+ assert self.wait_for_record(reg) is not None
- self.conf_routes("\"routes/$cookie_foo_bar\"")
- check_cookie('foo_bar=blah', 210)
- check_cookie('fOo_bar=blah', 404)
- assert self.get()['status'] == 404
- check_cookie('foo_bar', 404)
- check_cookie('foo_bar=', 404)
+ check_no_cookie('fOo_bar=0')
+ check_no_cookie('foo_bar=')
def test_variables_invalid(self):
- def check_variables(routes):
+ def check_variables(format):
assert 'error' in self.conf(
- routes, 'listeners/*:7080/pass'
- ), 'invalid variables'
-
- check_variables("\"routes$\"")
- check_variables("\"routes${\"")
- check_variables("\"routes${}\"")
- check_variables("\"routes$ur\"")
- check_variables("\"routes$uriblah\"")
- check_variables("\"routes${uri\"")
- check_variables("\"routes${{uri}\"")
- check_variables("\"routes$ar\"")
- check_variables("\"routes$arg\"")
- check_variables("\"routes$arg_\"")
- check_variables("\"routes$cookie\"")
- check_variables("\"routes$cookie_\"")
- check_variables("\"routes$header\"")
- check_variables("\"routes$header_\"")
+ {
+ 'path': option.temp_dir + '/access.log',
+ 'format': format,
+ },
+ 'access_log',
+ ), 'access_log format'
+
+ check_variables("$")
+ check_variables("${")
+ check_variables("${}")
+ check_variables("$ur")
+ check_variables("$uri$$host")
+ check_variables("$uriblah")
+ check_variables("${uri")
+ check_variables("${{uri}")
+ check_variables("$ar")
+ check_variables("$arg")
+ check_variables("$arg_")
+ check_variables("$cookie")
+ check_variables("$cookie_")
+ check_variables("$header")
+ check_variables("$header_")
diff --git a/test/unit/applications/lang/go.py b/test/unit/applications/lang/go.py
index 3db955f3..14e76362 100644
--- a/test/unit/applications/lang/go.py
+++ b/test/unit/applications/lang/go.py
@@ -67,7 +67,9 @@ replace unit.nginx.org/go => {replace_path}
print("\n$ GOPATH=" + env['GOPATH'] + " " + " ".join(args))
try:
- process = subprocess.run(args, env=env, cwd=temp_dir)
+ output = subprocess.check_output(
+ args, env=env, cwd=temp_dir, stderr=subprocess.STDOUT
+ )
except KeyboardInterrupt:
raise
@@ -75,7 +77,7 @@ replace unit.nginx.org/go => {replace_path}
except subprocess.CalledProcessError:
return None
- return process
+ return output
def load(self, script, name='app', **kwargs):
static_build = False
diff --git a/test/unit/applications/lang/java.py b/test/unit/applications/lang/java.py
index 50998978..c8936274 100644
--- a/test/unit/applications/lang/java.py
+++ b/test/unit/applications/lang/java.py
@@ -52,7 +52,7 @@ class TestApplicationJava(TestApplicationProto):
os.makedirs(classes_path)
classpath = (
- option.current_dir + '/build/tomcat-servlet-api-9.0.52.jar'
+ option.current_dir + '/build/tomcat-servlet-api-9.0.70.jar'
)
ws_jars = glob.glob(
diff --git a/test/unit/applications/lang/python.py b/test/unit/applications/lang/python.py
index 1e38f3fa..3768cf07 100644
--- a/test/unit/applications/lang/python.py
+++ b/test/unit/applications/lang/python.py
@@ -50,6 +50,7 @@ class TestApplicationPython(TestApplicationProto):
'protocol',
'targets',
'threads',
+ 'prefix',
):
if attr in kwargs:
app[attr] = kwargs.pop(attr)
diff --git a/test/unit/applications/websockets.py b/test/unit/applications/websockets.py
index d647ce9b..15f212ff 100644
--- a/test/unit/applications/websockets.py
+++ b/test/unit/applications/websockets.py
@@ -43,10 +43,9 @@ class TestApplicationWebsocket(TestApplicationProto):
'Sec-WebSocket-Version': 13,
}
- _, sock = self.get(
+ sock = self.get(
headers=headers,
no_recv=True,
- start=True,
)
resp = ''
diff --git a/test/unit/check/go.py b/test/unit/check/go.py
index 3d9d13e7..09ae641d 100644
--- a/test/unit/check/go.py
+++ b/test/unit/check/go.py
@@ -2,7 +2,5 @@ from unit.applications.lang.go import TestApplicationGo
def check_go():
- process = TestApplicationGo.prepare_env('empty')
-
- if process != None and process.returncode == 0:
+ if TestApplicationGo.prepare_env('empty') is not None:
return True
diff --git a/test/unit/check/njs.py b/test/unit/check/njs.py
new file mode 100644
index 00000000..433473a1
--- /dev/null
+++ b/test/unit/check/njs.py
@@ -0,0 +1,6 @@
+import re
+
+
+def check_njs(output_version):
+ if re.search('--njs', output_version):
+ return True
diff --git a/test/unit/check/regex.py b/test/unit/check/regex.py
index 734c0150..51cf966b 100644
--- a/test/unit/check/regex.py
+++ b/test/unit/check/regex.py
@@ -1,13 +1,8 @@
import re
-import subprocess
-def check_regex(unitd):
- output = subprocess.check_output(
- [unitd, '--version'], stderr=subprocess.STDOUT
- )
-
- if re.search('--no-regex', output.decode()):
+def check_regex(output_version):
+ if re.search('--no-regex', output_version):
return False
return True
diff --git a/test/unit/check/tls.py b/test/unit/check/tls.py
index b878ff7d..53ce5ffc 100644
--- a/test/unit/check/tls.py
+++ b/test/unit/check/tls.py
@@ -2,12 +2,11 @@ import re
import subprocess
-def check_openssl(unitd):
- subprocess.check_output(['which', 'openssl'])
+def check_openssl(output_version):
+ try:
+ subprocess.check_output(['which', 'openssl'])
+ except subprocess.CalledProcessError:
+ return None
- output = subprocess.check_output(
- [unitd, '--version'], stderr=subprocess.STDOUT
- )
-
- if re.search('--openssl', output.decode()):
+ if re.search('--openssl', output_version):
return True
diff --git a/test/unit/http.py b/test/unit/http.py
index b29667c9..c48a720f 100644
--- a/test/unit/http.py
+++ b/test/unit/http.py
@@ -102,7 +102,12 @@ class TestHTTP:
if 'read_buffer_size' in kwargs:
recvall_kwargs['buff_size'] = kwargs['read_buffer_size']
- resp = self.recvall(sock, **recvall_kwargs).decode(encoding)
+ resp = self.recvall(sock, **recvall_kwargs).decode(
+ encoding, errors='ignore'
+ )
+
+ else:
+ return sock
self.log_in(resp)
diff --git a/test/unit/utils.py b/test/unit/utils.py
index 43aaa81b..d6590b97 100644
--- a/test/unit/utils.py
+++ b/test/unit/utils.py
@@ -12,9 +12,15 @@ def public_dir(path):
for root, dirs, files in os.walk(path):
for d in dirs:
- os.chmod(os.path.join(root, d), 0o777)
+ try:
+ os.chmod(os.path.join(root, d), 0o777)
+ except FileNotFoundError:
+ pass
for f in files:
- os.chmod(os.path.join(root, f), 0o777)
+ try:
+ os.chmod(os.path.join(root, f), 0o777)
+ except FileNotFoundError:
+ pass
def waitforfiles(*files, timeout=50):
@@ -66,12 +72,19 @@ def waitforsocket(port):
pytest.fail('Can\'t connect to the 127.0.0.1:' + str(port))
-def findmnt():
+def check_findmnt():
try:
- out = subprocess.check_output(
+ return subprocess.check_output(
['findmnt', '--raw'], stderr=subprocess.STDOUT
).decode()
except FileNotFoundError:
+ return False
+
+
+def findmnt():
+ out = check_findmnt()
+
+ if not out:
pytest.skip('requires findmnt')
return out