blob: 33d7ec43ca90982adc31e7b52b4d3fc6cdd1dbfb [file] [log] [blame]
mbligh6231cd62008-02-02 19:18:33 +00001# Shell class for a test, inherited by all individual tests
2#
3# Methods:
4# __init__ initialise
5# initialize run once for each job
6# setup run once for each new version of the test installed
7# run run the test (wrapped by job.run_test())
8#
9# Data:
10# job backreference to the job this test instance is part of
11# outputdir eg. results/<job>/<testname.tag>
12# resultsdir eg. results/<job>/<testname.tag>/results
13# profdir eg. results/<job>/<testname.tag>/profiling
14# debugdir eg. results/<job>/<testname.tag>/debug
15# bindir eg. tests/<test>
16# src eg. tests/<test>/src
17# tmpdir eg. tmp/<testname.tag>
18
jadmanskicc549172008-05-21 18:11:51 +000019import os, sys, re, fcntl, shutil, tarfile, warnings
mbligh6231cd62008-02-02 19:18:33 +000020
jadmanskif55dfc92008-05-16 16:14:54 +000021from autotest_lib.client.common_lib import error, utils
mbligh6231cd62008-02-02 19:18:33 +000022
23
24class base_test:
25 preserve_srcdir = False
26
27 def __init__(self, job, bindir, outputdir):
28 self.job = job
29 self.autodir = job.autodir
30
31 self.outputdir = outputdir
32 tagged_testname = os.path.basename(self.outputdir)
33 # check if the outputdir already exists, because if it does
34 # then this test has already been run with the same tag earlier
35 # in this job
36 if os.path.exists(self.outputdir):
37 testname, tag = (tagged_testname + '.').split('.', 1)
38 msg = ("%s already exists, test <%s> may have already "
39 + "run with tag <%s>") % (tagged_testname,
40 testname, tag)
mbligh313f12c2008-05-15 23:33:50 +000041 raise error.TestError(msg)
mbligh6231cd62008-02-02 19:18:33 +000042 else:
43 os.mkdir(self.outputdir)
44
45 self.resultsdir = os.path.join(self.outputdir, 'results')
46 os.mkdir(self.resultsdir)
47 self.profdir = os.path.join(self.outputdir, 'profiling')
48 os.mkdir(self.profdir)
49 self.debugdir = os.path.join(self.outputdir, 'debug')
50 os.mkdir(self.debugdir)
51 self.bindir = bindir
52 if hasattr(job, 'libdir'):
53 self.libdir = job.libdir
54 self.srcdir = os.path.join(self.bindir, 'src')
55
56 self.tmpdir = os.path.join(job.tmpdir, tagged_testname)
57
58 if os.path.exists(self.tmpdir):
59 shutil.rmtree(self.tmpdir)
60 os.mkdir(self.tmpdir)
61
62 self.job.stdout.tee_redirect(
63 os.path.join(self.debugdir, 'stdout'))
64 self.job.stderr.tee_redirect(
65 os.path.join(self.debugdir, 'stderr'))
66 try:
67 self.initialize()
68 # compile and install the test, if needed.
jadmanskif55dfc92008-05-16 16:14:54 +000069 utils.update_version(self.srcdir, self.preserve_srcdir,
70 self.version, self.setup)
mbligh6231cd62008-02-02 19:18:33 +000071 finally:
72 self.job.stderr.restore()
73 self.job.stdout.restore()
74
75
76 def assert_(self, expr, msg='Assertion failed.'):
77 if not expr:
mbligh313f12c2008-05-15 23:33:50 +000078 raise error.TestError(msg)
mbligh6231cd62008-02-02 19:18:33 +000079
80
jadmanskicc549172008-05-21 18:11:51 +000081 def write_test_keyval(self, attr_dict):
82 utils.write_keyval(self.outputdir, attr_dict)
83
84
85 @staticmethod
86 def _append_type_to_keys(dictionary, typename):
87 new_dict = {}
88 for key, value in dictionary.iteritems():
89 new_key = "%s{%s}" % (key, typename)
90 new_dict[new_key] = value
91 return new_dict
92
93
94 def write_iteration_keyval(self, attr_dict, perf_dict):
95 attr_dict = self._append_type_to_keys(attr_dict, "attr")
96 perf_dict = self._append_type_to_keys(perf_dict, "perf")
97
98 utils.write_keyval(self.resultsdir, attr_dict,
99 type_tag="attr")
100 utils.write_keyval(self.resultsdir, perf_dict,
101 type_tag="perf")
102
103 keyval_path = os.path.join(self.resultsdir, "keyval")
104 print >> open(keyval_path, "a"), ""
105
106
107 # TODO: deprecate, remove from code in favour of
108 # the write_*_keyval methods
mbligh6231cd62008-02-02 19:18:33 +0000109 def write_keyval(self, dictionary):
jadmanskicc549172008-05-21 18:11:51 +0000110 warnings.warn("test.write_keyval is deprecated, use "
111 "test.write_test_keyval or "
112 "test.write_iteration_keyval instead",
113 DeprecationWarning)
114 self.write_iteration_keyval({}, dictionary)
mbligh6231cd62008-02-02 19:18:33 +0000115
116
117 def initialize(self):
118 pass
119
120
121 def setup(self):
122 pass
123
124
125 def cleanup(self):
126 pass
127
128
129 def _exec(self, args, dargs):
130 try:
131 self.job.stdout.tee_redirect(
132 os.path.join(self.debugdir, 'stdout'))
133 self.job.stderr.tee_redirect(
134 os.path.join(self.debugdir, 'stderr'))
135
136 try:
137 os.chdir(self.outputdir)
jadmanskicc549172008-05-21 18:11:51 +0000138 version_dict = {'version': self.version}
139 self.write_test_keyval(version_dict)
mbligh6231cd62008-02-02 19:18:33 +0000140 self.execute(*args, **dargs)
141 finally:
142 self.cleanup()
143 self.job.stderr.restore()
144 self.job.stdout.restore()
mbligh313f12c2008-05-15 23:33:50 +0000145 except error.AutotestError:
mbligh6231cd62008-02-02 19:18:33 +0000146 raise
jadmanskicf8c4d62008-05-27 22:09:14 +0000147 except Exception, e:
148 msg = "Unhandled %s error occured during test\n"
149 msg %= str(e.__class__.__name__)
150 raise error.UnhandledError(msg)
mbligh6231cd62008-02-02 19:18:33 +0000151
152
153def testname(url):
154 # Extract the testname from the test url.
155 match = re.match('[^:]+://(.*)/([^/]*)$', url)
156 if not match:
157 return ('', url)
158 (group, filename) = match.groups()
159
160 # Generate the group prefix.
161 group = re.sub(r'\W', '_', group)
162
163 # Drop the extension to get the raw test name.
164 testname = re.sub(r'\.tgz', '', filename)
165
166 return (group, testname)
167
168
169def _installtest(job, url):
170 (group, name) = testname(url)
171
172 # Bail if the test is already installed
173 group_dir = os.path.join(job.testdir, "download", group)
174 if os.path.exists(os.path.join(group_dir, name)):
175 return (group, name)
176
177 # If the group directory is missing create it and add
178 # an empty __init__.py so that sub-directories are
179 # considered for import.
180 if not os.path.exists(group_dir):
181 os.mkdir(group_dir)
182 f = file(os.path.join(group_dir, '__init__.py'), 'w+')
183 f.close()
184
185 print name + ": installing test url=" + url
186 get_file(url, os.path.join(group_dir, 'test.tgz'))
187 old_wd = os.getcwd()
188 os.chdir(group_dir)
mblighc78b54e2008-05-13 22:29:49 +0000189 tar = tarfile.open('test.tgz')
mbligh6231cd62008-02-02 19:18:33 +0000190 for member in tar.getmembers():
191 tar.extract(member)
192 tar.close()
193 os.chdir(old_wd)
194 os.remove(os.path.join(group_dir, 'test.tgz'))
195
196 # For this 'sub-object' to be importable via the name
197 # 'group.name' we need to provide an __init__.py,
198 # so link the main entry point to this.
199 os.symlink(name + '.py', os.path.join(group_dir, name,
200 '__init__.py'))
201
202 # The test is now installed.
203 return (group, name)
204
205
206def runtest(job, url, tag, args, dargs,
207 local_namespace={}, global_namespace={}, after_test_hook=None):
208 local_namespace = local_namespace.copy()
209 global_namespace = global_namespace.copy()
210
211 # if this is not a plain test name then download and install the
212 # specified test
jadmanskif55dfc92008-05-16 16:14:54 +0000213 if utils.is_url(url):
mbligh6231cd62008-02-02 19:18:33 +0000214 (group, testname) = _installtest(job, url)
215 bindir = os.path.join(job.testdir, 'download', group, testname)
216 site_bindir = None
217 else:
218 # if the test is local, it can be found in either testdir
219 # or site_testdir. tests in site_testdir override tests
220 # defined in testdir
221 (group, testname) = ('', url)
222 bindir = os.path.join(job.testdir, group, testname)
223 if hasattr(job, 'site_testdir'):
224 site_bindir = os.path.join(job.site_testdir,
225 group, testname)
226 else:
227 site_bindir = None
228
229 outputdir = os.path.join(job.resultdir, testname)
230 if tag:
231 outputdir += '.' + tag
232
233 # if we can find the test in site_bindir, use this version
234 if site_bindir and os.path.exists(site_bindir):
235 bindir = site_bindir
236 testdir = job.site_testdir
237 elif os.path.exists(bindir):
238 testdir = job.testdir
239 elif not os.path.exists(bindir):
mbligh313f12c2008-05-15 23:33:50 +0000240 raise error.TestError(testname + ': test does not exist')
mbligh6231cd62008-02-02 19:18:33 +0000241
242 if group:
243 sys.path.insert(0, os.path.join(testdir, 'download'))
244 group += '.'
245 else:
246 sys.path.insert(0, os.path.join(testdir, testname))
247
248 local_namespace['job'] = job
249 local_namespace['bindir'] = bindir
250 local_namespace['outputdir'] = outputdir
251
mblighb9e18dd2008-03-06 21:44:34 +0000252 lockfile = open(os.path.join(job.tmpdir, '.testlock'), 'w')
mbligh6231cd62008-02-02 19:18:33 +0000253 try:
mbligh6231cd62008-02-02 19:18:33 +0000254 fcntl.flock(lockfile, fcntl.LOCK_EX)
255 exec ("import %s%s" % (group, testname),
256 local_namespace, global_namespace)
257 exec ("mytest = %s%s.%s(job, bindir, outputdir)" %
258 (group, testname, testname),
259 local_namespace, global_namespace)
260 finally:
261 fcntl.flock(lockfile, fcntl.LOCK_UN)
262 lockfile.close()
263 sys.path.pop(0)
264
265 pwd = os.getcwd()
266 os.chdir(outputdir)
267 try:
268 mytest = global_namespace['mytest']
269 mytest._exec(args, dargs)
270 finally:
271 if after_test_hook:
272 after_test_hook(mytest)