job_unittest.py revision a536dbfc5e5a92a32520d31f856db8f4df4980d0
1#!/usr/bin/python
2
3import logging, os, unittest, shutil, sys, time, StringIO
4import common
5
6from autotest_lib.client.bin import job, boottool, config, sysinfo, harness
7from autotest_lib.client.bin import test, xen, kernel, utils
8from autotest_lib.client.common_lib import packages, error, log, logging_manager
9from autotest_lib.client.common_lib import logging_config
10from autotest_lib.client.common_lib.test_utils import mock
11
12
13class Dummy(object):
14    """A simple placeholder for attributes"""
15    pass
16
17
18class first_line_comparator(mock.argument_comparator):
19    def __init__(self, first_line):
20        self.first_line = first_line
21
22
23    def is_satisfied_by(self, parameter):
24        return self.first_line == parameter.splitlines()[0]
25
26
27class TestBaseJob(unittest.TestCase):
28    def setUp(self):
29        # make god
30        self.god = mock.mock_god()
31
32        # need to set some environ variables
33        self.autodir = "autodir"
34        os.environ['AUTODIR'] = self.autodir
35
36        # set up some variables
37        self.control = "control"
38        self.jobtag = "jobtag"
39
40        # get rid of stdout and logging
41        sys.stdout = StringIO.StringIO()
42        logging_manager.configure_logging(logging_config.TestingConfig())
43        logging.disable(logging.CRITICAL)
44        def dummy_configure_logging(*args, **kwargs):
45            pass
46        self.god.stub_with(logging_manager, 'configure_logging',
47                           dummy_configure_logging)
48        real_get_logging_manager = logging_manager.get_logging_manager
49        def get_logging_manager_no_fds(manage_stdout_and_stderr=False,
50                                       redirect_fds=False):
51            return real_get_logging_manager(manage_stdout_and_stderr, False)
52        self.god.stub_with(logging_manager, 'get_logging_manager',
53                           get_logging_manager_no_fds)
54
55        # stub out some stuff
56        self.god.stub_function(os.path, 'exists')
57        self.god.stub_function(os.path, 'isdir')
58        self.god.stub_function(os, 'makedirs')
59        self.god.stub_function(os, 'mkdir')
60        self.god.stub_function(os, 'remove')
61        self.god.stub_function(shutil, 'rmtree')
62        self.god.stub_function(shutil, 'copyfile')
63        self.god.stub_function(job, 'open')
64        self.god.stub_function(utils, 'system')
65        self.god.stub_function(utils, 'drop_caches')
66        self.god.stub_function(harness, 'select')
67        self.god.stub_function(sysinfo, 'log_per_reboot_data')
68
69        self.god.stub_class(config, 'config')
70        self.god.stub_class(job.local_host, 'LocalHost')
71        self.god.stub_class(boottool, 'boottool')
72        self.god.stub_class(sysinfo, 'sysinfo')
73
74        self.god.stub_class_method(job.base_job, '_cleanup_results_dir')
75
76
77    def tearDown(self):
78        sys.stdout = sys.__stdout__
79        self.god.unstub_all()
80
81
82    def _setup_pre_record_init(self, cont):
83        self.god.stub_function(self.job, '_init_group_level')
84        self.god.stub_function(self.job, '_load_state')
85
86        resultdir = os.path.join(self.autodir, 'results', self.jobtag)
87        tmpdir = os.path.join(self.autodir, 'tmp')
88        os.path.exists.expect_call(resultdir).and_return(False)
89        os.makedirs.expect_call(resultdir)
90        if not cont:
91            job.base_job._cleanup_results_dir.expect_call()
92            os.path.exists.expect_call(tmpdir).and_return(False)
93            os.mkdir.expect_call(tmpdir)
94
95        self.job._load_state.expect_call()
96        self.job._init_group_level.expect_call()
97
98        my_harness = self.god.create_mock_class(harness.harness,
99                                                'my_harness')
100        harness.select.expect_call(None,
101                                   self.job).and_return(my_harness)
102
103        return resultdir, my_harness
104
105
106    def _setup_post_record_init(self, cont, resultdir, my_harness):
107        # now some specific stubs
108        self.god.stub_function(self.job, 'config_get')
109        self.god.stub_function(self.job, 'config_set')
110        self.god.stub_function(self.job, 'record')
111        self.god.stub_function(self.job, '_increment_group_level')
112        self.god.stub_function(self.job, '_decrement_group_level')
113        self.god.stub_function(self.job, 'get_state')
114        self.god.stub_function(self.job, 'set_state')
115
116        # other setup
117        results = os.path.join(self.autodir, 'results')
118        download = os.path.join(self.autodir, 'tests', 'download')
119        pkgdir = os.path.join(self.autodir, 'packages')
120
121        utils.drop_caches.expect_call()
122        self.job.get_state.expect_call("__run_test_cleanup",
123                                       default=True).and_return(True)
124        job_sysinfo = sysinfo.sysinfo.expect_new(resultdir)
125        self.job.get_state.expect_call("__sysinfo",
126                                       None).and_return(None)
127        self.job.get_state.expect_call("__last_boot_tag",
128                                       default=None).and_return(None)
129        self.job.get_state.expect_call("__job_tag",
130                                       default=None).and_return('1337-gps')
131        if not cont:
132            os.path.exists.expect_call(pkgdir).and_return(False)
133            os.mkdir.expect_call(pkgdir)
134            os.path.exists.expect_call(results).and_return(False)
135            os.mkdir.expect_call(results)
136            os.path.exists.expect_call(download).and_return(False)
137            os.mkdir.expect_call(download)
138            os.makedirs.expect_call(os.path.join(resultdir, 'analysis'))
139            shutil.copyfile.expect_call(mock.is_string_comparator(),
140                                 os.path.join(resultdir, 'control'))
141
142        self.config = config.config.expect_new(self.job)
143        job.local_host.LocalHost.expect_new(hostname='localhost')
144        self.job.config_get.expect_call(
145                'boottool.executable').and_return(None)
146        bootloader = boottool.boottool.expect_new(None)
147        job_sysinfo.log_per_reboot_data.expect_call()
148        if not cont:
149            self.job.record.expect_call('START', None, None)
150            self.job._increment_group_level.expect_call()
151
152        my_harness.run_start.expect_call()
153        self.job.get_state.expect_call('__monitor_disk',
154                                       default=0.0).and_return(0.0)
155
156        self.god.stub_function(utils, 'read_one_line')
157        utils.read_one_line.expect_call('/proc/cmdline').and_return(
158            'blah more-blah root=lala IDENT=81234567 blah-again console=tty1')
159        self.job.config_set.expect_call('boot.default_args',
160                                        'more-blah console=tty1')
161
162
163    def construct_job(self, cont):
164        # will construct class instance using __new__
165        self.job = job.base_job.__new__(job.base_job)
166
167        # record
168        resultdir, my_harness = self._setup_pre_record_init(cont)
169        self._setup_post_record_init(cont, resultdir, my_harness)
170
171        # finish constructor
172        options = Dummy()
173        options.tag = self.jobtag
174        options.cont = cont
175        options.harness = None
176        options.log = False
177        options.verbose = False
178        options.hostname = 'localhost'
179        options.autoserv_user = 'my_user'
180        self.job.__init__(self.control, options,
181                          extra_copy_cmdline=['more-blah'])
182
183        # check
184        self.god.check_playback()
185
186
187    def get_partition_mock(self, devname):
188        """
189        Create a mock of a partition object and return it.
190        """
191        class mock(object):
192            device = devname
193            get_mountpoint = self.god.create_mock_function('get_mountpoint')
194        return mock
195
196
197    def test_constructor_first_run(self):
198        self.construct_job(False)
199
200
201    def test_constructor_continuation(self):
202        self.construct_job(True)
203
204
205    def test_constructor_post_record_failure(self):
206        """
207        Test post record initialization failure.
208        """
209        self.job = job.base_job.__new__(job.base_job)
210        options = Dummy()
211        options.tag = self.jobtag
212        options.cont = False
213        options.harness = None
214        options.log = False
215        options.verbose = False
216        options.hostname = 'localhost'
217        options.autoserv_user = 'my_user'
218        error = Exception('fail')
219
220        self.god.stub_function(self.job, '_post_record_init')
221        self.god.stub_function(self.job, 'record')
222
223        self._setup_pre_record_init(False)
224        self.job._post_record_init.expect_call(
225                self.control, options, True, ['more-blah']).and_raises(error)
226        self.job.record.expect_call(
227                'ABORT', None, None,'client.bin.job.__init__ failed: %s' %
228                str(error))
229
230        self.assertRaises(
231                Exception, self.job.__init__, self.control, options,
232                drop_caches=True, extra_copy_cmdline=['more-blah'])
233
234        # check
235        self.god.check_playback()
236
237
238    def test_monitor_disk_usage(self):
239        self.construct_job(True)
240
241        # record
242        max_rate = 10.0
243        self.job.set_state.expect_call('__monitor_disk', max_rate)
244
245        # test
246        self.job.monitor_disk_usage(max_rate)
247        self.god.check_playback()
248
249
250    def test_relative_path(self):
251        self.construct_job(True)
252        dummy = "asdf"
253        ret = self.job.relative_path(os.path.join(self.job.resultdir, dummy))
254        self.assertEquals(ret, dummy)
255
256
257    def test_control_functions(self):
258        self.construct_job(True)
259        control_file = "blah"
260        self.job.control_set(control_file)
261        self.assertEquals(self.job.control_get(), os.path.abspath(control_file))
262
263
264    def test_harness_select(self):
265        self.construct_job(True)
266
267        # record
268        which = "which"
269        harness.select.expect_call(which, self.job).and_return(None)
270
271        # run and test
272        self.job.harness_select(which)
273        self.god.check_playback()
274
275
276    def test_config_set(self):
277        self.construct_job(True)
278
279        # unstub config_set
280        self.god.unstub(self.job, 'config_set')
281        # record
282        name = "foo"
283        val = 10
284        self.config.set.expect_call(name, val)
285
286        # run and test
287        self.job.config_set(name, val)
288        self.god.check_playback()
289
290
291    def test_config_get(self):
292        self.construct_job(True)
293
294        # unstub config_get
295        self.god.unstub(self.job, 'config_get')
296        # record
297        name = "foo"
298        val = 10
299        self.config.get.expect_call(name).and_return(val)
300
301        # run and test
302        self.job.config_get(name)
303        self.god.check_playback()
304
305
306    def test_setup_dirs_raise(self):
307        self.construct_job(True)
308
309        # setup
310        results_dir = 'foo'
311        tmp_dir = 'bar'
312
313        # record
314        os.path.exists.expect_call(tmp_dir).and_return(True)
315        os.path.isdir.expect_call(tmp_dir).and_return(False)
316
317        # test
318        self.assertRaises(ValueError, self.job.setup_dirs, results_dir, tmp_dir)
319        self.god.check_playback()
320
321
322    def test_setup_dirs(self):
323        self.construct_job(True)
324
325        # setup
326        results_dir1 = os.path.join(self.job.resultdir, 'build')
327        results_dir2 = os.path.join(self.job.resultdir, 'build.2')
328        results_dir3 = os.path.join(self.job.resultdir, 'build.3')
329        tmp_dir = 'bar'
330
331        # record
332        os.path.exists.expect_call(tmp_dir).and_return(False)
333        os.mkdir.expect_call(tmp_dir)
334        os.path.isdir.expect_call(tmp_dir).and_return(True)
335        os.path.exists.expect_call(results_dir1).and_return(True)
336        os.path.exists.expect_call(results_dir2).and_return(True)
337        os.path.exists.expect_call(results_dir3).and_return(False)
338        os.path.exists.expect_call(results_dir3).and_return(False)
339        os.mkdir.expect_call(results_dir3)
340
341        # test
342        self.assertEqual(self.job.setup_dirs(None, tmp_dir),
343                         (results_dir3, tmp_dir))
344        self.god.check_playback()
345
346
347    def test_xen(self):
348        self.construct_job(True)
349
350        # setup
351        self.god.stub_function(self.job, "setup_dirs")
352        self.god.stub_class(xen, "xen")
353        results = 'results_dir'
354        tmp = 'tmp'
355        build = 'xen'
356        base_tree = object()
357
358        # record
359        self.job.setup_dirs.expect_call(results,
360                                        tmp).and_return((results, tmp))
361        myxen = xen.xen.expect_new(self.job, base_tree, results, tmp, build,
362                                   False, None)
363
364        # run job and check
365        axen = self.job.xen(base_tree, results, tmp)
366        self.god.check_playback()
367        self.assertEquals(myxen, axen)
368
369
370    def test_kernel_rpm(self):
371        self.construct_job(True)
372
373        # setup
374        self.god.stub_function(self.job, "setup_dirs")
375        self.god.stub_class(kernel, "rpm_kernel")
376        self.god.stub_function(kernel, "preprocess_path")
377        self.god.stub_function(self.job.pkgmgr, "fetch_pkg")
378        self.god.stub_function(utils, "get_os_vendor")
379        results = 'results_dir'
380        tmp = 'tmp'
381        build = 'xen'
382        path = "somepath.rpm"
383        packages_dir = os.path.join("autodir/packages", path)
384
385        # record
386        self.job.setup_dirs.expect_call(results,
387                                        tmp).and_return((results, tmp))
388        kernel.preprocess_path.expect_call(path).and_return(path)
389        os.path.exists.expect_call(path).and_return(False)
390        self.job.pkgmgr.fetch_pkg.expect_call(path, packages_dir, repo_url='')
391        utils.get_os_vendor.expect_call()
392        mykernel = kernel.rpm_kernel.expect_new(self.job, [packages_dir],
393                                                results)
394
395        # check
396        akernel = self.job.kernel(path, results, tmp)
397        self.god.check_playback()
398        self.assertEquals(mykernel, akernel)
399
400
401    def test_kernel(self):
402        self.construct_job(True)
403
404        # setup
405        self.god.stub_function(self.job, "setup_dirs")
406        self.god.stub_class(kernel, "kernel")
407        self.god.stub_function(kernel, "preprocess_path")
408        results = 'results_dir'
409        tmp = 'tmp'
410        build = 'linux'
411        path = "somepath.deb"
412
413        # record
414        self.job.setup_dirs.expect_call(results,
415                                        tmp).and_return((results, tmp))
416        kernel.preprocess_path.expect_call(path).and_return(path)
417        mykernel = kernel.kernel.expect_new(self.job, path, results, tmp,
418                                            build, False)
419
420        # check
421        akernel = self.job.kernel(path, results, tmp)
422        self.god.check_playback()
423        self.assertEquals(mykernel, akernel)
424
425
426    def test_run_test_logs_test_error_from_unhandled_error(self):
427        self.construct_job(True)
428
429        # set up stubs
430        self.god.stub_function(self.job.pkgmgr, 'get_package_name')
431        self.god.stub_function(self.job, "_runtest")
432
433        # create an unhandled error object
434        class MyError(error.TestError):
435            pass
436        real_error = MyError("this is the real error message")
437        unhandled_error = error.UnhandledTestError(real_error)
438
439        # set up the recording
440        testname = "error_test"
441        outputdir = os.path.join(self.job.resultdir, testname)
442        self.job.pkgmgr.get_package_name.expect_call(
443            testname, 'test').and_return(("", testname))
444        self.job.get_state.expect_call(
445                self.job._RUN_NUMBER_STATE, default=0).and_return(0)
446        self.job.get_state.expect_call(
447                self.job._KERNEL_IN_TAG_STATE, default=False).and_return(False)
448        os.path.exists.expect_call(outputdir).and_return(False)
449        os.mkdir.expect_call(outputdir)
450        self.job.record.expect_call("START", testname, testname)
451        self.job._increment_group_level.expect_call()
452        self.job._runtest.expect_call(testname, "", (), {}).and_raises(
453            unhandled_error)
454        self.job.record.expect_call("ERROR", testname, testname,
455                                    first_line_comparator(str(real_error)))
456        self.job._decrement_group_level.expect_call()
457        self.job.record.expect_call("END ERROR", testname, testname)
458        self.job.harness.run_test_complete.expect_call()
459        utils.drop_caches.expect_call()
460
461        # run and check
462        self.job.run_test(testname)
463        self.god.check_playback()
464
465
466    def test_run_test_logs_non_test_error_from_unhandled_error(self):
467        self.construct_job(True)
468
469        # set up stubs
470        self.god.stub_function(self.job.pkgmgr, 'get_package_name')
471        self.god.stub_function(self.job, "_runtest")
472
473        # create an unhandled error object
474        class MyError(Exception):
475            pass
476        real_error = MyError("this is the real error message")
477        unhandled_error = error.UnhandledTestError(real_error)
478        reason = first_line_comparator("Unhandled MyError: %s" % real_error)
479
480        # set up the recording
481        testname = "error_test"
482        outputdir = os.path.join(self.job.resultdir, testname)
483        self.job.pkgmgr.get_package_name.expect_call(
484            testname, 'test').and_return(("", testname))
485        self.job.get_state.expect_call(
486                self.job._RUN_NUMBER_STATE, default=0).and_return(0)
487        self.job.get_state.expect_call(
488                self.job._KERNEL_IN_TAG_STATE, default=False).and_return(False)
489        os.path.exists.expect_call(outputdir).and_return(False)
490        os.mkdir.expect_call(outputdir)
491        self.job.record.expect_call("START", testname, testname)
492        self.job._increment_group_level.expect_call()
493        self.job._runtest.expect_call(testname, "", (), {}).and_raises(
494            unhandled_error)
495        self.job.record.expect_call("ERROR", testname, testname, reason)
496        self.job._decrement_group_level.expect_call()
497        self.job.record.expect_call("END ERROR", testname, testname)
498        self.job.harness.run_test_complete.expect_call()
499        utils.drop_caches.expect_call()
500
501        # run and check
502        self.job.run_test(testname)
503        self.god.check_playback()
504
505
506    def test_record(self):
507        self.construct_job(True)
508
509        # steup
510        self.job.group_level = 1
511        status = ''
512        status_code = "PASS"
513        subdir = "subdir"
514        operation = "super_fun"
515        mytime = "1234"
516        msg_tag = ""
517        if "." in self.job.log_filename:
518            msg_tag = self.job.log_filename.split(".", 1)[1]
519        epoch_time = int(mytime)
520        local_time = time.localtime(epoch_time)
521        optional_fields = {}
522        optional_fields["timestamp"] = str(epoch_time)
523        optional_fields["localtime"] = time.strftime("%b %d %H:%M:%S",
524                                                     local_time)
525        fields = [status_code, subdir, operation]
526        fields += ["%s=%s" % x for x in optional_fields.iteritems()]
527        fields.append(status)
528        msg = '\t'.join(str(x) for x in fields)
529        msg = '\t' * self.job.group_level + msg
530
531        self.god.stub_function(log, "is_valid_status")
532        self.god.stub_function(time, "time")
533        self.god.stub_function(self.job, "open")
534
535
536        # record
537        log.is_valid_status.expect_call(status_code).and_return(True)
538        time.time.expect_call().and_return(mytime)
539        self.job.harness.test_status_detail.expect_call(status_code, subdir,
540                                                        operation, '', msg_tag)
541        self.job.harness.test_status.expect_call(msg, msg_tag)
542        myfile = self.god.create_mock_class(file, "file")
543        status_file = os.path.join(self.job.resultdir, self.job.log_filename)
544        self.job.open.expect_call(status_file, "a").and_return(myfile)
545        myfile.write.expect_call(msg + "\n")
546
547        dir = os.path.join(self.job.resultdir, subdir)
548        status_file = os.path.join(dir, self.job.DEFAULT_LOG_FILENAME)
549        self.job.open.expect_call(status_file, "a").and_return(myfile)
550        myfile.write.expect_call(msg + "\n")
551
552
553        # run test
554        self.god.unstub(self.job, "record")
555        self.job.record(status_code, subdir, operation)
556        self.god.check_playback()
557
558
559    def test_report_reboot_failure(self):
560        self.construct_job(True)
561
562        # record
563        self.job.record.expect_call("ABORT", "sub", "reboot.verify",
564                                    "boot failure")
565        self.job._decrement_group_level.expect_call()
566        self.job.record.expect_call("END ABORT", "sub", "reboot",
567                                    optional_fields={"kernel": "2.6.15-smp"})
568
569        # playback
570        self.job._record_reboot_failure("sub", "reboot.verify", "boot failure",
571                                        running_id="2.6.15-smp")
572        self.god.check_playback()
573
574
575    def _setup_check_post_reboot(self, mount_info):
576        # setup
577        self.god.stub_function(job.partition_lib, "get_partition_list")
578
579        part_list = [self.get_partition_mock("/dev/hda1"),
580                     self.get_partition_mock("/dev/hdb1")]
581        mount_list = ["/mnt/hda1", "/mnt/hdb1"]
582
583        # record
584        job.partition_lib.get_partition_list.expect_call(self.job).and_return(
585                part_list)
586        for i in xrange(len(part_list)):
587            part_list[i].get_mountpoint.expect_call().and_return(mount_list[i])
588        self.job.get_state.expect_call("__mount_info").and_return(mount_info)
589
590
591    def test_check_post_reboot_success(self):
592        self.construct_job(True)
593
594        mount_info = set([("/dev/hda1", "/mnt/hda1"),
595                          ("/dev/hdb1", "/mnt/hdb1")])
596        self._setup_check_post_reboot(mount_info)
597
598        # playback
599        self.job._check_post_reboot("sub")
600        self.god.check_playback()
601
602
603    def test_check_post_reboot_mounts_failure(self):
604        self.construct_job(True)
605
606        mount_info = set([("/dev/hda1", "/mnt/hda1")])
607        self._setup_check_post_reboot(mount_info)
608
609        self.god.stub_function(self.job, "_record_reboot_failure")
610        self.job._record_reboot_failure.expect_call("sub",
611                "reboot.verify_config", "mounted partitions are different after"
612                " reboot (old entries: set([]), new entries: set([('/dev/hdb1',"
613                " '/mnt/hdb1')]))", running_id=None)
614
615        # playback
616        self.assertRaises(error.JobError, self.job._check_post_reboot, "sub")
617        self.god.check_playback()
618
619
620    def test_end_boot(self):
621        self.construct_job(True)
622        self.god.stub_function(self.job, "_check_post_reboot")
623
624        # set up the job class
625        self.job.group_level = 2
626
627        self.job._check_post_reboot.expect_call("sub", running_id=None)
628        self.job._decrement_group_level.expect_call()
629        self.job.record.expect_call("END GOOD", "sub", "reboot",
630                                    optional_fields={"kernel": "2.6.15-smp",
631                                                     "patch0": "patchname"})
632
633        # run test
634        self.job.end_reboot("sub", "2.6.15-smp", ["patchname"])
635        self.god.check_playback()
636
637
638    def test_end_boot_and_verify_success(self):
639        self.construct_job(True)
640        self.god.stub_function(self.job, "_check_post_reboot")
641
642        # set up the job class
643        self.job.group_level = 2
644
645        self.god.stub_function(utils, "running_os_ident")
646        utils.running_os_ident.expect_call().and_return("2.6.15-smp")
647
648        utils.read_one_line.expect_call("/proc/cmdline").and_return(
649            "blah more-blah root=lala IDENT=81234567 blah-again")
650
651        self.god.stub_function(utils, "running_os_full_version")
652        running_id = "2.6.15-smp"
653        utils.running_os_full_version.expect_call().and_return(running_id)
654
655        self.job.record.expect_call("GOOD", "sub", "reboot.verify",
656                                    running_id)
657        self.job._check_post_reboot.expect_call("sub", running_id=running_id)
658        self.job._decrement_group_level.expect_call()
659        self.job.record.expect_call("END GOOD", "sub", "reboot",
660                                    optional_fields={"kernel": running_id})
661
662        # run test
663        self.job.end_reboot_and_verify(81234567, "2.6.15-smp", "sub")
664        self.god.check_playback()
665
666
667    def test_end_boot_and_verify_failure(self):
668        self.construct_job(True)
669        self.god.stub_function(self.job, "_record_reboot_failure")
670
671        # set up the job class
672        self.job.group_level = 2
673
674        self.god.stub_function(utils, "running_os_ident")
675        utils.running_os_ident.expect_call().and_return("2.6.15-smp")
676
677        utils.read_one_line.expect_call("/proc/cmdline").and_return(
678            "blah more-blah root=lala IDENT=81234567 blah-again")
679
680        self.job._record_reboot_failure.expect_call("sub", "reboot.verify",
681                "boot failure", running_id="2.6.15-smp")
682
683        # run test
684        self.assertRaises(error.JobError, self.job.end_reboot_and_verify,
685                          91234567, "2.6.16-smp", "sub")
686        self.god.check_playback()
687
688
689    def test_default_tag(self):
690        self.construct_job(cont=False)
691
692        self.job.set_state.expect_call("__job_tag", None)
693        self.job.default_tag(None)
694        self.assertEqual(None, self.job.tag)
695
696        self.job.set_state.expect_call("__job_tag", '1337-gps')
697        self.job.default_tag('1337-gps')
698        self.assertEqual('1337-gps', self.job.tag)
699
700        self.construct_job(cont=True)
701        self.job.default_tag(None)
702        self.god.check_playback()
703
704
705if __name__ == "__main__":
706    unittest.main()
707