summaryrefslogtreecommitdiffhomepage
path: root/test/unit
diff options
context:
space:
mode:
Diffstat (limited to 'test/unit')
-rw-r--r--test/unit/applications/lang/go.py3
-rw-r--r--test/unit/applications/lang/java.py2
-rw-r--r--test/unit/applications/lang/node.py4
-rw-r--r--test/unit/applications/lang/perl.py2
-rw-r--r--test/unit/applications/lang/php.py2
-rw-r--r--test/unit/applications/lang/python.py2
-rw-r--r--test/unit/applications/lang/ruby.py2
-rw-r--r--test/unit/applications/proto.py2
-rw-r--r--test/unit/applications/tls.py2
-rw-r--r--test/unit/check/isolation.py158
-rw-r--r--test/unit/control.py2
-rw-r--r--test/unit/feature/isolation.py160
-rw-r--r--test/unit/http.py5
-rw-r--r--test/unit/main.py42
-rw-r--r--test/unit/option.py16
-rw-r--r--test/unit/utils.py94
16 files changed, 282 insertions, 216 deletions
diff --git a/test/unit/applications/lang/go.py b/test/unit/applications/lang/go.py
index 866dec47..a17b1af4 100644
--- a/test/unit/applications/lang/go.py
+++ b/test/unit/applications/lang/go.py
@@ -1,8 +1,8 @@
import os
import subprocess
-from conftest import option
from unit.applications.proto import TestApplicationProto
+from unit.option import option
class TestApplicationGo(TestApplicationProto):
@@ -12,6 +12,7 @@ class TestApplicationGo(TestApplicationProto):
env = os.environ.copy()
env['GOPATH'] = option.current_dir + '/build/go'
+ env['GOCACHE'] = option.cache_dir + '/go'
if static:
args = [
diff --git a/test/unit/applications/lang/java.py b/test/unit/applications/lang/java.py
index 0ff85187..b2e17f23 100644
--- a/test/unit/applications/lang/java.py
+++ b/test/unit/applications/lang/java.py
@@ -4,8 +4,8 @@ import shutil
import subprocess
import pytest
-from conftest import option
from unit.applications.proto import TestApplicationProto
+from unit.option import option
class TestApplicationJava(TestApplicationProto):
diff --git a/test/unit/applications/lang/node.py b/test/unit/applications/lang/node.py
index 98fd9ffc..cc6d06ef 100644
--- a/test/unit/applications/lang/node.py
+++ b/test/unit/applications/lang/node.py
@@ -1,9 +1,9 @@
import shutil
from urllib.parse import quote
-from conftest import option
-from conftest import public_dir
from unit.applications.proto import TestApplicationProto
+from unit.option import option
+from unit.utils import public_dir
class TestApplicationNode(TestApplicationProto):
diff --git a/test/unit/applications/lang/perl.py b/test/unit/applications/lang/perl.py
index 9dc24ace..58b867f0 100644
--- a/test/unit/applications/lang/perl.py
+++ b/test/unit/applications/lang/perl.py
@@ -1,5 +1,5 @@
-from conftest import option
from unit.applications.proto import TestApplicationProto
+from unit.option import option
class TestApplicationPerl(TestApplicationProto):
diff --git a/test/unit/applications/lang/php.py b/test/unit/applications/lang/php.py
index 3dbb32f5..90c0078c 100644
--- a/test/unit/applications/lang/php.py
+++ b/test/unit/applications/lang/php.py
@@ -1,8 +1,8 @@
-from conftest import option
import os
import shutil
from unit.applications.proto import TestApplicationProto
+from unit.option import option
class TestApplicationPHP(TestApplicationProto):
diff --git a/test/unit/applications/lang/python.py b/test/unit/applications/lang/python.py
index 792a86fa..287d23f0 100644
--- a/test/unit/applications/lang/python.py
+++ b/test/unit/applications/lang/python.py
@@ -3,8 +3,8 @@ import shutil
from urllib.parse import quote
import pytest
-from conftest import option
from unit.applications.proto import TestApplicationProto
+from unit.option import option
class TestApplicationPython(TestApplicationProto):
diff --git a/test/unit/applications/lang/ruby.py b/test/unit/applications/lang/ruby.py
index 82d66e65..02644584 100644
--- a/test/unit/applications/lang/ruby.py
+++ b/test/unit/applications/lang/ruby.py
@@ -1,5 +1,5 @@
-from conftest import option
from unit.applications.proto import TestApplicationProto
+from unit.option import option
class TestApplicationRuby(TestApplicationProto):
diff --git a/test/unit/applications/proto.py b/test/unit/applications/proto.py
index 6e760c70..af05d071 100644
--- a/test/unit/applications/proto.py
+++ b/test/unit/applications/proto.py
@@ -2,8 +2,8 @@ import os
import re
import time
-from conftest import option
from unit.control import TestControl
+from unit.option import option
class TestApplicationProto(TestControl):
diff --git a/test/unit/applications/tls.py b/test/unit/applications/tls.py
index fb1b112c..b0cd5abb 100644
--- a/test/unit/applications/tls.py
+++ b/test/unit/applications/tls.py
@@ -2,8 +2,8 @@ import os
import ssl
import subprocess
-from conftest import option
from unit.applications.proto import TestApplicationProto
+from unit.option import option
class TestApplicationTLS(TestApplicationProto):
diff --git a/test/unit/check/isolation.py b/test/unit/check/isolation.py
new file mode 100644
index 00000000..fe5a41f8
--- /dev/null
+++ b/test/unit/check/isolation.py
@@ -0,0 +1,158 @@
+import json
+import os
+
+from unit.applications.lang.go import TestApplicationGo
+from unit.applications.lang.java import TestApplicationJava
+from unit.applications.lang.node import TestApplicationNode
+from unit.applications.proto import TestApplicationProto
+from unit.http import TestHTTP
+from unit.option import option
+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
+
+ conf = ''
+ if 'go' in available['modules']:
+ TestApplicationGo().prepare_env('empty', 'app')
+
+ conf = {
+ "listeners": {"*:7080": {"pass": "applications/empty"}},
+ "applications": {
+ "empty": {
+ "type": "external",
+ "processes": {"spare": 0},
+ "working_directory": option.test_dir + "/go/empty",
+ "executable": option.temp_dir + "/go/app",
+ "isolation": {"namespaces": {"credential": True}},
+ },
+ },
+ }
+
+ elif 'python' in available['modules']:
+ conf = {
+ "listeners": {"*:7080": {"pass": "applications/empty"}},
+ "applications": {
+ "empty": {
+ "type": "python",
+ "processes": {"spare": 0},
+ "path": option.test_dir + "/python/empty",
+ "working_directory": option.test_dir + "/python/empty",
+ "module": "wsgi",
+ "isolation": {"namespaces": {"credential": True}},
+ }
+ },
+ }
+
+ elif 'php' in available['modules']:
+ conf = {
+ "listeners": {"*:7080": {"pass": "applications/phpinfo"}},
+ "applications": {
+ "phpinfo": {
+ "type": "php",
+ "processes": {"spare": 0},
+ "root": option.test_dir + "/php/phpinfo",
+ "working_directory": option.test_dir + "/php/phpinfo",
+ "index": "index.php",
+ "isolation": {"namespaces": {"credential": True}},
+ }
+ },
+ }
+
+ elif 'ruby' in available['modules']:
+ conf = {
+ "listeners": {"*:7080": {"pass": "applications/empty"}},
+ "applications": {
+ "empty": {
+ "type": "ruby",
+ "processes": {"spare": 0},
+ "working_directory": option.test_dir + "/ruby/empty",
+ "script": option.test_dir + "/ruby/empty/config.ru",
+ "isolation": {"namespaces": {"credential": True}},
+ }
+ },
+ }
+
+ elif 'java' in available['modules']:
+ TestApplicationJava().prepare_env('empty')
+
+ conf = {
+ "listeners": {"*:7080": {"pass": "applications/empty"}},
+ "applications": {
+ "empty": {
+ "unit_jars": option.current_dir + "/build",
+ "type": "java",
+ "processes": {"spare": 0},
+ "working_directory": option.test_dir + "/java/empty/",
+ "webapp": option.temp_dir + "/java",
+ "isolation": {"namespaces": {"credential": True}},
+ }
+ },
+ }
+
+ elif 'node' in available['modules']:
+ TestApplicationNode().prepare_env('basic')
+
+ conf = {
+ "listeners": {"*:7080": {"pass": "applications/basic"}},
+ "applications": {
+ "basic": {
+ "type": "external",
+ "processes": {"spare": 0},
+ "working_directory": option.temp_dir + "/node",
+ "executable": "app.js",
+ "isolation": {"namespaces": {"credential": True}},
+ }
+ },
+ }
+
+ elif 'perl' in available['modules']:
+ conf = {
+ "listeners": {"*:7080": {"pass": "applications/body_empty"}},
+ "applications": {
+ "body_empty": {
+ "type": "perl",
+ "processes": {"spare": 0},
+ "working_directory": option.test_dir
+ + "/perl/body_empty",
+ "script": option.test_dir + "/perl/body_empty/psgi.pl",
+ "isolation": {"namespaces": {"credential": True}},
+ }
+ },
+ }
+
+ else:
+ return
+
+ resp = http.put(
+ url='/config',
+ sock_type='unix',
+ addr=option.temp_dir + '/control.unit.sock',
+ body=json.dumps(conf),
+ )
+
+ if 'success' not in resp['body']:
+ return
+
+ userns = getns('user')
+ if not userns:
+ return
+
+ available['features']['isolation'] = {'user': userns}
+
+ unp_clone_path = '/proc/sys/kernel/unprivileged_userns_clone'
+ if os.path.exists(unp_clone_path):
+ with open(unp_clone_path, 'r') as f:
+ if str(f.read()).rstrip() == '1':
+ available['features']['isolation'][
+ 'unprivileged_userns_clone'
+ ] = True
+
+ for ns in allns:
+ ns_value = getns(ns)
+ if ns_value:
+ available['features']['isolation'][ns] = ns_value
diff --git a/test/unit/control.py b/test/unit/control.py
index f05aa827..3008a64b 100644
--- a/test/unit/control.py
+++ b/test/unit/control.py
@@ -1,7 +1,7 @@
import json
-from conftest import option
from unit.http import TestHTTP
+from unit.option import option
def args_handler(conf_func):
diff --git a/test/unit/feature/isolation.py b/test/unit/feature/isolation.py
deleted file mode 100644
index 7877c03a..00000000
--- a/test/unit/feature/isolation.py
+++ /dev/null
@@ -1,160 +0,0 @@
-import os
-
-from unit.applications.lang.go import TestApplicationGo
-from unit.applications.lang.java import TestApplicationJava
-from unit.applications.lang.node import TestApplicationNode
-from unit.applications.proto import TestApplicationProto
-from conftest import option
-
-
-class TestFeatureIsolation(TestApplicationProto):
- allns = ['pid', 'mnt', 'ipc', 'uts', 'cgroup', 'net']
-
- def check(self, available, temp_dir):
- test_conf = {"namespaces": {"credential": True}}
-
- conf = ''
- if 'go' in available['modules']:
- TestApplicationGo().prepare_env('empty', 'app')
-
- conf = {
- "listeners": {"*:7080": {"pass": "applications/empty"}},
- "applications": {
- "empty": {
- "type": "external",
- "processes": {"spare": 0},
- "working_directory": option.test_dir + "/go/empty",
- "executable": option.temp_dir + "/go/app",
- "isolation": {"namespaces": {"credential": True}},
- },
- },
- }
-
- elif 'python' in available['modules']:
- conf = {
- "listeners": {"*:7080": {"pass": "applications/empty"}},
- "applications": {
- "empty": {
- "type": "python",
- "processes": {"spare": 0},
- "path": option.test_dir + "/python/empty",
- "working_directory": option.test_dir + "/python/empty",
- "module": "wsgi",
- "isolation": {"namespaces": {"credential": True}},
- }
- },
- }
-
- elif 'php' in available['modules']:
- conf = {
- "listeners": {"*:7080": {"pass": "applications/phpinfo"}},
- "applications": {
- "phpinfo": {
- "type": "php",
- "processes": {"spare": 0},
- "root": option.test_dir + "/php/phpinfo",
- "working_directory": option.test_dir + "/php/phpinfo",
- "index": "index.php",
- "isolation": {"namespaces": {"credential": True}},
- }
- },
- }
-
- elif 'ruby' in available['modules']:
- conf = {
- "listeners": {"*:7080": {"pass": "applications/empty"}},
- "applications": {
- "empty": {
- "type": "ruby",
- "processes": {"spare": 0},
- "working_directory": option.test_dir + "/ruby/empty",
- "script": option.test_dir + "/ruby/empty/config.ru",
- "isolation": {"namespaces": {"credential": True}},
- }
- },
- }
-
- elif 'java' in available['modules']:
- TestApplicationJava().prepare_env('empty')
-
- conf = {
- "listeners": {"*:7080": {"pass": "applications/empty"}},
- "applications": {
- "empty": {
- "unit_jars": option.current_dir + "/build",
- "type": "java",
- "processes": {"spare": 0},
- "working_directory": option.test_dir + "/java/empty/",
- "webapp": option.temp_dir + "/java",
- "isolation": {"namespaces": {"credential": True}},
- }
- },
- }
-
- elif 'node' in available['modules']:
- TestApplicationNode().prepare_env('basic')
-
- conf = {
- "listeners": {"*:7080": {"pass": "applications/basic"}},
- "applications": {
- "basic": {
- "type": "external",
- "processes": {"spare": 0},
- "working_directory": option.temp_dir + "/node",
- "executable": "app.js",
- "isolation": {"namespaces": {"credential": True}},
- }
- },
- }
-
- elif 'perl' in available['modules']:
- conf = {
- "listeners": {"*:7080": {"pass": "applications/body_empty"}},
- "applications": {
- "body_empty": {
- "type": "perl",
- "processes": {"spare": 0},
- "working_directory": option.test_dir
- + "/perl/body_empty",
- "script": option.test_dir + "/perl/body_empty/psgi.pl",
- "isolation": {"namespaces": {"credential": True}},
- }
- },
- }
-
- else:
- return
-
- if 'success' not in self.conf(conf):
- return
-
- userns = self.getns('user')
- if not userns:
- return
-
- available['features']['isolation'] = {'user': userns}
-
- unp_clone_path = '/proc/sys/kernel/unprivileged_userns_clone'
- if os.path.exists(unp_clone_path):
- with open(unp_clone_path, 'r') as f:
- if str(f.read()).rstrip() == '1':
- available['features']['isolation'][
- 'unprivileged_userns_clone'
- ] = True
-
- for ns in self.allns:
- ns_value = self.getns(ns)
- if ns_value:
- available['features']['isolation'][ns] = ns_value
-
- def getns(self, nstype):
- # read namespace id from symlink file:
- # it points to: '<nstype>:[<ns id>]'
- # # eg.: 'pid:[4026531836]'
- nspath = '/proc/self/ns/' + nstype
- data = None
-
- if os.path.exists(nspath):
- data = int(os.readlink(nspath)[len(nstype) + 2 : -1])
-
- return data
diff --git a/test/unit/http.py b/test/unit/http.py
index 8d964978..57e6ed3a 100644
--- a/test/unit/http.py
+++ b/test/unit/http.py
@@ -7,11 +7,10 @@ import select
import socket
import pytest
-from conftest import option
-from unit.main import TestUnit
+from unit.option import option
-class TestHTTP(TestUnit):
+class TestHTTP():
def http(self, start_str, **kwargs):
sock_type = kwargs.get('sock_type', 'ipv4')
port = kwargs.get('port', 7080)
diff --git a/test/unit/main.py b/test/unit/main.py
deleted file mode 100644
index 488b3f4d..00000000
--- a/test/unit/main.py
+++ /dev/null
@@ -1,42 +0,0 @@
-import pytest
-from conftest import option
-
-
-class TestUnit():
- @classmethod
- def setup_class(cls, complete_check=True):
- def check():
- missed = []
-
- # check modules
-
- if 'modules' in cls.prerequisites:
- available_modules = list(option.available['modules'].keys())
-
- for module in cls.prerequisites['modules']:
- if module in available_modules:
- continue
-
- missed.append(module)
-
- if missed:
- pytest.skip('Unit has no ' + ', '.join(missed) + ' module(s)')
-
- # check features
-
- if 'features' in cls.prerequisites:
- available_features = list(option.available['features'].keys())
-
- for feature in cls.prerequisites['features']:
- if feature in available_features:
- continue
-
- missed.append(feature)
-
- if missed:
- pytest.skip(', '.join(missed) + ' feature(s) not supported')
-
- if complete_check:
- check()
- else:
- return check
diff --git a/test/unit/option.py b/test/unit/option.py
new file mode 100644
index 00000000..677d806e
--- /dev/null
+++ b/test/unit/option.py
@@ -0,0 +1,16 @@
+class Options():
+ _options = {
+ 'skip_alerts': [],
+ 'skip_sanitizer': False,
+ }
+
+ def __setattr__(self, name, value):
+ Options._options[name] = value
+
+ def __getattr__(self, name):
+ if name in Options._options:
+ return Options._options[name]
+
+ raise AttributeError
+
+option = Options()
diff --git a/test/unit/utils.py b/test/unit/utils.py
new file mode 100644
index 00000000..7a0a3fe5
--- /dev/null
+++ b/test/unit/utils.py
@@ -0,0 +1,94 @@
+import os
+import socket
+import subprocess
+import time
+
+import pytest
+
+
+def public_dir(path):
+ os.chmod(path, 0o777)
+
+ for root, dirs, files in os.walk(path):
+ for d in dirs:
+ os.chmod(os.path.join(root, d), 0o777)
+ for f in files:
+ os.chmod(os.path.join(root, f), 0o777)
+
+
+def waitforfiles(*files):
+ for i in range(50):
+ wait = False
+
+ for f in files:
+ if not os.path.exists(f):
+ wait = True
+ break
+
+ if not wait:
+ return True
+
+ time.sleep(0.1)
+
+ return False
+
+
+def waitforsocket(port):
+ for i in range(50):
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
+ try:
+ sock.settimeout(5)
+ sock.connect(('127.0.0.1', port))
+ return
+
+ except ConnectionRefusedError:
+ time.sleep(0.1)
+
+ except KeyboardInterrupt:
+ raise
+
+ pytest.fail('Can\'t connect to the 127.0.0.1:' + port)
+
+
+def findmnt():
+ try:
+ out = subprocess.check_output(
+ ['findmnt', '--raw'], stderr=subprocess.STDOUT
+ ).decode()
+ except FileNotFoundError:
+ pytest.skip('requires findmnt')
+
+ return out
+
+
+def waitformount(template, wait=50):
+ for i in range(wait):
+ if findmnt().find(template) != -1:
+ return True
+
+ time.sleep(0.1)
+
+ return False
+
+
+def waitforunmount(template, wait=50):
+ for i in range(wait):
+ if findmnt().find(template) == -1:
+ return True
+
+ time.sleep(0.1)
+
+ return False
+
+
+def getns(nstype):
+ # read namespace id from symlink file:
+ # it points to: '<nstype>:[<ns id>]'
+ # # eg.: 'pid:[4026531836]'
+ nspath = '/proc/self/ns/' + nstype
+ data = None
+
+ if os.path.exists(nspath):
+ data = int(os.readlink(nspath)[len(nstype) + 2 : -1])
+
+ return data