def test_tester_smart(Device: pySMART.Device): Device.run_selftest = MagicMock(return_value=(0, None, 3)) Device.update = MagicMock() Device.tests = [MagicMock()] Device.tests[0].remain = '0%' Device.tests[0].hours = '24' Device.tests[0].LBA = '0' Device.tests[0].type = 'foo-type' Device.tests[0].status = 'foo-status' Device.attributes = [None] * 256 Device.attributes[9] = MagicMock() Device.attributes[9].raw = 99 Device.attributes[12] = MagicMock() Device.attributes[12].raw = '11' Device.assessment = 'PASS' r = Tester.smart('/foo/bar', test_type=Smart.short) assert r == { 'lifetime': 24, '@type': 'TestHardDrive', 'error': False, 'type': 'foo-type', 'status': 'foo-status', 'firstError': 0, 'passedLifetime': 99, 'assessment': True, 'powerCycleCount': 11 }
def smart(cls, disk: str, test_type: Smart) -> dict: # Enable SMART on hard drive with catch_warnings(): filterwarnings('error') try: hdd = Device(disk) # type: Device except Warning: status = 'SMART cannot be enabled on this device.' print(status, file=sys.stderr) return { '@type': 'TestHardDrive', 'error': True, 'status': status } status_code, status_message, completion_time = hdd.run_selftest( test_type.value) if status_code > 1: print(status_message, file=sys.stderr) return { '@type': 'TestHardDrive', 'error': True, 'status': status_message, } # get estimated end of the test try: test_end = parser.parse(completion_time) except TypeError: # completion_time is None, estimate end time duration = 2 if test_type == Smart.short else 120 test_end = datetime.now() + timedelta(minutes=duration) print(' It will finish around {}:'.format(test_end)) # follow progress of test until it ends or the estimated time is reached remaining = 100 # test completion pending percentage with tqdm(total=remaining, leave=True) as bar: while remaining > 0: sleep(2) # wait a few seconds between smart retrievals hdd.update() try: last_test = hdd.tests[0] except (TypeError, IndexError): pass # The suppress: test is None, no tests # work around because SMART has not been initialized # yet but pySMART library doesn't wait # Just ignore the error because we alreaday have an # estimation of the ending time else: last = remaining with suppress(ValueError): remaining = int(last_test.remain.strip('%')) completed = last - remaining if completed > 0: bar.update(completed) # only allow a few seconds more than the estimated time if datetime.now() > test_end + cls.SMART_GRACE_TIME: break # show last test hdd.update() last_test = hdd.tests[0] try: lba_first_error = int(last_test.LBA, 0) # accept hex and decimal value except ValueError: lba_first_error = None ret = { '@type': 'TestHardDrive', 'type': last_test.type, 'error': bool(lba_first_error), 'status': last_test.status, 'firstError': lba_first_error, 'passedLifetime': int(hdd.attributes[9].raw), 'assessment': True if hdd.assessment == 'PASS' else False } with suppress(ValueError): ret['lifetime'] = int(last_test.hours) for key, name in cls.SMART_ATTRIBUTES.items(): with suppress(AttributeError): ret[name] = int(hdd.attributes[key].raw) return ret