unit/test/test_python_procman.py
Andrei Zeliankou c183bd8749 Tests: get rid of classes in test files.
Class usage came from the unittest framework and it was always redundant
after migration to the pytest.  This commit removes classes from files
containing tests to make them more readable and understandable.
2023-06-14 18:20:09 +01:00

302 lines
7.2 KiB
Python

import re
import shutil
import subprocess
import time
import pytest
from unit.applications.lang.python import ApplicationPython
from unit.option import option
prerequisites = {'modules': {'python': 'any'}}
client = ApplicationPython()
@pytest.fixture(autouse=True)
def setup_method_fixture(temp_dir):
client.app_name = f'app-{temp_dir.split("/")[-1]}'
client.app_proc = f'applications/{client.app_name}/processes'
client.load('empty', client.app_name)
def pids_for_process():
time.sleep(0.2)
output = subprocess.check_output(['ps', 'ax'])
pids = set()
for m in re.findall(
fr'.*unit: "{client.app_name}" application', output.decode()
):
pids.add(re.search(r'^\s*(\d+)', m).group(1))
return pids
def conf_proc(conf, path=None):
if path is None:
path = client.app_proc
assert 'success' in client.conf(conf, path), 'configure processes'
def stop_all():
assert 'success' in client.conf({"listeners": {}, "applications": {}})
assert len(pids_for_process()) == 0, 'stop all'
@pytest.mark.skip('not yet')
def test_python_processes_idle_timeout_zero():
conf_proc({"spare": 0, "max": 2, "idle_timeout": 0})
client.get()
assert len(pids_for_process()) == 0, 'idle timeout 0'
def test_python_prefork():
conf_proc('2')
pids = pids_for_process()
assert len(pids) == 2, 'prefork 2'
client.get()
assert pids_for_process() == pids, 'prefork still 2'
conf_proc('4')
pids = pids_for_process()
assert len(pids) == 4, 'prefork 4'
client.get()
assert pids_for_process() == pids, 'prefork still 4'
stop_all()
@pytest.mark.skip('not yet')
def test_python_prefork_same_processes():
conf_proc('2')
pids = pids_for_process()
conf_proc('4')
pids_new = pids_for_process()
assert pids.issubset(pids_new), 'prefork same processes'
def test_python_ondemand():
conf_proc({"spare": 0, "max": 8, "idle_timeout": 1})
assert len(pids_for_process()) == 0, 'on-demand 0'
client.get()
pids = pids_for_process()
assert len(pids) == 1, 'on-demand 1'
client.get()
assert pids_for_process() == pids, 'on-demand still 1'
time.sleep(1)
assert len(pids_for_process()) == 0, 'on-demand stop idle'
stop_all()
def test_python_scale_updown():
conf_proc({"spare": 2, "max": 8, "idle_timeout": 1})
pids = pids_for_process()
assert len(pids) == 2, 'updown 2'
client.get()
pids_new = pids_for_process()
assert len(pids_new) == 3, 'updown 3'
assert pids.issubset(pids_new), 'updown 3 only 1 new'
client.get()
assert pids_for_process() == pids_new, 'updown still 3'
time.sleep(1)
pids = pids_for_process()
assert len(pids) == 2, 'updown stop idle'
client.get()
pids_new = pids_for_process()
assert len(pids_new) == 3, 'updown again 3'
assert pids.issubset(pids_new), 'updown again 3 only 1 new'
stop_all()
def test_python_reconfigure():
conf_proc({"spare": 2, "max": 6, "idle_timeout": 1})
pids = pids_for_process()
assert len(pids) == 2, 'reconf 2'
client.get()
pids_new = pids_for_process()
assert len(pids_new) == 3, 'reconf 3'
assert pids.issubset(pids_new), 'reconf 3 only 1 new'
conf_proc('6', f'{client.app_proc}/spare')
pids = pids_for_process()
assert len(pids) == 6, 'reconf 6'
client.get()
assert pids_for_process() == pids, 'reconf still 6'
stop_all()
def test_python_idle_timeout():
conf_proc({"spare": 0, "max": 6, "idle_timeout": 2})
client.get()
pids = pids_for_process()
assert len(pids) == 1, 'idle timeout 1'
time.sleep(1)
client.get()
time.sleep(1)
pids_new = pids_for_process()
assert len(pids_new) == 1, 'idle timeout still 1'
assert pids_for_process() == pids, 'idle timeout still 1 same pid'
time.sleep(1)
assert len(pids_for_process()) == 0, 'idle timed out'
def test_python_processes_connection_keepalive():
conf_proc({"spare": 0, "max": 6, "idle_timeout": 2})
(_, sock) = client.get(
headers={'Host': 'localhost', 'Connection': 'keep-alive'},
start=True,
read_timeout=1,
)
assert len(pids_for_process()) == 1, 'keepalive connection 1'
time.sleep(2)
assert len(pids_for_process()) == 0, 'keepalive connection 0'
sock.close()
def test_python_processes_access():
conf_proc('1')
path = f'/{client.app_proc}'
assert 'error' in client.conf_get(f'{path}/max')
assert 'error' in client.conf_get(f'{path}/spare')
assert 'error' in client.conf_get(f'{path}/idle_timeout')
def test_python_processes_invalid():
assert 'error' in client.conf(
{"spare": -1}, client.app_proc
), 'negative spare'
assert 'error' in client.conf({"max": -1}, client.app_proc), 'negative max'
assert 'error' in client.conf(
{"idle_timeout": -1}, client.app_proc
), 'negative idle_timeout'
assert 'error' in client.conf(
{"spare": 2}, client.app_proc
), 'spare gt max default'
assert 'error' in client.conf(
{"spare": 2, "max": 1}, client.app_proc
), 'spare gt max'
assert 'error' in client.conf(
{"spare": 0, "max": 0}, client.app_proc
), 'max zero'
def test_python_restart(temp_dir):
shutil.copyfile(
f'{option.test_dir}/python/restart/v1.py', f'{temp_dir}/wsgi.py'
)
client.load(
temp_dir,
name=client.app_name,
processes=1,
environment={'PYTHONDONTWRITEBYTECODE': '1'},
)
b = client.get()['body']
assert b == "v1", 'process started'
shutil.copyfile(
f'{option.test_dir}/python/restart/v2.py', f'{temp_dir}/wsgi.py'
)
b = client.get()['body']
assert b == "v1", 'still old process'
assert 'success' in client.conf_get(
f'/control/applications/{client.app_name}/restart'
), 'restart processes'
b = client.get()['body']
assert b == "v2", 'new process started'
assert 'error' in client.conf_get(
'/control/applications/blah/restart'
), 'application incorrect'
assert 'error' in client.conf_delete(
f'/control/applications/{client.app_name}/restart'
), 'method incorrect'
def test_python_restart_multi():
conf_proc('2')
pids = pids_for_process()
assert len(pids) == 2, 'restart 2 started'
assert 'success' in client.conf_get(
f'/control/applications/{client.app_name}/restart'
), 'restart processes'
new_pids = pids_for_process()
assert len(new_pids) == 2, 'restart still 2'
assert len(new_pids.intersection(pids)) == 0, 'restart all new'
def test_python_restart_longstart():
client.load(
'restart',
name=client.app_name,
module="longstart",
processes={"spare": 1, "max": 2, "idle_timeout": 5},
)
assert len(pids_for_process()) == 1, 'longstarts == 1'
client.get()
pids = pids_for_process()
assert len(pids) == 2, 'longstarts == 2'
assert 'success' in client.conf_get(
f'/control/applications/{client.app_name}/restart'
), 'restart processes'
# wait for longstarted app
time.sleep(2)
new_pids = pids_for_process()
assert len(new_pids) == 1, 'restart 1'
assert len(new_pids.intersection(pids)) == 0, 'restart all new'