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