blob: 5e3e42e3461dc9a2346aac64405443cf9d6d256b [file] [log] [blame]
Gaurav Shaha7fb8962011-08-16 15:06:32 -07001# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
Daniel Erat3e3f7f42010-03-29 17:19:14 -07002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Elly Jones2f0ebba2011-10-27 13:43:20 -04005import logging, os, platform, re, signal, tempfile, time, uuid
Daniel Erat3e3f7f42010-03-29 17:19:14 -07006from autotest_lib.client.common_lib import error
Vadim Bendeburye7970922011-04-07 17:07:37 -07007from autotest_lib.client.common_lib import utils
Daniel Erat3e3f7f42010-03-29 17:19:14 -07008
rgindaf25f73f2010-04-07 14:55:25 -07009class TimeoutError(error.TestError):
10 """Error raised when we time out when waiting on a condition."""
David Jamesd51ac9c2011-09-10 00:45:24 -070011 pass
rgindaf25f73f2010-04-07 14:55:25 -070012
13
Vadim Bendeburye7970922011-04-07 17:07:37 -070014class Crossystem(object):
15 """A wrapper for the crossystem utility."""
16
17 def __init__(self, client):
18 self.cros_system_data = {}
19 self._client = client
20
21 def init(self):
22 self.cros_system_data = {}
23 (_, fname) = tempfile.mkstemp()
24 f = open(fname, 'w')
25 self._client.run('crossystem', stdout_tee=f)
26 f.close()
27 text = utils.read_file(fname)
28 for line in text.splitlines():
29 assignment_string = line.split('#')[0]
30 if not assignment_string.count('='):
31 continue
32 (name, value) = assignment_string.split('=', 1)
33 self.cros_system_data[name.strip()] = value.strip()
34 os.remove(fname)
35
36 def __getattr__(self, name):
37 """
38 Retrieve a crosssystem attribute.
39
40 The call crossystemobject.name() will return the crossystem reported
41 string.
42 """
43 return lambda : self.cros_system_data[name]
44
45
David Jamesd51ac9c2011-09-10 00:45:24 -070046def nuke_process_by_name(name, with_prejudice=False):
47 try:
48 pid = int(utils.system_output('pgrep -o ^%s$' % name).split()[0])
49 except Exception as e:
50 logging.error(e)
51 return
52 if with_prejudice:
53 utils.nuke_pid(pid, [signal.SIGKILL])
54 else:
55 utils.nuke_pid(pid)
56
57
Daniel Erat3e3f7f42010-03-29 17:19:14 -070058def poll_for_condition(
rgindaf25f73f2010-04-07 14:55:25 -070059 condition, exception=None, timeout=10, sleep_interval=0.1, desc=None):
Daniel Erat3e3f7f42010-03-29 17:19:14 -070060 """Poll until a condition becomes true.
61
Jon Salz4f646a32011-11-30 14:42:51 +080062 Arguments:
63 condition: function taking no args and returning bool
64 exception: exception to throw if condition doesn't become true
65 timeout: maximum number of seconds to wait
66 sleep_interval: time to sleep between polls
67 desc: description of default TimeoutError used if 'exception' is None
68
69 Returns:
70 The true value that caused the poll loop to terminate.
Daniel Erat3e3f7f42010-03-29 17:19:14 -070071
72 Raises:
rgindaf25f73f2010-04-07 14:55:25 -070073 'exception' arg if supplied; site_utils.TimeoutError otherwise
Daniel Erat3e3f7f42010-03-29 17:19:14 -070074 """
75 start_time = time.time()
76 while True:
Jon Salz4f646a32011-11-30 14:42:51 +080077 value = condition()
78 if value:
79 return value
Daniel Erat3e3f7f42010-03-29 17:19:14 -070080 if time.time() + sleep_interval - start_time > timeout:
rgindaf25f73f2010-04-07 14:55:25 -070081 if exception:
Gaurav Shaha7fb8962011-08-16 15:06:32 -070082 logging.error(exception)
rgindaf25f73f2010-04-07 14:55:25 -070083 raise exception
84
85 if desc:
86 desc = 'Timed out waiting for condition: %s' % desc
87 else:
88 desc = 'Timed out waiting for unnamed condition'
Gaurav Shaha7fb8962011-08-16 15:06:32 -070089 logging.error(desc)
Mitsuru Oshima5d3e4542010-08-18 13:46:06 -070090 raise TimeoutError, desc
rgindaf25f73f2010-04-07 14:55:25 -070091
Daniel Erat3e3f7f42010-03-29 17:19:14 -070092 time.sleep(sleep_interval)
Thieu Le1904d002010-11-30 17:10:24 -080093
94
95def save_vm_state(checkpoint):
96 """Saves the current state of the virtual machine.
97
98 This function is a NOOP if the test is not running under a virtual machine
99 with the USB serial port redirected.
100
101 Arguments:
102 checkpoint - Name used to identify this state
103
104 Returns:
105 None
106 """
107 # The QEMU monitor has been redirected to the guest serial port located at
108 # /dev/ttyUSB0. To save the state of the VM, we just send the 'savevm'
109 # command to the serial port.
110 proc = platform.processor()
111 if 'QEMU' in proc and os.path.exists('/dev/ttyUSB0'):
112 logging.info('Saving VM state "%s"' % checkpoint)
113 serial = open('/dev/ttyUSB0', 'w')
114 serial.write("savevm %s\r\n" % checkpoint)
115 logging.info('Done saving VM state "%s"' % checkpoint)
Mandeep Singh Baines142ac8d2011-02-18 13:31:08 -0800116
117
118def check_raw_dmesg(dmesg, message_level, whitelist):
119 """Checks dmesg for unexpected warnings.
120
121 This function parses dmesg for message with message_level <= message_level
122 which do not appear in the whitelist.
123
124 Arguments:
125 dmesg - string containing raw dmesg buffer
126 message_level - minimum message priority to check
127 whitelist - messages to ignore
128
129 Returns:
130 List of unexpected warnings
131 """
Vadim Bendeburye7970922011-04-07 17:07:37 -0700132 whitelist_re = re.compile(r'(%s)' % '|'.join(whitelist))
Mandeep Singh Baines142ac8d2011-02-18 13:31:08 -0800133 unexpected = []
134 for line in dmesg.splitlines():
135 if int(line[1]) <= message_level:
Vadim Bendeburye7970922011-04-07 17:07:37 -0700136 stripped_line = line.split('] ', 1)[1]
137 if whitelist_re.search(stripped_line):
138 continue
139 unexpected.append(stripped_line)
Mandeep Singh Baines142ac8d2011-02-18 13:31:08 -0800140 return unexpected
Vadim Bendebury29916f22011-04-13 10:54:47 -0700141
142def verify_mesg_set(mesg, regex, whitelist):
143 """Verifies that the exact set of messages are present in a text.
144
145 This function finds all strings in the text matching a certain regex, and
146 then verifies that all expected strings are present in the set, and no
147 unexpected strings are there.
148
149 Arguments:
150 mesg - the mutiline text to be scanned
151 regex - regular expression to match
152 whitelist - messages to find in the output, a list of strings
153 (potentially regexes) to look for in the filtered output. All these
154 strings must be there, and no other strings should be present in the
155 filtered output.
156
157 Returns:
158 string of inconsistent findings (i.e. an empty string on success).
159 """
160
161 rv = []
162
163 missing_strings = []
164 present_strings = []
165 for line in mesg.splitlines():
166 if not re.search(r'%s' % regex, line):
167 continue
168 present_strings.append(line.split('] ', 1)[1])
169
170 for string in whitelist:
171 for present_string in list(present_strings):
172 if re.search(r'^%s$' % string, present_string):
173 present_strings.remove(present_string)
174 break
175 else:
176 missing_strings.append(string)
177
178 if present_strings:
179 rv.append('unexpected strings:')
180 rv.extend(present_strings)
181 if missing_strings:
182 rv.append('missing strings:')
183 rv.extend(missing_strings)
184
185 return '\n'.join(rv)
Ahmad Shariff8e92622011-05-24 12:37:39 -0700186
187
188def target_is_x86_pie():
189 """Returns whether the toolchain produces an x86 PIE (position independent
190 executable) by default.
191
192 Arguments:
193 None
194
195 Returns:
196 True if the target toolchain produces an x86 PIE by default.
197 False otherwise.
198 """
199
200
201 command = "echo \"int main(){return 0;}\" | ${CC} -o /tmp/a.out -xc -"
202 command += "&& file /tmp/a.out"
203 result = utils.system_output(command, retain_output=True,
204 ignore_status=True)
205 if re.search("80\d86", result) and re.search("shared object", result):
206 return True
207 else:
208 return False
Elly Jones686c2f42011-10-24 16:45:07 -0400209
Sonny Rao172edad2012-02-07 23:23:58 +0000210def target_is_x86():
211 """Returns whether the toolchain produces an x86 object
212
213 Arguments:
214 None
215
216 Returns:
217 True if the target toolchain produces an x86 object
218 False otherwise.
219 """
220
221
222 command = "echo \"int main(){return 0;}\" | ${CC} -o /tmp/a.out -xc -"
223 command += "&& file /tmp/a.out"
224 result = utils.system_output(command, retain_output=True,
225 ignore_status=True)
226 if re.search("80\d86", result) or re.search("x86-64", result):
227 return True
228 else:
229 return False
230
Elly Jones686c2f42011-10-24 16:45:07 -0400231def mounts():
232 ret = []
233 for line in file('/proc/mounts'):
234 m = re.match(r'(?P<src>\S+) (?P<dest>\S+) (?P<type>\S+) (?P<opts>\S+).*', line)
235 if m:
236 ret.append(m.groupdict())
237 return ret
238
239def is_mountpoint(path):
240 return path in [ m['dest'] for m in mounts() ]
241
242def require_mountpoint(path):
243 """
244 Raises an exception if path is not a mountpoint.
245 """
246 if not is_mountpoint(path):
247 raise error.TestFail('Path not mounted: "%s"' % path)
Elly Jones2f0ebba2011-10-27 13:43:20 -0400248
249def random_username():
250 return str(uuid.uuid4()) + '@example.com'