job_unittest.py revision 9e722984cea169afec7b6515f7178a131a22bb0b
1ef77253961f909f87e82e6d2b620e87af33e9665yaberauneya#!/usr/bin/python
2ef77253961f909f87e82e6d2b620e87af33e9665yaberauneya
3ef77253961f909f87e82e6d2b620e87af33e9665yaberauneyaimport os, unittest, pickle, shutil, sys, time
4ef77253961f909f87e82e6d2b620e87af33e9665yaberauneyaimport common
5ef77253961f909f87e82e6d2b620e87af33e9665yaberauneya
6ef77253961f909f87e82e6d2b620e87af33e9665yaberauneyafrom autotest_lib.client.bin import job, boottool, config, sysinfo, harness
7ef77253961f909f87e82e6d2b620e87af33e9665yaberauneyafrom autotest_lib.client.bin import test, xen, kernel, autotest_utils, cpuset
8ef77253961f909f87e82e6d2b620e87af33e9665yaberauneyafrom autotest_lib.client.common_lib import utils, error, logging
9ef77253961f909f87e82e6d2b620e87af33e9665yaberauneyafrom autotest_lib.client.common_lib.test_utils import mock
10ef77253961f909f87e82e6d2b620e87af33e9665yaberauneya
11ef77253961f909f87e82e6d2b620e87af33e9665yaberauneya
12ef77253961f909f87e82e6d2b620e87af33e9665yaberauneyaclass first_line_comparator(mock.argument_comparator):
13ef77253961f909f87e82e6d2b620e87af33e9665yaberauneya    def __init__(self, first_line):
14ef77253961f909f87e82e6d2b620e87af33e9665yaberauneya        self.first_line = first_line
15ef77253961f909f87e82e6d2b620e87af33e9665yaberauneya
16ef77253961f909f87e82e6d2b620e87af33e9665yaberauneya
17ef77253961f909f87e82e6d2b620e87af33e9665yaberauneya    def is_satisfied_by(self, parameter):
18ef77253961f909f87e82e6d2b620e87af33e9665yaberauneya        return self.first_line == parameter.splitlines()[0]
19ef77253961f909f87e82e6d2b620e87af33e9665yaberauneya
208967f960f820f449162101a02ee5747f195a8a57Ngie Cooper
21ef77253961f909f87e82e6d2b620e87af33e9665yaberauneyaclass TestBaseJob(unittest.TestCase):
22865695bbc89088b9526ea9045410e5afb70a985cplars    def setUp(self):
23ef77253961f909f87e82e6d2b620e87af33e9665yaberauneya        # make god
24865695bbc89088b9526ea9045410e5afb70a985cplars        self.god = mock.mock_god()
25ef77253961f909f87e82e6d2b620e87af33e9665yaberauneya
2648ef3a4bb94e8e55952cd983dbcce749229c1bebnstraz        # need to set some environ variables
27ef77253961f909f87e82e6d2b620e87af33e9665yaberauneya        self.autodir = "autodir"
28ef77253961f909f87e82e6d2b620e87af33e9665yaberauneya        os.environ['AUTODIR'] = self.autodir
29865695bbc89088b9526ea9045410e5afb70a985cplars
30ef77253961f909f87e82e6d2b620e87af33e9665yaberauneya        # set up some variables
31865695bbc89088b9526ea9045410e5afb70a985cplars        self.control = "control"
32ef77253961f909f87e82e6d2b620e87af33e9665yaberauneya        self.jobtag = "jobtag"
33ef77253961f909f87e82e6d2b620e87af33e9665yaberauneya
34ef77253961f909f87e82e6d2b620e87af33e9665yaberauneya        # stub out some stuff
35ef77253961f909f87e82e6d2b620e87af33e9665yaberauneya        self.god.stub_function(os.path, 'exists')
36ef77253961f909f87e82e6d2b620e87af33e9665yaberauneya        self.god.stub_function(os.path, 'isdir')
37        self.god.stub_function(os, 'mkdir')
38        self.god.stub_function(shutil, 'copyfile')
39        self.god.stub_function(job, 'open')
40        self.god.stub_function(utils, 'system')
41        self.god.stub_function(harness, 'select')
42        self.god.stub_function(sysinfo, 'log_per_reboot_data')
43        self.god.stub_function(pickle, 'load')
44        self.god.stub_function(sysinfo, 'log_per_reboot_data')
45
46        self.god.stub_class(config, 'config')
47        self.god.stub_class(boottool, 'boottool')
48
49
50    def tearDown(self):
51        self.god.unstub_all()
52
53
54    def construct_job(self, cont):
55        # will construct class instance using __new__
56        self.job = job.base_job.__new__(job.base_job)
57
58        # now some specific stubs
59        self.god.stub_function(self.job, '_load_state')
60        self.god.stub_function(self.job, '_init_group_level')
61        self.god.stub_function(self.job, 'config_get')
62        self.god.stub_function(self.job, 'record')
63        self.god.stub_function(self.job, '_increment_group_level')
64        self.god.stub_function(self.job, '_decrement_group_level')
65        self.god.stub_function(self.job, 'get_state')
66
67        # other setup
68        tmpdir = os.path.join(self.autodir, 'tmp')
69        results = os.path.join(self.autodir, 'results')
70        download = os.path.join(self.autodir, 'tests', 'download')
71        resultdir = os.path.join(self.autodir, 'results', self.jobtag)
72        sysinfodir = os.path.join(resultdir, 'sysinfo')
73
74        # record
75        self.job._load_state.expect_call()
76        if not cont:
77            os.path.exists.expect_call(tmpdir).and_return(False)
78            os.mkdir.expect_call(tmpdir)
79            os.path.exists.expect_call(results).and_return(False)
80            os.mkdir.expect_call(results)
81            os.path.exists.expect_call(download).and_return(False)
82            os.mkdir.expect_call(download)
83            os.path.exists.expect_call(resultdir).and_return(True)
84            utils.system.expect_call('rm -rf ' + resultdir)
85            os.mkdir.expect_call(resultdir)
86            os.mkdir.expect_call(sysinfodir)
87            os.mkdir.expect_call(os.path.join(resultdir, 'debug'))
88            os.mkdir.expect_call(os.path.join(resultdir,
89                                              'analysis'))
90            shutil.copyfile.expect_call(mock.is_string_comparator(),
91                                 os.path.join(resultdir, 'control'))
92
93        self.job._init_group_level.expect_call()
94        self.config = config.config.expect_new(self.job)
95        my_harness = self.god.create_mock_class(harness.harness,
96                                                'my_harness')
97        harness.select.expect_call(None,
98                                   self.job).and_return(my_harness)
99        self.job.config_get.expect_call(
100                'boottool.executable').and_return(None)
101        bootloader = boottool.boottool.expect_new(None)
102        sysinfo.log_per_reboot_data.expect_call(sysinfodir)
103        if not cont:
104            self.job.record.expect_call('START', None, None)
105            self.job._increment_group_level.expect_call()
106
107        my_harness.run_start.expect_call()
108        self.job.get_state.expect_call('__monitor_disk',
109                                       default=0.0).and_return(0.0)
110
111        # finish constructor
112        self.job.__init__(self.control, self.jobtag, cont)
113
114        # check
115        self.god.check_playback()
116
117
118    def test_constructor(self):
119        self.construct_job(False)
120
121
122    def test_monitor_disk_usage(self):
123        self.construct_job(True)
124
125        # setup
126        self.god.stub_function(self.job, 'set_state')
127
128        # record
129        max_rate = 10.0
130        self.job.set_state.expect_call('__monitor_disk', max_rate)
131
132        # test
133        self.job.monitor_disk_usage(max_rate)
134        self.god.check_playback()
135
136
137    def test_relative_path(self):
138        self.construct_job(True)
139        dummy = "asdf"
140        ret = self.job.relative_path(os.path.join(self.job.resultdir, dummy))
141        self.assertEquals(ret, dummy)
142
143
144    def test_control_functions(self):
145        self.construct_job(True)
146        control_file = "blah"
147        self.job.control_set(control_file)
148        self.assertEquals(self.job.control_get(), os.path.abspath(control_file))
149
150
151    def test_harness_select(self):
152        self.construct_job(True)
153
154        # record
155        which = "which"
156        harness.select.expect_call(which, self.job).and_return(None)
157
158        # run and test
159        self.job.harness_select(which)
160        self.god.check_playback()
161
162
163    def test_config_set(self):
164        self.construct_job(True)
165
166        # record
167        name = "foo"
168        val = 10
169        self.config.set.expect_call(name, val)
170
171        # run and test
172        self.job.config_set(name, val)
173        self.god.check_playback()
174
175
176    def test_config_get(self):
177        self.construct_job(True)
178
179        # unstub config_get
180        self.god.unstub(self.job, 'config_get')
181        # record
182        name = "foo"
183        val = 10
184        self.config.get.expect_call(name).and_return(val)
185
186        # run and test
187        self.job.config_get(name)
188        self.god.check_playback()
189
190
191    def test_setup_dirs_raise(self):
192        self.construct_job(True)
193
194        # setup
195        results_dir = 'foo'
196        tmp_dir = 'bar'
197
198        # record
199        os.path.exists.expect_call(tmp_dir).and_return(True)
200        os.path.isdir.expect_call(tmp_dir).and_return(False)
201
202        # test
203        self.assertRaises(ValueError, self.job.setup_dirs, results_dir, tmp_dir)
204        self.god.check_playback()
205
206
207    def test_setup_dirs(self):
208        self.construct_job(True)
209
210        # setup
211        results_dir1 = os.path.join(self.job.resultdir, 'build')
212        results_dir2 = os.path.join(self.job.resultdir, 'build.2')
213        results_dir3 = os.path.join(self.job.resultdir, 'build.3')
214        tmp_dir = 'bar'
215
216        # record
217        os.path.exists.expect_call(tmp_dir).and_return(False)
218        os.mkdir.expect_call(tmp_dir)
219        os.path.isdir.expect_call(tmp_dir).and_return(True)
220        os.path.exists.expect_call(results_dir1).and_return(True)
221        os.path.exists.expect_call(results_dir2).and_return(True)
222        os.path.exists.expect_call(results_dir3).and_return(False)
223        os.path.exists.expect_call(results_dir3).and_return(False)
224        os.mkdir.expect_call(results_dir3)
225
226        # test
227        self.assertEqual(self.job.setup_dirs(None, tmp_dir),
228                         (results_dir3, tmp_dir))
229        self.god.check_playback()
230
231
232    def test_xen(self):
233        self.construct_job(True)
234
235        # setup
236        self.god.stub_function(self.job, "setup_dirs")
237        self.god.stub_class(xen, "xen")
238        results = 'results_dir'
239        tmp = 'tmp'
240        build = 'xen'
241        base_tree = object()
242
243        # record
244        self.job.setup_dirs.expect_call(results,
245                                        tmp).and_return((results, tmp))
246        myxen = xen.xen.expect_new(self.job, base_tree, results, tmp, build,
247                                   False, None)
248
249        # run job and check
250        axen = self.job.xen(base_tree, results, tmp)
251        self.god.check_playback()
252        self.assertEquals(myxen, axen)
253
254
255    def test_kernel_rpm(self):
256        self.construct_job(True)
257
258        # setup
259        self.god.stub_function(self.job, "setup_dirs")
260        self.god.stub_class(kernel, "rpm_kernel")
261        self.god.stub_function(kernel, "preprocess_path")
262        results = 'results_dir'
263        tmp = 'tmp'
264        build = 'xen'
265        path = "somepath.rpm"
266
267        # record
268        self.job.setup_dirs.expect_call(results,
269                                        tmp).and_return((results, tmp))
270        kernel.preprocess_path.expect_call(path).and_return(path)
271        mykernel = kernel.rpm_kernel.expect_new(self.job, path, results)
272
273        # check
274        akernel = self.job.kernel(path, results, tmp)
275        self.god.check_playback()
276        self.assertEquals(mykernel, akernel)
277
278
279    def test_kernel(self):
280        self.construct_job(True)
281
282        # setup
283        self.god.stub_function(self.job, "setup_dirs")
284        self.god.stub_class(kernel, "kernel")
285        self.god.stub_function(kernel, "preprocess_path")
286        results = 'results_dir'
287        tmp = 'tmp'
288        build = 'linux'
289        path = "somepath.deb"
290
291        # record
292        self.job.setup_dirs.expect_call(results,
293                                        tmp).and_return((results, tmp))
294        kernel.preprocess_path.expect_call(path).and_return(path)
295        mykernel = kernel.kernel.expect_new(self.job, path, results, tmp,
296                                            build, False)
297
298        # check
299        akernel = self.job.kernel(path, results, tmp)
300        self.god.check_playback()
301        self.assertEquals(mykernel, akernel)
302
303
304    def test_run_test_logs_test_error_from_unhandled_error(self):
305        self.construct_job(True)
306
307        # set up stubs
308        self.god.stub_function(test, "testname")
309        self.god.stub_function(self.job, "_runtest")
310
311        # create an unhandled error object
312        class MyError(error.TestError):
313            pass
314        real_error = MyError("this is the real error message")
315        unhandled_error = error.UnhandledError(real_error)
316
317        # set up the recording
318        testname = "error_test"
319        outputdir = os.path.join(self.job.resultdir, testname)
320        test.testname.expect_call(testname).and_return(("", testname))
321        os.path.exists.expect_call(outputdir).and_return(False)
322        os.mkdir.expect_call(outputdir)
323        self.job.record.expect_call("START", testname, testname)
324        self.job._increment_group_level.expect_call()
325        self.job._runtest.expect_call(testname, "", (), {}).and_raises(
326            unhandled_error)
327        self.job.record.expect_call("FAIL", testname, testname,
328                                    first_line_comparator(str(real_error)))
329        self.job._decrement_group_level.expect_call()
330        self.job.record.expect_call("END FAIL", testname, testname,
331                                    first_line_comparator(str(real_error)))
332
333        # run and check
334        self.job.run_test(testname)
335        self.god.check_playback()
336
337
338    def test_run_test_logs_non_test_error_from_unhandled_error(self):
339        self.construct_job(True)
340
341        # set up stubs
342        self.god.stub_function(test, "testname")
343        self.god.stub_function(self.job, "_runtest")
344
345        # create an unhandled error object
346        class MyError(Exception):
347            pass
348        real_error = MyError("this is the real error message")
349        unhandled_error = error.UnhandledError(real_error)
350        reason = first_line_comparator("Unhandled MyError: %s" % real_error)
351
352        # set up the recording
353        testname = "error_test"
354        outputdir = os.path.join(self.job.resultdir, testname)
355        test.testname.expect_call(testname).and_return(("", testname))
356        os.path.exists.expect_call(outputdir).and_return(False)
357        os.mkdir.expect_call(outputdir)
358        self.job.record.expect_call("START", testname, testname)
359        self.job._increment_group_level.expect_call()
360        self.job._runtest.expect_call(testname, "", (), {}).and_raises(
361            unhandled_error)
362        self.job.record.expect_call("FAIL", testname, testname, reason)
363        self.job._decrement_group_level.expect_call()
364        self.job.record.expect_call("END FAIL", testname, testname, reason)
365
366        # run and check
367        self.job.run_test(testname)
368        self.god.check_playback()
369
370
371    def new_container(self):
372        self.construct_job(True)
373
374        # set up stubs
375        self.god.stub_function(autotest_utils, "grep")
376        self.god.stub_function(os, "getpid")
377        self.god.stub_class(cpuset, "cpuset")
378        pid = 100
379        name = 'test%d' % pid
380
381        # record
382        autotest_utils.grep.expect_call('cpuset',
383            '/proc/filesystems').and_return(True)
384        os.getpid.expect_call().and_return(pid)
385
386        container = cpuset.cpuset.expect_new(name, job_size=None, job_pid=pid,
387                                             cpus=None, root=None,
388                                             network=None)
389
390        # run test
391        self.job.new_container()
392        self.god.check_playback()
393        return container
394
395
396    def test_new_container(self):
397        container = self.new_container()
398        self.assertEquals(self.job.container, container)
399
400
401    def test_release_container(self):
402        self.new_container()
403
404        # record
405        self.job.container.release.expect_call()
406
407        # run
408        self.job.release_container()
409        self.god.check_playback()
410        self.assertEquals(self.job.container, None)
411
412
413    def test_record(self):
414        self.construct_job(True)
415
416        # steup
417        self.job.group_level = 1
418        status = ''
419        status_code = "PASS"
420        subdir = "subdir"
421        operation = "super_fun"
422        mytime = "1234"
423        msg_tag = ""
424        if "." in self.job.log_filename:
425            msg_tag = self.job.log_filename.split(".", 1)[1]
426        epoch_time = int(mytime)
427        local_time = time.localtime(epoch_time)
428        optional_fields = {}
429        optional_fields["timestamp"] = str(epoch_time)
430        optional_fields["localtime"] = time.strftime("%b %d %H:%M:%S",
431                                                     local_time)
432        fields = [status_code, subdir, operation]
433        fields += ["%s=%s" % x for x in optional_fields.iteritems()]
434        fields.append(status)
435        msg = '\t'.join(str(x) for x in fields)
436        msg = '\t' * self.job.group_level + msg
437
438        self.god.stub_function(logging, "is_valid_status")
439        self.god.stub_function(time, "time")
440        self.god.stub_function(self.job, "open")
441
442
443        # record
444        logging.is_valid_status.expect_call(status_code).and_return(True)
445        time.time.expect_call().and_return(mytime)
446        self.job.harness.test_status_detail.expect_call(status_code, subdir,
447                                                        operation, '', msg_tag)
448        self.job.harness.test_status.expect_call(msg, msg_tag)
449        myfile = self.god.create_mock_class(file, "file")
450        status_file = os.path.join(self.job.resultdir, self.job.log_filename)
451        self.job.open.expect_call(status_file, "a").and_return(myfile)
452        myfile.write.expect_call(msg + "\n")
453
454        dir = os.path.join(self.job.resultdir, subdir)
455        status_file = os.path.join(dir, self.job.DEFAULT_LOG_FILENAME)
456        self.job.open.expect_call(status_file, "a").and_return(myfile)
457        myfile.write.expect_call(msg + "\n")
458
459
460        # run test
461        self.god.unstub(self.job, "record")
462        self.job.record(status_code, subdir, operation)
463        self.god.check_playback()
464
465
466if __name__ == "__main__":
467    unittest.main()
468