blob: e9aa96a785c1e275a820c962234844beb8c0dfdb [file] [log] [blame]
mbligh05269362007-10-16 16:58:11 +00001# Copyright Martin J. Bligh, Andy Whitcroft, 2007
2#
mblighea397bb2008-02-02 19:17:51 +00003# Define the server-side test class
mbligh05269362007-10-16 16:58:11 +00004#
mbligh05269362007-10-16 16:58:11 +00005
mbligh089f1e32009-06-22 18:26:45 +00006import os, tempfile, logging
mblighea397bb2008-02-02 19:17:51 +00007
jadmanski54f90af2008-10-10 16:20:55 +00008from autotest_lib.client.common_lib import log, utils, test as common_test
mbligh05269362007-10-16 16:58:11 +00009
10
mblighccb9e182008-04-17 15:42:10 +000011class test(common_test.base_test):
mbligh089f1e32009-06-22 18:26:45 +000012 disable_sysinfo_install_cache = False
mbligh43dd5492009-09-03 20:20:51 +000013 host_parameter = None
mblighdccabe32008-02-01 17:39:32 +000014
15
mbligh4395bbd2009-03-25 19:34:17 +000016_sysinfo_before_test_script = """\
jadmanski54f90af2008-10-10 16:20:55 +000017import pickle
18from autotest_lib.client.bin import test
19mytest = test.test(job, '', %r)
20job.sysinfo.log_before_each_test(mytest)
21sysinfo_pickle = os.path.join(mytest.outputdir, 'sysinfo.pickle')
22pickle.dump(job.sysinfo, open(sysinfo_pickle, 'w'))
23job.record('GOOD', '', 'sysinfo.before')
24"""
25
mbligh4395bbd2009-03-25 19:34:17 +000026_sysinfo_after_test_script = """\
jadmanski54f90af2008-10-10 16:20:55 +000027import pickle
28from autotest_lib.client.bin import test
29mytest = test.test(job, '', %r)
Dan Shi4eba9f02014-06-18 13:58:05 -070030# success is passed in so diffable_logdir can decide if or not to collect
31# full log content.
32mytest.success = %s
jadmanski54f90af2008-10-10 16:20:55 +000033sysinfo_pickle = os.path.join(mytest.outputdir, 'sysinfo.pickle')
34if os.path.exists(sysinfo_pickle):
35 job.sysinfo = pickle.load(open(sysinfo_pickle))
36 job.sysinfo.__init__(job.resultdir)
37job.sysinfo.log_after_each_test(mytest)
38job.record('GOOD', '', 'sysinfo.after')
39"""
40
mbligh4395bbd2009-03-25 19:34:17 +000041# this script is ran after _sysinfo_before_test_script and before
42# _sysinfo_after_test_script which means the pickle file exists
43# already and should be dumped with updated state for
44# _sysinfo_after_test_script to pick it up later
45_sysinfo_iteration_script = """\
46import pickle
47from autotest_lib.client.bin import test
48mytest = test.test(job, '', %r)
49sysinfo_pickle = os.path.join(mytest.outputdir, 'sysinfo.pickle')
50if os.path.exists(sysinfo_pickle):
51 job.sysinfo = pickle.load(open(sysinfo_pickle))
52 job.sysinfo.__init__(job.resultdir)
53job.sysinfo.%s(mytest, iteration=%d)
54pickle.dump(job.sysinfo, open(sysinfo_pickle, 'w'))
55job.record('GOOD', '', 'sysinfo.iteration.%s')
56"""
57
jadmanski54f90af2008-10-10 16:20:55 +000058
jadmanski7c7aff32009-03-25 22:43:07 +000059def install_autotest_and_run(func):
60 def wrapper(self, mytest):
mbligh35245892009-06-08 16:43:21 +000061 host, at, outputdir = self._install()
Kevin Cheng70936692015-10-13 14:57:26 -070062 # TODO(kevcheng): remove when host client install is supported for
63 # ADBHost. crbug.com/543702
64 if not host.is_client_install_supported:
65 logging.debug('host client install not supported, skipping %s:',
66 func.__name__)
67 return
68
mbligh089f1e32009-06-22 18:26:45 +000069 try:
70 host.erase_dir_contents(outputdir)
71 func(self, mytest, host, at, outputdir)
72 finally:
73 # the test class can define this flag to make us remove the
74 # sysinfo install files and outputdir contents after each run
75 if mytest.disable_sysinfo_install_cache:
76 self.cleanup(host_close=False)
mbligh35245892009-06-08 16:43:21 +000077
jadmanski7c7aff32009-03-25 22:43:07 +000078 return wrapper
79
80
jadmanski54f90af2008-10-10 16:20:55 +000081class _sysinfo_logger(object):
82 def __init__(self, job):
83 self.job = job
84 self.pickle = None
mbligh35245892009-06-08 16:43:21 +000085
86 # for now support a single host
87 self.host = None
88 self.autotest = None
89 self.outputdir = None
90
jadmanski54f90af2008-10-10 16:20:55 +000091 if len(job.machines) != 1:
92 # disable logging on multi-machine tests
93 self.before_hook = self.after_hook = None
mbligh35245892009-06-08 16:43:21 +000094 self.before_iteration_hook = self.after_iteration_hook = None
jadmanski54f90af2008-10-10 16:20:55 +000095
96
97 def _install(self):
mbligh35245892009-06-08 16:43:21 +000098 if not self.host:
99 from autotest_lib.server import hosts, autotest
Dan Shid7f12422016-01-04 11:51:32 -0800100 self.host = hosts.create_target_machine(
101 self.job.machine_dict_list[0])
Kevin Cheng70936692015-10-13 14:57:26 -0700102 # TODO(kevcheng): remove when host client install is supported for
103 # ADBHost. crbug.com/543702
104 if not self.host.is_client_install_supported:
105 return self.host, None, None
mblighf780bbf2009-09-03 20:45:46 +0000106 try:
Dale Curtis74a314b2011-06-23 14:55:46 -0700107 tmp_dir = self.host.get_tmp_dir(parent="/tmp/sysinfo")
mblighf780bbf2009-09-03 20:45:46 +0000108 self.autotest = autotest.Autotest(self.host)
Dale Curtis74a314b2011-06-23 14:55:46 -0700109 self.autotest.install(autodir=tmp_dir)
mblighf780bbf2009-09-03 20:45:46 +0000110 self.outputdir = self.host.get_tmp_dir()
111 except:
112 # if installation fails roll back the host
113 try:
114 self.host.close()
115 except:
116 logging.exception("Unable to close host %s",
117 self.host.hostname)
118 self.host = None
119 self.autotest = None
120 raise
mbligh089f1e32009-06-22 18:26:45 +0000121 else:
Kevin Cheng70936692015-10-13 14:57:26 -0700122 # TODO(kevcheng): remove when host client install is supported for
123 # ADBHost. crbug.com/543702
124 if not self.host.is_client_install_supported:
125 return self.host, None, None
mbligh089f1e32009-06-22 18:26:45 +0000126
127 # if autotest client dir does not exist, reinstall (it may have
128 # been removed by the test code)
Kevin Cheng70936692015-10-13 14:57:26 -0700129 autodir = self.host.get_autodir()
130 if not autodir or not self.host.path_exists(autodir):
jadmanski27b52912009-08-14 17:09:15 +0000131 self.autotest.install(autodir=autodir)
mbligh089f1e32009-06-22 18:26:45 +0000132
133 # if the output dir does not exist, recreate it
Kevin Cheng70936692015-10-13 14:57:26 -0700134 if not self.host.path_exists(self.outputdir):
135 self.host.run('mkdir -p %s' % self.outputdir)
mbligh35245892009-06-08 16:43:21 +0000136
137 return self.host, self.autotest, self.outputdir
jadmanski54f90af2008-10-10 16:20:55 +0000138
139
mbligh4395bbd2009-03-25 19:34:17 +0000140 def _pull_pickle(self, host, outputdir):
141 """Pulls from the client the pickle file with the saved sysinfo state.
142 """
jadmanski54f90af2008-10-10 16:20:55 +0000143 fd, path = tempfile.mkstemp(dir=self.job.tmpdir)
144 os.close(fd)
145 host.get_file(os.path.join(outputdir, "sysinfo.pickle"), path)
146 self.pickle = path
147
148
mbligh4395bbd2009-03-25 19:34:17 +0000149 def _push_pickle(self, host, outputdir):
150 """Pushes the server saved sysinfo pickle file to the client.
151 """
jadmanski54f90af2008-10-10 16:20:55 +0000152 if self.pickle:
153 host.send_file(self.pickle,
154 os.path.join(outputdir, "sysinfo.pickle"))
155 os.remove(self.pickle)
156 self.pickle = None
157
jadmanski54f90af2008-10-10 16:20:55 +0000158
mbligh4395bbd2009-03-25 19:34:17 +0000159 def _pull_sysinfo_keyval(self, host, outputdir, mytest):
160 """Pulls sysinfo and keyval data from the client.
161 """
jadmanski54f90af2008-10-10 16:20:55 +0000162 # pull the sysinfo data back on to the server
163 host.get_file(os.path.join(outputdir, "sysinfo"), mytest.outputdir)
164
165 # pull the keyval data back into the local one
166 fd, path = tempfile.mkstemp(dir=self.job.tmpdir)
167 os.close(fd)
168 host.get_file(os.path.join(outputdir, "keyval"), path)
169 keyval = utils.read_keyval(path)
170 os.remove(path)
171 mytest.write_test_keyval(keyval)
172
173
mbligh4395bbd2009-03-25 19:34:17 +0000174 @log.log_and_ignore_errors("pre-test server sysinfo error:")
jadmanski7c7aff32009-03-25 22:43:07 +0000175 @install_autotest_and_run
176 def before_hook(self, mytest, host, at, outputdir):
mbligh4395bbd2009-03-25 19:34:17 +0000177 # run the pre-test sysinfo script
xixuan02b6fee2017-02-01 18:35:20 -0800178 logging.debug('before_hook starts running for test %r.', mytest)
mbligh4395bbd2009-03-25 19:34:17 +0000179 at.run(_sysinfo_before_test_script % outputdir,
Dale Curtis9285ddf2011-01-05 11:47:24 -0800180 results_dir=self.job.resultdir)
mbligh4395bbd2009-03-25 19:34:17 +0000181
182 self._pull_pickle(host, outputdir)
xixuan02b6fee2017-02-01 18:35:20 -0800183 logging.debug('before_hook ends running.')
mbligh4395bbd2009-03-25 19:34:17 +0000184
185
186 @log.log_and_ignore_errors("pre-test iteration server sysinfo error:")
jadmanski7c7aff32009-03-25 22:43:07 +0000187 @install_autotest_and_run
188 def before_iteration_hook(self, mytest, host, at, outputdir):
mbligh4395bbd2009-03-25 19:34:17 +0000189 # this function is called after before_hook() se we have sysinfo state
190 # to push to the server
xixuan02b6fee2017-02-01 18:35:20 -0800191 logging.debug('before_iteration_hook starts running for test %r.',
192 mytest)
mbligh4395bbd2009-03-25 19:34:17 +0000193 self._push_pickle(host, outputdir);
194 # run the pre-test iteration sysinfo script
195 at.run(_sysinfo_iteration_script %
196 (outputdir, 'log_before_each_iteration', mytest.iteration,
197 'before'),
Dale Curtis9285ddf2011-01-05 11:47:24 -0800198 results_dir=self.job.resultdir)
mbligh4395bbd2009-03-25 19:34:17 +0000199
200 # get the new sysinfo state from the client
201 self._pull_pickle(host, outputdir)
xixuan02b6fee2017-02-01 18:35:20 -0800202 logging.debug('before_iteration_hook ends running.')
mbligh4395bbd2009-03-25 19:34:17 +0000203
204
205 @log.log_and_ignore_errors("post-test iteration server sysinfo error:")
jadmanski7c7aff32009-03-25 22:43:07 +0000206 @install_autotest_and_run
207 def after_iteration_hook(self, mytest, host, at, outputdir):
mbligh4395bbd2009-03-25 19:34:17 +0000208 # push latest sysinfo state to the client
xixuan02b6fee2017-02-01 18:35:20 -0800209 logging.debug('after_iteration_hook starts running for test %r.',
210 mytest)
mbligh4395bbd2009-03-25 19:34:17 +0000211 self._push_pickle(host, outputdir);
212 # run the post-test iteration sysinfo script
213 at.run(_sysinfo_iteration_script %
214 (outputdir, 'log_after_each_iteration', mytest.iteration,
215 'after'),
Dale Curtis9285ddf2011-01-05 11:47:24 -0800216 results_dir=self.job.resultdir)
mbligh4395bbd2009-03-25 19:34:17 +0000217
218 # get the new sysinfo state from the client
219 self._pull_pickle(host, outputdir)
xixuan02b6fee2017-02-01 18:35:20 -0800220 logging.debug('after_iteration_hook ends running.')
mbligh4395bbd2009-03-25 19:34:17 +0000221
222
223 @log.log_and_ignore_errors("post-test server sysinfo error:")
jadmanski7c7aff32009-03-25 22:43:07 +0000224 @install_autotest_and_run
225 def after_hook(self, mytest, host, at, outputdir):
xixuan02b6fee2017-02-01 18:35:20 -0800226 logging.debug('after_hook starts running for test %r.', mytest)
mbligh4395bbd2009-03-25 19:34:17 +0000227 self._push_pickle(host, outputdir);
228 # run the post-test sysinfo script
Dan Shi4eba9f02014-06-18 13:58:05 -0700229 at.run(_sysinfo_after_test_script % (outputdir, mytest.success),
Dale Curtis9285ddf2011-01-05 11:47:24 -0800230 results_dir=self.job.resultdir)
mbligh4395bbd2009-03-25 19:34:17 +0000231
232 self._pull_sysinfo_keyval(host, outputdir, mytest)
xixuan02b6fee2017-02-01 18:35:20 -0800233 logging.debug('after_hook ends running.')
mbligh4395bbd2009-03-25 19:34:17 +0000234
235
mbligh089f1e32009-06-22 18:26:45 +0000236 def cleanup(self, host_close=True):
mbligh35245892009-06-08 16:43:21 +0000237 if self.host and self.autotest:
238 try:
mbligh089f1e32009-06-22 18:26:45 +0000239 try:
240 self.autotest.uninstall()
241 finally:
242 if host_close:
243 self.host.close()
244 else:
245 self.host.erase_dir_contents(self.outputdir)
246
247 except Exception:
248 # ignoring exceptions here so that we don't hide the true
249 # reason of failure from runtest
250 logging.exception('Error cleaning up the sysinfo autotest/host '
251 'objects, ignoring it')
mbligh35245892009-06-08 16:43:21 +0000252
253
mbligh05269362007-10-16 16:58:11 +0000254def runtest(job, url, tag, args, dargs):
Fang Dengc2282212015-01-26 13:10:01 -0800255 """Server-side runtest.
256
257 @param job: A server_job instance.
258 @param url: URL to the test.
259 @param tag: Test tag that will be appended to the test name.
260 See client/common_lib/test.py:runtest
261 @param args: args to pass to the test.
262 @param dargs: key-val based args to pass to the test.
263 """
264
265 disable_before_test_hook = dargs.pop('disable_before_test_sysinfo', False)
266 disable_after_test_hook = dargs.pop('disable_after_test_sysinfo', False)
267 disable_before_iteration_hook = dargs.pop(
268 'disable_before_iteration_sysinfo', False)
269 disable_after_iteration_hook = dargs.pop(
270 'disable_after_iteration_sysinfo', False)
271
mbligh79a2ee12008-11-05 22:07:38 +0000272 if not dargs.pop('disable_sysinfo', False):
273 logger = _sysinfo_logger(job)
Fang Dengc2282212015-01-26 13:10:01 -0800274 logging_args = [
275 logger.before_hook if not disable_before_test_hook else None,
276 logger.after_hook if not disable_after_test_hook else None,
277 (logger.before_iteration_hook
278 if not disable_before_iteration_hook else None),
279 (logger.after_iteration_hook
280 if not disable_after_iteration_hook else None),
281 ]
mbligh79a2ee12008-11-05 22:07:38 +0000282 else:
mbligh35245892009-06-08 16:43:21 +0000283 logger = None
284 logging_args = [None, None, None, None]
285
mbligh43dd5492009-09-03 20:20:51 +0000286 # add in a hook that calls host.log_kernel if we can
287 def log_kernel_hook(mytest, existing_hook=logging_args[0]):
288 if mytest.host_parameter:
289 host = dargs[mytest.host_parameter]
290 if host:
291 host.log_kernel()
292 # chain this call with any existing hook
293 if existing_hook:
294 existing_hook(mytest)
295 logging_args[0] = log_kernel_hook
296
mbligh35245892009-06-08 16:43:21 +0000297 try:
298 common_test.runtest(job, url, tag, args, dargs, locals(), globals(),
299 *logging_args)
300 finally:
301 if logger:
302 logger.cleanup()