blob: b1421fbd779045cace3b6aa13cb4bdce5b11d89c [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
David Jamesd51ac9c2011-09-10 00:45:24 -07005import logging, os, platform, re, signal, tempfile, time
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
9
rgindaf25f73f2010-04-07 14:55:25 -070010class TimeoutError(error.TestError):
11 """Error raised when we time out when waiting on a condition."""
David Jamesd51ac9c2011-09-10 00:45:24 -070012 pass
rgindaf25f73f2010-04-07 14:55:25 -070013
14
Vadim Bendeburye7970922011-04-07 17:07:37 -070015class Crossystem(object):
16 """A wrapper for the crossystem utility."""
17
18 def __init__(self, client):
19 self.cros_system_data = {}
20 self._client = client
21
22 def init(self):
23 self.cros_system_data = {}
24 (_, fname) = tempfile.mkstemp()
25 f = open(fname, 'w')
26 self._client.run('crossystem', stdout_tee=f)
27 f.close()
28 text = utils.read_file(fname)
29 for line in text.splitlines():
30 assignment_string = line.split('#')[0]
31 if not assignment_string.count('='):
32 continue
33 (name, value) = assignment_string.split('=', 1)
34 self.cros_system_data[name.strip()] = value.strip()
35 os.remove(fname)
36
37 def __getattr__(self, name):
38 """
39 Retrieve a crosssystem attribute.
40
41 The call crossystemobject.name() will return the crossystem reported
42 string.
43 """
44 return lambda : self.cros_system_data[name]
45
46
David Jamesd51ac9c2011-09-10 00:45:24 -070047def nuke_process_by_name(name, with_prejudice=False):
48 try:
49 pid = int(utils.system_output('pgrep -o ^%s$' % name).split()[0])
50 except Exception as e:
51 logging.error(e)
52 return
53 if with_prejudice:
54 utils.nuke_pid(pid, [signal.SIGKILL])
55 else:
56 utils.nuke_pid(pid)
57
58
Daniel Erat3e3f7f42010-03-29 17:19:14 -070059def poll_for_condition(
rgindaf25f73f2010-04-07 14:55:25 -070060 condition, exception=None, timeout=10, sleep_interval=0.1, desc=None):
Daniel Erat3e3f7f42010-03-29 17:19:14 -070061 """Poll until a condition becomes true.
62
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
rgindaf25f73f2010-04-07 14:55:25 -070067 desc: description of default TimeoutError used if 'exception' is None
Daniel Erat3e3f7f42010-03-29 17:19:14 -070068
69 Raises:
rgindaf25f73f2010-04-07 14:55:25 -070070 'exception' arg if supplied; site_utils.TimeoutError otherwise
Daniel Erat3e3f7f42010-03-29 17:19:14 -070071 """
72 start_time = time.time()
73 while True:
74 if condition():
75 return
76 if time.time() + sleep_interval - start_time > timeout:
rgindaf25f73f2010-04-07 14:55:25 -070077 if exception:
Gaurav Shaha7fb8962011-08-16 15:06:32 -070078 logging.error(exception)
rgindaf25f73f2010-04-07 14:55:25 -070079 raise exception
80
81 if desc:
82 desc = 'Timed out waiting for condition: %s' % desc
83 else:
84 desc = 'Timed out waiting for unnamed condition'
Gaurav Shaha7fb8962011-08-16 15:06:32 -070085 logging.error(desc)
Mitsuru Oshima5d3e4542010-08-18 13:46:06 -070086 raise TimeoutError, desc
rgindaf25f73f2010-04-07 14:55:25 -070087
Daniel Erat3e3f7f42010-03-29 17:19:14 -070088 time.sleep(sleep_interval)
Thieu Le1904d002010-11-30 17:10:24 -080089
90
91def save_vm_state(checkpoint):
92 """Saves the current state of the virtual machine.
93
94 This function is a NOOP if the test is not running under a virtual machine
95 with the USB serial port redirected.
96
97 Arguments:
98 checkpoint - Name used to identify this state
99
100 Returns:
101 None
102 """
103 # The QEMU monitor has been redirected to the guest serial port located at
104 # /dev/ttyUSB0. To save the state of the VM, we just send the 'savevm'
105 # command to the serial port.
106 proc = platform.processor()
107 if 'QEMU' in proc and os.path.exists('/dev/ttyUSB0'):
108 logging.info('Saving VM state "%s"' % checkpoint)
109 serial = open('/dev/ttyUSB0', 'w')
110 serial.write("savevm %s\r\n" % checkpoint)
111 logging.info('Done saving VM state "%s"' % checkpoint)
Mandeep Singh Baines142ac8d2011-02-18 13:31:08 -0800112
113
114def check_raw_dmesg(dmesg, message_level, whitelist):
115 """Checks dmesg for unexpected warnings.
116
117 This function parses dmesg for message with message_level <= message_level
118 which do not appear in the whitelist.
119
120 Arguments:
121 dmesg - string containing raw dmesg buffer
122 message_level - minimum message priority to check
123 whitelist - messages to ignore
124
125 Returns:
126 List of unexpected warnings
127 """
Vadim Bendeburye7970922011-04-07 17:07:37 -0700128 whitelist_re = re.compile(r'(%s)' % '|'.join(whitelist))
Mandeep Singh Baines142ac8d2011-02-18 13:31:08 -0800129 unexpected = []
130 for line in dmesg.splitlines():
131 if int(line[1]) <= message_level:
Vadim Bendeburye7970922011-04-07 17:07:37 -0700132 stripped_line = line.split('] ', 1)[1]
133 if whitelist_re.search(stripped_line):
134 continue
135 unexpected.append(stripped_line)
Mandeep Singh Baines142ac8d2011-02-18 13:31:08 -0800136 return unexpected
Vadim Bendebury29916f22011-04-13 10:54:47 -0700137
138def verify_mesg_set(mesg, regex, whitelist):
139 """Verifies that the exact set of messages are present in a text.
140
141 This function finds all strings in the text matching a certain regex, and
142 then verifies that all expected strings are present in the set, and no
143 unexpected strings are there.
144
145 Arguments:
146 mesg - the mutiline text to be scanned
147 regex - regular expression to match
148 whitelist - messages to find in the output, a list of strings
149 (potentially regexes) to look for in the filtered output. All these
150 strings must be there, and no other strings should be present in the
151 filtered output.
152
153 Returns:
154 string of inconsistent findings (i.e. an empty string on success).
155 """
156
157 rv = []
158
159 missing_strings = []
160 present_strings = []
161 for line in mesg.splitlines():
162 if not re.search(r'%s' % regex, line):
163 continue
164 present_strings.append(line.split('] ', 1)[1])
165
166 for string in whitelist:
167 for present_string in list(present_strings):
168 if re.search(r'^%s$' % string, present_string):
169 present_strings.remove(present_string)
170 break
171 else:
172 missing_strings.append(string)
173
174 if present_strings:
175 rv.append('unexpected strings:')
176 rv.extend(present_strings)
177 if missing_strings:
178 rv.append('missing strings:')
179 rv.extend(missing_strings)
180
181 return '\n'.join(rv)
Ahmad Shariff8e92622011-05-24 12:37:39 -0700182
183
184def target_is_x86_pie():
185 """Returns whether the toolchain produces an x86 PIE (position independent
186 executable) by default.
187
188 Arguments:
189 None
190
191 Returns:
192 True if the target toolchain produces an x86 PIE by default.
193 False otherwise.
194 """
195
196
197 command = "echo \"int main(){return 0;}\" | ${CC} -o /tmp/a.out -xc -"
198 command += "&& file /tmp/a.out"
199 result = utils.system_output(command, retain_output=True,
200 ignore_status=True)
201 if re.search("80\d86", result) and re.search("shared object", result):
202 return True
203 else:
204 return False
Elly Jones686c2f42011-10-24 16:45:07 -0400205
206def mounts():
207 ret = []
208 for line in file('/proc/mounts'):
209 m = re.match(r'(?P<src>\S+) (?P<dest>\S+) (?P<type>\S+) (?P<opts>\S+).*', line)
210 if m:
211 ret.append(m.groupdict())
212 return ret
213
214def is_mountpoint(path):
215 return path in [ m['dest'] for m in mounts() ]
216
217def require_mountpoint(path):
218 """
219 Raises an exception if path is not a mountpoint.
220 """
221 if not is_mountpoint(path):
222 raise error.TestFail('Path not mounted: "%s"' % path)