- bin/secop-server options -v and -q applied to console logger only - level for logfile taken from general config - option for automatic deletion of old logfiles - added 'comlog' level (between debug and info) This allows to run the servers by default with 'comlog' level on the logfiles, which helps a lot for analyzing very rare communication errors in retrospect. to avoid spamming of the normal log files, comlog data is stored separately, one file per communicator + redesign of remote logging (no more need of LoggerAdapter) Change-Id: Ie156a202b1e7304e50bbe830901bc75872f6ffe2 Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27427 Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de> Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
276 lines
9.0 KiB
Python
276 lines
9.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
# *****************************************************************************
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify it under
|
|
# the terms of the GNU General Public License as published by the Free Software
|
|
# Foundation; either version 2 of the License, or (at your option) any later
|
|
# version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
# details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along with
|
|
# this program; if not, write to the Free Software Foundation, Inc.,
|
|
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
#
|
|
# Module authors:
|
|
# Markus Zolliker <markus.zolliker@psi.ch>
|
|
#
|
|
# *****************************************************************************
|
|
|
|
import pytest
|
|
import mlzlog
|
|
from secop.modules import Module
|
|
from secop.protocol.dispatcher import Dispatcher
|
|
from secop.protocol.interface import encode_msg_frame, decode_msg
|
|
import secop.logging
|
|
from secop.logging import logger, generalConfig, HasComlog
|
|
|
|
|
|
class ServerStub:
|
|
restart = None
|
|
shutdown = None
|
|
|
|
def __init__(self):
|
|
self.dispatcher = Dispatcher('', logger.log.getChild('dispatcher'), {}, self)
|
|
|
|
|
|
class Connection:
|
|
def __init__(self, name, dispatcher, result):
|
|
self.result = result
|
|
self.dispatcher = dispatcher
|
|
self.name = name
|
|
dispatcher.add_connection(self)
|
|
|
|
def send_reply(self, msg):
|
|
self.result.append(encode_msg_frame(*msg).strip().decode())
|
|
|
|
def send(self, msg):
|
|
request = decode_msg(msg.encode())
|
|
assert self.dispatcher.handle_request(self, request) == request
|
|
|
|
|
|
@pytest.fixture(name='init')
|
|
def init_(monkeypatch):
|
|
logger.__init__()
|
|
|
|
class Playground:
|
|
def __init__(self, console_level='debug', comlog=True, com_module=True):
|
|
self.result_dict = result_dict = dict(
|
|
console=[], comlog=[], conn1=[], conn2=[])
|
|
|
|
class ConsoleHandler(mlzlog.Handler):
|
|
def __init__(self, *args, **kwds):
|
|
super().__init__()
|
|
self.result = result_dict['console']
|
|
|
|
def emit(self, record):
|
|
if record.name != 'frappy.dispatcher':
|
|
self.result.append('%s %s %s' % (record.name, record.levelname, record.getMessage()))
|
|
|
|
class ComLogHandler(mlzlog.Handler):
|
|
def __init__(self, *args, **kwds):
|
|
super().__init__()
|
|
self.result = result_dict['comlog']
|
|
|
|
def emit(self, record):
|
|
self.result.append('%s %s' % (record.name.split('.')[1], record.getMessage()))
|
|
|
|
class LogfileHandler(mlzlog.Handler):
|
|
def __init__(self, *args, **kwds):
|
|
super().__init__()
|
|
|
|
def noop(self, *args):
|
|
pass
|
|
|
|
close = flush = emit = noop
|
|
|
|
monkeypatch.setattr(mlzlog, 'ColoredConsoleHandler', ConsoleHandler)
|
|
monkeypatch.setattr(secop.logging, 'ComLogfileHandler', ComLogHandler)
|
|
monkeypatch.setattr(secop.logging, 'LogfileHandler', LogfileHandler)
|
|
|
|
class Mod(Module):
|
|
result = []
|
|
|
|
def __init__(self, name, srv, **kwds):
|
|
kwds['description'] = ''
|
|
super().__init__(name or 'mod', logger.log.getChild(name), kwds, srv)
|
|
srv.dispatcher.register_module(self, name, name)
|
|
self.result[:] = []
|
|
|
|
def earlyInit(self):
|
|
pass
|
|
|
|
class Com(HasComlog, Mod):
|
|
def __init__(self, name, srv, **kwds):
|
|
super().__init__(name, srv, **kwds)
|
|
self.earlyInit()
|
|
self.log.handlers[-1].result = result_dict['comlog']
|
|
|
|
def communicate(self, request):
|
|
self.comLog('> %s', request)
|
|
|
|
generalConfig.init()
|
|
generalConfig.comlog = comlog
|
|
logger.init(console_level)
|
|
self.srv = ServerStub()
|
|
|
|
self.conn1 = Connection('conn1', self.srv.dispatcher, self.result_dict['conn1'])
|
|
self.conn2 = Connection('conn2', self.srv.dispatcher, self.result_dict['conn2'])
|
|
self.mod = Mod('mod', self.srv)
|
|
self.com = Com('com', self.srv, comlog=com_module)
|
|
for item in self.result_dict.values():
|
|
assert item == []
|
|
|
|
def check(self, both=None, **expected):
|
|
if both:
|
|
expected['conn1'] = expected['conn2'] = both
|
|
assert self.result_dict['console'] == expected.get('console', [])
|
|
assert self.result_dict['comlog'] == expected.get('comlog', [])
|
|
assert self.result_dict['conn1'] == expected.get('conn1', [])
|
|
assert self.result_dict['conn2'] == expected.get('conn2', [])
|
|
for item in self.result_dict.values():
|
|
item[:] = []
|
|
|
|
def comlog(self, flag):
|
|
logger.comlog = flag
|
|
|
|
yield Playground
|
|
# revert settings
|
|
generalConfig.__init__()
|
|
logger.__init__()
|
|
|
|
|
|
def test_mod_info(init):
|
|
p = init()
|
|
p.mod.log.info('i')
|
|
p.check(console=['frappy.mod INFO i'])
|
|
p.conn1.send('logging mod "debug"')
|
|
p.conn2.send('logging mod "info"')
|
|
p.mod.log.info('i')
|
|
p.check(console=['frappy.mod INFO i'], both=['log mod:info "i"'])
|
|
|
|
|
|
def test_mod_debug(init):
|
|
p = init()
|
|
p.mod.log.debug('d')
|
|
p.check(console=['frappy.mod DEBUG d'])
|
|
p.conn1.send('logging mod "debug"')
|
|
p.conn2.send('logging mod "info"')
|
|
p.mod.log.debug('d')
|
|
p.check(console=['frappy.mod DEBUG d'], conn1=['log mod:debug "d"'])
|
|
|
|
|
|
def test_com_info(init):
|
|
p = init()
|
|
p.com.log.info('i')
|
|
p.check(console=['frappy.com INFO i'])
|
|
p.conn1.send('logging com "info"')
|
|
p.conn2.send('logging com "debug"')
|
|
p.com.log.info('i')
|
|
p.check(console=['frappy.com INFO i'], both=['log com:info "i"'])
|
|
|
|
|
|
def test_com_debug(init):
|
|
p = init()
|
|
p.com.log.debug('d')
|
|
p.check(console=['frappy.com DEBUG d'])
|
|
p.conn2.send('logging com "debug"')
|
|
p.com.log.debug('d')
|
|
p.check(console=['frappy.com DEBUG d'], conn2=['log com:debug "d"'])
|
|
|
|
|
|
def test_com_com(init):
|
|
p = init()
|
|
p.com.communicate('x')
|
|
p.check(console=['frappy.com COMLOG > x'], comlog=['com > x'])
|
|
p.conn1.send('logging mod "debug"')
|
|
p.conn2.send('logging mod "info"')
|
|
p.conn2.send('logging com "debug"')
|
|
p.com.communicate('x')
|
|
p.check(console=['frappy.com COMLOG > x'], comlog=['com > x'], conn2=['log com:comlog "> x"'])
|
|
|
|
|
|
def test_main_info(init):
|
|
p = init(console_level='info')
|
|
p.mod.log.debug('d')
|
|
p.com.communicate('x')
|
|
p.check(comlog=['com > x'])
|
|
p.conn1.send('logging mod "debug"')
|
|
p.conn2.send('logging mod "info"')
|
|
p.conn2.send('logging com "debug"')
|
|
p.com.communicate('x')
|
|
p.check(comlog=['com > x'], conn2=['log com:comlog "> x"'])
|
|
|
|
|
|
def test_comlog_off(init):
|
|
p = init(console_level='info', comlog=False)
|
|
p.mod.log.debug('d')
|
|
p.com.communicate('x')
|
|
p.check()
|
|
|
|
|
|
def test_comlog_module_off(init):
|
|
p = init(console_level='info', com_module=False)
|
|
p.mod.log.debug('d')
|
|
p.com.communicate('x')
|
|
p.check()
|
|
|
|
|
|
def test_remote_all_off(init):
|
|
p = init()
|
|
p.conn1.send('logging mod "debug"')
|
|
p.conn2.send('logging mod "info"')
|
|
p.conn2.send('logging com "debug"')
|
|
p.mod.log.debug('d')
|
|
p.com.communicate('x')
|
|
p.mod.log.info('i')
|
|
checks = dict(
|
|
console=['frappy.mod DEBUG d', 'frappy.com COMLOG > x', 'frappy.mod INFO i'],
|
|
comlog=['com > x'],
|
|
conn1=['log mod:debug "d"', 'log mod:info "i"'],
|
|
conn2=['log com:comlog "> x"', 'log mod:info "i"'])
|
|
p.check(**checks)
|
|
p.conn1.send('logging "off"')
|
|
p.mod.log.debug('d')
|
|
p.com.communicate('x')
|
|
p.mod.log.info('i')
|
|
checks.pop('conn1')
|
|
p.check(**checks)
|
|
p.conn2.send('logging . "off"')
|
|
p.mod.log.debug('d')
|
|
p.com.communicate('x')
|
|
p.mod.log.info('i')
|
|
checks.pop('conn2')
|
|
p.check(**checks)
|
|
|
|
|
|
def test_remote_single_off(init):
|
|
p = init()
|
|
p.conn1.send('logging mod "debug"')
|
|
p.conn2.send('logging mod "info"')
|
|
p.conn2.send('logging com "debug"')
|
|
p.mod.log.debug('d')
|
|
p.com.communicate('x')
|
|
p.mod.log.info('i')
|
|
checks = dict(
|
|
console=['frappy.mod DEBUG d', 'frappy.com COMLOG > x', 'frappy.mod INFO i'],
|
|
comlog=['com > x'],
|
|
conn1=['log mod:debug "d"', 'log mod:info "i"'],
|
|
conn2=['log com:comlog "> x"', 'log mod:info "i"'])
|
|
p.check(**checks)
|
|
p.conn2.send('logging com "off"')
|
|
p.mod.log.debug('d')
|
|
p.com.communicate('x')
|
|
p.mod.log.info('i')
|
|
checks['conn2'] = ['log mod:info "i"']
|
|
p.check(**checks)
|
|
p.conn2.send('logging mod "off"')
|
|
p.mod.log.debug('d')
|
|
p.com.communicate('x')
|
|
p.mod.log.info('i')
|
|
checks['conn2'] = []
|
|
p.check(**checks)
|