Group results by device instead of test
This commit is contained in:
parent
503e6f2b42
commit
4c0bb1c9b7
1 changed files with 87 additions and 52 deletions
|
|
@ -79,7 +79,7 @@ class CpuObj():
|
||||||
"""Object for tracking CPU specific data."""
|
"""Object for tracking CPU specific data."""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.lscpu = {}
|
self.lscpu = {}
|
||||||
self.tests = {}
|
self.tests = OrderedDict()
|
||||||
self.get_details()
|
self.get_details()
|
||||||
self.name = self.lscpu.get('Model name', 'Unknown CPU')
|
self.name = self.lscpu.get('Model name', 'Unknown CPU')
|
||||||
|
|
||||||
|
|
@ -102,6 +102,18 @@ class CpuObj():
|
||||||
continue
|
continue
|
||||||
self.lscpu[_field] = _data
|
self.lscpu[_field] = _data
|
||||||
|
|
||||||
|
def generate_cpu_report(self):
|
||||||
|
"""Generate CPU report with data from all tests."""
|
||||||
|
report = []
|
||||||
|
report.append('{BLUE}Device{CLEAR}'.format(**COLORS))
|
||||||
|
report.append(' {}'.format(self.name))
|
||||||
|
|
||||||
|
# Tests
|
||||||
|
for test in self.tests.values():
|
||||||
|
report.extend(test.report)
|
||||||
|
|
||||||
|
return report
|
||||||
|
|
||||||
class DiskObj():
|
class DiskObj():
|
||||||
"""Object for tracking disk specific data."""
|
"""Object for tracking disk specific data."""
|
||||||
def __init__(self, disk_path):
|
def __init__(self, disk_path):
|
||||||
|
|
@ -115,9 +127,10 @@ class DiskObj():
|
||||||
self.smart_self_test = {}
|
self.smart_self_test = {}
|
||||||
self.smartctl = {}
|
self.smartctl = {}
|
||||||
self.tests = OrderedDict()
|
self.tests = OrderedDict()
|
||||||
|
self.warnings = []
|
||||||
self.get_details()
|
self.get_details()
|
||||||
self.get_smart_details()
|
self.get_smart_details()
|
||||||
self.description = '{size:>6} ({tran}) {model} {serial}'.format(
|
self.description = '{size} ({tran}) {model} {serial}'.format(
|
||||||
**self.lsblk)
|
**self.lsblk)
|
||||||
|
|
||||||
def check_attributes(self, silent=False):
|
def check_attributes(self, silent=False):
|
||||||
|
|
@ -159,8 +172,8 @@ class DiskObj():
|
||||||
print_standard(' (Have you tried swapping the disk cable?)')
|
print_standard(' (Have you tried swapping the disk cable?)')
|
||||||
else:
|
else:
|
||||||
# Override?
|
# Override?
|
||||||
show_report(self.generate_report())
|
show_report(self.generate_attribute_report(description=True))
|
||||||
print_warning('{} error(s) detected.'.format(attr_type))
|
print_warning(' {} error(s) detected.'.format(attr_type))
|
||||||
if override_disabled:
|
if override_disabled:
|
||||||
print_standard('Tests disabled for this device')
|
print_standard('Tests disabled for this device')
|
||||||
pause()
|
pause()
|
||||||
|
|
@ -172,13 +185,15 @@ class DiskObj():
|
||||||
if self.nvme_attributes or not self.smart_attributes:
|
if self.nvme_attributes or not self.smart_attributes:
|
||||||
# i.e. only leave enabled for SMART short-tests
|
# i.e. only leave enabled for SMART short-tests
|
||||||
self.tests['NVMe / SMART'].disabled = True
|
self.tests['NVMe / SMART'].disabled = True
|
||||||
|
print_standard(' ')
|
||||||
|
|
||||||
def generate_report(self, brief=False, short_test=False):
|
def generate_attribute_report(
|
||||||
|
self, description=False, short_test=False, timestamp=False):
|
||||||
"""Generate NVMe / SMART report, returns list."""
|
"""Generate NVMe / SMART report, returns list."""
|
||||||
report = []
|
report = []
|
||||||
if not brief:
|
if description:
|
||||||
report.append('{BLUE}Device: {dev_path}{CLEAR}'.format(
|
report.append('{BLUE}Device ({name}){CLEAR}'.format(
|
||||||
dev_path=self.path, **COLORS))
|
name=self.name, **COLORS))
|
||||||
report.append(' {}'.format(self.description))
|
report.append(' {}'.format(self.description))
|
||||||
|
|
||||||
# Warnings
|
# Warnings
|
||||||
|
|
@ -203,8 +218,8 @@ class DiskObj():
|
||||||
# Attributes
|
# Attributes
|
||||||
report.append('{BLUE}{a} Attributes{YELLOW}{u:>23} {t}{CLEAR}'.format(
|
report.append('{BLUE}{a} Attributes{YELLOW}{u:>23} {t}{CLEAR}'.format(
|
||||||
a=attr_type,
|
a=attr_type,
|
||||||
u='Updated:' if brief else '',
|
u='Updated:' if timestamp else '',
|
||||||
t=time.strftime('%Y-%m-%d %H:%M %Z') if brief else '',
|
t=time.strftime('%Y-%m-%d %H:%M %Z') if timestamp else '',
|
||||||
**COLORS))
|
**COLORS))
|
||||||
if self.nvme_attributes:
|
if self.nvme_attributes:
|
||||||
attr_type = 'NVMe'
|
attr_type = 'NVMe'
|
||||||
|
|
@ -259,6 +274,21 @@ class DiskObj():
|
||||||
# Done
|
# Done
|
||||||
return report
|
return report
|
||||||
|
|
||||||
|
def generate_disk_report(self):
|
||||||
|
"""Generate disk report with data from all tests."""
|
||||||
|
report = []
|
||||||
|
report.append('{BLUE}Device ({name}){CLEAR}'.format(
|
||||||
|
name=self.name, **COLORS))
|
||||||
|
report.append(' {}'.format(self.description))
|
||||||
|
for w in self.warnings:
|
||||||
|
report.append(' {YELLOW}{w}{CLEAR}'.format(w=w, **COLORS))
|
||||||
|
|
||||||
|
# Tests
|
||||||
|
for test in self.tests.values():
|
||||||
|
report.extend(test.report)
|
||||||
|
|
||||||
|
return report
|
||||||
|
|
||||||
def get_details(self):
|
def get_details(self):
|
||||||
"""Get data from lsblk."""
|
"""Get data from lsblk."""
|
||||||
cmd = ['lsblk', '--json', '--output-all', '--paths', self.path]
|
cmd = ['lsblk', '--json', '--output-all', '--paths', self.path]
|
||||||
|
|
@ -338,14 +368,14 @@ class DiskObj():
|
||||||
|
|
||||||
# Check if a self-test is currently running
|
# Check if a self-test is currently running
|
||||||
if 'remaining_percent' in self.smart_self_test['status']:
|
if 'remaining_percent' in self.smart_self_test['status']:
|
||||||
_msg='SMART self-test in progress, all tests disabled'
|
_msg = 'SMART self-test in progress, all tests disabled'
|
||||||
if not silent:
|
if not silent:
|
||||||
print_warning('WARNING: {}'.format(_msg))
|
print_warning('WARNING: {}'.format(_msg))
|
||||||
print_standard(' ')
|
print_standard(' ')
|
||||||
if ask('Abort HW Diagnostics?'):
|
if ask('Abort HW Diagnostics?'):
|
||||||
exit_script()
|
exit_script()
|
||||||
if 'NVMe / SMART' in self.tests:
|
if 'NVMe / SMART' in self.tests:
|
||||||
self.tests['NVMe / SMART'].report = self.generate_report()
|
self.tests['NVMe / SMART'].report = self.generate_attribute_report()
|
||||||
self.tests['NVMe / SMART'].report.append(
|
self.tests['NVMe / SMART'].report.append(
|
||||||
'{YELLOW}WARNING: {msg}{CLEAR}'.format(msg=_msg, **COLORS))
|
'{YELLOW}WARNING: {msg}{CLEAR}'.format(msg=_msg, **COLORS))
|
||||||
for t in self.tests.values():
|
for t in self.tests.values():
|
||||||
|
|
@ -359,17 +389,20 @@ class DiskObj():
|
||||||
if silent:
|
if silent:
|
||||||
self.disk_ok = HW_OVERRIDES_FORCED
|
self.disk_ok = HW_OVERRIDES_FORCED
|
||||||
else:
|
else:
|
||||||
print_warning(
|
_msg = 'No NVMe or SMART data available'
|
||||||
' WARNING: No NVMe or SMART attributes available for: {}'.format(
|
self.warnings.append(_msg)
|
||||||
self.path))
|
print_info('Device ({})'.format(self.name))
|
||||||
|
print_standard(' {}'.format(self.description))
|
||||||
|
print_warning(' {}'.format(_msg))
|
||||||
self.disk_ok = HW_OVERRIDES_FORCED or ask(
|
self.disk_ok = HW_OVERRIDES_FORCED or ask(
|
||||||
'Run tests on this device anyway?')
|
'Run tests on this device anyway?')
|
||||||
|
print_standard(' ')
|
||||||
|
|
||||||
if not self.disk_ok:
|
if not self.disk_ok:
|
||||||
if 'NVMe / SMART' in self.tests:
|
if 'NVMe / SMART' in self.tests:
|
||||||
# NOTE: This will not overwrite the existing status if set
|
# NOTE: This will not overwrite the existing status if set
|
||||||
if not self.tests['NVMe / SMART'].report:
|
if not self.tests['NVMe / SMART'].report:
|
||||||
self.tests['NVMe / SMART'].report = self.generate_report()
|
self.tests['NVMe / SMART'].report = self.generate_attribute_report()
|
||||||
self.tests['NVMe / SMART'].update_status('NS')
|
self.tests['NVMe / SMART'].update_status('NS')
|
||||||
self.tests['NVMe / SMART'].disabled = True
|
self.tests['NVMe / SMART'].disabled = True
|
||||||
for t in ['badblocks', 'I/O Benchmark']:
|
for t in ['badblocks', 'I/O Benchmark']:
|
||||||
|
|
@ -743,7 +776,7 @@ def run_badblocks_test(state, test):
|
||||||
|
|
||||||
# Show disk details
|
# Show disk details
|
||||||
clear_screen()
|
clear_screen()
|
||||||
show_report(test.dev.generate_report())
|
show_report(test.dev.generate_attribute_report())
|
||||||
print_standard(' ')
|
print_standard(' ')
|
||||||
|
|
||||||
# Start badblocks
|
# Start badblocks
|
||||||
|
|
@ -757,6 +790,7 @@ def run_badblocks_test(state, test):
|
||||||
raise GenericAbort('Aborted')
|
raise GenericAbort('Aborted')
|
||||||
|
|
||||||
# Check result and create report
|
# Check result and create report
|
||||||
|
test.report.append('{BLUE}badblocks{CLEAR}'.format(**COLORS))
|
||||||
try:
|
try:
|
||||||
test.badblocks_out = test.badblocks_proc.stdout.read().decode()
|
test.badblocks_out = test.badblocks_proc.stdout.read().decode()
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
|
|
@ -787,7 +821,6 @@ def run_badblocks_test(state, test):
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
tmux_kill_pane(state.panes['badblocks'])
|
tmux_kill_pane(state.panes['badblocks'])
|
||||||
pause()
|
|
||||||
|
|
||||||
def run_hw_tests(state):
|
def run_hw_tests(state):
|
||||||
"""Run enabled hardware tests."""
|
"""Run enabled hardware tests."""
|
||||||
|
|
@ -825,15 +858,6 @@ def run_hw_tests(state):
|
||||||
for disk in state.disks:
|
for disk in state.disks:
|
||||||
disk.safety_check(silent=state.quick_mode)
|
disk.safety_check(silent=state.quick_mode)
|
||||||
|
|
||||||
# TODO Remove
|
|
||||||
clear_screen()
|
|
||||||
print_info('Running tests:')
|
|
||||||
for k, v in state.tests.items():
|
|
||||||
if v['Enabled']:
|
|
||||||
print_standard(' {}'.format(k))
|
|
||||||
update_progress_pane(state)
|
|
||||||
pause()
|
|
||||||
|
|
||||||
# Run tests
|
# Run tests
|
||||||
## Because state.tests is an OrderedDict and the disks were added
|
## Because state.tests is an OrderedDict and the disks were added
|
||||||
## in order, the tests will be run in order.
|
## in order, the tests will be run in order.
|
||||||
|
|
@ -1010,6 +1034,7 @@ def run_mprime_test(state, test):
|
||||||
global_vars['LogDir']))
|
global_vars['LogDir']))
|
||||||
|
|
||||||
# Check results and build report
|
# Check results and build report
|
||||||
|
test.report.append('{BLUE}Prime95{CLEAR}'.format(**COLORS))
|
||||||
test.logs = {}
|
test.logs = {}
|
||||||
for log in ['results.txt', 'prime.log']:
|
for log in ['results.txt', 'prime.log']:
|
||||||
lines = []
|
lines = []
|
||||||
|
|
@ -1026,20 +1051,18 @@ def run_mprime_test(state, test):
|
||||||
|
|
||||||
# results.txt (NS check)
|
# results.txt (NS check)
|
||||||
if log == 'results.txt':
|
if log == 'results.txt':
|
||||||
_tmp = []
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
|
line = line.strip()
|
||||||
if re.search(r'(error|fail)', line, re.IGNORECASE):
|
if re.search(r'(error|fail)', line, re.IGNORECASE):
|
||||||
test.failed = True
|
test.failed = True
|
||||||
test.update_status('NS')
|
test.update_status('NS')
|
||||||
_tmp.append(' {YELLOW}{line}{CLEAR}'.format(line=line, **COLORS))
|
test.report.append(' {YELLOW}{line}{CLEAR}'.format(line=line, **COLORS))
|
||||||
if _tmp:
|
|
||||||
test.report.append('{BLUE}Log: results.txt{CLEAR}'.format(**COLORS))
|
|
||||||
test.report.extend(_tmp)
|
|
||||||
|
|
||||||
# prime.log (CS check)
|
# prime.log (CS check)
|
||||||
if log == 'prime.log':
|
if log == 'prime.log':
|
||||||
_tmp = {'Pass': {}, 'Warn': {}}
|
_tmp = {'Pass': {}, 'Warn': {}}
|
||||||
for line in lines:
|
for line in lines:
|
||||||
|
line = line.strip()
|
||||||
_r = re.search(
|
_r = re.search(
|
||||||
r'(completed.*(\d+) errors, (\d+) warnings)',
|
r'(completed.*(\d+) errors, (\d+) warnings)',
|
||||||
line,
|
line,
|
||||||
|
|
@ -1059,18 +1082,19 @@ def run_mprime_test(state, test):
|
||||||
elif len(_tmp['Pass']) > 0:
|
elif len(_tmp['Pass']) > 0:
|
||||||
test.passed = True
|
test.passed = True
|
||||||
test.update_status('CS')
|
test.update_status('CS')
|
||||||
if len(_tmp['Pass']) + len(_tmp['Warn']) > 0:
|
for line in sorted(_tmp['Pass'].keys()):
|
||||||
test.report.append('{BLUE}Log: prime.log{CLEAR}'.format(**COLORS))
|
test.report.append(' {}'.format(line))
|
||||||
for line in sorted(_tmp['Pass'].keys()):
|
for line in sorted(_tmp['Warn'].keys()):
|
||||||
test.report.append(' {}'.format(line))
|
test.report.append(' {YELLOW}{line}{CLEAR}'.format(line=line, **COLORS))
|
||||||
for line in sorted(_tmp['Warn'].keys()):
|
|
||||||
test.report.append(' {YELLOW}{line}{CLEAR}'.format(line=line, **COLORS))
|
|
||||||
|
|
||||||
# Finalize report
|
# Unknown result
|
||||||
if not (test.aborted or test.failed or test.passed):
|
if not (test.aborted or test.failed or test.passed):
|
||||||
|
test.report.append(' {YELLOW}Unknown result{CLEAR}'.format(**COLORS))
|
||||||
test.update_status('Unknown')
|
test.update_status('Unknown')
|
||||||
|
|
||||||
|
# Add temps to report
|
||||||
test.report.append('{BLUE}Temps{CLEAR}'.format(**COLORS))
|
test.report.append('{BLUE}Temps{CLEAR}'.format(**COLORS))
|
||||||
for line in generate_report(
|
for line in generate_sensor_report(
|
||||||
test.sensor_data, 'Idle', 'Max', 'Cooldown', core_only=True):
|
test.sensor_data, 'Idle', 'Max', 'Cooldown', core_only=True):
|
||||||
test.report.append(' {}'.format(line))
|
test.report.append(' {}'.format(line))
|
||||||
|
|
||||||
|
|
@ -1144,10 +1168,10 @@ def run_nvme_smart_tests(state, test):
|
||||||
|
|
||||||
# Show attributes
|
# Show attributes
|
||||||
clear_screen()
|
clear_screen()
|
||||||
for line in test.dev.generate_report():
|
print_info('Device ({})'.format(test.dev.name))
|
||||||
# Not saving to log; that will happen after all tests have been run
|
print_standard(' {}'.format(test.dev.description))
|
||||||
print(line)
|
show_report(test.dev.generate_attribute_report())
|
||||||
print(' ')
|
print_standard(' ')
|
||||||
|
|
||||||
# Start short test
|
# Start short test
|
||||||
print_standard('Running self-test...')
|
print_standard('Running self-test...')
|
||||||
|
|
@ -1203,7 +1227,7 @@ def run_nvme_smart_tests(state, test):
|
||||||
tmux_kill_pane(state.panes['smart'])
|
tmux_kill_pane(state.panes['smart'])
|
||||||
|
|
||||||
# Save report
|
# Save report
|
||||||
test.report = test.dev.generate_report(
|
test.report = test.dev.generate_attribute_report(
|
||||||
short_test=_include_short_test)
|
short_test=_include_short_test)
|
||||||
|
|
||||||
# Done
|
# Done
|
||||||
|
|
@ -1231,13 +1255,24 @@ def show_results(state):
|
||||||
tmux_update_pane(
|
tmux_update_pane(
|
||||||
state.panes['Top'], text='{}\n{}'.format(
|
state.panes['Top'], text='{}\n{}'.format(
|
||||||
TOP_PANE_TEXT, 'Results'))
|
TOP_PANE_TEXT, 'Results'))
|
||||||
for k, v in state.tests.items():
|
|
||||||
# Skip disabled tests
|
# CPU tests
|
||||||
if not v['Enabled']:
|
_enabled = False
|
||||||
continue
|
for k in TESTS_CPU:
|
||||||
print_success('{}:'.format(k))
|
_enabled |= state.tests[k]['Enabled']
|
||||||
for obj in v['Objects']:
|
if _enabled:
|
||||||
show_report(obj.report)
|
print_success('CPU:'.format(k))
|
||||||
|
show_report(state.cpu.generate_cpu_report())
|
||||||
|
print_standard(' ')
|
||||||
|
|
||||||
|
# Disk tests
|
||||||
|
for k in TESTS_DISK:
|
||||||
|
_enabled |= state.tests[k]['Enabled']
|
||||||
|
if _enabled:
|
||||||
|
print_success('Disk{}:'.format(
|
||||||
|
'' if len(state.disks) == 1 else 's'))
|
||||||
|
for disk in state.disks:
|
||||||
|
show_report(disk.generate_disk_report())
|
||||||
print_standard(' ')
|
print_standard(' ')
|
||||||
|
|
||||||
def update_main_options(state, selection, main_options):
|
def update_main_options(state, selection, main_options):
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue