From 3e4fa1e2022970dee003bea0932ea0c10f8744ba Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Thu, 25 May 2023 14:26:12 +0100 Subject: Tests: removed unused variables. --- test/test_configuration.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'test/test_configuration.py') diff --git a/test/test_configuration.py b/test/test_configuration.py index e3ddc891..d774ceb3 100644 --- a/test/test_configuration.py +++ b/test/test_configuration.py @@ -25,7 +25,7 @@ class TestConfiguration(TestControl): def test_json_unicode(self): assert 'success' in self.conf( - u""" + """ { "ap\u0070": { "type": "\u0070ython", @@ -64,7 +64,7 @@ class TestConfiguration(TestControl): def test_json_unicode_number(self): assert 'success' in self.conf( - u""" + """ { "app": { "type": "python", @@ -252,7 +252,7 @@ class TestConfiguration(TestControl): ) def test_listeners_port_release(self): - for i in range(10): + for _ in range(10): fail = False with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) -- cgit From 31ff94add9c4043a753683d9e8b68733c69aa1ac Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Mon, 29 May 2023 16:45:49 +0100 Subject: Tests: more fixtures. Common methods from applications/proto.py converted to the fixtures. sysctl check moved to the specific file where it is using. Some options moved to the constructor to have early access. --- test/test_configuration.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'test/test_configuration.py') diff --git a/test/test_configuration.py b/test/test_configuration.py index d774ceb3..e78a2957 100644 --- a/test/test_configuration.py +++ b/test/test_configuration.py @@ -2,7 +2,6 @@ import socket import pytest from unit.control import TestControl -from unit.option import option class TestConfiguration(TestControl): @@ -227,8 +226,8 @@ class TestConfiguration(TestControl): {"*:7080": {"pass": "applications/app"}}, 'listeners' ), 'listeners no app' - def test_listeners_unix_abstract(self): - if option.system != 'Linux': + def test_listeners_unix_abstract(self, system): + if system != 'Linux': assert 'error' in self.try_addr("unix:@sock"), 'abstract at' pytest.skip('not yet') -- cgit From ce2405ec3dd97e8bdf8f63312e3c6ce59ef562d4 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Mon, 12 Jun 2023 14:16:59 +0100 Subject: Tests: prerequisites checking reworked. Prerequisites check moved to the module level to simplify class structure. Discovery and prerequisites checks functions moved to the separate files. Introduced "require" fixture to provide per-test requirements check. --- test/test_configuration.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'test/test_configuration.py') diff --git a/test/test_configuration.py b/test/test_configuration.py index e78a2957..0c48ad57 100644 --- a/test/test_configuration.py +++ b/test/test_configuration.py @@ -3,10 +3,10 @@ import socket import pytest from unit.control import TestControl +prerequisites = {'modules': {'python': 'any'}} -class TestConfiguration(TestControl): - prerequisites = {'modules': {'python': 'any'}} +class TestConfiguration(TestControl): def try_addr(self, addr): return self.conf( { @@ -420,10 +420,10 @@ class TestConfiguration(TestControl): assert 'success' in self.conf(conf) - def test_unprivileged_user_error(self, is_su, skip_alert): + def test_unprivileged_user_error(self, require, skip_alert): + require({'privileged_user': False}) + skip_alert(r'cannot set user "root"', r'failed to apply new conf') - if is_su: - pytest.skip('unprivileged tests') assert 'error' in self.conf( { -- cgit From c183bd8749a19477390f8cb77efe5f6d223f0905 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Wed, 14 Jun 2023 18:20:09 +0100 Subject: Tests: get rid of classes in test files. Class usage came from the unittest framework and it was always redundant after migration to the pytest. This commit removes classes from files containing tests to make them more readable and understandable. --- test/test_configuration.py | 749 +++++++++++++++++++++++---------------------- 1 file changed, 388 insertions(+), 361 deletions(-) (limited to 'test/test_configuration.py') diff --git a/test/test_configuration.py b/test/test_configuration.py index 0c48ad57..19a2a1a5 100644 --- a/test/test_configuration.py +++ b/test/test_configuration.py @@ -1,438 +1,465 @@ import socket import pytest -from unit.control import TestControl +from unit.control import Control prerequisites = {'modules': {'python': 'any'}} +client = Control() -class TestConfiguration(TestControl): - def try_addr(self, addr): - return self.conf( - { - "listeners": {addr: {"pass": "routes"}}, - "routes": [{"action": {"return": 200}}], - "applications": {}, - } - ) - def test_json_empty(self): - assert 'error' in self.conf(''), 'empty' +def try_addr(addr): + return client.conf( + { + "listeners": {addr: {"pass": "routes"}}, + "routes": [{"action": {"return": 200}}], + "applications": {}, + } + ) - def test_json_leading_zero(self): - assert 'error' in self.conf('00'), 'leading zero' - def test_json_unicode(self): - assert 'success' in self.conf( - """ - { - "ap\u0070": { - "type": "\u0070ython", - "processes": { "spare": 0 }, - "path": "\u002Fapp", - "module": "wsgi" - } +def test_json_empty(): + assert 'error' in client.conf(''), 'empty' + + +def test_json_leading_zero(): + assert 'error' in client.conf('00'), 'leading zero' + + +def test_json_unicode(): + assert 'success' in client.conf( + """ + { + "ap\u0070": { + "type": "\u0070ython", + "processes": { "spare": 0 }, + "path": "\u002Fapp", + "module": "wsgi" } - """, - 'applications', - ), 'unicode' + } + """, + 'applications', + ), 'unicode' + + assert client.conf_get('applications') == { + "app": { + "type": "python", + "processes": {"spare": 0}, + "path": "/app", + "module": "wsgi", + } + }, 'unicode get' - assert self.conf_get('applications') == { - "app": { + +def test_json_unicode_2(): + assert 'success' in client.conf( + { + "приложение": { "type": "python", "processes": {"spare": 0}, "path": "/app", "module": "wsgi", } - }, 'unicode get' + }, + 'applications', + ), 'unicode 2' - def test_json_unicode_2(self): - assert 'success' in self.conf( - { - "приложение": { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - } - }, - 'applications', - ), 'unicode 2' + assert 'приложение' in client.conf_get('applications') - assert 'приложение' in self.conf_get('applications'), 'unicode 2 get' - def test_json_unicode_number(self): - assert 'success' in self.conf( - """ - { - "app": { - "type": "python", - "processes": { "spare": \u0030 }, - "path": "/app", - "module": "wsgi" - } +def test_json_unicode_number(): + assert 'success' in client.conf( + """ + { + "app": { + "type": "python", + "processes": { "spare": \u0030 }, + "path": "/app", + "module": "wsgi" } - """, - 'applications', - ), 'unicode number' + } + """, + 'applications', + ), 'unicode number' - def test_json_utf8_bom(self): - assert 'success' in self.conf( - b"""\xEF\xBB\xBF - { - "app": { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi" - } - } - """, - 'applications', - ), 'UTF-8 BOM' - - def test_json_comment_single_line(self): - assert 'success' in self.conf( - b""" - // this is bridge - { - "//app": { - "type": "python", // end line - "processes": {"spare": 0}, - // inside of block - "path": "/app", - "module": "wsgi" - } - // double // + +def test_json_utf8_bom(): + assert 'success' in client.conf( + b"""\xEF\xBB\xBF + { + "app": { + "type": "python", + "processes": {"spare": 0}, + "path": "/app", + "module": "wsgi" } - // end of json \xEF\t - """, - 'applications', - ), 'single line comments' - - def test_json_comment_multi_line(self): - assert 'success' in self.conf( - b""" - /* this is bridge */ - { - "/*app": { - /** - * multiple lines - **/ - "type": "python", - "processes": /* inline */ {"spare": 0}, - "path": "/app", - "module": "wsgi" - /* - // end of block */ - } - /* blah * / blah /* blah */ + } + """, + 'applications', + ), 'UTF-8 BOM' + + +def test_json_comment_single_line(): + assert 'success' in client.conf( + b""" + // this is bridge + { + "//app": { + "type": "python", // end line + "processes": {"spare": 0}, + // inside of block + "path": "/app", + "module": "wsgi" } - /* end of json \xEF\t\b */ - """, - 'applications', - ), 'multi line comments' - - def test_json_comment_invalid(self): - assert 'error' in self.conf(b'/{}', 'applications'), 'slash' - assert 'error' in self.conf(b'//{}', 'applications'), 'comment' - assert 'error' in self.conf(b'{} /', 'applications'), 'slash end' - assert 'error' in self.conf(b'/*{}', 'applications'), 'slash star' - assert 'error' in self.conf(b'{} /*', 'applications'), 'slash star end' - - def test_applications_open_brace(self): - assert 'error' in self.conf('{', 'applications'), 'open brace' - - def test_applications_string(self): - assert 'error' in self.conf('"{}"', 'applications'), 'string' - - @pytest.mark.skip('not yet, unsafe') - def test_applications_type_only(self): - assert 'error' in self.conf( - {"app": {"type": "python"}}, 'applications' - ), 'type only' - - def test_applications_miss_quote(self): - assert 'error' in self.conf( - """ - { - app": { - "type": "python", - "processes": { "spare": 0 }, - "path": "/app", - "module": "wsgi" - } + // double // + } + // end of json \xEF\t + """, + 'applications', + ), 'single line comments' + + +def test_json_comment_multi_line(): + assert 'success' in client.conf( + b""" + /* this is bridge */ + { + "/*app": { + /** + * multiple lines + **/ + "type": "python", + "processes": /* inline */ {"spare": 0}, + "path": "/app", + "module": "wsgi" + /* + // end of block */ } - """, - 'applications', - ), 'miss quote' + /* blah * / blah /* blah */ + } + /* end of json \xEF\t\b */ + """, + 'applications', + ), 'multi line comments' - def test_applications_miss_colon(self): - assert 'error' in self.conf( - """ - { - "app" { - "type": "python", - "processes": { "spare": 0 }, - "path": "/app", - "module": "wsgi" - } + +def test_json_comment_invalid(): + assert 'error' in client.conf(b'/{}', 'applications'), 'slash' + assert 'error' in client.conf(b'//{}', 'applications'), 'comment' + assert 'error' in client.conf(b'{} /', 'applications'), 'slash end' + assert 'error' in client.conf(b'/*{}', 'applications'), 'slash star' + assert 'error' in client.conf(b'{} /*', 'applications'), 'slash star end' + + +def test_applications_open_brace(): + assert 'error' in client.conf('{', 'applications'), 'open brace' + + +def test_applications_string(): + assert 'error' in client.conf('"{}"', 'applications'), 'string' + + +@pytest.mark.skip('not yet, unsafe') +def test_applications_type_only(): + assert 'error' in client.conf( + {"app": {"type": "python"}}, 'applications' + ), 'type only' + + +def test_applications_miss_quote(): + assert 'error' in client.conf( + """ + { + app": { + "type": "python", + "processes": { "spare": 0 }, + "path": "/app", + "module": "wsgi" } - """, - 'applications', - ), 'miss colon' + } + """, + 'applications', + ), 'miss quote' - def test_applications_miss_comma(self): - assert 'error' in self.conf( - """ - { - "app": { - "type": "python" - "processes": { "spare": 0 }, - "path": "/app", - "module": "wsgi" - } + +def test_applications_miss_colon(): + assert 'error' in client.conf( + """ + { + "app" { + "type": "python", + "processes": { "spare": 0 }, + "path": "/app", + "module": "wsgi" } - """, - 'applications', - ), 'miss comma' + } + """, + 'applications', + ), 'miss colon' - def test_applications_skip_spaces(self): - assert 'success' in self.conf( - b'{ \n\r\t}', 'applications' - ), 'skip spaces' - def test_applications_relative_path(self): - assert 'success' in self.conf( - { - "app": { - "type": "python", - "processes": {"spare": 0}, - "path": "../app", - "module": "wsgi", - } - }, - 'applications', - ), 'relative path' +def test_applications_miss_comma(): + assert 'error' in client.conf( + """ + { + "app": { + "type": "python" + "processes": { "spare": 0 }, + "path": "/app", + "module": "wsgi" + } + } + """, + 'applications', + ), 'miss comma' - @pytest.mark.skip('not yet, unsafe') - def test_listeners_empty(self): - assert 'error' in self.conf( - {"*:7080": {}}, 'listeners' - ), 'listener empty' - def test_listeners_no_app(self): - assert 'error' in self.conf( - {"*:7080": {"pass": "applications/app"}}, 'listeners' - ), 'listeners no app' +def test_applications_skip_spaces(): + assert 'success' in client.conf(b'{ \n\r\t}', 'applications'), 'skip spaces' - def test_listeners_unix_abstract(self, system): - if system != 'Linux': - assert 'error' in self.try_addr("unix:@sock"), 'abstract at' - pytest.skip('not yet') +def test_applications_relative_path(): + assert 'success' in client.conf( + { + "app": { + "type": "python", + "processes": {"spare": 0}, + "path": "../app", + "module": "wsgi", + } + }, + 'applications', + ), 'relative path' - assert 'error' in self.try_addr("unix:\0soc"), 'abstract \0' - assert 'error' in self.try_addr("unix:\u0000soc"), 'abstract \0 unicode' - def test_listeners_addr(self): - assert 'success' in self.try_addr("*:7080"), 'wildcard' - assert 'success' in self.try_addr("127.0.0.1:7081"), 'explicit' - assert 'success' in self.try_addr("[::1]:7082"), 'explicit ipv6' +@pytest.mark.skip('not yet, unsafe') +def test_listeners_empty(): + assert 'error' in client.conf({"*:7080": {}}, 'listeners'), 'listener empty' - def test_listeners_addr_error(self): - assert 'error' in self.try_addr("127.0.0.1"), 'no port' - def test_listeners_addr_error_2(self, skip_alert): - skip_alert(r'bind.*failed', r'failed to apply new conf') +def test_listeners_no_app(): + assert 'error' in client.conf( + {"*:7080": {"pass": "applications/app"}}, 'listeners' + ), 'listeners no app' - assert 'error' in self.try_addr( - "[f607:7403:1e4b:6c66:33b2:843f:2517:da27]:7080" - ) - def test_listeners_port_release(self): - for _ in range(10): - fail = False - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: - s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) +def test_listeners_unix_abstract(system): + if system != 'Linux': + assert 'error' in try_addr("unix:@sock"), 'abstract at' - self.conf( - { - "listeners": {"127.0.0.1:7080": {"pass": "routes"}}, - "routes": [], - } - ) + pytest.skip('not yet') - resp = self.conf({"listeners": {}, "applications": {}}) + assert 'error' in try_addr("unix:\0soc"), 'abstract \0' + assert 'error' in try_addr("unix:\u0000soc"), 'abstract \0 unicode' - try: - s.bind(('127.0.0.1', 7080)) - s.listen() - except OSError: - fail = True +def test_listeners_addr(): + assert 'success' in try_addr("*:7080"), 'wildcard' + assert 'success' in try_addr("127.0.0.1:7081"), 'explicit' + assert 'success' in try_addr("[::1]:7082"), 'explicit ipv6' - if fail: - pytest.fail('cannot bind or listen to the address') - assert 'success' in resp, 'port release' +def test_listeners_addr_error(): + assert 'error' in try_addr("127.0.0.1"), 'no port' - def test_json_application_name_large(self): - name = "X" * 1024 * 1024 - assert 'success' in self.conf( - { - "listeners": {"*:7080": {"pass": f"applications/{name}"}}, - "applications": { - name: { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - } - }, - } - ) +def test_listeners_addr_error_2(skip_alert): + skip_alert(r'bind.*failed', r'failed to apply new conf') - @pytest.mark.skip('not yet') - def test_json_application_many(self): - apps = 999 + assert 'error' in try_addr("[f607:7403:1e4b:6c66:33b2:843f:2517:da27]:7080") - conf = { - "applications": { - f"app-{a}": { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - } - for a in range(apps) - }, - "listeners": { - f"*:{(7000 + a)}": {"pass": f"applications/app-{a}"} - for a in range(apps) - }, - } - assert 'success' in self.conf(conf) +def test_listeners_port_release(): + for _ in range(10): + fail = False + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - 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": [ + client.conf( { - "match": {"uri": "/app/*"}, - "action": {"pass": "applications/sub-app"}, + "listeners": {"127.0.0.1:7080": {"pass": "routes"}}, + "routes": [], } - ], - } + ) - assert 'success' in self.conf(conf) + resp = client.conf({"listeners": {}, "applications": {}}) - 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"}, - }, - ], - } + try: + s.bind(('127.0.0.1', 7080)) + s.listen() - assert 'success' in self.conf(conf) + except OSError: + fail = True - 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"}}, - } + if fail: + pytest.fail('cannot bind or listen to the address') - assert 'error' in self.conf(conf) + assert 'success' in resp, 'port release' - 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_name_large(): + name = "X" * 1024 * 1024 - def test_json_application_many2(self): - conf = { + assert 'success' in client.conf( + { + "listeners": {"*:7080": {"pass": f"applications/{name}"}}, "applications": { - f"app-{a}": { + name: { "type": "python", "processes": {"spare": 0}, "path": "/app", "module": "wsgi", } - # Larger number of applications can cause test fail with default - # open files limit due to the lack of file descriptors. - for a in range(100) }, - "listeners": {"*:7080": {"pass": "applications/app-1"}}, } + ) + + +@pytest.mark.skip('not yet') +def test_json_application_many(): + apps = 999 + + conf = { + "applications": { + f"app-{a}": { + "type": "python", + "processes": {"spare": 0}, + "path": "/app", + "module": "wsgi", + } + for a in range(apps) + }, + "listeners": { + f"*:{(7000 + a)}": {"pass": f"applications/app-{a}"} + for a in range(apps) + }, + } - assert 'success' in self.conf(conf) + assert 'success' in client.conf(conf) - def test_unprivileged_user_error(self, require, skip_alert): - require({'privileged_user': False}) - skip_alert(r'cannot set user "root"', r'failed to apply new conf') +def test_json_application_python_prefix(): + 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 client.conf(conf) + - assert 'error' in self.conf( +def test_json_application_prefix_target(): + 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": [ { - "app": { - "type": "external", - "processes": 1, - "executable": "/app", - "user": "root", - } + "match": {"uri": "/app/*"}, + "action": {"pass": "applications/sub-app/foo"}, + }, + { + "match": {"uri": "/api/*"}, + "action": {"pass": "applications/sub-app/bar"}, }, - 'applications', - ), 'setting user' + ], + } + + assert 'success' in client.conf(conf) + + +def test_json_application_invalid_python_prefix(): + conf = { + "applications": { + "sub-app": { + "type": "python", + "processes": {"spare": 0}, + "path": "/app", + "module": "wsgi", + "prefix": "app", + } + }, + "listeners": {"*:7080": {"pass": "applications/sub-app"}}, + } + + assert 'error' in client.conf(conf) + + +def test_json_application_empty_python_prefix(): + conf = { + "applications": { + "sub-app": { + "type": "python", + "processes": {"spare": 0}, + "path": "/app", + "module": "wsgi", + "prefix": "", + } + }, + "listeners": {"*:7080": {"pass": "applications/sub-app"}}, + } + + assert 'error' in client.conf(conf) + + +def test_json_application_many2(): + conf = { + "applications": { + f"app-{a}": { + "type": "python", + "processes": {"spare": 0}, + "path": "/app", + "module": "wsgi", + } + # Larger number of applications can cause test fail with default + # open files limit due to the lack of file descriptors. + for a in range(100) + }, + "listeners": {"*:7080": {"pass": "applications/app-1"}}, + } + + assert 'success' in client.conf(conf) + + +def test_unprivileged_user_error(require, skip_alert): + require({'privileged_user': False}) + + skip_alert(r'cannot set user "root"', r'failed to apply new conf') + + assert 'error' in client.conf( + { + "app": { + "type": "external", + "processes": 1, + "executable": "/app", + "user": "root", + } + }, + 'applications', + ), 'setting user' -- cgit