Tests: preserving unit.log when run without restart.

Introducing "unit.log.Log" class for "unit.log" file management.
Moving "findall()" function into TestApplicationProto.
Using "os.kill()" to send signals.
This commit is contained in:
Max Romanov
2021-04-08 19:11:11 +03:00
parent 30922c5741
commit 74b1b1fc17
9 changed files with 94 additions and 96 deletions

View File

@@ -22,6 +22,7 @@ from unit.check.regex import check_regex
from unit.check.tls import check_openssl
from unit.http import TestHTTP
from unit.option import option
from unit.log import Log
from unit.utils import public_dir
from unit.utils import waitforfiles
@@ -71,7 +72,6 @@ def pytest_addoption(parser):
unit_instance = {}
unit_log_copy = "unit.log.copy"
_processes = []
_fds_check = {
'main': {'fds': 0, 'skip': False},
@@ -165,12 +165,11 @@ def pytest_sessionstart(session):
option.available = {'modules': {}, 'features': {}}
unit = unit_run()
option.temp_dir = unit['temp_dir']
# read unit.log
for i in range(50):
with open(unit['temp_dir'] + '/unit.log', 'r') as f:
with open(Log.get_path(), 'r') as f:
log = f.read()
m = re.search('controller started', log)
@@ -216,9 +215,6 @@ def pytest_sessionstart(session):
if option.restart:
shutil.rmtree(unit_instance['temp_dir'])
elif option.save_log:
open(unit_instance['temp_dir'] + '/' + unit_log_copy, 'w').close()
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
@@ -269,7 +265,6 @@ def check_prerequisites(request):
@pytest.fixture(autouse=True)
def run(request):
unit = unit_run()
option.temp_dir = unit['temp_dir']
option.skip_alerts = [
r'read signalfd\(4\) failed',
@@ -291,34 +286,25 @@ def run(request):
# prepare log
with open(
unit_instance['log'], 'r', encoding='utf-8', errors='ignore'
) as f:
with Log.open(encoding='utf-8') as f:
log = f.read()
if not option.restart and option.save_log:
with open(unit_instance['temp_dir'] + '/' + unit_log_copy, 'a') as f:
f.write(log)
# remove unit.log
Log.set_pos(f.tell())
if not option.save_log and option.restart:
shutil.rmtree(unit['temp_dir'])
Log.set_pos(0)
# clean temp_dir before the next test
if not option.restart:
_clear_conf(unit['temp_dir'] + '/control.unit.sock', log)
open(unit['log'], 'w').close()
for item in os.listdir(unit['temp_dir']):
if item not in [
'control.unit.sock',
'state',
'unit.pid',
'unit.log',
unit_log_copy,
]:
path = os.path.join(unit['temp_dir'], item)
@@ -439,10 +425,12 @@ def unit_run():
exit('Could not start unit')
unit_instance['temp_dir'] = temp_dir
unit_instance['log'] = temp_dir + '/unit.log'
unit_instance['control_sock'] = temp_dir + '/control.unit.sock'
unit_instance['unitd'] = unitd
option.temp_dir = temp_dir
Log.temp_dir = temp_dir
with open(temp_dir + '/unit.pid', 'r') as f:
unit_instance['pid'] = f.read().rstrip()
@@ -489,12 +477,9 @@ def unit_stop():
return 'Could not terminate unit'
def _check_alerts(path=None, log=None):
if path is None:
path = unit_instance['log']
def _check_alerts(log=None):
if log is None:
with open(path, 'r', encoding='utf-8', errors='ignore') as f:
with Log.open(encoding='utf-8') as f:
log = f.read()
found = False
@@ -526,7 +511,7 @@ def _check_alerts(path=None, log=None):
def _print_log(data=None):
path = unit_instance['log']
path = Log.get_path()
print('Path to unit.log:\n' + path + '\n')
@@ -679,7 +664,7 @@ def unit_pid(request):
def pytest_sessionfinish(session):
if not option.restart and option.save_log:
print('Path to unit.log:\n' + unit_instance['log'] + '\n')
print('Path to unit.log:\n' + Log.get_path() + '\n')
option.restart = True

View File

@@ -249,7 +249,7 @@ Connection: close
assert self.search_in_log(r'/delete', 'access.log') is None, 'delete'
def test_access_log_change(self, temp_dir):
def test_access_log_change(self):
self.load('empty')
self.get()

View File

@@ -14,10 +14,6 @@ class TestASGIApplication(TestApplicationPython):
}
load_module = 'asgi'
def findall(self, pattern):
with open(option.temp_dir + '/unit.log', 'r', errors='ignore') as f:
return re.findall(pattern, f.read())
def test_asgi_application_variables(self):
self.load('variables')

View File

@@ -1,8 +1,8 @@
import os
import re
import shutil
import signal
import time
from subprocess import call
import pytest
@@ -95,37 +95,29 @@ class TestPHPApplication(TestApplicationPHP):
assert resp['status'] == 200, 'query string empty status'
assert resp['headers']['Query-String'] == '', 'query string empty'
def test_php_application_fastcgi_finish_request(self, temp_dir):
def test_php_application_fastcgi_finish_request(self, unit_pid):
self.load('fastcgi_finish_request')
assert self.get()['body'] == '0123'
with open(temp_dir + '/unit.pid', 'r') as f:
pid = f.read().rstrip()
os.kill(unit_pid, signal.SIGUSR1);
call(['kill', '-s', 'USR1', pid])
errs = self.findall(r'Error in fastcgi_finish_request')
with open(temp_dir + '/unit.log', 'r', errors='ignore') as f:
errs = re.findall(r'Error in fastcgi_finish_request', f.read())
assert len(errs) == 0, 'no error'
assert len(errs) == 0, 'no error'
def test_php_application_fastcgi_finish_request_2(self, temp_dir):
def test_php_application_fastcgi_finish_request_2(self, unit_pid):
self.load('fastcgi_finish_request')
resp = self.get(url='/?skip')
assert resp['status'] == 200
assert resp['body'] == ''
with open(temp_dir + '/unit.pid', 'r') as f:
pid = f.read().rstrip()
os.kill(unit_pid, signal.SIGUSR1);
call(['kill', '-s', 'USR1', pid])
errs = self.findall(r'Error in fastcgi_finish_request')
with open(temp_dir + '/unit.log', 'r', errors='ignore') as f:
errs = re.findall(r'Error in fastcgi_finish_request', f.read())
assert len(errs) == 0, 'no error'
assert len(errs) == 0, 'no error'
def test_php_application_query_string_absent(self):
self.load('query_string')
@@ -538,7 +530,7 @@ class TestPHPApplication(TestApplicationPHP):
r'012345', self.get()['body']
), 'disable_classes before'
def test_php_application_error_log(self, temp_dir):
def test_php_application_error_log(self):
self.load('error_log')
assert self.get()['status'] == 200, 'status'
@@ -551,14 +543,13 @@ class TestPHPApplication(TestApplicationPHP):
assert self.wait_for_record(pattern) is not None, 'errors print'
with open(temp_dir + '/unit.log', 'r', errors='ignore') as f:
errs = re.findall(pattern, f.read())
errs = self.findall(pattern)
assert len(errs) == 2, 'error_log count'
assert len(errs) == 2, 'error_log count'
date = errs[0].split('[')[0]
date2 = errs[1].split('[')[0]
assert date != date2, 'date diff'
date = errs[0].split('[')[0]
date2 = errs[1].split('[')[0]
assert date != date2, 'date diff'
def test_php_application_script(self):
assert 'success' in self.conf(

View File

@@ -7,16 +7,11 @@ import time
import pytest
from unit.applications.lang.python import TestApplicationPython
from unit.option import option
class TestPythonApplication(TestApplicationPython):
prerequisites = {'modules': {'python': 'all'}}
def findall(self, pattern):
with open(option.temp_dir + '/unit.log', 'r', errors='ignore') as f:
return re.findall(pattern, f.read())
def test_python_application_variables(self):
self.load('variables')

View File

@@ -6,16 +6,11 @@ import subprocess
import pytest
from unit.applications.tls import TestApplicationTLS
from unit.option import option
class TestTLS(TestApplicationTLS):
prerequisites = {'modules': {'python': 'any', 'openssl': 'any'}}
def findall(self, pattern):
with open(option.temp_dir + '/unit.log', 'r', errors='ignore') as f:
return re.findall(pattern, f.read())
def openssl_date_to_sec_epoch(self, date):
return self.date_to_sec_epoch(date, '%b %d %H:%M:%S %Y %Z')

View File

@@ -1,14 +1,15 @@
import os
from subprocess import call
import signal
from unit.applications.lang.python import TestApplicationPython
from unit.log import Log
from unit.utils import waitforfiles
class TestUSR1(TestApplicationPython):
prerequisites = {'modules': {'python': 'any'}}
def test_usr1_access_log(self, temp_dir):
def test_usr1_access_log(self, temp_dir, unit_pid):
self.load('empty')
log = 'access.log'
@@ -31,10 +32,7 @@ class TestUSR1(TestApplicationPython):
), 'rename new'
assert not os.path.isfile(log_path), 'rename old'
with open(temp_dir + '/unit.pid', 'r') as f:
pid = f.read().rstrip()
call(['kill', '-s', 'USR1', pid])
os.kill(unit_pid, signal.SIGUSR1)
assert waitforfiles(log_path), 'reopen'
@@ -46,7 +44,7 @@ class TestUSR1(TestApplicationPython):
), 'reopen 2'
assert self.search_in_log(r'/usr1', log_new) is None, 'rename new 2'
def test_usr1_unit_log(self, temp_dir):
def test_usr1_unit_log(self, temp_dir, unit_pid):
self.load('log_body')
log_new = 'new.log'
@@ -55,28 +53,37 @@ class TestUSR1(TestApplicationPython):
os.rename(log_path, log_path_new)
body = 'body_for_a_log_new'
assert self.post(body=body)['status'] == 200
Log.swap(log_new)
assert self.wait_for_record(body, log_new) is not None, 'rename new'
assert not os.path.isfile(log_path), 'rename old'
try:
body = 'body_for_a_log_new\n'
assert self.post(body=body)['status'] == 200
with open(temp_dir + '/unit.pid', 'r') as f:
pid = f.read().rstrip()
assert (
self.wait_for_record(body, log_new) is not None
), 'rename new'
assert not os.path.isfile(log_path), 'rename old'
call(['kill', '-s', 'USR1', pid])
os.kill(unit_pid, signal.SIGUSR1)
assert waitforfiles(log_path), 'reopen'
assert waitforfiles(log_path), 'reopen'
body = 'body_for_a_log_unit'
assert self.post(body=body)['status'] == 200
body = 'body_for_a_log_unit\n'
assert self.post(body=body)['status'] == 200
assert self.wait_for_record(body) is not None, 'rename new'
assert self.search_in_log(body, log_new) is None, 'rename new 2'
assert self.wait_for_record(body) is not None, 'rename new'
assert self.search_in_log(body, log_new) is None, 'rename new 2'
# merge two log files into unit.log to check alerts
finally:
# merge two log files into unit.log to check alerts
with open(log_path, 'w') as unit_log, open(
log_path_new, 'r'
) as unit_log_new:
unit_log.write(unit_log_new.read())
with open(log_path, 'r', errors='ignore') as unit_log:
log = unit_log.read()
with open(log_path, 'w') as unit_log, open(
log_path_new, 'r', errors='ignore'
) as unit_log_new:
unit_log.write(unit_log_new.read())
unit_log.write(log)
Log.swap(log_new)

View File

@@ -4,6 +4,7 @@ import time
from unit.control import TestControl
from unit.option import option
from unit.log import Log
class TestApplicationProto(TestControl):
@@ -15,18 +16,23 @@ class TestApplicationProto(TestControl):
def date_to_sec_epoch(self, date, template='%a, %d %b %Y %H:%M:%S %Z'):
return time.mktime(time.strptime(date, template))
def findall(self, pattern, name='unit.log'):
with Log.open(name) as f:
return re.findall(pattern, f.read())
def search_in_log(self, pattern, name='unit.log'):
with open(option.temp_dir + '/' + name, 'r', errors='ignore') as f:
with Log.open(name) as f:
return re.search(pattern, f.read())
def wait_for_record(self, pattern, name='unit.log', wait=150):
for i in range(wait):
found = self.search_in_log(pattern, name)
with Log.open(name) as f:
for i in range(wait):
found = re.search(pattern, f.read())
if found is not None:
break
if found is not None:
break
time.sleep(0.1)
time.sleep(0.1)
return found

23
test/unit/log.py Normal file
View File

@@ -0,0 +1,23 @@
UNIT_LOG = 'unit.log'
class Log:
temp_dir = None
pos = {}
def open(name=UNIT_LOG, encoding=None):
f = open(Log.get_path(name), 'r', encoding=encoding, errors='ignore')
f.seek(Log.pos.get(name, 0))
return f
def set_pos(pos, name=UNIT_LOG):
Log.pos[name] = pos
def swap(name):
pos = Log.pos.get(UNIT_LOG, 0)
Log.pos[UNIT_LOG] = Log.pos.get(name, 0)
Log.pos[name] = pos
def get_path(name=UNIT_LOG):
return Log.temp_dir + '/' + name