xref: /aosp_15_r20/external/autotest/client/bin/job_unittest.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li#!/usr/bin/python3
2*9c5db199SXin Li# pylint: disable=missing-docstring
3*9c5db199SXin Li
4*9c5db199SXin Liimport logging
5*9c5db199SXin Liimport os
6*9c5db199SXin Liimport re
7*9c5db199SXin Liimport shutil
8*9c5db199SXin Liimport sys
9*9c5db199SXin Liimport tempfile
10*9c5db199SXin Liimport unittest
11*9c5db199SXin Li
12*9c5db199SXin Lifrom six.moves import range
13*9c5db199SXin Liimport six
14*9c5db199SXin Li
15*9c5db199SXin Liimport common
16*9c5db199SXin Lifrom autotest_lib.client.bin import job, sysinfo, harness
17*9c5db199SXin Lifrom autotest_lib.client.bin import utils
18*9c5db199SXin Lifrom autotest_lib.client.common_lib import error
19*9c5db199SXin Lifrom autotest_lib.client.common_lib import logging_manager, logging_config
20*9c5db199SXin Lifrom autotest_lib.client.common_lib import base_job_unittest
21*9c5db199SXin Lifrom autotest_lib.client.common_lib.test_utils import mock
22*9c5db199SXin Li
23*9c5db199SXin Li
24*9c5db199SXin Liclass job_test_case(unittest.TestCase):
25*9c5db199SXin Li    """Generic job TestCase class that defines a standard job setUp and
26*9c5db199SXin Li    tearDown, with some standard stubs."""
27*9c5db199SXin Li
28*9c5db199SXin Li    job_class = job.base_client_job
29*9c5db199SXin Li
30*9c5db199SXin Li    def setUp(self):
31*9c5db199SXin Li        self.god = mock.mock_god(ut=self)
32*9c5db199SXin Li        self.god.stub_with(job.base_client_job, '_get_environ_autodir',
33*9c5db199SXin Li                           classmethod(lambda cls: '/adir'))
34*9c5db199SXin Li        self.job = self.job_class.__new__(self.job_class)
35*9c5db199SXin Li        self.job._job_directory = base_job_unittest.stub_job_directory
36*9c5db199SXin Li
37*9c5db199SXin Li        _, self.control_file = tempfile.mkstemp()
38*9c5db199SXin Li
39*9c5db199SXin Li
40*9c5db199SXin Li    def tearDown(self):
41*9c5db199SXin Li        self.god.unstub_all()
42*9c5db199SXin Li        os.remove(self.control_file)
43*9c5db199SXin Li
44*9c5db199SXin Li
45*9c5db199SXin Liclass test_find_base_directories(
46*9c5db199SXin Li        base_job_unittest.test_find_base_directories.generic_tests,
47*9c5db199SXin Li        job_test_case):
48*9c5db199SXin Li
49*9c5db199SXin Li    def test_autodir_equals_clientdir(self):
50*9c5db199SXin Li        autodir, clientdir, _ = self.job._find_base_directories()
51*9c5db199SXin Li        self.assertEqual(autodir, '/adir')
52*9c5db199SXin Li        self.assertEqual(clientdir, '/adir')
53*9c5db199SXin Li
54*9c5db199SXin Li
55*9c5db199SXin Li    def test_serverdir_is_none(self):
56*9c5db199SXin Li        _, _, serverdir = self.job._find_base_directories()
57*9c5db199SXin Li        self.assertEqual(serverdir, None)
58*9c5db199SXin Li
59*9c5db199SXin Li
60*9c5db199SXin Liclass abstract_test_init(base_job_unittest.test_init.generic_tests):
61*9c5db199SXin Li    """Generic client job mixin used when defining variations on the
62*9c5db199SXin Li    job.__init__ generic tests."""
63*9c5db199SXin Li
64*9c5db199SXin Li    PUBLIC_ATTRIBUTES = (
65*9c5db199SXin Li            base_job_unittest.test_init.generic_tests.PUBLIC_ATTRIBUTES -
66*9c5db199SXin Li            set(['force_full_log_collection']))
67*9c5db199SXin Li
68*9c5db199SXin Li    OPTIONAL_ATTRIBUTES = (
69*9c5db199SXin Li            base_job_unittest.test_init.generic_tests.OPTIONAL_ATTRIBUTES -
70*9c5db199SXin Li            set(['control', 'harness', 'force_full_log_collection']))
71*9c5db199SXin Li
72*9c5db199SXin Li
73*9c5db199SXin Liclass test_init_minimal_options(abstract_test_init, job_test_case):
74*9c5db199SXin Li
75*9c5db199SXin Li    def call_init(self):
76*9c5db199SXin Li        # TODO(jadmanski): refactor more of the __init__ code to not need to
77*9c5db199SXin Li        # stub out countless random APIs
78*9c5db199SXin Li        self.god.stub_function_to_return(job.os, 'mkdir', None)
79*9c5db199SXin Li        self.god.stub_function_to_return(job.os.path, 'exists', True)
80*9c5db199SXin Li        self.god.stub_function_to_return(self.job, '_load_state', None)
81*9c5db199SXin Li        self.god.stub_function_to_return(self.job, 'record', None)
82*9c5db199SXin Li        self.god.stub_function_to_return(job.shutil, 'copyfile', None)
83*9c5db199SXin Li        self.god.stub_function_to_return(job.logging_manager,
84*9c5db199SXin Li                                         'configure_logging', None)
85*9c5db199SXin Li        class manager:
86*9c5db199SXin Li            def start_logging(self):
87*9c5db199SXin Li                return None
88*9c5db199SXin Li        self.god.stub_function_to_return(job.logging_manager,
89*9c5db199SXin Li                                         'get_logging_manager', manager())
90*9c5db199SXin Li        class stub_sysinfo:
91*9c5db199SXin Li            def log_per_reboot_data(self):
92*9c5db199SXin Li                return None
93*9c5db199SXin Li        self.god.stub_function_to_return(job.sysinfo, 'sysinfo',
94*9c5db199SXin Li                                         stub_sysinfo())
95*9c5db199SXin Li        class stub_harness:
96*9c5db199SXin Li            run_start = lambda self: None
97*9c5db199SXin Li        self.god.stub_function_to_return(job.harness, 'select', stub_harness())
98*9c5db199SXin Li        class options:
99*9c5db199SXin Li            tag = ''
100*9c5db199SXin Li            verbose = False
101*9c5db199SXin Li            cont = False
102*9c5db199SXin Li            harness = 'stub'
103*9c5db199SXin Li            harness_args = None
104*9c5db199SXin Li            hostname = None
105*9c5db199SXin Li            user = None
106*9c5db199SXin Li            log = False
107*9c5db199SXin Li            args = ''
108*9c5db199SXin Li            output_dir = ''
109*9c5db199SXin Li
110*9c5db199SXin Li        self.god.stub_function_to_return(job.utils, 'drop_caches', None)
111*9c5db199SXin Li
112*9c5db199SXin Li        self.job._job_state = base_job_unittest.stub_job_state
113*9c5db199SXin Li        self.job.__init__(self.control_file, options)
114*9c5db199SXin Li
115*9c5db199SXin Li
116*9c5db199SXin Liclass placeholder(object):
117*9c5db199SXin Li    """A simple placeholder for attributes"""
118*9c5db199SXin Li    pass
119*9c5db199SXin Li
120*9c5db199SXin Li
121*9c5db199SXin Liclass first_line_comparator(mock.argument_comparator):
122*9c5db199SXin Li    def __init__(self, first_line):
123*9c5db199SXin Li        self.first_line = first_line
124*9c5db199SXin Li
125*9c5db199SXin Li
126*9c5db199SXin Li    def is_satisfied_by(self, parameter):
127*9c5db199SXin Li        return self.first_line == parameter.splitlines()[0]
128*9c5db199SXin Li
129*9c5db199SXin Li
130*9c5db199SXin Liclass test_base_job(unittest.TestCase):
131*9c5db199SXin Li    def setUp(self):
132*9c5db199SXin Li        # make god
133*9c5db199SXin Li        self.god = mock.mock_god(ut=self)
134*9c5db199SXin Li
135*9c5db199SXin Li        # need to set some environ variables
136*9c5db199SXin Li        self.autodir = "autodir"
137*9c5db199SXin Li        os.environ['AUTODIR'] = self.autodir
138*9c5db199SXin Li
139*9c5db199SXin Li        # set up some variables
140*9c5db199SXin Li        _, self.control = tempfile.mkstemp()
141*9c5db199SXin Li        self.jobtag = "jobtag"
142*9c5db199SXin Li
143*9c5db199SXin Li        # get rid of stdout and logging
144*9c5db199SXin Li        sys.stdout = six.StringIO()
145*9c5db199SXin Li        logging_manager.configure_logging(logging_config.TestingConfig())
146*9c5db199SXin Li        logging.disable(logging.CRITICAL)
147*9c5db199SXin Li        def placeholder_configure_logging(*args, **kwargs):
148*9c5db199SXin Li            pass
149*9c5db199SXin Li        self.god.stub_with(logging_manager, 'configure_logging',
150*9c5db199SXin Li                           placeholder_configure_logging)
151*9c5db199SXin Li        real_get_logging_manager = logging_manager.get_logging_manager
152*9c5db199SXin Li        def get_logging_manager_no_fds(manage_stdout_and_stderr=False,
153*9c5db199SXin Li                                       redirect_fds=False):
154*9c5db199SXin Li            return real_get_logging_manager(manage_stdout_and_stderr, False)
155*9c5db199SXin Li        self.god.stub_with(logging_manager, 'get_logging_manager',
156*9c5db199SXin Li                           get_logging_manager_no_fds)
157*9c5db199SXin Li
158*9c5db199SXin Li        # stub out some stuff
159*9c5db199SXin Li        self.god.stub_function(os.path, 'exists')
160*9c5db199SXin Li        self.god.stub_function(os.path, 'isdir')
161*9c5db199SXin Li        self.god.stub_function(os, 'makedirs')
162*9c5db199SXin Li        self.god.stub_function(os, 'mkdir')
163*9c5db199SXin Li        self.god.stub_function(os, 'remove')
164*9c5db199SXin Li        self.god.stub_function(shutil, 'rmtree')
165*9c5db199SXin Li        self.god.stub_function(shutil, 'copyfile')
166*9c5db199SXin Li        self.god.stub_function(job, 'open')
167*9c5db199SXin Li        self.god.stub_function(utils, 'system')
168*9c5db199SXin Li        self.god.stub_function(utils, 'drop_caches')
169*9c5db199SXin Li        self.god.stub_function(harness, 'select')
170*9c5db199SXin Li        self.god.stub_function(sysinfo, 'log_per_reboot_data')
171*9c5db199SXin Li
172*9c5db199SXin Li        self.god.stub_class(job.local_host, 'LocalHost')
173*9c5db199SXin Li        self.god.stub_class(sysinfo, 'sysinfo')
174*9c5db199SXin Li
175*9c5db199SXin Li        self.god.stub_class_method(job.base_client_job,
176*9c5db199SXin Li                                   '_cleanup_debugdir_files')
177*9c5db199SXin Li        self.god.stub_class_method(job.base_client_job, '_cleanup_results_dir')
178*9c5db199SXin Li
179*9c5db199SXin Li        self.god.stub_with(job.base_job.job_directory, '_ensure_valid',
180*9c5db199SXin Li                           lambda *_: None)
181*9c5db199SXin Li
182*9c5db199SXin Li
183*9c5db199SXin Li    def tearDown(self):
184*9c5db199SXin Li        sys.stdout = sys.__stdout__
185*9c5db199SXin Li        self.god.unstub_all()
186*9c5db199SXin Li        os.remove(self.control)
187*9c5db199SXin Li
188*9c5db199SXin Li
189*9c5db199SXin Li    def _setup_pre_record_init(self, cont):
190*9c5db199SXin Li        self.god.stub_function(self.job, '_load_state')
191*9c5db199SXin Li
192*9c5db199SXin Li        resultdir = os.path.join(self.autodir, 'results', self.jobtag)
193*9c5db199SXin Li        tmpdir = os.path.join(self.autodir, 'tmp')
194*9c5db199SXin Li        if not cont:
195*9c5db199SXin Li            job.base_client_job._cleanup_debugdir_files.expect_call()
196*9c5db199SXin Li            job.base_client_job._cleanup_results_dir.expect_call()
197*9c5db199SXin Li
198*9c5db199SXin Li        self.job._load_state.expect_call()
199*9c5db199SXin Li
200*9c5db199SXin Li        my_harness = self.god.create_mock_class(harness.harness,
201*9c5db199SXin Li                                                'my_harness')
202*9c5db199SXin Li        harness.select.expect_call(None,
203*9c5db199SXin Li                                   self.job,
204*9c5db199SXin Li                                   None).and_return(my_harness)
205*9c5db199SXin Li
206*9c5db199SXin Li        return resultdir, my_harness
207*9c5db199SXin Li
208*9c5db199SXin Li
209*9c5db199SXin Li    def _setup_post_record_init(self, cont, resultdir, my_harness):
210*9c5db199SXin Li        # now some specific stubs
211*9c5db199SXin Li        self.god.stub_function(self.job, 'config_get')
212*9c5db199SXin Li        self.god.stub_function(self.job, 'config_set')
213*9c5db199SXin Li        self.god.stub_function(self.job, 'record')
214*9c5db199SXin Li
215*9c5db199SXin Li        # other setup
216*9c5db199SXin Li        results = os.path.join(self.autodir, 'results')
217*9c5db199SXin Li        download = os.path.join(self.autodir, 'tests', 'download')
218*9c5db199SXin Li        pkgdir = os.path.join(self.autodir, 'packages')
219*9c5db199SXin Li
220*9c5db199SXin Li        utils.drop_caches.expect_call()
221*9c5db199SXin Li        job_sysinfo = sysinfo.sysinfo.expect_new(resultdir)
222*9c5db199SXin Li        if not cont:
223*9c5db199SXin Li            os.path.exists.expect_call(download).and_return(False)
224*9c5db199SXin Li            os.mkdir.expect_call(download)
225*9c5db199SXin Li            shutil.copyfile.expect_call(mock.is_string_comparator(),
226*9c5db199SXin Li                                 os.path.join(resultdir, 'control'))
227*9c5db199SXin Li
228*9c5db199SXin Li        job.local_host.LocalHost.expect_new(hostname='localhost')
229*9c5db199SXin Li        job_sysinfo.log_per_reboot_data.expect_call()
230*9c5db199SXin Li        if not cont:
231*9c5db199SXin Li            self.job.record.expect_call('START', None, None)
232*9c5db199SXin Li
233*9c5db199SXin Li        my_harness.run_start.expect_call()
234*9c5db199SXin Li
235*9c5db199SXin Li
236*9c5db199SXin Li    def construct_job(self, cont):
237*9c5db199SXin Li        # will construct class instance using __new__
238*9c5db199SXin Li        self.job = job.base_client_job.__new__(job.base_client_job)
239*9c5db199SXin Li
240*9c5db199SXin Li        # record
241*9c5db199SXin Li        resultdir, my_harness = self._setup_pre_record_init(cont)
242*9c5db199SXin Li        self._setup_post_record_init(cont, resultdir, my_harness)
243*9c5db199SXin Li
244*9c5db199SXin Li        # finish constructor
245*9c5db199SXin Li        options = placeholder()
246*9c5db199SXin Li        options.tag = self.jobtag
247*9c5db199SXin Li        options.cont = cont
248*9c5db199SXin Li        options.harness = None
249*9c5db199SXin Li        options.harness_args = None
250*9c5db199SXin Li        options.log = False
251*9c5db199SXin Li        options.verbose = False
252*9c5db199SXin Li        options.hostname = 'localhost'
253*9c5db199SXin Li        options.user = 'my_user'
254*9c5db199SXin Li        options.args = ''
255*9c5db199SXin Li        options.output_dir = ''
256*9c5db199SXin Li        self.job.__init__(self.control, options)
257*9c5db199SXin Li
258*9c5db199SXin Li        # check
259*9c5db199SXin Li        self.god.check_playback()
260*9c5db199SXin Li
261*9c5db199SXin Li
262*9c5db199SXin Li    def get_partition_mock(self, devname):
263*9c5db199SXin Li        """
264*9c5db199SXin Li        Create a mock of a partition object and return it.
265*9c5db199SXin Li        """
266*9c5db199SXin Li        class mock(object):
267*9c5db199SXin Li            device = devname
268*9c5db199SXin Li            get_mountpoint = self.god.create_mock_function('get_mountpoint')
269*9c5db199SXin Li        return mock
270*9c5db199SXin Li
271*9c5db199SXin Li
272*9c5db199SXin Li    def test_constructor_first_run(self):
273*9c5db199SXin Li        self.construct_job(False)
274*9c5db199SXin Li
275*9c5db199SXin Li
276*9c5db199SXin Li    def test_constructor_continuation(self):
277*9c5db199SXin Li        self.construct_job(True)
278*9c5db199SXin Li
279*9c5db199SXin Li
280*9c5db199SXin Li    def test_constructor_post_record_failure(self):
281*9c5db199SXin Li        """
282*9c5db199SXin Li        Test post record initialization failure.
283*9c5db199SXin Li        """
284*9c5db199SXin Li        self.job = job.base_client_job.__new__(job.base_client_job)
285*9c5db199SXin Li        options = placeholder()
286*9c5db199SXin Li        options.tag = self.jobtag
287*9c5db199SXin Li        options.cont = False
288*9c5db199SXin Li        options.harness = None
289*9c5db199SXin Li        options.harness_args = None
290*9c5db199SXin Li        options.log = False
291*9c5db199SXin Li        options.verbose = False
292*9c5db199SXin Li        options.hostname = 'localhost'
293*9c5db199SXin Li        options.user = 'my_user'
294*9c5db199SXin Li        options.args = ''
295*9c5db199SXin Li        options.output_dir = ''
296*9c5db199SXin Li        error = Exception('fail')
297*9c5db199SXin Li
298*9c5db199SXin Li        self.god.stub_function(self.job, '_post_record_init')
299*9c5db199SXin Li        self.god.stub_function(self.job, 'record')
300*9c5db199SXin Li
301*9c5db199SXin Li        self._setup_pre_record_init(False)
302*9c5db199SXin Li        self.job._post_record_init.expect_call(
303*9c5db199SXin Li                self.control, options, True).and_raises(error)
304*9c5db199SXin Li        self.job.record.expect_call(
305*9c5db199SXin Li                'ABORT', None, None,'client.bin.job.__init__ failed: %s' %
306*9c5db199SXin Li                str(error))
307*9c5db199SXin Li
308*9c5db199SXin Li        self.assertRaises(
309*9c5db199SXin Li                Exception, self.job.__init__, self.control, options,
310*9c5db199SXin Li                drop_caches=True)
311*9c5db199SXin Li
312*9c5db199SXin Li        # check
313*9c5db199SXin Li        self.god.check_playback()
314*9c5db199SXin Li
315*9c5db199SXin Li
316*9c5db199SXin Li    def test_control_functions(self):
317*9c5db199SXin Li        self.construct_job(True)
318*9c5db199SXin Li        control_file = "blah"
319*9c5db199SXin Li        self.job.control_set(control_file)
320*9c5db199SXin Li        self.assertEquals(self.job.control_get(), os.path.abspath(control_file))
321*9c5db199SXin Li
322*9c5db199SXin Li
323*9c5db199SXin Li    def test_harness_select(self):
324*9c5db199SXin Li        self.construct_job(True)
325*9c5db199SXin Li
326*9c5db199SXin Li        # record
327*9c5db199SXin Li        which = "which"
328*9c5db199SXin Li        harness_args = ''
329*9c5db199SXin Li        harness.select.expect_call(which, self.job,
330*9c5db199SXin Li                                   harness_args).and_return(None)
331*9c5db199SXin Li
332*9c5db199SXin Li        # run and test
333*9c5db199SXin Li        self.job.harness_select(which, harness_args)
334*9c5db199SXin Li        self.god.check_playback()
335*9c5db199SXin Li
336*9c5db199SXin Li
337*9c5db199SXin Li    def test_setup_dirs_raise(self):
338*9c5db199SXin Li        self.construct_job(True)
339*9c5db199SXin Li
340*9c5db199SXin Li        # setup
341*9c5db199SXin Li        results_dir = 'foo'
342*9c5db199SXin Li        tmp_dir = 'bar'
343*9c5db199SXin Li
344*9c5db199SXin Li        # record
345*9c5db199SXin Li        os.path.exists.expect_call(tmp_dir).and_return(True)
346*9c5db199SXin Li        os.path.isdir.expect_call(tmp_dir).and_return(False)
347*9c5db199SXin Li
348*9c5db199SXin Li        # test
349*9c5db199SXin Li        self.assertRaises(ValueError, self.job.setup_dirs, results_dir, tmp_dir)
350*9c5db199SXin Li        self.god.check_playback()
351*9c5db199SXin Li
352*9c5db199SXin Li
353*9c5db199SXin Li    def test_setup_dirs(self):
354*9c5db199SXin Li        self.construct_job(True)
355*9c5db199SXin Li
356*9c5db199SXin Li        # setup
357*9c5db199SXin Li        results_dir1 = os.path.join(self.job.resultdir, 'build')
358*9c5db199SXin Li        results_dir2 = os.path.join(self.job.resultdir, 'build.2')
359*9c5db199SXin Li        results_dir3 = os.path.join(self.job.resultdir, 'build.3')
360*9c5db199SXin Li        tmp_dir = 'bar'
361*9c5db199SXin Li
362*9c5db199SXin Li        # record
363*9c5db199SXin Li        os.path.exists.expect_call(tmp_dir).and_return(False)
364*9c5db199SXin Li        os.mkdir.expect_call(tmp_dir)
365*9c5db199SXin Li        os.path.isdir.expect_call(tmp_dir).and_return(True)
366*9c5db199SXin Li        os.path.exists.expect_call(results_dir1).and_return(True)
367*9c5db199SXin Li        os.path.exists.expect_call(results_dir2).and_return(True)
368*9c5db199SXin Li        os.path.exists.expect_call(results_dir3).and_return(False)
369*9c5db199SXin Li        os.path.exists.expect_call(results_dir3).and_return(False)
370*9c5db199SXin Li        os.mkdir.expect_call(results_dir3)
371*9c5db199SXin Li
372*9c5db199SXin Li        # test
373*9c5db199SXin Li        self.assertEqual(self.job.setup_dirs(None, tmp_dir),
374*9c5db199SXin Li                         (results_dir3, tmp_dir))
375*9c5db199SXin Li        self.god.check_playback()
376*9c5db199SXin Li
377*9c5db199SXin Li
378*9c5db199SXin Li    def test_run_test_logs_test_error_from_unhandled_error(self):
379*9c5db199SXin Li        self.construct_job(True)
380*9c5db199SXin Li
381*9c5db199SXin Li        # set up stubs
382*9c5db199SXin Li        self.god.stub_function(self.job.pkgmgr, 'get_package_name')
383*9c5db199SXin Li        self.god.stub_function(self.job, "_runtest")
384*9c5db199SXin Li
385*9c5db199SXin Li        # create an unhandled error object
386*9c5db199SXin Li        class MyError(error.TestError):
387*9c5db199SXin Li            pass
388*9c5db199SXin Li        real_error = MyError("this is the real error message")
389*9c5db199SXin Li        unhandled_error = error.UnhandledTestError(real_error)
390*9c5db199SXin Li
391*9c5db199SXin Li        # set up the recording
392*9c5db199SXin Li        testname = "error_test"
393*9c5db199SXin Li        outputdir = os.path.join(self.job.resultdir, testname)
394*9c5db199SXin Li        self.job.pkgmgr.get_package_name.expect_call(
395*9c5db199SXin Li            testname, 'test').and_return(("", testname))
396*9c5db199SXin Li        os.path.exists.expect_call(outputdir).and_return(False)
397*9c5db199SXin Li        self.job.record.expect_call("START", testname, testname,
398*9c5db199SXin Li                                    optional_fields=None)
399*9c5db199SXin Li        self.job._runtest.expect_call(testname, "", None, (), {}).and_raises(
400*9c5db199SXin Li            unhandled_error)
401*9c5db199SXin Li        self.job.record.expect_call("ERROR", testname, testname,
402*9c5db199SXin Li                                    first_line_comparator(str(real_error)))
403*9c5db199SXin Li        self.job.record.expect_call("END ERROR", testname, testname)
404*9c5db199SXin Li        self.job.harness.run_test_complete.expect_call()
405*9c5db199SXin Li        utils.drop_caches.expect_call()
406*9c5db199SXin Li
407*9c5db199SXin Li        # run and check
408*9c5db199SXin Li        self.job.run_test(testname)
409*9c5db199SXin Li        self.god.check_playback()
410*9c5db199SXin Li
411*9c5db199SXin Li
412*9c5db199SXin Li    def test_run_test_logs_non_test_error_from_unhandled_error(self):
413*9c5db199SXin Li        self.construct_job(True)
414*9c5db199SXin Li
415*9c5db199SXin Li        # set up stubs
416*9c5db199SXin Li        self.god.stub_function(self.job.pkgmgr, 'get_package_name')
417*9c5db199SXin Li        self.god.stub_function(self.job, "_runtest")
418*9c5db199SXin Li
419*9c5db199SXin Li        # create an unhandled error object
420*9c5db199SXin Li        class MyError(Exception):
421*9c5db199SXin Li            pass
422*9c5db199SXin Li        real_error = MyError("this is the real error message")
423*9c5db199SXin Li        unhandled_error = error.UnhandledTestError(real_error)
424*9c5db199SXin Li        reason = first_line_comparator("Unhandled MyError: %s" % real_error)
425*9c5db199SXin Li
426*9c5db199SXin Li        # set up the recording
427*9c5db199SXin Li        testname = "error_test"
428*9c5db199SXin Li        outputdir = os.path.join(self.job.resultdir, testname)
429*9c5db199SXin Li        self.job.pkgmgr.get_package_name.expect_call(
430*9c5db199SXin Li            testname, 'test').and_return(("", testname))
431*9c5db199SXin Li        os.path.exists.expect_call(outputdir).and_return(False)
432*9c5db199SXin Li        self.job.record.expect_call("START", testname, testname,
433*9c5db199SXin Li                                    optional_fields=None)
434*9c5db199SXin Li        self.job._runtest.expect_call(testname, "", None, (), {}).and_raises(
435*9c5db199SXin Li            unhandled_error)
436*9c5db199SXin Li        self.job.record.expect_call("ERROR", testname, testname, reason)
437*9c5db199SXin Li        self.job.record.expect_call("END ERROR", testname, testname)
438*9c5db199SXin Li        self.job.harness.run_test_complete.expect_call()
439*9c5db199SXin Li        utils.drop_caches.expect_call()
440*9c5db199SXin Li
441*9c5db199SXin Li        # run and check
442*9c5db199SXin Li        self.job.run_test(testname)
443*9c5db199SXin Li        self.god.check_playback()
444*9c5db199SXin Li
445*9c5db199SXin Li
446*9c5db199SXin Li    def test_report_reboot_failure(self):
447*9c5db199SXin Li        self.construct_job(True)
448*9c5db199SXin Li
449*9c5db199SXin Li        # record
450*9c5db199SXin Li        self.job.record.expect_call("ABORT", "sub", "reboot.verify",
451*9c5db199SXin Li                                    "boot failure")
452*9c5db199SXin Li        self.job.record.expect_call("END ABORT", "sub", "reboot",
453*9c5db199SXin Li                                    optional_fields={"kernel": "2.6.15-smp"})
454*9c5db199SXin Li
455*9c5db199SXin Li        # playback
456*9c5db199SXin Li        self.job._record_reboot_failure("sub", "reboot.verify", "boot failure",
457*9c5db199SXin Li                                        running_id="2.6.15-smp")
458*9c5db199SXin Li        self.god.check_playback()
459*9c5db199SXin Li
460*9c5db199SXin Li
461*9c5db199SXin Li    def _setup_check_post_reboot(self, mount_info, cpu_count):
462*9c5db199SXin Li        # setup
463*9c5db199SXin Li        self.god.stub_function(job.partition_lib, "get_partition_list")
464*9c5db199SXin Li        self.god.stub_function(utils, "count_cpus")
465*9c5db199SXin Li
466*9c5db199SXin Li        part_list = [self.get_partition_mock("/dev/hda1"),
467*9c5db199SXin Li                     self.get_partition_mock("/dev/hdb1")]
468*9c5db199SXin Li        mount_list = ["/mnt/hda1", "/mnt/hdb1"]
469*9c5db199SXin Li
470*9c5db199SXin Li        # record
471*9c5db199SXin Li        job.partition_lib.get_partition_list.expect_call(
472*9c5db199SXin Li                self.job, exclude_swap=False).and_return(part_list)
473*9c5db199SXin Li        for i in range(len(part_list)):
474*9c5db199SXin Li            part_list[i].get_mountpoint.expect_call().and_return(mount_list[i])
475*9c5db199SXin Li        if cpu_count is not None:
476*9c5db199SXin Li            utils.count_cpus.expect_call().and_return(cpu_count)
477*9c5db199SXin Li        self.job._state.set('client', 'mount_info', mount_info)
478*9c5db199SXin Li        self.job._state.set('client', 'cpu_count', 8)
479*9c5db199SXin Li
480*9c5db199SXin Li
481*9c5db199SXin Li    def test_check_post_reboot_success(self):
482*9c5db199SXin Li        self.construct_job(True)
483*9c5db199SXin Li
484*9c5db199SXin Li        mount_info = set([("/dev/hda1", "/mnt/hda1"),
485*9c5db199SXin Li                          ("/dev/hdb1", "/mnt/hdb1")])
486*9c5db199SXin Li        self._setup_check_post_reboot(mount_info, 8)
487*9c5db199SXin Li
488*9c5db199SXin Li        # playback
489*9c5db199SXin Li        self.job._check_post_reboot("sub")
490*9c5db199SXin Li        self.god.check_playback()
491*9c5db199SXin Li
492*9c5db199SXin Li
493*9c5db199SXin Li    def test_check_post_reboot_mounts_failure(self):
494*9c5db199SXin Li        self.construct_job(True)
495*9c5db199SXin Li
496*9c5db199SXin Li        mount_info = set([("/dev/hda1", "/mnt/hda1")])
497*9c5db199SXin Li        self._setup_check_post_reboot(mount_info, None)
498*9c5db199SXin Li
499*9c5db199SXin Li        self.god.stub_function(self.job, "_record_reboot_failure")
500*9c5db199SXin Li
501*9c5db199SXin Li        if six.PY2:
502*9c5db199SXin Li            self.job._record_reboot_failure.expect_call(
503*9c5db199SXin Li                    "sub",
504*9c5db199SXin Li                    "reboot.verify_config",
505*9c5db199SXin Li                    "mounted partitions are different after"
506*9c5db199SXin Li                    " reboot (old entries: set([]), new entries: set([('/dev/hdb1',"
507*9c5db199SXin Li                    " '/mnt/hdb1')]))",
508*9c5db199SXin Li                    running_id=None)
509*9c5db199SXin Li        else:
510*9c5db199SXin Li            # Py3 string formatting of sets is a bit different...
511*9c5db199SXin Li            self.job._record_reboot_failure.expect_call(
512*9c5db199SXin Li                    "sub",
513*9c5db199SXin Li                    "reboot.verify_config",
514*9c5db199SXin Li                    "mounted partitions are different after"
515*9c5db199SXin Li                    " reboot (old entries: set(), new entries: {('/dev/hdb1',"
516*9c5db199SXin Li                    " '/mnt/hdb1')})",
517*9c5db199SXin Li                    running_id=None)
518*9c5db199SXin Li
519*9c5db199SXin Li        # playback
520*9c5db199SXin Li        self.assertRaises(error.JobError, self.job._check_post_reboot, "sub")
521*9c5db199SXin Li        self.god.check_playback()
522*9c5db199SXin Li
523*9c5db199SXin Li
524*9c5db199SXin Li    def test_check_post_reboot_cpu_failure(self):
525*9c5db199SXin Li        self.construct_job(True)
526*9c5db199SXin Li
527*9c5db199SXin Li        mount_info = set([("/dev/hda1", "/mnt/hda1"),
528*9c5db199SXin Li                          ("/dev/hdb1", "/mnt/hdb1")])
529*9c5db199SXin Li        self._setup_check_post_reboot(mount_info, 4)
530*9c5db199SXin Li
531*9c5db199SXin Li        self.god.stub_function(self.job, "_record_reboot_failure")
532*9c5db199SXin Li        self.job._record_reboot_failure.expect_call(
533*9c5db199SXin Li            'sub', 'reboot.verify_config',
534*9c5db199SXin Li            'Number of CPUs changed after reboot (old count: 8, new count: 4)',
535*9c5db199SXin Li            running_id=None)
536*9c5db199SXin Li
537*9c5db199SXin Li        # playback
538*9c5db199SXin Li        self.assertRaises(error.JobError, self.job._check_post_reboot, "sub")
539*9c5db199SXin Li        self.god.check_playback()
540*9c5db199SXin Li
541*9c5db199SXin Li
542*9c5db199SXin Li    def test_parse_args(self):
543*9c5db199SXin Li        test_set = {"a='foo bar baz' b='moo apt'":
544*9c5db199SXin Li                    ["a='foo bar baz'", "b='moo apt'"],
545*9c5db199SXin Li                    "a='foo bar baz' only=gah":
546*9c5db199SXin Li                    ["a='foo bar baz'", "only=gah"],
547*9c5db199SXin Li                    "a='b c d' no=argh":
548*9c5db199SXin Li                    ["a='b c d'", "no=argh"]}
549*9c5db199SXin Li        for t in test_set:
550*9c5db199SXin Li            parsed_args = job.base_client_job._parse_args(t)
551*9c5db199SXin Li            expected_args = test_set[t]
552*9c5db199SXin Li            self.assertEqual(parsed_args, expected_args)
553*9c5db199SXin Li
554*9c5db199SXin Li
555*9c5db199SXin Li    def test_run_test_timeout_parameter_is_propagated(self):
556*9c5db199SXin Li        self.construct_job(True)
557*9c5db199SXin Li
558*9c5db199SXin Li        # set up stubs
559*9c5db199SXin Li        self.god.stub_function(self.job.pkgmgr, 'get_package_name')
560*9c5db199SXin Li        self.god.stub_function(self.job, "_runtest")
561*9c5db199SXin Li
562*9c5db199SXin Li        # create an unhandled error object
563*9c5db199SXin Li        #class MyError(error.TestError):
564*9c5db199SXin Li        #    pass
565*9c5db199SXin Li        #real_error = MyError("this is the real error message")
566*9c5db199SXin Li        #unhandled_error = error.UnhandledTestError(real_error)
567*9c5db199SXin Li
568*9c5db199SXin Li        # set up the recording
569*9c5db199SXin Li        testname = "test"
570*9c5db199SXin Li        outputdir = os.path.join(self.job.resultdir, testname)
571*9c5db199SXin Li        self.job.pkgmgr.get_package_name.expect_call(
572*9c5db199SXin Li            testname, 'test').and_return(("", testname))
573*9c5db199SXin Li        os.path.exists.expect_call(outputdir).and_return(False)
574*9c5db199SXin Li        timeout = 60
575*9c5db199SXin Li        optional_fields = {}
576*9c5db199SXin Li        optional_fields['timeout'] = timeout
577*9c5db199SXin Li        self.job.record.expect_call("START", testname, testname,
578*9c5db199SXin Li                                    optional_fields=optional_fields)
579*9c5db199SXin Li        self.job._runtest.expect_call(testname, "", timeout, (), {})
580*9c5db199SXin Li        self.job.record.expect_call("GOOD", testname, testname,
581*9c5db199SXin Li                                    "completed successfully")
582*9c5db199SXin Li        self.job.record.expect_call("END GOOD", testname, testname)
583*9c5db199SXin Li        self.job.harness.run_test_complete.expect_call()
584*9c5db199SXin Li        utils.drop_caches.expect_call()
585*9c5db199SXin Li
586*9c5db199SXin Li        # run and check
587*9c5db199SXin Li        self.job.run_test(testname, timeout=timeout)
588*9c5db199SXin Li        self.god.check_playback()
589*9c5db199SXin Li
590*9c5db199SXin Li
591*9c5db199SXin Liclass test_name_pattern(unittest.TestCase):
592*9c5db199SXin Li    """Tests for _NAME_PATTERN."""
593*9c5db199SXin Li
594*9c5db199SXin Li    def _one_name_pattern_test(self, line, want):
595*9c5db199SXin Li        """Parametrized test."""
596*9c5db199SXin Li        match = re.match(job._NAME_PATTERN, line)
597*9c5db199SXin Li        self.assertIsNotNone(match)
598*9c5db199SXin Li        self.assertEqual(match.group(1), want)
599*9c5db199SXin Li
600*9c5db199SXin Li    def test_name_pattern_nospace_single(self):
601*9c5db199SXin Li        self._one_name_pattern_test("NAME='some_Test'", 'some_Test')
602*9c5db199SXin Li
603*9c5db199SXin Li    def test_name_pattern_nospace_double(self):
604*9c5db199SXin Li        self._one_name_pattern_test('NAME="some_Test"', 'some_Test')
605*9c5db199SXin Li
606*9c5db199SXin Li    def test_name_pattern_space_single(self):
607*9c5db199SXin Li        self._one_name_pattern_test("NAME  =  'some_Test'", 'some_Test')
608*9c5db199SXin Li
609*9c5db199SXin Li    def test_name_pattern_space_double(self):
610*9c5db199SXin Li        self._one_name_pattern_test('NAME  =  "some_Test"', 'some_Test')
611*9c5db199SXin Li
612*9c5db199SXin Li
613*9c5db199SXin Liif __name__ == "__main__":
614*9c5db199SXin Li    unittest.main()
615