From baf92303987582d226fb90175f51c4cf8457cb96 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Thu, 12 Mar 2020 17:14:16 +0000 Subject: Tests: skip "close failed" alert in test_proxy_parallel test. --- test/test_proxy.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'test') diff --git a/test/test_proxy.py b/test/test_proxy.py index 74bd0873..5568550a 100644 --- a/test/test_proxy.py +++ b/test/test_proxy.py @@ -196,6 +196,8 @@ Content-Length: 10 self.assertEqual(resp['body'], payload, 'body') def test_proxy_parallel(self): + self.skip_alerts.append(r'close\(\d+\) failed') + payload = 'X' * 4096 * 257 buff_size = 4096 * 258 -- cgit From c6f9ca79e6a8517544a0995414de8421a9983687 Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Tue, 17 Mar 2020 14:44:11 +0300 Subject: Fixing body fd access racing condition. To avoid closing the body fd prematurely, the fd value is moved from the request struct to the app link. The body fd should not be closed immediately after the request is sent to the application due to possible request rescheduling. --- test/test_proxy.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'test') diff --git a/test/test_proxy.py b/test/test_proxy.py index 5568550a..74bd0873 100644 --- a/test/test_proxy.py +++ b/test/test_proxy.py @@ -196,8 +196,6 @@ Content-Length: 10 self.assertEqual(resp['body'], payload, 'body') def test_proxy_parallel(self): - self.skip_alerts.append(r'close\(\d+\) failed') - payload = 'X' * 4096 * 257 buff_size = 4096 * 258 -- cgit From 06c790ac1eea241224d184d48927f5f501df1309 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Thu, 19 Mar 2020 03:15:50 +0000 Subject: Tests: fixed prerequisite in test_share_fallback.py. --- test/test_share_fallback.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/test/test_share_fallback.py b/test/test_share_fallback.py index 8c45793e..1a5d4e4b 100644 --- a/test/test_share_fallback.py +++ b/test/test_share_fallback.py @@ -1,10 +1,10 @@ import os import unittest -from unit.applications.proto import TestApplicationProto +from unit.applications.lang.python import TestApplicationPython -class TestStatic(TestApplicationProto): - prerequisites = {} +class TestStatic(TestApplicationPython): + prerequisites = {'modules': ['python']} def setUp(self): super().setUp() -- cgit From 93207d4a8c462525cf2160d2099e44b86aa68b27 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Thu, 19 Mar 2020 03:17:00 +0000 Subject: Tests: test_python_procman.py refactored. --- test/test_python_procman.py | 173 +++++++++++++++----------------------------- 1 file changed, 58 insertions(+), 115 deletions(-) (limited to 'test') diff --git a/test/test_python_procman.py b/test/test_python_procman.py index 52d8cacb..8fb499f7 100644 --- a/test/test_python_procman.py +++ b/test/test_python_procman.py @@ -8,6 +8,13 @@ from unit.applications.lang.python import TestApplicationPython class TestPythonProcman(TestApplicationPython): prerequisites = {'modules': ['python']} + def setUp(self): + super().setUp() + + self.app_name = "app-" + self.testdir.split('/')[-1] + self.app_proc = 'applications/' + self.app_name + '/processes' + self.load('empty', self.app_name) + def pids_for_process(self): time.sleep(0.2) @@ -19,103 +26,20 @@ class TestPythonProcman(TestApplicationPython): return pids - def setUp(self): - super().setUp() - - self.app_name = "app-" + self.testdir.split('/')[-1] - self.load('empty', self.app_name) - - def test_python_processes_access(self): - self.conf('1', 'applications/' + self.app_name + '/processes') - - self.assertIn( - 'error', - self.conf_get('/applications/' + self.app_name + '/processes/max'), - 'max no access', - ) - self.assertIn( - 'error', - self.conf_get( - '/applications/' + self.app_name + '/processes/spare' - ), - 'spare no access', - ) - self.assertIn( - 'error', - self.conf_get( - '/applications/' + self.app_name + '/processes/idle_timeout' - ), - 'idle_timeout no access', - ) - - def test_python_processes_spare_negative(self): - self.assertIn( - 'error', - self.conf( - {"spare": -1}, 'applications/' + self.app_name + '/processes' - ), - 'negative spare', - ) - - def test_python_processes_max_negative(self): - self.assertIn( - 'error', - self.conf( - {"max": -1}, 'applications/' + self.app_name + '/processes' - ), - 'negative max', - ) - - def test_python_processes_idle_timeout_negative(self): - self.assertIn( - 'error', - self.conf( - {"idle_timeout": -1}, - 'applications/' + self.app_name + '/processes', - ), - 'negative idle_timeout', - ) - - def test_python_processes_spare_gt_max_default(self): - self.assertIn( - 'error', - self.conf( - {"spare": 2}, 'applications/' + self.app_name + '/processes' - ), - 'spare greater than max default', - ) - - def test_python_processes_spare_gt_max(self): - self.assertIn( - 'error', - self.conf( - {"spare": 2, "max": 1, "idle_timeout": 1}, - '/applications/' + self.app_name + '/processes', - ), - 'spare greater than max', - ) + def conf_proc(self, conf, path=None): + if path is None: + path = self.app_proc - def test_python_processes_max_zero(self): - self.assertIn( - 'error', - self.conf( - {"spare": 0, "max": 0, "idle_timeout": 1}, - 'applications/' + self.app_name + '/processes', - ), - 'max 0', - ) + self.assertIn('success', self.conf(conf, path), 'configure processes') def test_python_processes_idle_timeout_zero(self): - self.conf( - {"spare": 0, "max": 2, "idle_timeout": 0}, - 'applications/' + self.app_name + '/processes', - ) + self.conf_proc({"spare": 0, "max": 2, "idle_timeout": 0}) self.get() self.assertEqual(len(self.pids_for_process()), 0, 'idle timeout 0') def test_python_prefork(self): - self.conf('2', 'applications/' + self.app_name + '/processes') + self.conf_proc('2') pids = self.pids_for_process() self.assertEqual(len(pids), 2, 'prefork 2') @@ -123,7 +47,7 @@ class TestPythonProcman(TestApplicationPython): self.get() self.assertSetEqual(self.pids_for_process(), pids, 'prefork still 2') - self.conf('4', 'applications/' + self.app_name + '/processes') + self.conf_proc('4') pids = self.pids_for_process() self.assertEqual(len(pids), 4, 'prefork 4') @@ -135,21 +59,16 @@ class TestPythonProcman(TestApplicationPython): @unittest.skip('not yet') def test_python_prefork_same_processes(self): - self.conf('2', 'applications/' + self.app_name + '/processes') - + self.conf_proc('2') pids = self.pids_for_process() - self.conf('4', 'applications/' + self.app_name + '/processes') - + self.conf_proc('4') pids_new = self.pids_for_process() self.assertTrue(pids.issubset(pids_new), 'prefork same processes') def test_python_ondemand(self): - self.conf( - {"spare": 0, "max": 8, "idle_timeout": 1}, - 'applications/' + self.app_name + '/processes', - ) + self.conf_proc({"spare": 0, "max": 8, "idle_timeout": 1}) self.assertEqual(len(self.pids_for_process()), 0, 'on-demand 0') @@ -169,10 +88,7 @@ class TestPythonProcman(TestApplicationPython): self.stop_all() def test_python_scale_updown(self): - self.conf( - {"spare": 2, "max": 8, "idle_timeout": 1}, - 'applications/' + self.app_name + '/processes', - ) + self.conf_proc({"spare": 2, "max": 8, "idle_timeout": 1}) pids = self.pids_for_process() self.assertEqual(len(pids), 2, 'updown 2') @@ -200,10 +116,7 @@ class TestPythonProcman(TestApplicationPython): self.stop_all() def test_python_reconfigure(self): - self.conf( - {"spare": 2, "max": 6, "idle_timeout": 1}, - 'applications/' + self.app_name + '/processes', - ) + self.conf_proc({"spare": 2, "max": 6, "idle_timeout": 1}) pids = self.pids_for_process() self.assertEqual(len(pids), 2, 'reconf 2') @@ -213,7 +126,7 @@ class TestPythonProcman(TestApplicationPython): self.assertEqual(len(pids_new), 3, 'reconf 3') self.assertTrue(pids.issubset(pids_new), 'reconf 3 only 1 new') - self.conf('6', 'applications/' + self.app_name + '/processes/spare') + self.conf_proc('6', self.app_proc + '/spare') pids = self.pids_for_process() self.assertEqual(len(pids), 6, 'reconf 6') @@ -224,10 +137,7 @@ class TestPythonProcman(TestApplicationPython): self.stop_all() def test_python_idle_timeout(self): - self.conf( - {"spare": 0, "max": 6, "idle_timeout": 2}, - 'applications/' + self.app_name + '/processes', - ) + self.conf_proc({"spare": 0, "max": 6, "idle_timeout": 2}) self.get() pids = self.pids_for_process() @@ -250,10 +160,7 @@ class TestPythonProcman(TestApplicationPython): self.assertEqual(len(self.pids_for_process()), 0, 'idle timed out') def test_python_processes_connection_keepalive(self): - self.conf( - {"spare": 0, "max": 6, "idle_timeout": 2}, - 'applications/' + self.app_name + '/processes', - ) + self.conf_proc({"spare": 0, "max": 6, "idle_timeout": 2}) (resp, sock) = self.get( headers={'Host': 'localhost', 'Connection': 'keep-alive'}, @@ -272,6 +179,42 @@ class TestPythonProcman(TestApplicationPython): sock.close() + def test_python_processes_access(self): + self.conf_proc('1') + + path = '/' + self.app_proc + self.assertIn('error', self.conf_get(path + '/max')) + self.assertIn('error', self.conf_get(path + '/spare')) + self.assertIn('error', self.conf_get(path + '/idle_timeout')) + + def test_python_processes_invalid(self): + self.assertIn( + 'error', self.conf({"spare": -1}, self.app_proc), 'negative spare', + ) + self.assertIn( + 'error', self.conf({"max": -1}, self.app_proc), 'negative max', + ) + self.assertIn( + 'error', + self.conf({"idle_timeout": -1}, self.app_proc,), + 'negative idle_timeout', + ) + self.assertIn( + 'error', + self.conf({"spare": 2}, self.app_proc), + 'spare gt max default', + ) + self.assertIn( + 'error', + self.conf({"spare": 2, "max": 1}, self.app_proc,), + 'spare gt max', + ) + self.assertIn( + 'error', + self.conf({"spare": 0, "max": 0}, self.app_proc,), + 'max zero', + ) + def stop_all(self): self.conf({"listeners": {}, "applications": {}}) -- cgit From c7cc247baa2f9b6cd2499416644adf0bd13ff070 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Mon, 23 Mar 2020 02:12:44 +0000 Subject: Tests: terminate unitd process on exit(). --- test/unit/main.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'test') diff --git a/test/unit/main.py b/test/unit/main.py index 69234dcc..a1182e5c 100644 --- a/test/unit/main.py +++ b/test/unit/main.py @@ -4,6 +4,7 @@ import sys import stat import time import fcntl +import atexit import shutil import signal import argparse @@ -188,10 +189,9 @@ class TestUnit(unittest.TestCase): self._print_log() def stop(self): - if self._started: - self._stop() - + self._stop() self.stop_processes() + atexit.unregister(self.stop) def _run(self): build_dir = self.pardir + '/build' @@ -224,11 +224,11 @@ class TestUnit(unittest.TestCase): stderr=log, ) + atexit.register(self.stop) + if not self.waitforfiles(self.testdir + '/control.unit.sock'): exit("Could not start unit") - self._started = True - self.skip_alerts = [ r'read signalfd\(4\) failed', r'last message send failed', @@ -238,6 +238,9 @@ class TestUnit(unittest.TestCase): self.skip_sanitizer = False def _stop(self): + if self._p.poll() is not None: + return + with self._p as p: p.send_signal(signal.SIGQUIT) @@ -248,10 +251,8 @@ class TestUnit(unittest.TestCase): "Child process terminated with code " + str(retcode) ) except: - self.fail("Could not terminate unit") p.kill() - - self._started = False + self.fail("Could not terminate unit") def _check_alerts(self, log): found = False @@ -295,11 +296,12 @@ class TestUnit(unittest.TestCase): return for process in self._processes: - process.terminate() - process.join(timeout=5) - if process.is_alive(): - self.fail('Fail to stop process') + process.terminate() + process.join(timeout=15) + + if process.is_alive(): + self.fail('Fail to stop process') def waitforfiles(self, *files): for i in range(50): -- cgit From 3fd4b4cfab9541437d07048f3973368e568fe98f Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Mon, 23 Mar 2020 02:13:46 +0000 Subject: Tests: rearranging functions in main.py. --- test/unit/main.py | 138 +++++++++++++++++++++++++++--------------------------- 1 file changed, 69 insertions(+), 69 deletions(-) (limited to 'test') diff --git a/test/unit/main.py b/test/unit/main.py index a1182e5c..cdab486f 100644 --- a/test/unit/main.py +++ b/test/unit/main.py @@ -152,47 +152,6 @@ class TestUnit(unittest.TestCase): def setUp(self): self._run() - def tearDown(self): - self.stop() - - # detect errors and failures for current test - - def list2reason(exc_list): - if exc_list and exc_list[-1][0] is self: - return exc_list[-1][1] - - if hasattr(self, '_outcome'): - result = self.defaultTestResult() - self._feedErrorsToResult(result, self._outcome.errors) - else: - result = getattr( - self, '_outcomeForDoCleanups', self._resultForDoCleanups - ) - - success = not list2reason(result.errors) and not list2reason( - result.failures - ) - - # check unit.log for alerts - - unit_log = self.testdir + '/unit.log' - - with open(unit_log, 'r', encoding='utf-8', errors='ignore') as f: - self._check_alerts(f.read()) - - # remove unit.log - - if not TestUnit.save_log and success: - shutil.rmtree(self.testdir) - - else: - self._print_log() - - def stop(self): - self._stop() - self.stop_processes() - atexit.unregister(self.stop) - def _run(self): build_dir = self.pardir + '/build' self.unitd = build_dir + '/unitd' @@ -237,6 +196,47 @@ class TestUnit(unittest.TestCase): ] self.skip_sanitizer = False + def tearDown(self): + self.stop() + + # detect errors and failures for current test + + def list2reason(exc_list): + if exc_list and exc_list[-1][0] is self: + return exc_list[-1][1] + + if hasattr(self, '_outcome'): + result = self.defaultTestResult() + self._feedErrorsToResult(result, self._outcome.errors) + else: + result = getattr( + self, '_outcomeForDoCleanups', self._resultForDoCleanups + ) + + success = not list2reason(result.errors) and not list2reason( + result.failures + ) + + # check unit.log for alerts + + unit_log = self.testdir + '/unit.log' + + with open(unit_log, 'r', encoding='utf-8', errors='ignore') as f: + self._check_alerts(f.read()) + + # remove unit.log + + if not TestUnit.save_log and success: + shutil.rmtree(self.testdir) + + else: + self._print_log() + + def stop(self): + self._stop() + self.stop_processes() + atexit.unregister(self.stop) + def _stop(self): if self._p.poll() is not None: return @@ -254,34 +254,6 @@ class TestUnit(unittest.TestCase): p.kill() self.fail("Could not terminate unit") - def _check_alerts(self, log): - found = False - - alerts = re.findall('.+\[alert\].+', log) - - if alerts: - print('All alerts/sanitizer errors found in log:') - [print(alert) for alert in alerts] - found = True - - if self.skip_alerts: - for skip in self.skip_alerts: - alerts = [al for al in alerts if re.search(skip, al) is None] - - if alerts: - self._print_log(log) - self.assertFalse(alerts, 'alert(s)') - - if not self.skip_sanitizer: - sanitizer_errors = re.findall('.+Sanitizer.+', log) - - if sanitizer_errors: - self._print_log(log) - self.assertFalse(sanitizer_errors, 'sanitizer error(s)') - - if found: - print('skipped.') - def run_process(self, target, *args): if not hasattr(self, '_processes'): self._processes = [] @@ -331,6 +303,34 @@ class TestUnit(unittest.TestCase): for f in files: os.chmod(os.path.join(root, f), 0o777) + def _check_alerts(self, log): + found = False + + alerts = re.findall('.+\[alert\].+', log) + + if alerts: + print('All alerts/sanitizer errors found in log:') + [print(alert) for alert in alerts] + found = True + + if self.skip_alerts: + for skip in self.skip_alerts: + alerts = [al for al in alerts if re.search(skip, al) is None] + + if alerts: + self._print_log(log) + self.assertFalse(alerts, 'alert(s)') + + if not self.skip_sanitizer: + sanitizer_errors = re.findall('.+Sanitizer.+', log) + + if sanitizer_errors: + self._print_log(log) + self.assertFalse(sanitizer_errors, 'sanitizer error(s)') + + if found: + print('skipped.') + @staticmethod def _parse_args(): parser = argparse.ArgumentParser(add_help=False) -- cgit From b0161df42e9a20c69c912f67176c226ae9172b21 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Mon, 23 Mar 2020 19:09:29 +0000 Subject: Tests: wait for unit.pid file before running tests. Waiting for control.unit.sock was replaced by unit.pid due to current problem with race between connect() and listen() calls for control.unit.sock. This change should be reverted after fix. --- test/unit/main.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/unit/main.py b/test/unit/main.py index cdab486f..3d95a5b1 100644 --- a/test/unit/main.py +++ b/test/unit/main.py @@ -185,7 +185,10 @@ class TestUnit(unittest.TestCase): atexit.register(self.stop) - if not self.waitforfiles(self.testdir + '/control.unit.sock'): + # Due to race between connect() and listen() after the socket binding + # tests waits for unit.pid file which is created after listen(). + + if not self.waitforfiles(self.testdir + '/unit.pid'): exit("Could not start unit") self.skip_alerts = [ -- cgit From ac9ca6d75cf8987b6650923aa126c0d3ab06f41e Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Mon, 23 Mar 2020 19:12:22 +0000 Subject: Tests: added notification on unsuccessful connect(). --- test/unit/http.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/unit/http.py b/test/unit/http.py index 47fb48f1..281b27d6 100644 --- a/test/unit/http.py +++ b/test/unit/http.py @@ -60,7 +60,7 @@ class TestHTTP(TestUnit): sock.connect(connect_args) except ConnectionRefusedError: sock.close() - return None + self.fail('Client can\'t connect to the server.') else: sock = kwargs['sock'] -- cgit From 48ad88ee7209fd949f3ed1075f62ca78c2220224 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Mon, 23 Mar 2020 19:18:26 +0000 Subject: Tests: increase default "read_timeout" value to 60s. This change is necessary to avoid errors on slow hosts. Also slightly reworked argument passing to the recvall() function. --- test/unit/applications/websockets.py | 4 ++-- test/unit/http.py | 27 ++++++++++++++------------- 2 files changed, 16 insertions(+), 15 deletions(-) (limited to 'test') diff --git a/test/unit/applications/websockets.py b/test/unit/applications/websockets.py index ef16f433..eaed2ee7 100644 --- a/test/unit/applications/websockets.py +++ b/test/unit/applications/websockets.py @@ -52,7 +52,7 @@ class TestApplicationWebsocket(TestApplicationProto): ) resp = '' - while select.select([sock], [], [], 30)[0]: + while select.select([sock], [], [], 60)[0]: resp += sock.recv(4096).decode() if ( @@ -70,7 +70,7 @@ class TestApplicationWebsocket(TestApplicationProto): def serialize_close(self, code=1000, reason=''): return struct.pack('!H', code) + reason.encode('utf-8') - def frame_read(self, sock, read_timeout=30): + def frame_read(self, sock, read_timeout=60): def recv_bytes(sock, bytes): data = b'' while select.select([sock], [], [], read_timeout)[0]: diff --git a/test/unit/http.py b/test/unit/http.py index 281b27d6..8c71825a 100644 --- a/test/unit/http.py +++ b/test/unit/http.py @@ -17,11 +17,6 @@ class TestHTTP(TestUnit): port = 7080 if 'port' not in kwargs else kwargs['port'] url = '/' if 'url' not in kwargs else kwargs['url'] http = 'HTTP/1.0' if 'http_10' in kwargs else 'HTTP/1.1' - read_buffer_size = ( - 4096 - if 'read_buffer_size' not in kwargs - else kwargs['read_buffer_size'] - ) headers = ( {'Host': 'localhost', 'Connection': 'close'} @@ -101,12 +96,15 @@ class TestHTTP(TestUnit): resp = '' if 'no_recv' not in kwargs: - read_timeout = ( - 30 if 'read_timeout' not in kwargs else kwargs['read_timeout'] - ) - resp = self.recvall( - sock, read_timeout=read_timeout, buff_size=read_buffer_size - ).decode(encoding) + recvall_kwargs = {} + + if 'read_timeout' in kwargs: + recvall_kwargs['read_timeout'] = kwargs['read_timeout'] + + if 'read_buffer_size' in kwargs: + recvall_kwargs['buff_size'] = kwargs['read_buffer_size'] + + resp = self.recvall(sock, **recvall_kwargs).decode(encoding) self.log_in(resp) @@ -174,9 +172,12 @@ class TestHTTP(TestUnit): def put(self, **kwargs): return self.http('PUT', **kwargs) - def recvall(self, sock, read_timeout=30, buff_size=4096): + def recvall(self, sock, **kwargs): + timeout = 60 if 'read_timeout' not in kwargs else kwargs['read_timeout'] + buff_size = 4096 if 'buff_size' not in kwargs else kwargs['buff_size'] + data = b'' - while select.select([sock], [], [], read_timeout)[0]: + while select.select([sock], [], [], timeout)[0]: try: part = sock.recv(buff_size) except: -- cgit From 2e4ad9fbc07a2ed408c017df93e5116d97a221e9 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Wed, 25 Mar 2020 19:31:42 +0000 Subject: Tests: UTF-8 BOM test. --- test/test_configuration.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'test') diff --git a/test/test_configuration.py b/test/test_configuration.py index 186e037d..2acb7ccd 100644 --- a/test/test_configuration.py +++ b/test/test_configuration.py @@ -83,6 +83,25 @@ class TestConfiguration(TestControl): 'unicode number', ) + def test_json_utf8_bom(self): + self.assertIn( + 'success', + self.conf( + b"""\xEF\xBB\xBF + { + "app": { + "type": "python", + "processes": {"spare": 0}, + "path": "/app", + "module": "wsgi" + } + } + """, + 'applications', + ), + 'UTF-8 BOM', + ) + def test_applications_open_brace(self): self.assertIn('error', self.conf('{', 'applications'), 'open brace') -- cgit From 8532cf6ae6e9ed7d03dd7e06e36eee63fd9d6ceb Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Wed, 25 Mar 2020 19:40:08 +0000 Subject: Tests: added tests for comments in JSON. --- test/test_configuration.py | 61 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'test') diff --git a/test/test_configuration.py b/test/test_configuration.py index 2acb7ccd..daba874b 100644 --- a/test/test_configuration.py +++ b/test/test_configuration.py @@ -102,6 +102,67 @@ class TestConfiguration(TestControl): 'UTF-8 BOM', ) + def test_json_comment_single_line(self): + self.assertIn( + 'success', + self.conf( + b""" + // this is bridge + { + "//app": { + "type": "python", // end line + "processes": {"spare": 0}, + // inside of block + "path": "/app", + "module": "wsgi" + } + // double // + } + // end of json \xEF\t + """, + 'applications', + ), + 'single line comments', + ) + + def test_json_comment_multi_line(self): + self.assertIn( + 'success', + 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 */ + } + /* end of json \xEF\t\b */ + """, + 'applications', + ), + 'multi line comments', + ) + + def test_json_comment_invalid(self): + self.assertIn('error', self.conf(b'/{}', 'applications'), 'slash') + self.assertIn('error', self.conf(b'//{}', 'applications'), 'comment') + self.assertIn('error', self.conf(b'{} /', 'applications'), 'slash end') + self.assertIn( + 'error', self.conf(b'/*{}', 'applications'), 'slash star' + ) + self.assertIn( + 'error', self.conf(b'{} /*', 'applications'), 'slash star end' + ) + def test_applications_open_brace(self): self.assertIn('error', self.conf('{', 'applications'), 'open brace') -- cgit From 5f2d07019c44855deabfc3f0a83ab7506f0d0183 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Fri, 27 Mar 2020 15:48:39 +0000 Subject: Tests: increase default "read_timeout" to 60s in message_read(). --- test/unit/applications/websockets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/unit/applications/websockets.py b/test/unit/applications/websockets.py index eaed2ee7..309d37a3 100644 --- a/test/unit/applications/websockets.py +++ b/test/unit/applications/websockets.py @@ -221,7 +221,7 @@ class TestApplicationWebsocket(TestApplicationProto): op_code = self.OP_CONT pos = end - def message_read(self, sock, read_timeout=10): + def message_read(self, sock, read_timeout=60): frame = self.frame_read(sock, read_timeout=read_timeout) while not frame['fin']: -- cgit From 6e5b5d2a0b97f6e981fef749a267103e21898a72 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Fri, 27 Mar 2020 15:50:09 +0000 Subject: Tests: added tests for "return" action. --- test/test_return.py | 103 ++++++++++++++++++++++++++ test/test_routing.py | 161 +++++++---------------------------------- test/test_routing_tls.py | 26 ++----- test/test_share_fallback.py | 171 +++++++++++++++----------------------------- 4 files changed, 191 insertions(+), 270 deletions(-) create mode 100644 test/test_return.py (limited to 'test') diff --git a/test/test_return.py b/test/test_return.py new file mode 100644 index 00000000..f973f05b --- /dev/null +++ b/test/test_return.py @@ -0,0 +1,103 @@ +import re +import unittest +from unit.applications.proto import TestApplicationProto + + +class TestReturn(TestApplicationProto): + prerequisites = {} + + def setUp(self): + super().setUp() + + self._load_conf( + { + "listeners": {"*:7080": {"pass": "routes"}}, + "routes": [{"action": {"return": 200}}], + "applications": {}, + } + ) + + def get_resps_sc(self, req=10): + to_send = b"""GET / HTTP/1.1 +Host: localhost + +""" * ( + req - 1 + ) + + to_send += b"""GET / HTTP/1.1 +Host: localhost +Connection: close + +""" + + return self.http(to_send, raw_resp=True, raw=True) + + def test_return(self): + resp = self.get() + self.assertEqual(resp['status'], 200) + self.assertIn('Server', resp['headers']) + self.assertIn('Date', resp['headers']) + self.assertEqual(resp['headers']['Content-Length'], '0') + self.assertEqual(resp['headers']['Connection'], 'close') + self.assertEqual(resp['body'], '', 'body') + + resp = self.post(body='blah') + self.assertEqual(resp['status'], 200) + self.assertEqual(resp['body'], '', 'body') + + resp = self.get_resps_sc() + self.assertEqual(len(re.findall('200 OK', resp)), 10) + self.assertEqual(len(re.findall('Connection:', resp)), 1) + self.assertEqual(len(re.findall('Connection: close', resp)), 1) + + resp = self.get(http_10=True) + self.assertEqual(resp['status'], 200) + self.assertIn('Server', resp['headers']) + self.assertIn('Date', resp['headers']) + self.assertEqual(resp['headers']['Content-Length'], '0') + self.assertNotIn('Connection', resp['headers']) + self.assertEqual(resp['body'], '', 'body') + + def test_return_update(self): + self.assertIn('success', self.conf('0', 'routes/0/action/return')) + + resp = self.get() + self.assertEqual(resp['status'], 0) + self.assertEqual(resp['body'], '') + + self.assertIn('success', self.conf('404', 'routes/0/action/return')) + + resp = self.get() + self.assertEqual(resp['status'], 404) + self.assertNotEqual(resp['body'], '') + + self.assertIn('success', self.conf('598', 'routes/0/action/return')) + + resp = self.get() + self.assertEqual(resp['status'], 598) + self.assertNotEqual(resp['body'], '') + + self.assertIn('success', self.conf('999', 'routes/0/action/return')) + + resp = self.get() + self.assertEqual(resp['status'], 999) + self.assertEqual(resp['body'], '') + + def test_return_invalid(self): + def check_error(conf): + self.assertIn('error', self.conf(conf, 'routes/0/action')) + + check_error({"return": "200"}) + check_error({"return": []}) + check_error({"return": 80.}) + check_error({"return": 1000}) + check_error({"return": 200, "share": "/blah"}) + + self.assertIn( + 'error', self.conf('001', 'routes/0/action/return'), 'leading zero' + ) + + +if __name__ == '__main__': + TestReturn.main() diff --git a/test/test_routing.py b/test/test_routing.py index 950923d6..bf741706 100644 --- a/test/test_routing.py +++ b/test/test_routing.py @@ -16,27 +16,10 @@ class TestRouting(TestApplicationProto): "routes": [ { "match": {"method": "GET"}, - "action": {"pass": "applications/empty"}, + "action": {"return": 200}, } ], - "applications": { - "empty": { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir + '/python/empty', - "working_directory": self.current_dir - + '/python/empty', - "module": "wsgi", - }, - "mirror": { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir + '/python/mirror', - "working_directory": self.current_dir - + '/python/mirror', - "module": "wsgi", - }, - }, + "applications": {}, } ), 'routing configure', @@ -48,18 +31,14 @@ class TestRouting(TestApplicationProto): def route_match(self, match): self.assertIn( 'success', - self.route( - {"match": match, "action": {"pass": "applications/empty"}} - ), + self.route({"match": match, "action": {"return": 200}}), 'route match configure', ) def route_match_invalid(self, match): self.assertIn( 'error', - self.route( - {"match": match, "action": {"pass": "applications/empty"}} - ), + self.route({"match": match, "action": {"return": 200}}), 'route match configure invalid', ) @@ -233,24 +212,7 @@ class TestRouting(TestApplicationProto): { "listeners": {"*:7080": {"pass": "routes/main"}}, "routes": {"main": []}, - "applications": { - "empty": { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir + '/python/empty', - "working_directory": self.current_dir - + '/python/empty', - "module": "wsgi", - }, - "mirror": { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir + '/python/mirror', - "working_directory": self.current_dir - + '/python/mirror', - "module": "wsgi", - }, - }, + "applications": {}, } ), 'route empty configure', @@ -272,7 +234,7 @@ class TestRouting(TestApplicationProto): def test_routes_route_match_absent(self): self.assertIn( 'success', - self.conf([{"action": {"pass": "applications/empty"}}], 'routes'), + self.conf([{"action": {"return": 200}}], 'routes'), 'route match absent configure', ) @@ -349,14 +311,8 @@ class TestRouting(TestApplicationProto): 'success', self.conf( [ - { - "match": {"method": "GET"}, - "action": {"pass": "applications/empty"}, - }, - { - "match": {"method": "POST"}, - "action": {"pass": "applications/mirror"}, - }, + {"match": {"method": "GET"}, "action": {"return": 200}}, + {"match": {"method": "POST"}, "action": {"return": 201}}, ], 'routes', ), @@ -364,18 +320,7 @@ class TestRouting(TestApplicationProto): ) self.assertEqual(self.get()['status'], 200, 'rules two match first') - self.assertEqual( - self.post( - headers={ - 'Host': 'localhost', - 'Content-Type': 'text/html', - 'Connection': 'close', - }, - body='X', - )['status'], - 200, - 'rules two match second', - ) + self.assertEqual(self.post()['status'], 201, 'rules two match second') def test_routes_two(self): self.assertIn( @@ -393,20 +338,11 @@ class TestRouting(TestApplicationProto): "second": [ { "match": {"host": "localhost"}, - "action": {"pass": "applications/empty"}, + "action": {"return": 200}, } ], }, - "applications": { - "empty": { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir + '/python/empty', - "working_directory": self.current_dir - + '/python/empty', - "module": "wsgi", - } - }, + "applications": {}, } ), 'routes two configure', @@ -556,7 +492,7 @@ class TestRouting(TestApplicationProto): self.assertIn( 'success', - self.conf([{"action": {"pass": "applications/empty"}}], 'routes'), + self.conf([{"action": {"return": 200}}], 'routes'), 'redefine 2', ) self.assertEqual(self.get()['status'], 200, 'redefine request 2') @@ -569,19 +505,8 @@ class TestRouting(TestApplicationProto): self.conf( { "listeners": {"*:7080": {"pass": "routes/main"}}, - "routes": { - "main": [{"action": {"pass": "applications/empty"}}] - }, - "applications": { - "empty": { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir + '/python/empty', - "working_directory": self.current_dir - + '/python/empty', - "module": "wsgi", - } - }, + "routes": {"main": [{"action": {"return": 200}}]}, + "applications": {}, } ), 'redefine 4', @@ -595,25 +520,19 @@ class TestRouting(TestApplicationProto): self.assertIn( 'success', - self.conf_post( - {"action": {"pass": "applications/empty"}}, 'routes/main' - ), + self.conf_post({"action": {"return": 200}}, 'routes/main'), 'redefine 6', ) self.assertEqual(self.get()['status'], 200, 'redefine request 6') self.assertIn( 'error', - self.conf( - {"action": {"pass": "applications/empty"}}, 'routes/main/2' - ), + self.conf({"action": {"return": 200}}, 'routes/main/2'), 'redefine 7', ) self.assertIn( 'success', - self.conf( - {"action": {"pass": "applications/empty"}}, 'routes/main/1' - ), + self.conf({"action": {"return": 201}}, 'routes/main/1'), 'redefine 8', ) @@ -631,10 +550,7 @@ class TestRouting(TestApplicationProto): self.assertIn( 'success', self.conf_post( - { - "match": {"method": "POST"}, - "action": {"pass": "applications/empty"}, - }, + {"match": {"method": "POST"}, "action": {"return": 200}}, 'routes', ), 'routes edit configure 2', @@ -654,9 +570,7 @@ class TestRouting(TestApplicationProto): self.assertEqual(self.post()['status'], 200, 'routes edit POST 2') self.assertIn( - 'success', - self.conf_delete('routes/0'), - 'routes edit configure 3', + 'success', self.conf_delete('routes/0'), 'routes edit configure 3', ) self.assertEqual(self.get()['status'], 404, 'routes edit GET 3') @@ -682,9 +596,7 @@ class TestRouting(TestApplicationProto): self.assertEqual(self.post()['status'], 200, 'routes edit POST 4') self.assertIn( - 'success', - self.conf_delete('routes/0'), - 'routes edit configure 5', + 'success', self.conf_delete('routes/0'), 'routes edit configure 5', ) self.assertEqual(self.get()['status'], 404, 'routes edit GET 5') @@ -693,10 +605,7 @@ class TestRouting(TestApplicationProto): self.assertIn( 'success', self.conf_post( - { - "match": {"method": "POST"}, - "action": {"pass": "applications/empty"}, - }, + {"match": {"method": "POST"}, "action": {"return": 200},}, 'routes', ), 'routes edit configure 6', @@ -710,19 +619,8 @@ class TestRouting(TestApplicationProto): self.conf( { "listeners": {"*:7080": {"pass": "routes/main"}}, - "routes": { - "main": [{"action": {"pass": "applications/empty"}}] - }, - "applications": { - "empty": { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir + '/python/empty', - "working_directory": self.current_dir - + '/python/empty', - "module": "wsgi", - } - }, + "routes": {"main": [{"action": {"return": 200}}]}, + "applications": {}, } ), 'route edit configure 7', @@ -1838,20 +1736,11 @@ class TestRouting(TestApplicationProto): "second": [ { "match": {"destination": ["127.0.0.1:7081"]}, - "action": {"pass": "applications/empty"}, + "action": {"return": 200}, } ], }, - "applications": { - "empty": { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir + "/python/empty", - "working_directory": self.current_dir - + "/python/empty", - "module": "wsgi", - } - }, + "applications": {}, } ), 'proxy configure', diff --git a/test/test_routing_tls.py b/test/test_routing_tls.py index c6648095..36bd9057 100644 --- a/test/test_routing_tls.py +++ b/test/test_routing_tls.py @@ -2,9 +2,9 @@ from unit.applications.tls import TestApplicationTLS class TestRoutingTLS(TestApplicationTLS): - prerequisites = {'modules': ['python', 'openssl']} + prerequisites = {'modules': ['openssl']} - def test_routes_match_scheme(self): + def test_routes_match_scheme_tls(self): self.certificate() self.assertIn( @@ -21,35 +21,21 @@ class TestRoutingTLS(TestApplicationTLS): "routes": [ { "match": {"scheme": "http"}, - "action": {"pass": "applications/empty"}, + "action": {"return": 200}, }, { "match": {"scheme": "https"}, - "action": {"pass": "applications/204_no_content"}, + "action": {"return": 201}, }, ], - "applications": { - "empty": { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir + "/python/empty", - "module": "wsgi", - }, - "204_no_content": { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir - + "/python/204_no_content", - "module": "wsgi", - }, - }, + "applications": {}, } ), 'scheme configure', ) self.assertEqual(self.get()['status'], 200, 'http') - self.assertEqual(self.get_ssl(port=7081)['status'], 204, 'https') + self.assertEqual(self.get_ssl(port=7081)['status'], 201, 'https') if __name__ == '__main__': diff --git a/test/test_share_fallback.py b/test/test_share_fallback.py index 1a5d4e4b..c51e43ee 100644 --- a/test/test_share_fallback.py +++ b/test/test_share_fallback.py @@ -1,10 +1,10 @@ import os import unittest -from unit.applications.lang.python import TestApplicationPython +from unit.applications.proto import TestApplicationProto -class TestStatic(TestApplicationPython): - prerequisites = {'modules': ['python']} +class TestStatic(TestApplicationProto): + prerequisites = {} def setUp(self): super().setUp() @@ -20,19 +20,10 @@ class TestStatic(TestApplicationPython): { "listeners": { "*:7080": {"pass": "routes"}, - "*:7081": {"pass": "applications/empty"}, + "*:7081": {"pass": "routes"}, }, "routes": [{"action": {"share": self.testdir + "/assets"}}], - "applications": { - "empty": { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir + "/python/empty", - "working_directory": self.current_dir - + "/python/empty", - "module": "wsgi", - } - }, + "applications": {}, } ) @@ -41,37 +32,22 @@ class TestStatic(TestApplicationPython): super().tearDown() + def action_update(self, conf): + self.assertIn('success', self.conf(conf, 'routes/0/action')) + def test_fallback(self): - self.assertIn( - 'success', - self.conf({"share": "/blah"}, 'routes/0/action'), - 'configure bad path no fallback', - ) + self.action_update({"share": "/blah"}) self.assertEqual(self.get()['status'], 404, 'bad path no fallback') - self.assertIn( - 'success', - self.conf( - {"share": "/blah", "fallback": {"pass": "applications/empty"}}, - 'routes/0/action', - ), - 'configure bad path fallback', - ) + self.action_update({"share": "/blah", "fallback": {"return": 200}}) + resp = self.get() self.assertEqual(resp['status'], 200, 'bad path fallback status') self.assertEqual(resp['body'], '', 'bad path fallback') def test_fallback_valid_path(self): - self.assertIn( - 'success', - self.conf( - { - "share": self.testdir + "/assets", - "fallback": {"pass": "applications/empty"}, - }, - 'routes/0/action', - ), - 'configure fallback', + self.action_update( + {"share": self.testdir + "/assets", "fallback": {"return": 200}} ) resp = self.get() self.assertEqual(resp['status'], 200, 'fallback status') @@ -90,36 +66,28 @@ class TestStatic(TestApplicationPython): ) def test_fallback_nested(self): - self.assertIn( - 'success', - self.conf( - { - "share": "/blah", - "fallback": { - "share": "/blah/blah", - "fallback": {"pass": "applications/empty"}, - }, + self.action_update( + { + "share": "/blah", + "fallback": { + "share": "/blah/blah", + "fallback": {"return": 200}, }, - 'routes/0/action', - ), - 'configure fallback nested', + } ) + resp = self.get() self.assertEqual(resp['status'], 200, 'fallback nested status') self.assertEqual(resp['body'], '', 'fallback nested') def test_fallback_share(self): - self.assertIn( - 'success', - self.conf( - { - "share": "/blah", - "fallback": {"share": self.testdir + "/assets"}, - }, - 'routes/0/action', - ), - 'configure fallback share', + self.action_update( + { + "share": "/blah", + "fallback": {"share": self.testdir + "/assets"}, + } ) + resp = self.get() self.assertEqual(resp['status'], 200, 'fallback share status') self.assertEqual(resp['body'], '0123456789', 'fallback share') @@ -136,76 +104,51 @@ class TestStatic(TestApplicationPython): self.assertIn( 'success', self.conf( - { - "share": "/blah", - "fallback": {"proxy": "http://127.0.0.1:7081"}, - }, - 'routes/0/action', + [ + { + "match": {"destination": "*:7081"}, + "action": {"return": 200}, + }, + { + "action": { + "share": "/blah", + "fallback": {"proxy": "http://127.0.0.1:7081"}, + } + }, + ], + 'routes', ), - 'configure fallback proxy', + 'configure fallback proxy route', ) + resp = self.get() self.assertEqual(resp['status'], 200, 'fallback proxy status') self.assertEqual(resp['body'], '', 'fallback proxy') @unittest.skip('not yet') def test_fallback_proxy_cycle(self): - self.assertIn( - 'success', - self.conf( - { - "share": "/blah", - "fallback": {"proxy": "http://127.0.0.1:7080"}, - }, - 'routes/0/action', - ), - 'configure fallback cycle', + self.action_update( + { + "share": "/blah", + "fallback": {"proxy": "http://127.0.0.1:7080"}, + } ) self.assertNotEqual(self.get()['status'], 200, 'fallback cycle') - self.assertIn( - 'success', self.conf_delete('listeners/*:7081'), 'delete listener' - ) + self.assertIn('success', self.conf_delete('listeners/*:7081')) self.assertNotEqual(self.get()['status'], 200, 'fallback cycle 2') def test_fallback_invalid(self): - self.assertIn( - 'error', - self.conf({"share": "/blah", "fallback": {}}, 'routes/0/action'), - 'configure fallback empty', - ) - self.assertIn( - 'error', - self.conf({"share": "/blah", "fallback": ""}, 'routes/0/action'), - 'configure fallback not object', - ) - self.assertIn( - 'error', - self.conf( - { - "proxy": "http://127.0.0.1:7081", - "fallback": {"share": "/blah"}, - }, - 'routes/0/action', - ), - 'configure fallback proxy invalid', - ) - self.assertIn( - 'error', - self.conf( - { - "pass": "applications/empty", - "fallback": {"share": "/blah"}, - }, - 'routes/0/action', - ), - 'configure fallback pass invalid', - ) - self.assertIn( - 'error', - self.conf({"fallback": {"share": "/blah"}}, 'routes/0/action'), - 'configure fallback only', + def check_error(conf): + self.assertIn('error', self.conf(conf, 'routes/0/action')) + + check_error({"share": "/blah", "fallback": {}}) + check_error({"share": "/blah", "fallback": ""}) + check_error({"return": 200, "fallback": {"share": "/blah"}}) + check_error( + {"proxy": "http://127.0.0.1:7081", "fallback": {"share": "/blah"}} ) + check_error({"fallback": {"share": "/blah"}}) if __name__ == '__main__': -- cgit From f94e31b294d69df40b59970ef4c721324cd3596e Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Fri, 27 Mar 2020 17:29:45 +0000 Subject: Tests: added tests for "location" option. --- test/test_return.py | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) (limited to 'test') diff --git a/test/test_return.py b/test/test_return.py index f973f05b..e3edb700 100644 --- a/test/test_return.py +++ b/test/test_return.py @@ -84,6 +84,97 @@ Connection: close self.assertEqual(resp['status'], 999) self.assertEqual(resp['body'], '') + def test_return_location(self): + reserved = ":/?#[]@!$&'()*+,;=" + unreserved = ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789-._~") + unsafe = " \"%<>\\^`{|}" + unsafe_enc = "%20%22%25%3C%3E%5C%5E%60%7B%7C%7D" + + def check_location(location, expect=None): + if expect is None: + expect = location + + self.assertIn( + 'success', + self.conf( + {"return": 301, "location": location}, 'routes/0/action' + ), + 'configure location' + ) + + self.assertEqual(self.get()['headers']['Location'], expect) + + # FAIL: can't specify empty header value. + # check_location("") + + check_location(reserved) + + # After first "?" all other "?" encoded. + check_location("/?" + reserved, "/?:/%3F#[]@!$&'()*+,;=") + check_location("???", "?%3F%3F") + + # After first "#" all other "?" or "#" encoded. + check_location("/#" + reserved, "/#:/%3F%23[]@!$&'()*+,;=") + check_location("##?#?", "#%23%3F%23%3F") + + # After first "?" next "#" not encoded. + check_location("/?#" + reserved, "/?#:/%3F%23[]@!$&'()*+,;=") + check_location("??##", "?%3F#%23") + check_location("/?##?", "/?#%23%3F") + + # Unreserved never encoded. + check_location(unreserved) + check_location("/" + unreserved + "?" + unreserved + "#" + unreserved) + + # Unsafe always encoded. + check_location(unsafe, unsafe_enc) + check_location("?" + unsafe, "?" + unsafe_enc) + check_location("#" + unsafe, "#" + unsafe_enc) + + # %00-%20 and %7F-%FF always encoded. + check_location(u"\u0000\u0018\u001F\u0020\u0021", "%00%18%1F%20!") + check_location(u"\u007F\u0080н\u20BD", "%7F%C2%80%D0%BD%E2%82%BD") + + # Encoded string detection. If at least one char need to be encoded + # then whole string will be encoded. + check_location("%20") + check_location("/%20?%20#%20") + check_location(" %20", "%20%2520") + check_location("%20 ", "%2520%20") + check_location("/%20?%20#%20 ", "/%2520?%2520#%2520%20") + + def test_return_location_edit(self): + self.assertIn( + 'success', + self.conf( + {"return": 302, "location": "blah"}, 'routes/0/action' + ), + 'configure init location' + ) + self.assertEqual(self.get()['headers']['Location'], 'blah') + + self.assertIn( + 'success', + self.conf_delete('routes/0/action/location'), + 'location delete' + ) + self.assertNotIn('Location', self.get()['headers']) + + self.assertIn( + 'success', + self.conf('"blah"', 'routes/0/action/location'), + 'location restore' + ) + self.assertEqual(self.get()['headers']['Location'], 'blah') + + self.assertIn( + 'error', + self.conf_post('"blah"', 'routes/0/action/location'), + 'location method not allowed' + ) + self.assertEqual(self.get()['headers']['Location'], 'blah') + def test_return_invalid(self): def check_error(conf): self.assertIn('error', self.conf(conf, 'routes/0/action')) @@ -98,6 +189,9 @@ Connection: close 'error', self.conf('001', 'routes/0/action/return'), 'leading zero' ) + check_error({"return": 301, "location": 0}) + check_error({"return": 301, "location": []}) + if __name__ == '__main__': TestReturn.main() -- cgit From ab7b42a072e741b226749c416440f89fcaff3d2c Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Mon, 30 Mar 2020 14:18:41 +0300 Subject: Handling change file message in libunit. This is required for proper log file rotation action. --- test/python/log_body/wsgi.py | 2 +- test/test_usr1.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'test') diff --git a/test/python/log_body/wsgi.py b/test/python/log_body/wsgi.py index 9dcb1b0c..0ec07a68 100644 --- a/test/python/log_body/wsgi.py +++ b/test/python/log_body/wsgi.py @@ -2,7 +2,7 @@ def application(environ, start_response): content_length = int(environ.get('CONTENT_LENGTH', 0)) body = bytes(environ['wsgi.input'].read(content_length)) - environ['wsgi.errors'].write(body) + environ['wsgi.errors'].write(body.decode()) environ['wsgi.errors'].flush() start_response('200', [('Content-Length', '0')]) diff --git a/test/test_usr1.py b/test/test_usr1.py index 2b4f394b..204e2e0c 100644 --- a/test/test_usr1.py +++ b/test/test_usr1.py @@ -51,7 +51,6 @@ class TestUSR1(TestApplicationPython): self.search_in_log(r'/usr1', log_new), 'rename new 2' ) - @unittest.skip('not yet') def test_usr1_unit_log(self): self.load('log_body') -- cgit From 0935630cba069d6619e967404bb6c7c2a93fbe7e Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Mon, 30 Mar 2020 14:18:51 +0300 Subject: Fixing application process infinite loop. Main process exiting before app process init may have caused hanging. --- test/test_node_websockets.py | 2 +- test/unit/main.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'test') diff --git a/test/test_node_websockets.py b/test/test_node_websockets.py index bb189552..cb6bf137 100644 --- a/test/test_node_websockets.py +++ b/test/test_node_websockets.py @@ -22,7 +22,7 @@ class TestNodeWebsockets(TestApplicationNode): ) self.skip_alerts.extend( - [r'last message send failed', r'socket close\(\d+\) failed'] + [r'socket close\(\d+\) failed'] ) def close_connection(self, sock): diff --git a/test/unit/main.py b/test/unit/main.py index 3d95a5b1..49c1eed3 100644 --- a/test/unit/main.py +++ b/test/unit/main.py @@ -193,7 +193,6 @@ class TestUnit(unittest.TestCase): self.skip_alerts = [ r'read signalfd\(4\) failed', - r'last message send failed', r'sendmsg.+failed', r'recvmsg.+failed', ] -- cgit From 5954839773a5c2ab5391ea2d99062de23581eee6 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Mon, 30 Mar 2020 18:44:50 +0100 Subject: Tests: added tests for rational numbers in upstream server weight. --- test/test_return.py | 2 +- test/test_upstreams_rr.py | 108 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 98 insertions(+), 12 deletions(-) (limited to 'test') diff --git a/test/test_return.py b/test/test_return.py index e3edb700..bd65b9bb 100644 --- a/test/test_return.py +++ b/test/test_return.py @@ -181,7 +181,7 @@ Connection: close check_error({"return": "200"}) check_error({"return": []}) - check_error({"return": 80.}) + check_error({"return": 80.1}) check_error({"return": 1000}) check_error({"return": 200, "share": "/blah"}) diff --git a/test/test_upstreams_rr.py b/test/test_upstreams_rr.py index 2bc2d90a..8dc83487 100644 --- a/test/test_upstreams_rr.py +++ b/test/test_upstreams_rr.py @@ -193,6 +193,67 @@ Connection: close self.assertEqual(resps[0], 60, 'weight 2 0') self.assertEqual(resps[2], 40, 'weight 2 1') + def test_upstreams_rr_weight_rational(self): + def set_weights(w1, w2): + self.assertIn( + 'success', + self.conf( + { + "127.0.0.1:7081": {"weight": w1}, + "127.0.0.1:7082": {"weight": w2}, + }, + 'upstreams/one/servers', + ), + 'configure weights', + ) + + def check_reqs(w1, w2, reqs=10): + resps = self.get_resps_sc(req=reqs) + self.assertEqual(resps[0], reqs * w1 / (w1 + w2), 'weight 1') + self.assertEqual(resps[1], reqs * w2 / (w1 + w2), 'weight 2') + + def check_weights(w1, w2): + set_weights(w1, w2) + check_reqs(w1, w2) + + check_weights(0, 1) + check_weights(0, 999999.0123456) + check_weights(1, 9) + check_weights(100000, 900000) + check_weights(1, .25) + check_weights(1, 0.25) + check_weights(0.2, .8) + check_weights(1, 1.5) + check_weights(1e-3, 1E-3) + check_weights(1e-20, 1e-20) + check_weights(1e4, 1e4) + check_weights(1000000, 1000000) + + set_weights(0.25, 0.25) + self.assertIn( + 'success', + self.conf_delete('upstreams/one/servers/127.0.0.1:7081/weight'), + 'delete weight', + ) + check_reqs(1, 0.25) + + self.assertIn( + 'success', + self.conf( + { + "127.0.0.1:7081": {"weight": 0.1}, + "127.0.0.1:7082": {"weight": 1}, + "127.0.0.1:7083": {"weight": 0.9}, + }, + 'upstreams/one/servers', + ), + 'configure weights', + ) + resps = self.get_resps_sc(req=20) + self.assertEqual(resps[0], 1, 'weight 3 1') + self.assertEqual(resps[1], 10, 'weight 3 2') + self.assertEqual(resps[2], 9, 'weight 3 3') + def test_upstreams_rr_independent(self): def sum_resps(*args): sum = [0] * len(args[0]) @@ -429,9 +490,29 @@ Connection: close self.conf({}, 'upstreams/one/servers'), 'configure servers empty', ) - self.assertEqual(self.get()['status'], 502, 'servers empty') + self.assertIn( + 'success', + self.conf( + {"127.0.0.1:7081": {"weight": 0}}, 'upstreams/one/servers' + ), + 'configure servers empty one', + ) + self.assertEqual(self.get()['status'], 502, 'servers empty one') + self.assertIn( + 'success', + self.conf( + { + "127.0.0.1:7081": {"weight": 0}, + "127.0.0.1:7082": {"weight": 0}, + }, + 'upstreams/one/servers', + ), + 'configure servers empty two', + ) + self.assertEqual(self.get()['status'], 502, 'servers empty two') + def test_upstreams_rr_invalid(self): self.assertIn( 'error', self.conf({}, 'upstreams'), 'upstreams empty', @@ -449,16 +530,21 @@ Connection: close self.conf({}, 'upstreams/one/servers/127.0.0.1:7081/blah'), 'invalid server option', ) - self.assertIn( - 'error', - self.conf({}, 'upstreams/one/servers/127.0.0.1:7081/weight'), - 'invalid weight option', - ) - self.assertIn( - 'error', - self.conf('-1', 'upstreams/one/servers/127.0.0.1:7081/weight'), - 'invalid negative weight', - ) + + def check_weight(w): + self.assertIn( + 'error', + self.conf(w, 'upstreams/one/servers/127.0.0.1:7081/weight'), + 'invalid weight option', + ) + check_weight({}) + check_weight('-1') + check_weight('1.') + check_weight('1.1.') + check_weight('.') + check_weight('.01234567890123') + check_weight('1000001') + check_weight('2e6') if __name__ == '__main__': -- cgit From 2bb8b3d88a191d96c6693007ad79ae808f872941 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Fri, 3 Apr 2020 01:03:26 +0100 Subject: Tests: minor fixes. --- test/test_java_websockets.py | 2 +- test/test_return.py | 1 + test/unit/main.py | 26 ++++++++++++++++++-------- 3 files changed, 20 insertions(+), 9 deletions(-) (limited to 'test') diff --git a/test/test_java_websockets.py b/test/test_java_websockets.py index d75ee3a6..e0dbf539 100644 --- a/test/test_java_websockets.py +++ b/test/test_java_websockets.py @@ -22,7 +22,7 @@ class TestJavaWebsockets(TestApplicationJava): ) self.skip_alerts.extend( - [r'last message send failed', r'socket close\(\d+\) failed'] + [r'socket close\(\d+\) failed'] ) def close_connection(self, sock): diff --git a/test/test_return.py b/test/test_return.py index bd65b9bb..fcb51745 100644 --- a/test/test_return.py +++ b/test/test_return.py @@ -183,6 +183,7 @@ Connection: close check_error({"return": []}) check_error({"return": 80.1}) check_error({"return": 1000}) + check_error({"return": -1}) check_error({"return": 200, "share": "/blah"}) self.assertIn( diff --git a/test/unit/main.py b/test/unit/main.py index 49c1eed3..060a03a5 100644 --- a/test/unit/main.py +++ b/test/unit/main.py @@ -199,7 +199,7 @@ class TestUnit(unittest.TestCase): self.skip_sanitizer = False def tearDown(self): - self.stop() + stop_errs = self.stop() # detect errors and failures for current test @@ -234,11 +234,19 @@ class TestUnit(unittest.TestCase): else: self._print_log() + self.assertListEqual(stop_errs, [None, None], 'stop errors') + def stop(self): - self._stop() - self.stop_processes() + errors = [] + + errors.append(self._stop()) + + errors.append(self.stop_processes()) + atexit.unregister(self.stop) + return errors + def _stop(self): if self._p.poll() is not None: return @@ -249,12 +257,10 @@ class TestUnit(unittest.TestCase): try: retcode = p.wait(15) if retcode: - self.fail( - "Child process terminated with code " + str(retcode) - ) + return 'Child process terminated with code ' + str(retcode) except: p.kill() - self.fail("Could not terminate unit") + return 'Could not terminate unit' def run_process(self, target, *args): if not hasattr(self, '_processes'): @@ -269,13 +275,17 @@ class TestUnit(unittest.TestCase): if not hasattr(self, '_processes'): return + fail = False for process in self._processes: if process.is_alive(): process.terminate() process.join(timeout=15) if process.is_alive(): - self.fail('Fail to stop process') + fail = True + + if fail: + return 'Fail to stop process' def waitforfiles(self, *files): for i in range(50): -- cgit From d7aa514d6a586115f0b05d5d6465787da1fa9b6c Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Fri, 3 Apr 2020 01:46:59 +0100 Subject: Tests: added notification on "read_timeout" expiration. --- test/unit/applications/websockets.py | 16 ++++++++++++++-- test/unit/http.py | 18 ++++++++++++++++-- 2 files changed, 30 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/test/unit/applications/websockets.py b/test/unit/applications/websockets.py index 309d37a3..fc15e8e4 100644 --- a/test/unit/applications/websockets.py +++ b/test/unit/applications/websockets.py @@ -52,7 +52,11 @@ class TestApplicationWebsocket(TestApplicationProto): ) resp = '' - while select.select([sock], [], [], 60)[0]: + while True: + rlist = select.select([sock], [], [], 60)[0] + if not rlist: + self.fail('Can\'t read response from server.') + resp += sock.recv(4096).decode() if ( @@ -73,7 +77,15 @@ class TestApplicationWebsocket(TestApplicationProto): def frame_read(self, sock, read_timeout=60): def recv_bytes(sock, bytes): data = b'' - while select.select([sock], [], [], read_timeout)[0]: + while True: + rlist = select.select([sock], [], [], read_timeout)[0] + if not rlist: + # For all current cases if the "read_timeout" was changed + # than test do not expect to get a response from server. + if read_timeout == 60: + self.fail('Can\'t read response from server.') + break + data += sock.recv(bytes - len(data)) if len(data) == bytes: diff --git a/test/unit/http.py b/test/unit/http.py index 8c71825a..8aacf18b 100644 --- a/test/unit/http.py +++ b/test/unit/http.py @@ -173,11 +173,25 @@ class TestHTTP(TestUnit): return self.http('PUT', **kwargs) def recvall(self, sock, **kwargs): - timeout = 60 if 'read_timeout' not in kwargs else kwargs['read_timeout'] + timeout_default = 60 + + timeout = ( + timeout_default + if 'read_timeout' not in kwargs + else kwargs['read_timeout'] + ) buff_size = 4096 if 'buff_size' not in kwargs else kwargs['buff_size'] data = b'' - while select.select([sock], [], [], timeout)[0]: + while True: + rlist = select.select([sock], [], [], timeout)[0] + if not rlist: + # For all current cases if the "read_timeout" was changed + # than test do not expect to get a response from server. + if timeout == timeout_default: + self.fail('Can\'t read response from server.') + break + try: part = sock.recv(buff_size) except: -- cgit From a49023229ec0a404665a711fbf35f6b3bf715825 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Fri, 3 Apr 2020 01:49:18 +0100 Subject: Tests: use "return" action in upstream tests. --- test/python/delayed/wsgi.py | 1 + test/python/upstreams/0/wsgi.py | 8 -- test/python/upstreams/1/wsgi.py | 8 -- test/python/upstreams/2/wsgi.py | 8 -- test/test_upstreams_rr.py | 174 +++++++++++++++++++++++----------------- 5 files changed, 101 insertions(+), 98 deletions(-) delete mode 100644 test/python/upstreams/0/wsgi.py delete mode 100644 test/python/upstreams/1/wsgi.py delete mode 100644 test/python/upstreams/2/wsgi.py (limited to 'test') diff --git a/test/python/delayed/wsgi.py b/test/python/delayed/wsgi.py index d25e2765..3eb5a6f8 100644 --- a/test/python/delayed/wsgi.py +++ b/test/python/delayed/wsgi.py @@ -11,6 +11,7 @@ def application(environ, start_response): write = start_response('200', [('Content-Length', str(len(body)))]) if not body: + time.sleep(delay) return [] step = int(len(body) / parts) diff --git a/test/python/upstreams/0/wsgi.py b/test/python/upstreams/0/wsgi.py deleted file mode 100644 index 2c88979b..00000000 --- a/test/python/upstreams/0/wsgi.py +++ /dev/null @@ -1,8 +0,0 @@ -import time - -def application(env, start_response): - delay = int(env.get('HTTP_X_DELAY', 0)) - - start_response('200', [('Content-Length', '0'), ('X-Upstream', '0')]) - time.sleep(delay) - return [] diff --git a/test/python/upstreams/1/wsgi.py b/test/python/upstreams/1/wsgi.py deleted file mode 100644 index 5077bdb1..00000000 --- a/test/python/upstreams/1/wsgi.py +++ /dev/null @@ -1,8 +0,0 @@ -import time - -def application(env, start_response): - delay = int(env.get('HTTP_X_DELAY', 0)) - - start_response('200', [('Content-Length', '0'), ('X-Upstream', '1')]) - time.sleep(delay) - return [] diff --git a/test/python/upstreams/2/wsgi.py b/test/python/upstreams/2/wsgi.py deleted file mode 100644 index bb0ce797..00000000 --- a/test/python/upstreams/2/wsgi.py +++ /dev/null @@ -1,8 +0,0 @@ -import time - -def application(env, start_response): - delay = int(env.get('HTTP_X_DELAY', 0)) - - start_response('200', [('Content-Length', '0'), ('X-Upstream', '2')]) - time.sleep(delay) - return [] diff --git a/test/test_upstreams_rr.py b/test/test_upstreams_rr.py index 8dc83487..7045318a 100644 --- a/test/test_upstreams_rr.py +++ b/test/test_upstreams_rr.py @@ -16,10 +16,10 @@ class TestUpstreamsRR(TestApplicationPython): { "listeners": { "*:7080": {"pass": "upstreams/one"}, - "*:7081": {"pass": "applications/ups_0"}, - "*:7082": {"pass": "applications/ups_1"}, - "*:7083": {"pass": "applications/ups_2"}, "*:7090": {"pass": "upstreams/two"}, + "*:7081": {"pass": "routes/one"}, + "*:7082": {"pass": "routes/two"}, + "*:7083": {"pass": "routes/three"}, }, "upstreams": { "one": { @@ -35,32 +35,12 @@ class TestUpstreamsRR(TestApplicationPython): }, }, }, - "applications": { - "ups_0": { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir + "/python/upstreams/0", - "working_directory": self.current_dir - + "/python/upstreams/0", - "module": "wsgi", - }, - "ups_1": { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir + "/python/upstreams/1", - "working_directory": self.current_dir - + "/python/upstreams/1", - "module": "wsgi", - }, - "ups_2": { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir + "/python/upstreams/2", - "working_directory": self.current_dir - + "/python/upstreams/2", - "module": "wsgi", - }, + "routes": { + "one": [{"action": {"return": 200}}], + "two": [{"action": {"return": 201}}], + "three": [{"action": {"return": 202}}], }, + "applications": {}, }, ), 'upstreams initial configuration', @@ -70,15 +50,17 @@ class TestUpstreamsRR(TestApplicationPython): def get_resps(self, req=100, port=7080): resps = [0] + for _ in range(req): - headers = self.get(port=port)['headers'] - if 'X-Upstream' in headers: - ups = int(headers['X-Upstream']) + status = self.get(port=port)['status'] + if 200 > status or status > 209: + continue - if ups > len(resps) - 1: - resps.extend([0] * (ups - len(resps) + 1)) + ups = status % 10 + if ups > len(resps) - 1: + resps.extend([0] * (ups - len(resps) + 1)) - resps[ups] += 1 + resps[ups] += 1 return resps @@ -97,16 +79,19 @@ Connection: close """ resp = self.http(to_send, raw_resp=True, raw=True, port=port) - ups = re.findall('X-Upstream: (\d+)', resp) - resps = [0] * (int(max(ups)) + 1) + status = re.findall(r'HTTP\/\d\.\d\s(\d\d\d)', resp) + status = list(filter(lambda x: x[:2] == '20', status)) + ups = list(map(lambda x: int(x[-1]), status)) + resps = [0] * (max(ups) + 1) for i in range(len(ups)): - resps[int(ups[i])] += 1 + resps[ups[i]] += 1 return resps def test_upstreams_rr_no_weight(self): resps = self.get_resps() + self.assertEqual(sum(resps), 100, 'no weight sum') self.assertLessEqual( abs(resps[0] - resps[1]), self.cpu_count, 'no weight' ) @@ -127,6 +112,7 @@ Connection: close ) resps = self.get_resps() + self.assertEqual(sum(resps), 100, 'no weight 3 sum') self.assertLessEqual( abs(resps[0] - resps[1]), self.cpu_count, 'no weight 3' ) @@ -138,6 +124,7 @@ Connection: close ) resps = self.get_resps() + self.assertEqual(sum(resps), 100, 'no weight 4 sum') self.assertLessEqual( max(resps) - min(resps), self.cpu_count, 'no weight 4' ) @@ -295,33 +282,71 @@ Connection: close r_one = sum_resps(r_one, self.get_resps(req=10)) r_two = sum_resps(r_two, self.get_resps(req=10, port=7090)) + + self.assertEqual(sum(r_one), 100, 'dep one mix sum') self.assertLessEqual( abs(r_one[0] - r_one[1]), self.cpu_count, 'dep one mix' ) + self.assertEqual(sum(r_two), 100, 'dep two mix sum') self.assertLessEqual( abs(r_two[0] - r_two[1]), self.cpu_count, 'dep two mix' ) def test_upstreams_rr_delay(self): - headers_delay_1 = { - 'Connection': 'close', - 'Host': 'localhost', - 'Content-Length': '0', - 'X-Delay': '1', - } - headers_no_delay = { - 'Connection': 'close', - 'Host': 'localhost', - 'Content-Length': '0', - } + self.assertIn( + 'success', + self.conf( + { + "listeners": { + "*:7080": {"pass": "upstreams/one"}, + "*:7081": {"pass": "routes"}, + "*:7082": {"pass": "routes"}, + }, + "upstreams": { + "one": { + "servers": { + "127.0.0.1:7081": {}, + "127.0.0.1:7082": {}, + }, + }, + }, + "routes": [ + { + "match": {"destination": "*:7081"}, + "action": {"pass": "applications/delayed"}, + }, + { + "match": {"destination": "*:7082"}, + "action": {"return": 201}, + }, + ], + "applications": { + "delayed": { + "type": "python", + "processes": {"spare": 0}, + "path": self.current_dir + "/python/delayed", + "working_directory": self.current_dir + + "/python/delayed", + "module": "wsgi", + } + }, + }, + ), + 'upstreams initial configuration', + ) req = 50 socks = [] for i in range(req): - headers = headers_delay_1 if i % 5 == 0 else headers_no_delay + delay = 1 if i % 5 == 0 else 0 _, sock = self.get( - headers=headers, + headers={ + 'Host': 'localhost', + 'Content-Length': '0', + 'X-Delay': str(delay), + 'Connection': 'close', + }, start=True, no_recv=True, ) @@ -332,12 +357,12 @@ Connection: close resp = self.recvall(socks[i]).decode() socks[i].close() - m = re.search('X-Upstream: (\d+)', resp) + m = re.search('HTTP/1.1 20(\d)', resp) + self.assertIsNotNone(m, 'status') resps[int(m.group(1))] += 1 - self.assertLessEqual( - abs(resps[0] - resps[1]), self.cpu_count, 'dep two mix' - ) + self.assertEqual(sum(resps), req, 'delay sum') + self.assertLessEqual(abs(resps[0] - resps[1]), self.cpu_count, 'delay') def test_upstreams_rr_active_req(self): conns = 5 @@ -364,7 +389,7 @@ Connection: close # Send one more request and read response to make sure that previous # requests had enough time to reach server. - self.assertEqual(self.get()['status'], 200) + self.assertEqual(self.get()['body'], '') self.assertIn( 'success', @@ -388,13 +413,17 @@ Connection: close ) for i in range(conns): - resp = self.recvall(socks[i]).decode() - socks[i].close() - - self.assertRegex(resp, r'X-Upstream', 'active req GET') + self.assertEqual( + self.http(b'', sock=socks[i], raw=True)['body'], + '', + 'active req GET', + ) - resp = self.http(b"""0123456789""", sock=socks2[i], raw=True) - self.assertEqual(resp['status'], 200, 'active req POST') + self.assertEqual( + self.http(b"""0123456789""", sock=socks2[i], raw=True)['body'], + '', + 'active req POST', + ) def test_upstreams_rr_bad_server(self): self.assertIn( @@ -417,14 +446,11 @@ Connection: close def test_upstreams_rr_post(self): resps = [0, 0] for _ in range(50): - resps[ - int(self.post(body='0123456789')['headers']['X-Upstream']) - ] += 1 - resps[int(self.get()['headers']['X-Upstream'])] += 1 + resps[self.get()['status'] % 10] += 1 + resps[self.post(body='0123456789')['status'] % 10] += 1 - self.assertLessEqual( - abs(resps[0] - resps[1]), self.cpu_count, 'post' - ) + self.assertEqual(sum(resps), 100, 'post sum') + self.assertLessEqual(abs(resps[0] - resps[1]), self.cpu_count, 'post') def test_upstreams_rr_unix(self): addr_0 = self.testdir + '/sock_0' @@ -435,8 +461,8 @@ Connection: close self.conf( { "*:7080": {"pass": "upstreams/one"}, - "unix:" + addr_0: {"pass": "applications/ups_0"}, - "unix:" + addr_1: {"pass": "applications/ups_1"}, + "unix:" + addr_0: {"pass": "routes/one"}, + "unix:" + addr_1: {"pass": "routes/two"}, }, 'listeners', ), @@ -446,7 +472,7 @@ Connection: close self.assertIn( 'success', self.conf( - {"unix:" + addr_0: {}, "unix:" + addr_1: {},}, + {"unix:" + addr_0: {}, "unix:" + addr_1: {}}, 'upstreams/one/servers', ), 'configure servers unix', @@ -463,8 +489,8 @@ Connection: close self.conf( { "*:7080": {"pass": "upstreams/one"}, - "[::1]:7081": {"pass": "applications/ups_0"}, - "[::1]:7082": {"pass": "applications/ups_1"}, + "[::1]:7081": {"pass": "routes/one"}, + "[::1]:7082": {"pass": "routes/two"}, }, 'listeners', ), @@ -474,7 +500,7 @@ Connection: close self.assertIn( 'success', self.conf( - {"[::1]:7081": {}, "[::1]:7082": {},}, 'upstreams/one/servers' + {"[::1]:7081": {}, "[::1]:7082": {}}, 'upstreams/one/servers' ), 'configure servers ipv6', ) -- cgit From c7f5c1c6641838006088524c2122eae8f9c30431 Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Wed, 8 Apr 2020 15:15:24 +0300 Subject: Controller: improved handling of unix domain control socket. One of the ways to detect Unit's startup and subsequent readiness to accept commands relies on waiting for the control socket file to be created. Earlier, it was unreliable due to a race condition between the client's connect() and the daemon's listen() calls after the socket's bind() call. Now, unix domain listening sockets are created with a nxt_listen_socket_create() call as follows: s = socket(); unlink("path/to/socket.tmp") bind(s, "path/to/socket.tmp"); listen(s); rename("path/to/socket.tmp", "path/to/socket"); This eliminates a time-lapse when the socket file is already created but nobody is listening on it yet, which therefore prevents the condition described above. Also, it allows reliably detecting whether the socket is being used or simply wasn't cleaned after the daemon stopped abruptly. A successful connection to the socket file means the daemon has been started; otherwise, the file can be overwritten. --- test/unit/main.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'test') diff --git a/test/unit/main.py b/test/unit/main.py index 060a03a5..4507f71a 100644 --- a/test/unit/main.py +++ b/test/unit/main.py @@ -185,10 +185,7 @@ class TestUnit(unittest.TestCase): atexit.register(self.stop) - # Due to race between connect() and listen() after the socket binding - # tests waits for unit.pid file which is created after listen(). - - if not self.waitforfiles(self.testdir + '/unit.pid'): + if not self.waitforfiles(self.testdir + '/control.unit.sock'): exit("Could not start unit") self.skip_alerts = [ -- cgit From 0bfa09dfa0ec6a1474ba30d0e1f8aea832fbc1fc Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Tue, 14 Apr 2020 02:35:04 +0100 Subject: Tests: minor fixes and style. --- test/test_go_application.py | 10 +++--- test/test_java_application.py | 10 +++--- test/test_java_websockets.py | 26 ++++++++-------- test/test_node_application.py | 8 +++-- test/test_node_websockets.py | 26 ++++++++-------- test/test_perl_application.py | 10 +++--- test/test_php_application.py | 10 +++--- test/test_php_basic.py | 56 +++++---------------------------- test/test_python_application.py | 16 ++++++---- test/test_python_basic.py | 69 ++++++----------------------------------- test/test_python_procman.py | 6 ++-- test/test_routing.py | 2 +- test/test_ruby_application.py | 10 +++--- test/test_tls.py | 5 +-- test/test_usr1.py | 2 +- test/unit/http.py | 8 ++--- 16 files changed, 99 insertions(+), 175 deletions(-) (limited to 'test') diff --git a/test/test_go_application.py b/test/test_go_application.py index 42429be7..c9d4ba77 100644 --- a/test/test_go_application.py +++ b/test/test_go_application.py @@ -89,6 +89,7 @@ class TestGoApplication(TestApplicationGo): self.assertEqual(self.get()['status'], 200, 'init') + body = '0123456789' * 500 (resp, sock) = self.post( headers={ 'Host': 'localhost', @@ -96,12 +97,13 @@ class TestGoApplication(TestApplicationGo): 'Content-Type': 'text/html', }, start=True, - body='0123456789' * 500, + body=body, read_timeout=1, ) - self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1') + self.assertEqual(resp['body'], body, 'keep-alive 1') + body = '0123456789' resp = self.post( headers={ 'Host': 'localhost', @@ -109,10 +111,10 @@ class TestGoApplication(TestApplicationGo): 'Connection': 'close', }, sock=sock, - body='0123456789', + body=body, ) - self.assertEqual(resp['body'], '0123456789', 'keep-alive 2') + self.assertEqual(resp['body'], body, 'keep-alive 2') def test_go_application_cookies(self): self.load('cookies') diff --git a/test/test_java_application.py b/test/test_java_application.py index 9d873d6b..7bd351a4 100644 --- a/test/test_java_application.py +++ b/test/test_java_application.py @@ -1085,6 +1085,7 @@ class TestJavaApplication(TestApplicationJava): self.assertEqual(self.post()['status'], 200, 'init') + body = '0123456789' * 500 (resp, sock) = self.post( headers={ 'Connection': 'keep-alive', @@ -1092,12 +1093,13 @@ class TestJavaApplication(TestApplicationJava): 'Host': 'localhost', }, start=True, - body='0123456789' * 500, + body=body, read_timeout=1, ) - self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1') + self.assertEqual(resp['body'], body, 'keep-alive 1') + body = '0123456789' resp = self.post( headers={ 'Connection': 'close', @@ -1105,10 +1107,10 @@ class TestJavaApplication(TestApplicationJava): 'Host': 'localhost', }, sock=sock, - body='0123456789', + body=body, ) - self.assertEqual(resp['body'], '0123456789', 'keep-alive 2') + self.assertEqual(resp['body'], body, 'keep-alive 2') def test_java_application_http_10(self): self.load('empty') diff --git a/test/test_java_websockets.py b/test/test_java_websockets.py index e0dbf539..7ea04620 100644 --- a/test/test_java_websockets.py +++ b/test/test_java_websockets.py @@ -26,7 +26,7 @@ class TestJavaWebsockets(TestApplicationJava): ) def close_connection(self, sock): - self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty sock') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc') self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close()) @@ -441,12 +441,12 @@ class TestJavaWebsockets(TestApplicationJava): _, sock, _ = self.ws.upgrade() self.ws.frame_write(sock, self.ws.OP_PONG, '') - self.assertEqual(self.recvall(sock, read_timeout=1), b'', '2_7') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '2_7') # 2_8 self.ws.frame_write(sock, self.ws.OP_PONG, 'unsolicited pong payload') - self.assertEqual(self.recvall(sock, read_timeout=1), b'', '2_8') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '2_8') # 2_9 @@ -512,7 +512,7 @@ class TestJavaWebsockets(TestApplicationJava): self.check_close(sock, 1002, no_close=True) - self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty 3_2') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_2') sock.close() # 3_3 @@ -530,7 +530,7 @@ class TestJavaWebsockets(TestApplicationJava): self.check_close(sock, 1002, no_close=True) - self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty 3_3') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_3') sock.close() # 3_4 @@ -548,7 +548,7 @@ class TestJavaWebsockets(TestApplicationJava): self.check_close(sock, 1002, no_close=True) - self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty 3_4') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_4') sock.close() # 3_5 @@ -734,7 +734,7 @@ class TestJavaWebsockets(TestApplicationJava): # 5_4 self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False) - self.assertEqual(self.recvall(sock, read_timeout=1), b'', '5_4') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_4') self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True) frame = self.ws.frame_read(sock) @@ -771,7 +771,7 @@ class TestJavaWebsockets(TestApplicationJava): ping_payload = 'ping payload' self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False) - self.assertEqual(self.recvall(sock, read_timeout=1), b'', '5_7') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_7') self.ws.frame_write(sock, self.ws.OP_PING, ping_payload) @@ -955,7 +955,7 @@ class TestJavaWebsockets(TestApplicationJava): frame = self.ws.frame_read(sock) self.check_frame(frame, True, self.ws.OP_PONG, 'pongme 2!') - self.assertEqual(self.recvall(sock, read_timeout=1), b'', '5_20') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_20') self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment5') self.check_frame( @@ -1088,7 +1088,7 @@ class TestJavaWebsockets(TestApplicationJava): self.check_close(sock, no_close=True) self.ws.frame_write(sock, self.ws.OP_PING, '') - self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty sock') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc') sock.close() @@ -1100,7 +1100,7 @@ class TestJavaWebsockets(TestApplicationJava): self.check_close(sock, no_close=True) self.ws.frame_write(sock, self.ws.OP_TEXT, payload) - self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty sock') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc') sock.close() @@ -1113,7 +1113,7 @@ class TestJavaWebsockets(TestApplicationJava): self.check_close(sock, no_close=True) self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2') - self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty sock') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc') sock.close() @@ -1128,7 +1128,7 @@ class TestJavaWebsockets(TestApplicationJava): self.recvall(sock, read_timeout=1) self.ws.frame_write(sock, self.ws.OP_PING, '') - self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty sock') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc') sock.close() diff --git a/test/test_node_application.py b/test/test_node_application.py index b80d17d3..174af15d 100644 --- a/test/test_node_application.py +++ b/test/test_node_application.py @@ -112,6 +112,7 @@ class TestNodeApplication(TestApplicationNode): self.assertEqual(self.get()['status'], 200, 'init') + body = '0123456789' * 500 (resp, sock) = self.post( headers={ 'Host': 'localhost', @@ -119,12 +120,13 @@ class TestNodeApplication(TestApplicationNode): 'Content-Type': 'text/html', }, start=True, - body='0123456789' * 500, + body=body, read_timeout=1, ) self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1') + body = '0123456789' resp = self.post( headers={ 'Host': 'localhost', @@ -132,10 +134,10 @@ class TestNodeApplication(TestApplicationNode): 'Content-Type': 'text/html', }, sock=sock, - body='0123456789', + body=body, ) - self.assertEqual(resp['body'], '0123456789', 'keep-alive 2') + self.assertEqual(resp['body'], body, 'keep-alive 2') def test_node_application_write_buffer(self): self.load('write_buffer') diff --git a/test/test_node_websockets.py b/test/test_node_websockets.py index cb6bf137..4ce727db 100644 --- a/test/test_node_websockets.py +++ b/test/test_node_websockets.py @@ -26,7 +26,7 @@ class TestNodeWebsockets(TestApplicationNode): ) def close_connection(self, sock): - self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty sock') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc') self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close()) @@ -460,12 +460,12 @@ class TestNodeWebsockets(TestApplicationNode): _, sock, _ = self.ws.upgrade() self.ws.frame_write(sock, self.ws.OP_PONG, '') - self.assertEqual(self.recvall(sock, read_timeout=1), b'', '2_7') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '2_7') # 2_8 self.ws.frame_write(sock, self.ws.OP_PONG, 'unsolicited pong payload') - self.assertEqual(self.recvall(sock, read_timeout=1), b'', '2_8') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '2_8') # 2_9 @@ -531,7 +531,7 @@ class TestNodeWebsockets(TestApplicationNode): self.check_close(sock, 1002, no_close=True) - self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty 3_2') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_2') sock.close() # 3_3 @@ -549,7 +549,7 @@ class TestNodeWebsockets(TestApplicationNode): self.check_close(sock, 1002, no_close=True) - self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty 3_3') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_3') sock.close() # 3_4 @@ -567,7 +567,7 @@ class TestNodeWebsockets(TestApplicationNode): self.check_close(sock, 1002, no_close=True) - self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty 3_4') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_4') sock.close() # 3_5 @@ -753,7 +753,7 @@ class TestNodeWebsockets(TestApplicationNode): # 5_4 self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False) - self.assertEqual(self.recvall(sock, read_timeout=1), b'', '5_4') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_4') self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True) frame = self.ws.frame_read(sock) @@ -790,7 +790,7 @@ class TestNodeWebsockets(TestApplicationNode): ping_payload = 'ping payload' self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False) - self.assertEqual(self.recvall(sock, read_timeout=1), b'', '5_7') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_7') self.ws.frame_write(sock, self.ws.OP_PING, ping_payload) @@ -974,7 +974,7 @@ class TestNodeWebsockets(TestApplicationNode): frame = self.ws.frame_read(sock) self.check_frame(frame, True, self.ws.OP_PONG, 'pongme 2!') - self.assertEqual(self.recvall(sock, read_timeout=1), b'', '5_20') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_20') self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment5') self.check_frame( @@ -1107,7 +1107,7 @@ class TestNodeWebsockets(TestApplicationNode): self.check_close(sock, no_close=True) self.ws.frame_write(sock, self.ws.OP_PING, '') - self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty sock') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc') sock.close() @@ -1119,7 +1119,7 @@ class TestNodeWebsockets(TestApplicationNode): self.check_close(sock, no_close=True) self.ws.frame_write(sock, self.ws.OP_TEXT, payload) - self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty sock') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc') sock.close() @@ -1132,7 +1132,7 @@ class TestNodeWebsockets(TestApplicationNode): self.check_close(sock, no_close=True) self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2') - self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty sock') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc') sock.close() @@ -1147,7 +1147,7 @@ class TestNodeWebsockets(TestApplicationNode): self.recvall(sock, read_timeout=1) self.ws.frame_write(sock, self.ws.OP_PING, '') - self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty sock') + self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc') sock.close() diff --git a/test/test_perl_application.py b/test/test_perl_application.py index a4bac623..cc4eb915 100644 --- a/test/test_perl_application.py +++ b/test/test_perl_application.py @@ -197,6 +197,7 @@ class TestPerlApplication(TestApplicationPerl): self.assertEqual(self.get()['status'], 200, 'init') + body = '0123456789' * 500 (resp, sock) = self.post( headers={ 'Host': 'localhost', @@ -204,12 +205,13 @@ class TestPerlApplication(TestApplicationPerl): 'Content-Type': 'text/html', }, start=True, - body='0123456789' * 500, + body=body, read_timeout=1, ) - self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1') + self.assertEqual(resp['body'], body, 'keep-alive 1') + body = '0123456789' resp = self.post( headers={ 'Host': 'localhost', @@ -217,10 +219,10 @@ class TestPerlApplication(TestApplicationPerl): 'Content-Type': 'text/html', }, sock=sock, - body='0123456789', + body=body, ) - self.assertEqual(resp['body'], '0123456789', 'keep-alive 2') + self.assertEqual(resp['body'], body, 'keep-alive 2') def test_perl_body_io_fake(self): self.load('body_io_fake') diff --git a/test/test_php_application.py b/test/test_php_application.py index c3645a99..48e1e815 100644 --- a/test/test_php_application.py +++ b/test/test_php_application.py @@ -183,6 +183,7 @@ class TestPHPApplication(TestApplicationPHP): self.assertEqual(self.get()['status'], 200, 'init') + body = '0123456789' * 500 (resp, sock) = self.post( headers={ 'Host': 'localhost', @@ -190,12 +191,13 @@ class TestPHPApplication(TestApplicationPHP): 'Content-Type': 'text/html', }, start=True, - body='0123456789' * 500, + body=body, read_timeout=1, ) - self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1') + self.assertEqual(resp['body'], body, 'keep-alive 1') + body = '0123456789' resp = self.post( headers={ 'Host': 'localhost', @@ -203,10 +205,10 @@ class TestPHPApplication(TestApplicationPHP): 'Content-Type': 'text/html', }, sock=sock, - body='0123456789', + body=body, ) - self.assertEqual(resp['body'], '0123456789', 'keep-alive 2') + self.assertEqual(resp['body'], body, 'keep-alive 2') def test_php_application_conditional(self): self.load('conditional') diff --git a/test/test_php_basic.py b/test/test_php_basic.py index 7ecff1b2..5fde3e00 100644 --- a/test/test_php_basic.py +++ b/test/test_php_basic.py @@ -37,9 +37,6 @@ class TestPHPBasic(TestControl): 'applications', ) - def test_php_get_applications_prefix(self): - self.conf(self.conf_app, 'applications') - self.assertEqual( self.conf_get('applications'), { @@ -53,9 +50,6 @@ class TestPHPBasic(TestControl): 'applications prefix', ) - def test_php_get_applications_prefix_2(self): - self.conf(self.conf_app, 'applications') - self.assertEqual( self.conf_get('applications/app'), { @@ -67,9 +61,6 @@ class TestPHPBasic(TestControl): 'applications prefix 2', ) - def test_php_get_applications_prefix_3(self): - self.conf(self.conf_app, 'applications') - self.assertEqual(self.conf_get('applications/app/type'), 'php', 'type') self.assertEqual( self.conf_get('applications/app/processes/spare'), @@ -86,18 +77,12 @@ class TestPHPBasic(TestControl): 'listeners', ) - def test_php_get_listeners_prefix(self): - self.conf(self.conf_basic) - self.assertEqual( self.conf_get('listeners'), {"*:7080": {"pass": "applications/app"}}, 'listeners prefix', ) - def test_php_get_listeners_prefix_2(self): - self.conf(self.conf_basic) - self.assertEqual( self.conf_get('listeners/*:7080'), {"pass": "applications/app"}, @@ -147,49 +132,24 @@ class TestPHPBasic(TestControl): def test_php_delete(self): self.conf(self.conf_basic) - self.assertIn( - 'error', - self.conf_delete('applications/app'), - 'delete app before listener', - ) - self.assertIn( - 'success', self.conf_delete('listeners/*:7080'), 'delete listener' - ) - self.assertIn( - 'success', - self.conf_delete('applications/app'), - 'delete app after listener', - ) - self.assertIn( - 'error', self.conf_delete('applications/app'), 'delete app again' - ) + self.assertIn('error', self.conf_delete('applications/app')) + self.assertIn('success', self.conf_delete('listeners/*:7080')) + self.assertIn('success', self.conf_delete('applications/app')) + self.assertIn('error', self.conf_delete('applications/app')) def test_php_delete_blocks(self): self.conf(self.conf_basic) - self.assertIn( - 'success', - self.conf_delete('listeners'), - 'listeners delete', - ) - - self.assertIn( - 'success', - self.conf_delete('applications'), - 'applications delete', - ) - - self.assertIn( - 'success', - self.conf(self.conf_app, 'applications'), - 'listeners restore', - ) + self.assertIn('success', self.conf_delete('listeners')) + self.assertIn('success', self.conf_delete('applications')) + self.assertIn('success', self.conf(self.conf_app, 'applications')) self.assertIn( 'success', self.conf({"*:7081": {"pass": "applications/app"}}, 'listeners'), 'applications restore', ) + if __name__ == '__main__': TestPHPBasic.main() diff --git a/test/test_python_application.py b/test/test_python_application.py index 460cc804..5741d2d8 100644 --- a/test/test_python_application.py +++ b/test/test_python_application.py @@ -187,6 +187,7 @@ class TestPythonApplication(TestApplicationPython): self.assertEqual(self.get()['status'], 200, 'init') + body = '0123456789' * 500 (resp, sock) = self.post( headers={ 'Host': 'localhost', @@ -194,12 +195,13 @@ class TestPythonApplication(TestApplicationPython): 'Content-Type': 'text/html', }, start=True, - body='0123456789' * 500, + body=body, read_timeout=1, ) - self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1') + self.assertEqual(resp['body'], body, 'keep-alive 1') + body = '0123456789' resp = self.post( headers={ 'Host': 'localhost', @@ -207,10 +209,10 @@ class TestPythonApplication(TestApplicationPython): 'Content-Type': 'text/html', }, sock=sock, - body='0123456789', + body=body, ) - self.assertEqual(resp['body'], '0123456789', 'keep-alive 2') + self.assertEqual(resp['body'], body, 'keep-alive 2') def test_python_keepalive_reconfigure(self): self.skip_alerts.extend( @@ -340,14 +342,16 @@ class TestPythonApplication(TestApplicationPython): self.assertEqual(self.get()['status'], 200, 'init') - (resp, sock) = self.http( + (_, sock) = self.http( b"""GET / HTTP/1.1 """, start=True, raw=True, - read_timeout=5, + no_recv=True, ) + self.assertEqual(self.get()['status'], 200) + self.assertIn( 'success', self.conf({"listeners": {}, "applications": {}}), diff --git a/test/test_python_basic.py b/test/test_python_basic.py index 67a5f548..3233fca2 100644 --- a/test/test_python_basic.py +++ b/test/test_python_basic.py @@ -19,17 +19,9 @@ class TestPythonBasic(TestControl): } def test_python_get_empty(self): - self.assertEqual( - self.conf_get(), {'listeners': {}, 'applications': {}}, 'empty' - ) - - def test_python_get_prefix_listeners(self): - self.assertEqual(self.conf_get('listeners'), {}, 'listeners prefix') - - def test_python_get_prefix_applications(self): - self.assertEqual( - self.conf_get('applications'), {}, 'applications prefix' - ) + self.assertEqual(self.conf_get(), {'listeners': {}, 'applications': {}}) + self.assertEqual(self.conf_get('listeners'), {}) + self.assertEqual(self.conf_get('applications'), {}) def test_python_get_applications(self): self.conf(self.conf_app, 'applications') @@ -50,9 +42,6 @@ class TestPythonBasic(TestControl): 'applications', ) - def test_python_get_applications_prefix(self): - self.conf(self.conf_app, 'applications') - self.assertEqual( self.conf_get('applications'), { @@ -66,9 +55,6 @@ class TestPythonBasic(TestControl): 'applications prefix', ) - def test_python_get_applications_prefix_2(self): - self.conf(self.conf_app, 'applications') - self.assertEqual( self.conf_get('applications/app'), { @@ -80,9 +66,6 @@ class TestPythonBasic(TestControl): 'applications prefix 2', ) - def test_python_get_applications_prefix_3(self): - self.conf(self.conf_app, 'applications') - self.assertEqual( self.conf_get('applications/app/type'), 'python', 'type' ) @@ -99,18 +82,12 @@ class TestPythonBasic(TestControl): 'listeners', ) - def test_python_get_listeners_prefix(self): - self.conf(self.conf_basic) - self.assertEqual( self.conf_get('listeners'), {"*:7080": {"pass": "applications/app"}}, 'listeners prefix', ) - def test_python_get_listeners_prefix_2(self): - self.conf(self.conf_basic) - self.assertEqual( self.conf_get('listeners/*:7080'), {"pass": "applications/app"}, @@ -160,44 +137,18 @@ class TestPythonBasic(TestControl): def test_python_delete(self): self.conf(self.conf_basic) - self.assertIn( - 'error', - self.conf_delete('applications/app'), - 'delete app before listener', - ) - self.assertIn( - 'success', self.conf_delete('listeners/*:7080'), 'delete listener' - ) - self.assertIn( - 'success', - self.conf_delete('applications/app'), - 'delete app after listener', - ) - self.assertIn( - 'error', self.conf_delete('applications/app'), 'delete app again' - ) + self.assertIn('error', self.conf_delete('applications/app')) + self.assertIn('success', self.conf_delete('listeners/*:7080')) + self.assertIn('success', self.conf_delete('applications/app')) + self.assertIn('error', self.conf_delete('applications/app')) def test_python_delete_blocks(self): self.conf(self.conf_basic) - self.assertIn( - 'success', - self.conf_delete('listeners'), - 'listeners delete', - ) - - self.assertIn( - 'success', - self.conf_delete('applications'), - 'applications delete', - ) - - self.assertIn( - 'success', - self.conf(self.conf_app, 'applications'), - 'listeners restore', - ) + self.assertIn('success', self.conf_delete('listeners')) + self.assertIn('success', self.conf_delete('applications')) + self.assertIn('success', self.conf(self.conf_app, 'applications')) self.assertIn( 'success', self.conf({"*:7081": {"pass": "applications/app"}}, 'listeners'), diff --git a/test/test_python_procman.py b/test/test_python_procman.py index 8fb499f7..a2e6126c 100644 --- a/test/test_python_procman.py +++ b/test/test_python_procman.py @@ -196,7 +196,7 @@ class TestPythonProcman(TestApplicationPython): ) self.assertIn( 'error', - self.conf({"idle_timeout": -1}, self.app_proc,), + self.conf({"idle_timeout": -1}, self.app_proc), 'negative idle_timeout', ) self.assertIn( @@ -206,12 +206,12 @@ class TestPythonProcman(TestApplicationPython): ) self.assertIn( 'error', - self.conf({"spare": 2, "max": 1}, self.app_proc,), + self.conf({"spare": 2, "max": 1}, self.app_proc), 'spare gt max', ) self.assertIn( 'error', - self.conf({"spare": 0, "max": 0}, self.app_proc,), + self.conf({"spare": 0, "max": 0}, self.app_proc), 'max zero', ) diff --git a/test/test_routing.py b/test/test_routing.py index bf741706..ad793662 100644 --- a/test/test_routing.py +++ b/test/test_routing.py @@ -605,7 +605,7 @@ class TestRouting(TestApplicationProto): self.assertIn( 'success', self.conf_post( - {"match": {"method": "POST"}, "action": {"return": 200},}, + {"match": {"method": "POST"}, "action": {"return": 200}}, 'routes', ), 'routes edit configure 6', diff --git a/test/test_ruby_application.py b/test/test_ruby_application.py index 83a71f96..bdaabe51 100644 --- a/test/test_ruby_application.py +++ b/test/test_ruby_application.py @@ -322,6 +322,7 @@ class TestRubyApplication(TestApplicationRuby): self.assertEqual(self.get()['status'], 200, 'init') + body = '0123456789' * 500 (resp, sock) = self.post( headers={ 'Host': 'localhost', @@ -329,12 +330,13 @@ class TestRubyApplication(TestApplicationRuby): 'Content-Type': 'text/html', }, start=True, - body='0123456789' * 500, + body=body, read_timeout=1, ) - self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1') + self.assertEqual(resp['body'], body, 'keep-alive 1') + body = '0123456789' resp = self.post( headers={ 'Host': 'localhost', @@ -342,10 +344,10 @@ class TestRubyApplication(TestApplicationRuby): 'Content-Type': 'text/html', }, sock=sock, - body='0123456789', + body=body, ) - self.assertEqual(resp['body'], '0123456789', 'keep-alive 2') + self.assertEqual(resp['body'], body, 'keep-alive 2') def test_ruby_application_constants(self): self.load('constants') diff --git a/test/test_tls.py b/test/test_tls.py index 475e9919..d9dcf237 100644 --- a/test/test_tls.py +++ b/test/test_tls.py @@ -521,7 +521,6 @@ basicConstraints = critical,CA:TRUE""" ) def test_tls_application_respawn(self): - self.skip_alerts.append(r'process \d+ exited on signal 9') self.load('mirror') self.certificate() @@ -530,7 +529,7 @@ basicConstraints = critical,CA:TRUE""" self.add_tls(application='mirror') - (resp, sock) = self.post_ssl( + (_, sock) = self.post_ssl( headers={ 'Host': 'localhost', 'Connection': 'keep-alive', @@ -545,6 +544,8 @@ basicConstraints = critical,CA:TRUE""" subprocess.call(['kill', '-9', app_id]) + self.skip_alerts.append(r'process %s exited on signal 9' % app_id) + self.wait_for_record( re.compile( ' (?!' + app_id + '#)(\d+)#\d+ "mirror" application started' diff --git a/test/test_usr1.py b/test/test_usr1.py index 204e2e0c..155303ea 100644 --- a/test/test_usr1.py +++ b/test/test_usr1.py @@ -55,7 +55,7 @@ class TestUSR1(TestApplicationPython): self.load('log_body') log_new = 'new.log' - log_path = self.testdir + '/' + 'unit.log' + log_path = self.testdir + '/unit.log' log_path_new = self.testdir + '/' + log_new os.rename(log_path, log_path_new) diff --git a/test/unit/http.py b/test/unit/http.py index 8aacf18b..13384dc8 100644 --- a/test/unit/http.py +++ b/test/unit/http.py @@ -279,12 +279,8 @@ class TestHTTP(TestUnit): def _parse_json(self, resp): headers = resp['headers'] - self.assertIn('Content-Type', headers, 'Content-Type header set') - self.assertEqual( - headers['Content-Type'], - 'application/json', - 'Content-Type header is application/json', - ) + self.assertIn('Content-Type', headers) + self.assertEqual(headers['Content-Type'], 'application/json') resp['body'] = json.loads(resp['body']) -- cgit From 3c58a4bfc11d2d73fc72d1dbaeda4494d00508b8 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Tue, 14 Apr 2020 03:02:16 +0100 Subject: Tests: added test with rescheduling requests. --- test/test_python_application.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'test') diff --git a/test/test_python_application.py b/test/test_python_application.py index 5741d2d8..8d435b48 100644 --- a/test/test_python_application.py +++ b/test/test_python_application.py @@ -382,6 +382,38 @@ Connection: close self.wait_for_record(r'At exit called\.'), 'atexit' ) + def test_python_process_switch(self): + self.load('delayed') + + self.assertIn( + 'success', + self.conf('2', 'applications/delayed/processes'), + 'configure 2 processes', + ) + + self.get(headers={ + 'Host': 'localhost', + 'Content-Length': '0', + 'X-Delay': '5', + 'Connection': 'close', + }, no_recv=True) + + headers_delay_1 = { + 'Connection': 'close', + 'Host': 'localhost', + 'Content-Length': '0', + 'X-Delay': '1', + } + + self.get(headers=headers_delay_1, no_recv=True) + + time.sleep(0.5) + + for _ in range(10): + self.get(headers=headers_delay_1, no_recv=True) + + self.get(headers=headers_delay_1) + @unittest.skip('not yet') def test_python_application_start_response_exit(self): self.load('start_response_exit') -- cgit