Skip to content

Commit bf35b98

Browse files
author
Vasileios Karakasis
authored
Merge branch 'master' into feat/extractall_multiple
2 parents 8352b4a + 7348de4 commit bf35b98

File tree

14 files changed

+531
-74
lines changed

14 files changed

+531
-74
lines changed

config/cscs-ci.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
'hostnames': [
5656
'dom'
5757
],
58-
'modules_system': 'tmod4',
58+
'modules_system': 'tmod',
5959
'resourcesdir': '/apps/common/UES/reframe/resources',
6060
'partitions': [
6161
{

config/cscs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@
285285
'hostnames': [
286286
'dom'
287287
],
288-
'modules_system': 'tmod4',
288+
'modules_system': 'tmod',
289289
'resourcesdir': '/apps/common/UES/reframe/resources',
290290
'partitions': [
291291
{

docs/config_reference.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,6 +1111,16 @@ General Configuration
11111111
Purge any loaded environment modules before running any tests.
11121112

11131113

1114+
.. js:attribute:: .general[].report_file
1115+
1116+
:required: No
1117+
:default: ``"${HOME}/.reframe/reports/run-report-{sessionid}.json"``
1118+
1119+
The file where ReFrame will store its report.
1120+
1121+
.. versionadded:: 3.1
1122+
1123+
11141124
.. js:attribute:: .general[].save_log_files
11151125

11161126
:required: No

docs/manpage.rst

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,8 @@ Options controlling ReFrame output
225225
Normally, if the stage directory of a test exists, ReFrame will remove it and recreate it.
226226
This option disables this behavior.
227227

228+
This option can also be set using the :envvar:`RFM_CLEAN_STAGEDIR` environment variable or the :js:attr:`clean_stagedir` general configuration parameter.
229+
228230
.. versionadded:: 3.1
229231

230232
.. option:: --save-log-files
@@ -236,6 +238,16 @@ Options controlling ReFrame output
236238
This option can also be set using the :envvar:`RFM_SAVE_LOG_FILES` environment variable or the :js:attr:`save_log_files` general configuration parameter.
237239

238240

241+
.. option:: --report-file=FILE
242+
243+
The file where ReFrame will store its report.
244+
The ``FILE`` argument may contain the special placeholder ``{sessionid}``, in which case ReFrame will generate a new report each time it is run by appending a counter to the report file.
245+
246+
This option can also be set using the :envvar:`RFM_REPORT_FILE` environment variable or the :js:attr:`report_file` general configuration parameter.
247+
248+
.. versionadded:: 3.1
249+
250+
239251
-------------------------------------
240252
Options controlling ReFrame execution
241253
-------------------------------------
@@ -790,6 +802,21 @@ Here is an alphabetical list of the environment variables recognized by ReFrame:
790802
================================== ==================
791803

792804

805+
.. envvar:: RFM_REPORT_FILE
806+
807+
The file where ReFrame will store its report.
808+
809+
.. versionadded:: 3.1
810+
811+
.. table::
812+
:align: left
813+
814+
================================== ==================
815+
Associated command line option :option:`--report-file`
816+
Associated configuration parameter :js:attr:`report_file` general configuration parameter
817+
================================== ==================
818+
819+
793820
.. envvar:: RFM_SAVE_LOG_FILES
794821

795822
Save ReFrame log files in the output directory before exiting.

docs/tutorial_basics.rst

Lines changed: 80 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -90,28 +90,28 @@ Now it's time to run our first test:
9090
.. code-block:: none
9191
9292
[ReFrame Setup]
93-
version: 3.1-dev0 (rev: 986c3505)
94-
command: './bin/reframe -c tutorials/basics/hello/hello1.py -r'
95-
launched by: user@tresa.local
96-
working directory: '/Users/user/reframe'
93+
version: 3.1-dev2 (rev: 272e1aae)
94+
command: ./bin/reframe -c tutorials/basics/hello/hello1.py -r
95+
launched by: user@dhcp-133-44.cscs.ch
96+
working directory: '/Users/user/Repositories/reframe'
9797
settings file: '<builtin>'
98-
check search path: '/Users/user/reframe/tutorials/basics/hello/hello1.py'
99-
stage directory: '/Users/user/reframe/stage'
100-
output directory: '/Users/user/reframe/output'
98+
check search path: '/Users/user/Repositories/reframe/tutorials/basics/hello/hello1.py'
99+
stage directory: '/Users/user/Repositories/reframe/stage'
100+
output directory: '/Users/user/Repositories/reframe/output'
101101
102102
[==========] Running 1 check(s)
103-
[==========] Started on Sat Jun 20 09:44:52 2020
103+
[==========] Started on Fri Jul 24 11:05:46 2020
104104
105105
[----------] started processing HelloTest (HelloTest)
106106
[ RUN ] HelloTest on generic:default using builtin
107107
[----------] finished processing HelloTest (HelloTest)
108108
109109
[----------] waiting for spawned checks to finish
110-
[ OK ] (1/1) HelloTest on generic:default using builtin [compile: 0.735s run: 0.505s total: 1.272s]
110+
[ OK ] (1/1) HelloTest on generic:default using builtin [compile: 0.378s run: 0.299s total: 0.712s]
111111
[----------] all spawned checks have finished
112112
113113
[ PASSED ] Ran 1 test case(s) from 1 check(s) (0 failure(s))
114-
[==========] Finished on Sat Jun 20 09:44:53 2020
114+
[==========] Finished on Fri Jul 24 11:05:47 2020
115115
116116
117117
Perfect! We have verified that we have a functioning C compiler in our system.
@@ -121,7 +121,7 @@ On successful outcome of the test, the stage directory is removed by default, bu
121121
The prefixes of these directories are printed in the first section of the output.
122122
Let's inspect what files ReFrame produced for this test:
123123

124-
.. code-block:: bash
124+
.. code-block:: console
125125
126126
ls output/generic/default/builtin/HelloTest/
127127
@@ -133,6 +133,75 @@ Let's inspect what files ReFrame produced for this test:
133133
ReFrame stores in the output directory of the test the build and run scripts it generated for building and running the code along with their standard output and error.
134134
All these files are prefixed with ``rfm_``.
135135

136+
ReFrame also generates a detailed JSON report for the whole regression testing session.
137+
By default, this is stored inside the ``${HOME}/.reframe/reports`` directory and a new report file is generated every time ReFrame is run, but you can control this through the :option:`--report-file` command-line option.
138+
139+
Here are the contents of the report file for our first ReFrame run:
140+
141+
142+
.. code-block:: console
143+
144+
cat ~/.reframe/reports/run-report-0.json
145+
146+
.. code-block:: javascript
147+
148+
{
149+
"session_info": {
150+
"cmdline": "./bin/reframe -c tutorials/basics/hello/hello1.py -r",
151+
"config_file": "<builtin>",
152+
"data_version": "1.0",
153+
"hostname": "dhcp-133-44.cscs.ch",
154+
"prefix_output": "/Users/user/Repositories/reframe/output",
155+
"prefix_stage": "/Users/user/Repositories/reframe/stage",
156+
"user": "user",
157+
"version": "3.1-dev2 (rev: 272e1aae)",
158+
"workdir": "/Users/user/Repositories/reframe",
159+
"time_start": "2020-07-24T11:05:46+0200",
160+
"time_end": "2020-07-24T11:05:47+0200",
161+
"time_elapsed": 0.7293069362640381,
162+
"num_cases": 1,
163+
"num_failures": 0
164+
},
165+
"runs": [
166+
{
167+
"num_cases": 1,
168+
"num_failures": 0,
169+
"runid": 0,
170+
"testcases": [
171+
{
172+
"build_stderr": "rfm_HelloTest_build.err",
173+
"build_stdout": "rfm_HelloTest_build.out",
174+
"description": "HelloTest",
175+
"environment": "builtin",
176+
"fail_reason": null,
177+
"fail_phase": null,
178+
"jobid": 85063,
179+
"job_stderr": "rfm_HelloTest_job.err",
180+
"job_stdout": "rfm_HelloTest_job.out",
181+
"name": "HelloTest",
182+
"maintainers": [],
183+
"nodelist": [
184+
"dhcp-133-44.cscs.ch"
185+
],
186+
"outputdir": "/Users/user/Repositories/reframe/output/generic/default/builtin/HelloTest",
187+
"perfvars": null,
188+
"result": "success",
189+
"stagedir": null,
190+
"scheduler": "local",
191+
"system": "generic:default",
192+
"tags": [],
193+
"time_compile": 0.3776402473449707,
194+
"time_performance": 4.506111145019531e-05,
195+
"time_run": 0.2992382049560547,
196+
"time_sanity": 0.0005609989166259766,
197+
"time_setup": 0.0031709671020507812,
198+
"time_total": 0.7213571071624756
199+
}
200+
]
201+
}
202+
]
203+
}
204+
136205
137206
More of "Hello, World!"
138207
-----------------------

reframe/core/pipeline.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -925,6 +925,10 @@ def stderr(self):
925925
'''
926926
return self._job.stderr
927927

928+
@property
929+
def build_job(self):
930+
return self._build_job
931+
928932
@property
929933
@sn.sanity_function
930934
def build_stdout(self):

reframe/core/systems.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,12 +189,12 @@ def json(self):
189189
'container_platforms': [
190190
{
191191
'type': ctype,
192-
'modules': [m.name for m in cpenv.modules],
192+
'modules': [m for m in cpenv.modules],
193193
'variables': [[n, v] for n, v in cpenv.variables.items()]
194194
}
195195
for ctype, cpenv in self._container_environs.items()
196196
],
197-
'modules': [m.name for m in self._local_env.modules],
197+
'modules': [m for m in self._local_env.modules],
198198
'variables': [[n, v]
199199
for n, v in self._local_env.variables.items()],
200200
'environs': [e.name for e in self._environs],

reframe/frontend/cli.py

Lines changed: 83 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import re
1010
import socket
1111
import sys
12+
import time
1213
import traceback
1314

1415
import reframe
@@ -69,6 +70,23 @@ def list_checks(checks, printer, detailed=False):
6970
printer.info('\nFound %d check(s).' % len(checks))
7071

7172

73+
def generate_report_filename(filepatt):
74+
if '{sessionid}' not in filepatt:
75+
return filepatt
76+
77+
search_patt = os.path.basename(filepatt).replace('{sessionid}', r'(\d+)')
78+
new_id = -1
79+
basedir = os.path.dirname(filepatt) or '.'
80+
for filename in os.listdir(basedir):
81+
match = re.match(search_patt, filename)
82+
if match:
83+
found_id = int(match.group(1))
84+
new_id = max(found_id, new_id)
85+
86+
new_id += 1
87+
return filepatt.format(sessionid=new_id)
88+
89+
7290
def main():
7391
# Setup command line options
7492
argparser = argparse.ArgumentParser()
@@ -136,6 +154,12 @@ def main():
136154
help='Save ReFrame log files to the output directory',
137155
envvar='RFM_SAVE_LOG_FILES', configvar='general/save_log_files'
138156
)
157+
output_options.add_argument(
158+
'--report-file', action='store', metavar='FILE',
159+
help="Store JSON run report in FILE",
160+
envvar='RFM_REPORT_FILE',
161+
configvar='general/report_file'
162+
)
139163

140164
# Check discovery options
141165
locate_options.add_argument(
@@ -509,19 +533,33 @@ def print_infoline(param, value):
509533
param = param + ':'
510534
printer.info(f" {param.ljust(18)} {value}")
511535

536+
session_info = {
537+
'cmdline': ' '.join(sys.argv),
538+
'config_file': rt.site_config.filename,
539+
'data_version': '1.0',
540+
'hostname': socket.gethostname(),
541+
'prefix_output': rt.output_prefix,
542+
'prefix_stage': rt.stage_prefix,
543+
'user': os_ext.osuser(),
544+
'version': os_ext.reframe_version(),
545+
'workdir': os.getcwd(),
546+
}
547+
512548
# Print command line
513549
printer.info(f"[ReFrame Setup]")
514-
print_infoline('version', os_ext.reframe_version())
515-
print_infoline('command', repr(' '.join(sys.argv)))
516-
print_infoline('launched by',
517-
f"{os_ext.osuser() or '<unknown>'}@{socket.gethostname()}")
518-
print_infoline('working directory', repr(os.getcwd()))
519-
print_infoline('settings file', f'{site_config.filename!r}')
550+
print_infoline('version', session_info['version'])
551+
print_infoline('command', repr(session_info['cmdline']))
552+
print_infoline(
553+
f"launched by",
554+
f"{session_info['user'] or '<unknown>'}@{session_info['hostname']}"
555+
)
556+
print_infoline('working directory', repr(session_info['workdir']))
557+
print_infoline('settings file', f"{session_info['config_file']!r}")
520558
print_infoline('check search path',
521559
f"{'(R) ' if loader.recurse else ''}"
522560
f"{':'.join(loader.load_path)!r}")
523-
print_infoline('stage directory', repr(rt.stage_prefix))
524-
print_infoline('output directory', repr(rt.output_prefix))
561+
print_infoline('stage directory', repr(session_info['prefix_stage']))
562+
print_infoline('output directory', repr(session_info['prefix_output']))
525563
printer.info('')
526564
try:
527565
# Locate and load checks
@@ -696,8 +734,18 @@ def print_infoline(param, value):
696734
max_retries) from None
697735
runner = Runner(exec_policy, printer, max_retries)
698736
try:
737+
time_start = time.time()
738+
session_info['time_start'] = time.strftime(
739+
'%FT%T%z', time.localtime(time_start),
740+
)
699741
runner.runall(testcases)
700742
finally:
743+
time_end = time.time()
744+
session_info['time_end'] = time.strftime(
745+
'%FT%T%z', time.localtime(time_end)
746+
)
747+
session_info['time_elapsed'] = time_end - time_start
748+
701749
# Print a retry report if we did any retries
702750
if runner.stats.failures(run=0):
703751
printer.info(runner.stats.retry_report())
@@ -712,6 +760,33 @@ def print_infoline(param, value):
712760
if options.performance_report:
713761
printer.info(runner.stats.performance_report())
714762

763+
# Generate the report for this session
764+
report_file = os.path.normpath(
765+
os_ext.expandvars(rt.get_option('general/0/report_file'))
766+
)
767+
basedir = os.path.dirname(report_file)
768+
if basedir:
769+
os.makedirs(basedir, exist_ok=True)
770+
771+
# Build final JSON report
772+
run_stats = runner.stats.json()
773+
session_info.update({
774+
'num_cases': run_stats[0]['num_cases'],
775+
'num_failures': run_stats[-1]['num_failures']
776+
})
777+
json_report = {
778+
'session_info': session_info,
779+
'runs': run_stats
780+
}
781+
report_file = generate_report_filename(report_file)
782+
try:
783+
with open(report_file, 'w') as fp:
784+
json.dump(json_report, fp, indent=2)
785+
except OSError as e:
786+
printer.warning(
787+
f'failed to generate report in {report_file!r}: {e}'
788+
)
789+
715790
else:
716791
printer.error("No action specified. Please specify `-l'/`-L' for "
717792
"listing or `-r' for running. "

0 commit comments

Comments
 (0)