summaryrefslogtreecommitdiffhomepage
path: root/test/unit
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--test/unit/applications/lang/go.py1
-rw-r--r--test/unit/applications/lang/node.py21
-rw-r--r--test/unit/applications/lang/python.py11
-rw-r--r--test/unit/applications/proto.py18
-rw-r--r--test/unit/applications/tls.py42
-rw-r--r--test/unit/applications/websockets.py18
-rw-r--r--test/unit/check/chroot.py32
-rw-r--r--test/unit/check/go.py1
-rw-r--r--test/unit/check/isolation.py4
-rw-r--r--test/unit/check/node.py13
-rw-r--r--test/unit/http.py26
-rw-r--r--test/unit/log.py23
-rw-r--r--test/unit/option.py3
-rw-r--r--test/unit/utils.py11
14 files changed, 180 insertions, 44 deletions
diff --git a/test/unit/applications/lang/go.py b/test/unit/applications/lang/go.py
index a17b1af4..6be1667b 100644
--- a/test/unit/applications/lang/go.py
+++ b/test/unit/applications/lang/go.py
@@ -13,6 +13,7 @@ class TestApplicationGo(TestApplicationProto):
env = os.environ.copy()
env['GOPATH'] = option.current_dir + '/build/go'
env['GOCACHE'] = option.cache_dir + '/go'
+ env['GO111MODULE'] = 'auto'
if static:
args = [
diff --git a/test/unit/applications/lang/node.py b/test/unit/applications/lang/node.py
index cc6d06ef..5d05c70c 100644
--- a/test/unit/applications/lang/node.py
+++ b/test/unit/applications/lang/node.py
@@ -7,15 +7,16 @@ from unit.utils import public_dir
class TestApplicationNode(TestApplicationProto):
+ application_type = "node"
+ es_modules = False
+
def prepare_env(self, script):
# copy application
-
shutil.copytree(
option.test_dir + '/node/' + script, option.temp_dir + '/node'
)
# copy modules
-
shutil.copytree(
option.current_dir + '/node/node_modules',
option.temp_dir + '/node/node_modules',
@@ -26,6 +27,19 @@ class TestApplicationNode(TestApplicationProto):
def load(self, script, name='app.js', **kwargs):
self.prepare_env(script)
+ if self.es_modules:
+ arguments = [
+ "node",
+ "--loader",
+ "unit-http/loader.mjs",
+ "--require",
+ "unit-http/loader",
+ name,
+ ]
+
+ else:
+ arguments = ["node", "--require", "unit-http/loader", name]
+
self._load_conf(
{
"listeners": {
@@ -36,7 +50,8 @@ class TestApplicationNode(TestApplicationProto):
"type": "external",
"processes": {"spare": 0},
"working_directory": option.temp_dir + '/node',
- "executable": name,
+ "executable": '/usr/bin/env',
+ "arguments": arguments,
}
},
},
diff --git a/test/unit/applications/lang/python.py b/test/unit/applications/lang/python.py
index 287d23f0..b399dffd 100644
--- a/test/unit/applications/lang/python.py
+++ b/test/unit/applications/lang/python.py
@@ -42,8 +42,15 @@ class TestApplicationPython(TestApplicationProto):
"module": module,
}
- for attr in ('callable', 'home', 'limits', 'path', 'protocol',
- 'threads'):
+ for attr in (
+ 'callable',
+ 'home',
+ 'limits',
+ 'path',
+ 'protocol',
+ 'targets',
+ 'threads',
+ ):
if attr in kwargs:
app[attr] = kwargs.pop(attr)
diff --git a/test/unit/applications/proto.py b/test/unit/applications/proto.py
index 5c400621..92754c03 100644
--- a/test/unit/applications/proto.py
+++ b/test/unit/applications/proto.py
@@ -4,6 +4,7 @@ import time
from unit.control import TestControl
from unit.option import option
+from unit.log import Log
class TestApplicationProto(TestControl):
@@ -15,18 +16,23 @@ class TestApplicationProto(TestControl):
def date_to_sec_epoch(self, date, template='%a, %d %b %Y %H:%M:%S %Z'):
return time.mktime(time.strptime(date, template))
+ def findall(self, pattern, name='unit.log'):
+ with Log.open(name) as f:
+ return re.findall(pattern, f.read())
+
def search_in_log(self, pattern, name='unit.log'):
- with open(option.temp_dir + '/' + name, 'r', errors='ignore') as f:
+ with Log.open(name) as f:
return re.search(pattern, f.read())
def wait_for_record(self, pattern, name='unit.log', wait=150):
- for i in range(wait):
- found = self.search_in_log(pattern, name)
+ with Log.open(name) as f:
+ for i in range(wait):
+ found = re.search(pattern, f.read())
- if found is not None:
- break
+ if found is not None:
+ break
- time.sleep(0.1)
+ time.sleep(0.1)
return found
diff --git a/test/unit/applications/tls.py b/test/unit/applications/tls.py
index b0cd5abb..583b618f 100644
--- a/test/unit/applications/tls.py
+++ b/test/unit/applications/tls.py
@@ -21,10 +21,14 @@ class TestApplicationTLS(TestApplicationProto):
'req',
'-x509',
'-new',
- '-subj', '/CN=' + name + '/',
- '-config', option.temp_dir + '/openssl.conf',
- '-out', option.temp_dir + '/' + name + '.crt',
- '-keyout', option.temp_dir + '/' + name + '.key',
+ '-subj',
+ '/CN=' + name + '/',
+ '-config',
+ option.temp_dir + '/openssl.conf',
+ '-out',
+ option.temp_dir + '/' + name + '.crt',
+ '-keyout',
+ option.temp_dir + '/' + name + '.key',
],
stderr=subprocess.STDOUT,
)
@@ -63,19 +67,43 @@ class TestApplicationTLS(TestApplicationProto):
return ssl.get_server_certificate(addr, ssl_version=ssl_version)
- def openssl_conf(self):
+ def openssl_conf(self, rewrite=False, alt_names=[]):
conf_path = option.temp_dir + '/openssl.conf'
- if os.path.exists(conf_path):
+ if not rewrite and os.path.exists(conf_path):
return
+ # Generates alt_names section with dns names
+ a_names = "[alt_names]\n"
+ for i, k in enumerate(alt_names, 1):
+ k = k.split('|')
+
+ if k[0] == 'IP':
+ a_names += "IP.%d = %s\n" % (i, k[1])
+ else:
+ a_names += "DNS.%d = %s\n" % (i, k[0])
+
+ # Generates section for sign request extension
+ a_sec = """req_extensions = myca_req_extensions
+
+[ myca_req_extensions ]
+subjectAltName = @alt_names
+
+{a_names}""".format(
+ a_names=a_names
+ )
+
with open(conf_path, 'w') as f:
f.write(
"""[ req ]
default_bits = 2048
encrypt_key = no
distinguished_name = req_distinguished_name
-[ req_distinguished_name ]"""
+
+{a_sec}
+[ req_distinguished_name ]""".format(
+ a_sec=a_sec if alt_names else ""
+ )
)
def load(self, script, name=None):
diff --git a/test/unit/applications/websockets.py b/test/unit/applications/websockets.py
index cc720a98..aa83339c 100644
--- a/test/unit/applications/websockets.py
+++ b/test/unit/applications/websockets.py
@@ -43,11 +43,7 @@ class TestApplicationWebsocket(TestApplicationProto):
'Sec-WebSocket-Version': 13,
}
- _, sock = self.get(
- headers=headers,
- no_recv=True,
- start=True,
- )
+ _, sock = self.get(headers=headers, no_recv=True, start=True,)
resp = ''
while True:
@@ -57,7 +53,7 @@ class TestApplicationWebsocket(TestApplicationProto):
resp += sock.recv(4096).decode()
- if (resp.startswith('HTTP/') and '\r\n\r\n' in resp):
+ if resp.startswith('HTTP/') and '\r\n\r\n' in resp:
resp = self._resp_to_dict(resp)
break
@@ -90,8 +86,8 @@ class TestApplicationWebsocket(TestApplicationProto):
frame = {}
- head1, = struct.unpack('!B', recv_bytes(sock, 1))
- head2, = struct.unpack('!B', recv_bytes(sock, 1))
+ (head1,) = struct.unpack('!B', recv_bytes(sock, 1))
+ (head2,) = struct.unpack('!B', recv_bytes(sock, 1))
frame['fin'] = bool(head1 & 0b10000000)
frame['rsv1'] = bool(head1 & 0b01000000)
@@ -103,10 +99,10 @@ class TestApplicationWebsocket(TestApplicationProto):
length = head2 & 0b01111111
if length == 126:
data = recv_bytes(sock, 2)
- length, = struct.unpack('!H', data)
+ (length,) = struct.unpack('!H', data)
elif length == 127:
data = recv_bytes(sock, 8)
- length, = struct.unpack('!Q', data)
+ (length,) = struct.unpack('!Q', data)
if frame['mask']:
mask_bits = recv_bytes(sock, 4)
@@ -121,7 +117,7 @@ class TestApplicationWebsocket(TestApplicationProto):
if frame['opcode'] == self.OP_CLOSE:
if length >= 2:
- code, = struct.unpack('!H', data[:2])
+ (code,) = struct.unpack('!H', data[:2])
reason = data[2:].decode('utf-8')
if not (code in self.CLOSE_CODES or 3000 <= code < 5000):
pytest.fail('Invalid status code')
diff --git a/test/unit/check/chroot.py b/test/unit/check/chroot.py
new file mode 100644
index 00000000..40b75058
--- /dev/null
+++ b/test/unit/check/chroot.py
@@ -0,0 +1,32 @@
+import json
+
+from unit.http import TestHTTP
+from unit.option import option
+
+http = TestHTTP()
+
+
+def check_chroot():
+ available = option.available
+
+ resp = http.put(
+ url='/config',
+ sock_type='unix',
+ addr=option.temp_dir + '/control.unit.sock',
+ body=json.dumps(
+ {
+ "listeners": {"*:7080": {"pass": "routes"}},
+ "routes": [
+ {
+ "action": {
+ "share": option.temp_dir,
+ "chroot": option.temp_dir,
+ }
+ }
+ ],
+ }
+ ),
+ )
+
+ if 'success' in resp['body']:
+ available['features']['chroot'] = True
diff --git a/test/unit/check/go.py b/test/unit/check/go.py
index 35b0c2d5..309091c0 100644
--- a/test/unit/check/go.py
+++ b/test/unit/check/go.py
@@ -8,6 +8,7 @@ def check_go(current_dir, temp_dir, test_dir):
env = os.environ.copy()
env['GOPATH'] = current_dir + '/build/go'
+ env['GO111MODULE'] = 'auto'
try:
process = subprocess.Popen(
diff --git a/test/unit/check/isolation.py b/test/unit/check/isolation.py
index fe5a41f8..7c83ae35 100644
--- a/test/unit/check/isolation.py
+++ b/test/unit/check/isolation.py
@@ -12,6 +12,7 @@ from unit.utils import getns
allns = ['pid', 'mnt', 'ipc', 'uts', 'cgroup', 'net']
http = TestHTTP()
+
def check_isolation():
test_conf = {"namespaces": {"credential": True}}
available = option.available
@@ -117,8 +118,7 @@ def check_isolation():
"body_empty": {
"type": "perl",
"processes": {"spare": 0},
- "working_directory": option.test_dir
- + "/perl/body_empty",
+ "working_directory": option.test_dir + "/perl/body_empty",
"script": option.test_dir + "/perl/body_empty/psgi.pl",
"isolation": {"namespaces": {"credential": True}},
}
diff --git a/test/unit/check/node.py b/test/unit/check/node.py
index 236ba7b5..e053a749 100644
--- a/test/unit/check/node.py
+++ b/test/unit/check/node.py
@@ -1,6 +1,15 @@
import os
+import subprocess
def check_node(current_dir):
- if os.path.exists(current_dir + '/node/node_modules'):
- return True
+ if not os.path.exists(current_dir + '/node/node_modules'):
+ return None
+
+ try:
+ v_bytes = subprocess.check_output(['/usr/bin/env', 'node', '-v'])
+
+ return [str(v_bytes, 'utf-8').lstrip('v').rstrip()]
+
+ except subprocess.CalledProcessError:
+ return None
diff --git a/test/unit/http.py b/test/unit/http.py
index 57e6ed3a..797b7681 100644
--- a/test/unit/http.py
+++ b/test/unit/http.py
@@ -10,15 +10,16 @@ import pytest
from unit.option import option
-class TestHTTP():
+class TestHTTP:
def http(self, start_str, **kwargs):
sock_type = kwargs.get('sock_type', 'ipv4')
port = kwargs.get('port', 7080)
url = kwargs.get('url', '/')
http = 'HTTP/1.0' if 'http_10' in kwargs else 'HTTP/1.1'
- headers = kwargs.get('headers',
- {'Host': 'localhost', 'Connection': 'close'})
+ headers = kwargs.get(
+ 'headers', {'Host': 'localhost', 'Connection': 'close'}
+ )
body = kwargs.get('body', b'')
crlf = '\r\n'
@@ -44,7 +45,8 @@ class TestHTTP():
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
if 'wrapper' in kwargs:
- sock = kwargs['wrapper'](sock)
+ server_hostname = headers.get('Host', 'localhost')
+ sock = kwargs['wrapper'](sock, server_hostname=server_hostname)
connect_args = addr if sock_type == 'unix' else (addr, port)
try:
@@ -304,8 +306,9 @@ class TestHTTP():
return body, content_type
def form_url_encode(self, fields):
- data = "&".join("%s=%s" % (name, value)
- for name, value in fields.items()).encode()
+ data = "&".join(
+ "%s=%s" % (name, value) for name, value in fields.items()
+ ).encode()
return data, 'application/x-www-form-urlencoded'
def multipart_encode(self, fields):
@@ -325,7 +328,9 @@ class TestHTTP():
datatype = value['type']
if not isinstance(value['data'], io.IOBase):
- pytest.fail('multipart encoding of file requires a stream.')
+ pytest.fail(
+ 'multipart encoding of file requires a stream.'
+ )
data = value['data'].read()
@@ -335,9 +340,10 @@ class TestHTTP():
else:
pytest.fail('multipart requires a string or stream data')
- body += (
- "--%s\r\nContent-Disposition: form-data; name=\"%s\""
- ) % (boundary, field)
+ body += ("--%s\r\nContent-Disposition: form-data; name=\"%s\"") % (
+ boundary,
+ field,
+ )
if filename != '':
body += "; filename=\"%s\"" % filename
diff --git a/test/unit/log.py b/test/unit/log.py
new file mode 100644
index 00000000..7263443d
--- /dev/null
+++ b/test/unit/log.py
@@ -0,0 +1,23 @@
+UNIT_LOG = 'unit.log'
+
+
+class Log:
+ temp_dir = None
+ pos = {}
+
+ def open(name=UNIT_LOG, encoding=None):
+ f = open(Log.get_path(name), 'r', encoding=encoding, errors='ignore')
+ f.seek(Log.pos.get(name, 0))
+
+ return f
+
+ def set_pos(pos, name=UNIT_LOG):
+ Log.pos[name] = pos
+
+ def swap(name):
+ pos = Log.pos.get(UNIT_LOG, 0)
+ Log.pos[UNIT_LOG] = Log.pos.get(name, 0)
+ Log.pos[name] = pos
+
+ def get_path(name=UNIT_LOG):
+ return Log.temp_dir + '/' + name
diff --git a/test/unit/option.py b/test/unit/option.py
index 677d806e..cb3803dc 100644
--- a/test/unit/option.py
+++ b/test/unit/option.py
@@ -1,4 +1,4 @@
-class Options():
+class Options:
_options = {
'skip_alerts': [],
'skip_sanitizer': False,
@@ -13,4 +13,5 @@ class Options():
raise AttributeError
+
option = Options()
diff --git a/test/unit/utils.py b/test/unit/utils.py
index e80fc469..a627e9f5 100644
--- a/test/unit/utils.py
+++ b/test/unit/utils.py
@@ -61,6 +61,17 @@ def findmnt():
return out
+def sysctl():
+ try:
+ out = subprocess.check_output(
+ ['sysctl', '-a'], stderr=subprocess.STDOUT
+ ).decode()
+ except FileNotFoundError:
+ pytest.skip('requires sysctl')
+
+ return out
+
+
def waitformount(template, wait=50):
for i in range(wait):
if findmnt().find(template) != -1: