4
4
# SPDX-License-Identifier: BSD-3-Clause
5
5
6
6
import decimal
7
+ import collections
7
8
import functools
8
9
import inspect
9
10
import json
@@ -246,8 +247,8 @@ class RunReport:
246
247
'''
247
248
def __init__ (self ):
248
249
# Initialize the report with the required fields
249
- self .__filename = None
250
- self .__report = {
250
+ self ._filename = None
251
+ self ._report = {
251
252
'session_info' : {
252
253
'data_version' : DATA_VERSION ,
253
254
'hostname' : socket .gethostname (),
@@ -261,16 +262,16 @@ def __init__(self):
261
262
262
263
@property
263
264
def filename (self ):
264
- return self .__filename
265
+ return self ._filename
265
266
266
267
def __getattr__ (self , name ):
267
- return getattr (self .__report , name )
268
+ return getattr (self ._report , name )
268
269
269
270
def __getitem__ (self , key ):
270
- return self .__report [key ]
271
+ return self ._report [key ]
271
272
272
273
def __rfm_json_encode__ (self ):
273
- return self .__report
274
+ return self ._report
274
275
275
276
@classmethod
276
277
def create_from_perflog (cls , * logfiles , format = None ,
@@ -393,23 +394,60 @@ def _convert(x):
393
394
'run_index' : run_index ,
394
395
'testcases' : testcases
395
396
})
396
- return report
397
+ return [report ]
398
+
399
+ @classmethod
400
+ def create_from_sqlite_db (cls , * dbfiles , exclude_sessions = None ,
401
+ include_sessions = None , time_period = None ):
402
+ dst_backend = StorageBackend .default ()
403
+ dst_schema = dst_backend .schema_version ()
404
+ if not time_period :
405
+ time_period = {'start' : '19700101T0000+0000' , 'end' : 'now' }
406
+
407
+ start = time_period .get ('start' , '19700101T0000+0000' )
408
+ end = time_period .get ('end' , 'now' )
409
+ ts_start , ts_end = parse_time_period (f'{ start } :{ end } ' )
410
+ include_sessions = set (include_sessions ) if include_sessions else set ()
411
+ exclude_sessions = set (exclude_sessions ) if exclude_sessions else set ()
412
+ reports = []
413
+ for filename in dbfiles :
414
+ src_backend = StorageBackend .create ('sqlite' , filename )
415
+ src_schema = src_backend .schema_version ()
416
+ if src_schema != dst_schema :
417
+ getlogger ().warning (
418
+ f'ignoring DB file { filename } : schema version mismatch: '
419
+ f'cannot import from DB v{ src_schema } to v{ dst_schema } '
420
+ )
421
+ continue
422
+
423
+ sessions = src_backend .fetch_sessions_time_period (ts_start , ts_end )
424
+ for sess in sessions :
425
+ uuid = sess ['session_info' ]['uuid' ]
426
+ if include_sessions and uuid not in include_sessions :
427
+ continue
428
+
429
+ if exclude_sessions and uuid in exclude_sessions :
430
+ continue
431
+
432
+ reports .append (_ImportedRunReport (sess ))
433
+
434
+ return reports
397
435
398
436
def _add_run (self , run ):
399
- self .__report ['runs' ].append (run )
437
+ self ._report ['runs' ].append (run )
400
438
401
439
def update_session_info (self , session_info ):
402
440
# Remove timestamps
403
441
for key , val in session_info .items ():
404
442
if not key .startswith ('time_' ):
405
- self .__report ['session_info' ][key ] = val
443
+ self ._report ['session_info' ][key ] = val
406
444
407
445
def update_restored_cases (self , restored_cases , restored_session ):
408
- self .__report ['restored_cases' ] = [restored_session .case (c )
409
- for c in restored_cases ]
446
+ self ._report ['restored_cases' ] = [restored_session .case (c )
447
+ for c in restored_cases ]
410
448
411
449
def update_timestamps (self , ts_start , ts_end ):
412
- self .__report ['session_info' ].update ({
450
+ self ._report ['session_info' ].update ({
413
451
'time_start' : time .strftime (_DATETIME_FMT ,
414
452
time .localtime (ts_start )),
415
453
'time_start_unix' : ts_start ,
@@ -426,10 +464,10 @@ def update_extras(self, extras):
426
464
raise ValueError ('cannot use reserved keys '
427
465
f'`{ "," .join (clashed_keys )} ` as session extras' )
428
466
429
- self .__report ['session_info' ].update (extras )
467
+ self ._report ['session_info' ].update (extras )
430
468
431
469
def update_run_stats (self , stats ):
432
- session_uuid = self .__report ['session_info' ]['uuid' ]
470
+ session_uuid = self ._report ['session_info' ]['uuid' ]
433
471
for runidx , tasks in stats .runs ():
434
472
testcases = []
435
473
num_failures = 0
@@ -530,7 +568,7 @@ def update_run_stats(self, stats):
530
568
531
569
testcases .append (entry )
532
570
533
- self .__report ['runs' ].append ({
571
+ self ._report ['runs' ].append ({
534
572
'num_cases' : len (tasks ),
535
573
'num_failures' : num_failures ,
536
574
'num_aborted' : num_aborted ,
@@ -540,23 +578,23 @@ def update_run_stats(self, stats):
540
578
})
541
579
542
580
# Update session info from stats
543
- self .__report ['session_info' ].update ({
544
- 'num_cases' : self .__report ['runs' ][0 ]['num_cases' ],
545
- 'num_failures' : self .__report ['runs' ][- 1 ]['num_failures' ],
546
- 'num_aborted' : self .__report ['runs' ][- 1 ]['num_aborted' ],
547
- 'num_skipped' : self .__report ['runs' ][- 1 ]['num_skipped' ]
581
+ self ._report ['session_info' ].update ({
582
+ 'num_cases' : self ._report ['runs' ][0 ]['num_cases' ],
583
+ 'num_failures' : self ._report ['runs' ][- 1 ]['num_failures' ],
584
+ 'num_aborted' : self ._report ['runs' ][- 1 ]['num_aborted' ],
585
+ 'num_skipped' : self ._report ['runs' ][- 1 ]['num_skipped' ]
548
586
})
549
587
550
588
def _save (self , filename , compress , link_to_last ):
551
589
filename = _expand_report_filename (filename , newfile = True )
552
590
with open (filename , 'w' ) as fp :
553
591
if compress :
554
- jsonext .dump (self .__report , fp )
592
+ jsonext .dump (self ._report , fp )
555
593
else :
556
- jsonext .dump (self .__report , fp , indent = 2 )
594
+ jsonext .dump (self ._report , fp , indent = 2 )
557
595
fp .write ('\n ' )
558
596
559
- self .__filename = filename
597
+ self ._filename = filename
560
598
if not link_to_last :
561
599
return
562
600
@@ -576,7 +614,7 @@ def _save(self, filename, compress, link_to_last):
576
614
577
615
def is_empty (self ):
578
616
'''Return :obj:`True` is no test cases where run'''
579
- return self .__report ['session_info' ]['num_cases' ] == 0
617
+ return self ._report ['session_info' ]['num_cases' ] == 0
580
618
581
619
def save (self , filename , compress = False , link_to_last = True ):
582
620
prefix = os .path .dirname (filename ) or '.'
@@ -591,7 +629,7 @@ def store(self):
591
629
def generate_xml_report (self ):
592
630
'''Generate a JUnit report from a standard ReFrame JSON report.'''
593
631
594
- report = self .__report
632
+ report = self ._report
595
633
xml_testsuites = etree .Element ('testsuites' )
596
634
# Create a XSD-friendly timestamp
597
635
session_ts = time .strftime (
@@ -688,6 +726,30 @@ def __missing__(self, key):
688
726
raise KeyError (key )
689
727
690
728
729
+ class _ImportedRunReport (RunReport ):
730
+ def __init__ (self , report ):
731
+ self ._filename = f'{ report ["session_info" ]["uuid" ]} .json'
732
+ self ._report = report
733
+
734
+ def _add_run (self , run ):
735
+ raise NotImplementedError
736
+
737
+ def update_session_info (self , session_info ):
738
+ raise NotImplementedError
739
+
740
+ def update_restored_cases (self , restored_cases , restored_session ):
741
+ raise NotImplementedError
742
+
743
+ def update_timestamps (self , ts_start , ts_end ):
744
+ raise NotImplementedError
745
+
746
+ def update_extras (self , extras ):
747
+ raise NotImplementedError
748
+
749
+ def update_run_stats (self , stats ):
750
+ raise NotImplementedError
751
+
752
+
691
753
def _group_key (groups , testcase : _TCProxy ):
692
754
key = []
693
755
for grp in groups :
0 commit comments