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:
@@ -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
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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')
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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')
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
23
test/unit/log.py
Normal 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
|
||||
Reference in New Issue
Block a user