1*76b46939SStephen Warren# Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. 2*76b46939SStephen Warren# 3*76b46939SStephen Warren# SPDX-License-Identifier: GPL-2.0 4*76b46939SStephen Warren 5*76b46939SStephen Warren# Utility code shared across multiple tests. 6*76b46939SStephen Warren 7*76b46939SStephen Warrenimport hashlib 8*76b46939SStephen Warrenimport os 9*76b46939SStephen Warrenimport os.path 10*76b46939SStephen Warrenimport sys 11*76b46939SStephen Warrenimport time 12*76b46939SStephen Warren 13*76b46939SStephen Warrendef md5sum_data(data): 14*76b46939SStephen Warren '''Calculate the MD5 hash of some data. 15*76b46939SStephen Warren 16*76b46939SStephen Warren Args: 17*76b46939SStephen Warren data: The data to hash. 18*76b46939SStephen Warren 19*76b46939SStephen Warren Returns: 20*76b46939SStephen Warren The hash of the data, as a binary string. 21*76b46939SStephen Warren ''' 22*76b46939SStephen Warren 23*76b46939SStephen Warren h = hashlib.md5() 24*76b46939SStephen Warren h.update(data) 25*76b46939SStephen Warren return h.digest() 26*76b46939SStephen Warren 27*76b46939SStephen Warrendef md5sum_file(fn, max_length=None): 28*76b46939SStephen Warren '''Calculate the MD5 hash of the contents of a file. 29*76b46939SStephen Warren 30*76b46939SStephen Warren Args: 31*76b46939SStephen Warren fn: The filename of the file to hash. 32*76b46939SStephen Warren max_length: The number of bytes to hash. If the file has more 33*76b46939SStephen Warren bytes than this, they will be ignored. If None or omitted, the 34*76b46939SStephen Warren entire file will be hashed. 35*76b46939SStephen Warren 36*76b46939SStephen Warren Returns: 37*76b46939SStephen Warren The hash of the file content, as a binary string. 38*76b46939SStephen Warren ''' 39*76b46939SStephen Warren 40*76b46939SStephen Warren with open(fn, 'rb') as fh: 41*76b46939SStephen Warren if max_length: 42*76b46939SStephen Warren params = [max_length] 43*76b46939SStephen Warren else: 44*76b46939SStephen Warren params = [] 45*76b46939SStephen Warren data = fh.read(*params) 46*76b46939SStephen Warren return md5sum_data(data) 47*76b46939SStephen Warren 48*76b46939SStephen Warrenclass PersistentRandomFile(object): 49*76b46939SStephen Warren '''Generate and store information about a persistent file containing 50*76b46939SStephen Warren random data.''' 51*76b46939SStephen Warren 52*76b46939SStephen Warren def __init__(self, u_boot_console, fn, size): 53*76b46939SStephen Warren '''Create or process the persistent file. 54*76b46939SStephen Warren 55*76b46939SStephen Warren If the file does not exist, it is generated. 56*76b46939SStephen Warren 57*76b46939SStephen Warren If the file does exist, its content is hashed for later comparison. 58*76b46939SStephen Warren 59*76b46939SStephen Warren These files are always located in the "persistent data directory" of 60*76b46939SStephen Warren the current test run. 61*76b46939SStephen Warren 62*76b46939SStephen Warren Args: 63*76b46939SStephen Warren u_boot_console: A console connection to U-Boot. 64*76b46939SStephen Warren fn: The filename (without path) to create. 65*76b46939SStephen Warren size: The desired size of the file in bytes. 66*76b46939SStephen Warren 67*76b46939SStephen Warren Returns: 68*76b46939SStephen Warren Nothing. 69*76b46939SStephen Warren ''' 70*76b46939SStephen Warren 71*76b46939SStephen Warren self.fn = fn 72*76b46939SStephen Warren 73*76b46939SStephen Warren self.abs_fn = u_boot_console.config.persistent_data_dir + '/' + fn 74*76b46939SStephen Warren 75*76b46939SStephen Warren if os.path.exists(self.abs_fn): 76*76b46939SStephen Warren u_boot_console.log.action('Persistent data file ' + self.abs_fn + 77*76b46939SStephen Warren ' already exists') 78*76b46939SStephen Warren self.content_hash = md5sum_file(self.abs_fn) 79*76b46939SStephen Warren else: 80*76b46939SStephen Warren u_boot_console.log.action('Generating ' + self.abs_fn + 81*76b46939SStephen Warren ' (random, persistent, %d bytes)' % size) 82*76b46939SStephen Warren data = os.urandom(size) 83*76b46939SStephen Warren with open(self.abs_fn, 'wb') as fh: 84*76b46939SStephen Warren fh.write(data) 85*76b46939SStephen Warren self.content_hash = md5sum_data(data) 86*76b46939SStephen Warren 87*76b46939SStephen Warrendef attempt_to_open_file(fn): 88*76b46939SStephen Warren '''Attempt to open a file, without throwing exceptions. 89*76b46939SStephen Warren 90*76b46939SStephen Warren Any errors (exceptions) that occur during the attempt to open the file 91*76b46939SStephen Warren are ignored. This is useful in order to test whether a file (in 92*76b46939SStephen Warren particular, a device node) exists and can be successfully opened, in order 93*76b46939SStephen Warren to poll for e.g. USB enumeration completion. 94*76b46939SStephen Warren 95*76b46939SStephen Warren Args: 96*76b46939SStephen Warren fn: The filename to attempt to open. 97*76b46939SStephen Warren 98*76b46939SStephen Warren Returns: 99*76b46939SStephen Warren An open file handle to the file, or None if the file could not be 100*76b46939SStephen Warren opened. 101*76b46939SStephen Warren ''' 102*76b46939SStephen Warren 103*76b46939SStephen Warren try: 104*76b46939SStephen Warren return open(fn, 'rb') 105*76b46939SStephen Warren except: 106*76b46939SStephen Warren return None 107*76b46939SStephen Warren 108*76b46939SStephen Warrendef wait_until_open_succeeds(fn): 109*76b46939SStephen Warren '''Poll until a file can be opened, or a timeout occurs. 110*76b46939SStephen Warren 111*76b46939SStephen Warren Continually attempt to open a file, and return when this succeeds, or 112*76b46939SStephen Warren raise an exception after a timeout. 113*76b46939SStephen Warren 114*76b46939SStephen Warren Args: 115*76b46939SStephen Warren fn: The filename to attempt to open. 116*76b46939SStephen Warren 117*76b46939SStephen Warren Returns: 118*76b46939SStephen Warren An open file handle to the file. 119*76b46939SStephen Warren ''' 120*76b46939SStephen Warren 121*76b46939SStephen Warren for i in xrange(100): 122*76b46939SStephen Warren fh = attempt_to_open_file(fn) 123*76b46939SStephen Warren if fh: 124*76b46939SStephen Warren return fh 125*76b46939SStephen Warren time.sleep(0.1) 126*76b46939SStephen Warren raise Exception('File could not be opened') 127*76b46939SStephen Warren 128*76b46939SStephen Warrendef wait_until_file_open_fails(fn, ignore_errors): 129*76b46939SStephen Warren '''Poll until a file cannot be opened, or a timeout occurs. 130*76b46939SStephen Warren 131*76b46939SStephen Warren Continually attempt to open a file, and return when this fails, or 132*76b46939SStephen Warren raise an exception after a timeout. 133*76b46939SStephen Warren 134*76b46939SStephen Warren Args: 135*76b46939SStephen Warren fn: The filename to attempt to open. 136*76b46939SStephen Warren ignore_errors: Indicate whether to ignore timeout errors. If True, the 137*76b46939SStephen Warren function will simply return if a timeout occurs, otherwise an 138*76b46939SStephen Warren exception will be raised. 139*76b46939SStephen Warren 140*76b46939SStephen Warren Returns: 141*76b46939SStephen Warren Nothing. 142*76b46939SStephen Warren ''' 143*76b46939SStephen Warren 144*76b46939SStephen Warren for i in xrange(100): 145*76b46939SStephen Warren fh = attempt_to_open_file(fn) 146*76b46939SStephen Warren if not fh: 147*76b46939SStephen Warren return 148*76b46939SStephen Warren fh.close() 149*76b46939SStephen Warren time.sleep(0.1) 150*76b46939SStephen Warren if ignore_errors: 151*76b46939SStephen Warren return 152*76b46939SStephen Warren raise Exception('File can still be opened') 153*76b46939SStephen Warren 154*76b46939SStephen Warrendef run_and_log(u_boot_console, cmd, ignore_errors=False): 155*76b46939SStephen Warren '''Run a command and log its output. 156*76b46939SStephen Warren 157*76b46939SStephen Warren Args: 158*76b46939SStephen Warren u_boot_console: A console connection to U-Boot. 159*76b46939SStephen Warren cmd: The command to run, as an array of argv[]. 160*76b46939SStephen Warren ignore_errors: Indicate whether to ignore errors. If True, the function 161*76b46939SStephen Warren will simply return if the command cannot be executed or exits with 162*76b46939SStephen Warren an error code, otherwise an exception will be raised if such 163*76b46939SStephen Warren problems occur. 164*76b46939SStephen Warren 165*76b46939SStephen Warren Returns: 166*76b46939SStephen Warren Nothing. 167*76b46939SStephen Warren ''' 168*76b46939SStephen Warren 169*76b46939SStephen Warren runner = u_boot_console.log.get_runner(cmd[0], sys.stdout) 170*76b46939SStephen Warren runner.run(cmd, ignore_errors=ignore_errors) 171*76b46939SStephen Warren runner.close() 172