1 # Copyright Martin J. Bligh, Andy Whitcroft, 2007
3 # Define the server-side test class
6 import os
, tempfile
, logging
8 from autotest_lib
.client
.common_lib
import log
, utils
, test
as common_test
11 class test(common_test
.base_test
):
12 disable_sysinfo_install_cache
= False
16 _sysinfo_before_test_script
= """\
18 from autotest_lib.client.bin import test
19 mytest = test.test(job, '', %r)
20 job.sysinfo.log_before_each_test(mytest)
21 sysinfo_pickle = os.path.join(mytest.outputdir, 'sysinfo.pickle')
22 pickle.dump(job.sysinfo, open(sysinfo_pickle, 'w'))
23 job.record('GOOD', '', 'sysinfo.before')
26 _sysinfo_after_test_script
= """\
28 from autotest_lib.client.bin import test
29 mytest = test.test(job, '', %r)
30 sysinfo_pickle = os.path.join(mytest.outputdir, 'sysinfo.pickle')
31 if os.path.exists(sysinfo_pickle):
32 job.sysinfo = pickle.load(open(sysinfo_pickle))
33 job.sysinfo.__init__(job.resultdir)
34 job.sysinfo.log_after_each_test(mytest)
35 job.record('GOOD', '', 'sysinfo.after')
38 # this script is ran after _sysinfo_before_test_script and before
39 # _sysinfo_after_test_script which means the pickle file exists
40 # already and should be dumped with updated state for
41 # _sysinfo_after_test_script to pick it up later
42 _sysinfo_iteration_script
= """\
44 from autotest_lib.client.bin import test
45 mytest = test.test(job, '', %r)
46 sysinfo_pickle = os.path.join(mytest.outputdir, 'sysinfo.pickle')
47 if os.path.exists(sysinfo_pickle):
48 job.sysinfo = pickle.load(open(sysinfo_pickle))
49 job.sysinfo.__init__(job.resultdir)
50 job.sysinfo.%s(mytest, iteration=%d)
51 pickle.dump(job.sysinfo, open(sysinfo_pickle, 'w'))
52 job.record('GOOD', '', 'sysinfo.iteration.%s')
56 def install_autotest_and_run(func
):
57 def wrapper(self
, mytest
):
58 host
, at
, outputdir
= self
._install
()
60 host
.erase_dir_contents(outputdir
)
61 func(self
, mytest
, host
, at
, outputdir
)
63 # the test class can define this flag to make us remove the
64 # sysinfo install files and outputdir contents after each run
65 if mytest
.disable_sysinfo_install_cache
:
66 self
.cleanup(host_close
=False)
71 class _sysinfo_logger(object):
72 def __init__(self
, job
):
76 # for now support a single host
81 if len(job
.machines
) != 1:
82 # disable logging on multi-machine tests
83 self
.before_hook
= self
.after_hook
= None
84 self
.before_iteration_hook
= self
.after_iteration_hook
= None
89 from autotest_lib
.server
import hosts
, autotest
90 self
.host
= hosts
.create_host(self
.job
.machines
[0],
93 tmp_dir
= self
.host
.get_tmp_dir(parent
="/tmp/sysinfo")
94 self
.autotest
= autotest
.Autotest(self
.host
)
95 self
.autotest
.install(autodir
=tmp_dir
)
96 self
.outputdir
= self
.host
.get_tmp_dir()
98 # if installation fails roll back the host
102 logging
.exception("Unable to close host %s",
110 # if autotest client dir does not exist, reinstall (it may have
111 # been removed by the test code)
112 autodir
= host
.get_autodir()
113 if not autodir
or not host
.path_exists(autodir
):
114 self
.autotest
.install(autodir
=autodir
)
116 # if the output dir does not exist, recreate it
117 if not host
.path_exists(self
.outputdir
):
118 host
.run('mkdir -p %s' % self
.outputdir
)
120 return self
.host
, self
.autotest
, self
.outputdir
123 def _pull_pickle(self
, host
, outputdir
):
124 """Pulls from the client the pickle file with the saved sysinfo state.
126 fd
, path
= tempfile
.mkstemp(dir=self
.job
.tmpdir
)
128 host
.get_file(os
.path
.join(outputdir
, "sysinfo.pickle"), path
)
132 def _push_pickle(self
, host
, outputdir
):
133 """Pushes the server saved sysinfo pickle file to the client.
136 host
.send_file(self
.pickle
,
137 os
.path
.join(outputdir
, "sysinfo.pickle"))
138 os
.remove(self
.pickle
)
142 def _pull_sysinfo_keyval(self
, host
, outputdir
, mytest
):
143 """Pulls sysinfo and keyval data from the client.
145 # pull the sysinfo data back on to the server
146 host
.get_file(os
.path
.join(outputdir
, "sysinfo"), mytest
.outputdir
)
148 # pull the keyval data back into the local one
149 fd
, path
= tempfile
.mkstemp(dir=self
.job
.tmpdir
)
151 host
.get_file(os
.path
.join(outputdir
, "keyval"), path
)
152 keyval
= utils
.read_keyval(path
)
154 mytest
.write_test_keyval(keyval
)
157 @log.log_and_ignore_errors("pre-test server sysinfo error:")
158 @install_autotest_and_run
159 def before_hook(self
, mytest
, host
, at
, outputdir
):
160 # run the pre-test sysinfo script
161 at
.run(_sysinfo_before_test_script
% outputdir
,
162 results_dir
=self
.job
.resultdir
)
164 self
._pull
_pickle
(host
, outputdir
)
167 @log.log_and_ignore_errors("pre-test iteration server sysinfo error:")
168 @install_autotest_and_run
169 def before_iteration_hook(self
, mytest
, host
, at
, outputdir
):
170 # this function is called after before_hook() se we have sysinfo state
171 # to push to the server
172 self
._push
_pickle
(host
, outputdir
);
173 # run the pre-test iteration sysinfo script
174 at
.run(_sysinfo_iteration_script
%
175 (outputdir
, 'log_before_each_iteration', mytest
.iteration
,
177 results_dir
=self
.job
.resultdir
)
179 # get the new sysinfo state from the client
180 self
._pull
_pickle
(host
, outputdir
)
183 @log.log_and_ignore_errors("post-test iteration server sysinfo error:")
184 @install_autotest_and_run
185 def after_iteration_hook(self
, mytest
, host
, at
, outputdir
):
186 # push latest sysinfo state to the client
187 self
._push
_pickle
(host
, outputdir
);
188 # run the post-test iteration sysinfo script
189 at
.run(_sysinfo_iteration_script
%
190 (outputdir
, 'log_after_each_iteration', mytest
.iteration
,
192 results_dir
=self
.job
.resultdir
)
194 # get the new sysinfo state from the client
195 self
._pull
_pickle
(host
, outputdir
)
198 @log.log_and_ignore_errors("post-test server sysinfo error:")
199 @install_autotest_and_run
200 def after_hook(self
, mytest
, host
, at
, outputdir
):
201 self
._push
_pickle
(host
, outputdir
);
202 # run the post-test sysinfo script
203 at
.run(_sysinfo_after_test_script
% outputdir
,
204 results_dir
=self
.job
.resultdir
)
206 self
._pull
_sysinfo
_keyval
(host
, outputdir
, mytest
)
209 def cleanup(self
, host_close
=True):
210 if self
.host
and self
.autotest
:
213 self
.autotest
.uninstall()
218 self
.host
.erase_dir_contents(self
.outputdir
)
221 # ignoring exceptions here so that we don't hide the true
222 # reason of failure from runtest
223 logging
.exception('Error cleaning up the sysinfo autotest/host '
224 'objects, ignoring it')
227 def runtest(job
, url
, tag
, args
, dargs
):
228 if not dargs
.pop('disable_sysinfo', False):
229 logger
= _sysinfo_logger(job
)
230 logging_args
= [logger
.before_hook
, logger
.after_hook
,
231 logger
.before_iteration_hook
,
232 logger
.after_iteration_hook
]
235 logging_args
= [None, None, None, None]
237 # add in a hook that calls host.log_kernel if we can
238 def log_kernel_hook(mytest
, existing_hook
=logging_args
[0]):
239 if mytest
.host_parameter
:
240 host
= dargs
[mytest
.host_parameter
]
243 # chain this call with any existing hook
245 existing_hook(mytest
)
246 logging_args
[0] = log_kernel_hook
249 common_test
.runtest(job
, url
, tag
, args
, dargs
, locals(), globals(),