Skip to content

Commit 55d1ff4

Browse files
authored
Merge branch 'master' into bugfix/parameterize-equals
2 parents 74217df + abd5fad commit 55d1ff4

File tree

7 files changed

+63
-16
lines changed

7 files changed

+63
-16
lines changed

reframe/core/logging.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,19 @@ def adjust_verbosity(self, num_steps):
971971

972972
h.setLevel(new_level)
973973

974+
def set_handler_level(self, level, filter=None):
975+
'''Set handler level for handlers attached to this logger.
976+
977+
:arg level: The new level.
978+
:arg filter: A callable accepting a single argument, which is the
979+
handler type as declared in ReFrame's configuration. If the filter
980+
is :obj:`None` then the level applies to all handlers, otherwise
981+
it will apply to all handlers that the filter return :obj:`True`.
982+
'''
983+
for h in self.logger.handlers:
984+
if filter is None or filter(h._rfm_type):
985+
h.setLevel(level)
986+
974987

975988
# A logger that doesn't log anything
976989
null_logger = LoggerAdapter()

reframe/frontend/cli.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import reframe.utility.jsonext as jsonext
2929
import reframe.utility.osext as osext
3030
import reframe.utility.typecheck as typ
31+
from reframe.core.warnings import suppress_deprecations
3132
from reframe.frontend.testgenerators import (distribute_tests,
3233
getallnodes, repeat_tests,
3334
parameterize_tests)
@@ -149,13 +150,18 @@ def describe_checks(testcases, printer):
149150
#
150151
# 1. Add other fields that are relevant for users
151152
# 2. Remove all private fields
152-
rec['name'] = tc.check.name
153-
rec['unique_name'] = tc.check.unique_name
154-
rec['display_name'] = tc.check.display_name
153+
cls = type(tc.check)
154+
if hasattr(cls, 'loggable_attrs'):
155+
for name, alt_name in cls.loggable_attrs():
156+
key = alt_name if alt_name else name
157+
try:
158+
with suppress_deprecations():
159+
rec.setdefault(key, getattr(tc.check, name))
160+
except AttributeError:
161+
rec.setdefault(key, '<undefined>')
162+
155163
rec['pipeline_hooks'] = {}
156164
rec['perf_variables'] = list(rec['perf_variables'].keys())
157-
rec['prefix'] = tc.check.prefix
158-
rec['variant_num'] = tc.check.variant_num
159165
for stage, hooks in tc.check.pipeline_hooks().items():
160166
for hk in hooks:
161167
if hk.__name__ not in tc.check.disabled_hooks:
@@ -1040,6 +1046,8 @@ def restrict_logging():
10401046
if options.describe_stored_sessions:
10411047
# Restore logging level
10421048
printer.setLevel(logging.INFO)
1049+
printer.set_handler_level(logging.WARNING,
1050+
lambda htype: htype != 'stream')
10431051
with exit_gracefully_on_error('failed to retrieve session data',
10441052
printer):
10451053
printer.info(jsonext.dumps(reporting.session_info(
@@ -1050,6 +1058,8 @@ def restrict_logging():
10501058
if options.describe_stored_testcases:
10511059
# Restore logging level
10521060
printer.setLevel(logging.INFO)
1061+
printer.set_handler_level(logging.WARNING,
1062+
lambda htype: htype != 'stream')
10531063
namepatt = '|'.join(n.replace('%', ' %') for n in options.names)
10541064
with exit_gracefully_on_error('failed to retrieve test case data',
10551065
printer):

reframe/frontend/executors/__init__.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -591,8 +591,13 @@ def on_task_success(self, task):
591591
'''Called when a regression test has succeeded.'''
592592

593593

594-
def _handle_sigterm(signum, frame):
595-
raise ForceExitError('received TERM signal')
594+
def _force_exit(signum, frame):
595+
# ReFrame will exit, ignore all other signals that cause a graceful
596+
# termination
597+
signal.signal(signal.SIGINT, signal.SIG_IGN)
598+
signal.signal(signal.SIGHUP, signal.SIG_IGN)
599+
signal.signal(signal.SIGTERM, signal.SIG_IGN)
600+
raise ForceExitError(f'received signal {signum}')
596601

597602

598603
class Runner:
@@ -620,7 +625,8 @@ def __init__(self, policy, printer=None, max_retries=0,
620625
self._policy.printer = self._printer
621626
self._policy.max_failures = max_failures
622627

623-
signal.signal(signal.SIGTERM, _handle_sigterm)
628+
signal.signal(signal.SIGHUP, _force_exit)
629+
signal.signal(signal.SIGTERM, _force_exit)
624630

625631
@property
626632
def max_failures(self):

reframe/frontend/reporting/storage.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ def _db_store_report(self, conn, report, report_file_path):
228228

229229
return session_uuid
230230

231+
@time_function
231232
def store(self, report, report_file=None):
232233
with self._db_lock():
233234
with self._db_connect(self._db_file()) as conn:

unittests/conftest.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import contextlib
1111
import copy
1212
import pytest
13+
import signal
1314
import tempfile
1415

1516
import reframe.core.settings as settings
@@ -105,9 +106,17 @@ def _make_loader(check_search_path, *args, **kwargs):
105106
return _make_loader
106107

107108

109+
@pytest.fixture
110+
def restore_signals():
111+
yield
112+
signal.signal(signal.SIGTERM, signal.SIG_DFL)
113+
signal.signal(signal.SIGINT, signal.SIG_DFL)
114+
signal.signal(signal.SIGHUP, signal.SIG_DFL)
115+
116+
108117
@pytest.fixture(params=[policies.SerialExecutionPolicy,
109118
policies.AsynchronousExecutionPolicy])
110-
def make_runner(request):
119+
def make_runner(request, restore_signals):
111120
'''Test runner with all the execution policies'''
112121

113122
def _make_runner(*args, **kwargs):
@@ -120,7 +129,7 @@ def _make_runner(*args, **kwargs):
120129

121130

122131
@pytest.fixture
123-
def make_async_runner():
132+
def make_async_runner(restore_signals):
124133
def _make_runner(*args, **kwargs):
125134
policy = policies.AsynchronousExecutionPolicy()
126135
policy._pollctl.SLEEP_MIN = 0.001

unittests/resources/checks/frontend_checks.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
#
99

1010
import os
11-
import signal
1211
import sys
1312
import time
1413

@@ -190,10 +189,13 @@ class SelfKillCheck(rfm.RunOnlyRegressionTest, special=True):
190189
executable = 'echo'
191190
sanity_patterns = sn.assert_true(1)
192191

192+
def __init__(self, signum):
193+
self.signum = signum
194+
193195
def run(self):
194196
super().run()
195197
time.sleep(0.5)
196-
os.kill(os.getpid(), signal.SIGTERM)
198+
os.kill(os.getpid(), self.signum)
197199

198200

199201
class CompileFailureCheck(rfm.RegressionTest):

unittests/test_policies.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import contextlib
77
import os
88
import pytest
9+
import signal
910

1011
import reframe as rfm
1112
import reframe.core.runtime as rt
@@ -310,11 +311,16 @@ def test_pass_in_retries(make_runner, make_cases, tmp_path, common_exec_ctx):
310311
assert 0 == len(runner.stats.failed())
311312

312313

313-
def test_sigterm_handling(make_runner, make_cases, common_exec_ctx):
314+
@pytest.fixture(params=[signal.SIGTERM, signal.SIGHUP])
315+
def signum(request):
316+
return request.param
317+
318+
319+
def test_signal_handling(signum, make_runner, make_cases, common_exec_ctx):
314320
runner = make_runner()
315321
with pytest.raises(ForceExitError,
316-
match='received TERM signal'):
317-
runner.runall(make_cases([SelfKillCheck()]))
322+
match=f'received signal {signum}'):
323+
runner.runall(make_cases([SelfKillCheck(signum)]))
318324

319325
assert_all_dead(runner)
320326
assert runner.stats.num_cases() == 1
@@ -442,7 +448,7 @@ def max_jobs_opts(n):
442448

443449

444450
@pytest.fixture
445-
def make_async_runner():
451+
def make_async_runner(restore_signals):
446452
# We need to have control in the unit tests where the policy is created,
447453
# because in some cases we need it to be initialized after the execution
448454
# context. For this reason, we use a constructor fixture here.

0 commit comments

Comments
 (0)