blob: e44abf8837cf1fff95a03bf443a9102afbb6f393 [file] [log] [blame]
Chris Masone6fed6462011-10-20 16:36:43 -07001#!/usr/bin/python
2#
3# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7"""Unit tests for server/cros/dynamic_suite.py."""
8
9import logging
10import mox
11import shutil
12import tempfile
13import time
14import unittest
15
Chris Masone5552dd72012-02-15 15:01:04 -080016from autotest_lib.client.common_lib import base_job, control_data, global_config
Chris Masone6fed6462011-10-20 16:36:43 -070017from autotest_lib.server.cros import control_file_getter, dynamic_suite
18from autotest_lib.server import frontend
19
20class FakeJob(object):
21 """Faked out RPC-client-side Job object."""
22 def __init__(self, id=0, statuses=[]):
23 self.id = id
Scott Zawalskie5bb1c52012-02-29 13:15:50 -050024 self.owner = 'tester'
Chris Masone6fed6462011-10-20 16:36:43 -070025 self.name = 'Fake Job %d' % self.id
26 self.statuses = statuses
27
28
29class ReimagerTest(mox.MoxTestBase):
30 """Unit tests for dynamic_suite.Reimager.
31
32 @var _URL: fake image url
Chris Masone8b7cd422012-02-22 13:16:11 -080033 @var _BUILD: fake build
Chris Masone6fed6462011-10-20 16:36:43 -070034 @var _NUM: fake number of machines to run on
35 @var _BOARD: fake board to reimage
36 """
37
Chris Masone2ef1d4e2011-12-20 11:06:53 -080038 _URL = 'http://nothing/%s'
Chris Masone8b7cd422012-02-22 13:16:11 -080039 _BUILD = 'build'
Chris Masone6fed6462011-10-20 16:36:43 -070040 _NUM = 4
41 _BOARD = 'board'
Chris Masone5552dd72012-02-15 15:01:04 -080042 _CONFIG = global_config.global_config
Chris Masone6fed6462011-10-20 16:36:43 -070043
44
45 def setUp(self):
46 super(ReimagerTest, self).setUp()
47 self.afe = self.mox.CreateMock(frontend.AFE)
48 self.tko = self.mox.CreateMock(frontend.TKO)
49 self.reimager = dynamic_suite.Reimager('', afe=self.afe, tko=self.tko)
Chris Masone5552dd72012-02-15 15:01:04 -080050 self._CONFIG.override_config_value('CROS',
51 'sharding_factor',
52 "%d" % self._NUM)
Chris Masone6fed6462011-10-20 16:36:43 -070053
54
55 def testEnsureVersionLabelAlreadyExists(self):
56 """Should not create a label if it already exists."""
57 name = 'label'
58 self.afe.get_labels(name=name).AndReturn([name])
59 self.mox.ReplayAll()
60 self.reimager._ensure_version_label(name)
61
62
63 def testEnsureVersionLabel(self):
64 """Should create a label if it doesn't already exist."""
65 name = 'label'
66 self.afe.get_labels(name=name).AndReturn([])
67 self.afe.create_label(name=name)
68 self.mox.ReplayAll()
69 self.reimager._ensure_version_label(name)
70
71
72 def testInjectVars(self):
73 """Should inject dict of varibles into provided strings."""
74 def find_all_in(d, s):
75 """Returns true if all key-value pairs in |d| are printed in |s|."""
76 return reduce(lambda b,i: "%s='%s'\n" % i in s, d.iteritems(), True)
77
78 v = {'v1': 'one', 'v2': 'two'}
Chris Masone8b764252012-01-17 11:12:51 -080079 self.assertTrue(find_all_in(v, dynamic_suite.inject_vars(v, '')))
80 self.assertTrue(find_all_in(v, dynamic_suite.inject_vars(v, 'ctrl')))
Chris Masone6fed6462011-10-20 16:36:43 -070081
82
83 def testReportResultsGood(self):
84 """Should report results in the case where all jobs passed."""
85 job = self.mox.CreateMock(frontend.Job)
86 job.name = 'RPC Client job'
87 job.result = True
88 recorder = self.mox.CreateMock(base_job.base_job)
89 recorder.record('GOOD', mox.IgnoreArg(), job.name)
90 self.mox.ReplayAll()
91 self.reimager._report_results(job, recorder.record)
92
93
94 def testReportResultsBad(self):
95 """Should report results in various job failure cases.
96
97 In this test scenario, there are five hosts, all the 'netbook' platform.
98
99 h1: Did not run
100 h2: Two failed tests
101 h3: Two aborted tests
102 h4: completed, GOOD
103 h5: completed, GOOD
104 """
105 H1 = 'host1'
106 H2 = 'host2'
107 H3 = 'host3'
108 H4 = 'host4'
109 H5 = 'host5'
110
111 class FakeResult(object):
112 def __init__(self, reason):
113 self.reason = reason
114
115
116 # The RPC-client-side Job object that is annotated with results.
117 job = FakeJob()
118 job.result = None # job failed, there are results to report.
119
120 # The semantics of |results_platform_map| and |test_results| are
121 # drawn from frontend.AFE.poll_all_jobs()
122 job.results_platform_map = {'netbook': {'Aborted' : [H3],
Chris Masone8b7cd422012-02-22 13:16:11 -0800123 'Completed' : [H1, H4, H5],
124 'Failed': [H2]
Chris Masone6fed6462011-10-20 16:36:43 -0700125 }
126 }
127 # Gin up fake results for H2 and H3 failure cases.
128 h2 = frontend.TestResults()
129 h2.fail = [FakeResult('a'), FakeResult('b')]
130 h3 = frontend.TestResults()
131 h3.fail = [FakeResult('a'), FakeResult('b')]
132 # Skipping H1 in |test_status| dict means that it did not get run.
133 job.test_status = {H2: h2, H3: h3, H4: {}, H5: {}}
134
135 # Set up recording expectations.
136 rjob = self.mox.CreateMock(base_job.base_job)
137 for res in h2.fail:
138 rjob.record('FAIL', mox.IgnoreArg(), H2, res.reason).InAnyOrder()
139 for res in h3.fail:
140 rjob.record('ABORT', mox.IgnoreArg(), H3, res.reason).InAnyOrder()
141 rjob.record('GOOD', mox.IgnoreArg(), H4).InAnyOrder()
142 rjob.record('GOOD', mox.IgnoreArg(), H5).InAnyOrder()
143 rjob.record(
144 'ERROR', mox.IgnoreArg(), H1, mox.IgnoreArg()).InAnyOrder()
145
146 self.mox.ReplayAll()
147 self.reimager._report_results(job, rjob.record)
148
149
150 def testScheduleJob(self):
151 """Should be able to create a job with the AFE."""
152 # Fake out getting the autoupdate control file contents.
153 cf_getter = self.mox.CreateMock(control_file_getter.ControlFileGetter)
154 cf_getter.get_control_file_contents_by_name('autoupdate').AndReturn('')
155 self.reimager._cf_getter = cf_getter
156
Chris Masone6dca10a2012-02-15 15:41:42 -0800157 self._CONFIG.override_config_value('CROS',
158 'image_url_pattern',
159 self._URL)
Chris Masone6fed6462011-10-20 16:36:43 -0700160 self.afe.create_job(
Chris Masone8b7cd422012-02-22 13:16:11 -0800161 control_file=mox.And(mox.StrContains(self._BUILD),
162 mox.StrContains(self._URL % self._BUILD)),
163 name=mox.StrContains(self._BUILD),
Chris Masone6fed6462011-10-20 16:36:43 -0700164 control_type='Server',
Chris Masone8b7cd422012-02-22 13:16:11 -0800165 meta_hosts=['board:'+self._BOARD] * self._NUM,
166 dependencies=[])
Chris Masone6fed6462011-10-20 16:36:43 -0700167 self.mox.ReplayAll()
Chris Masone8b7cd422012-02-22 13:16:11 -0800168 self.reimager._schedule_reimage_job(self._BUILD, self._NUM, self._BOARD)
Chris Masone6fed6462011-10-20 16:36:43 -0700169
170
Chris Masone796fcf12012-02-22 16:53:31 -0800171 def expect_attempt(self, success, ex=None):
Chris Masone6fed6462011-10-20 16:36:43 -0700172 """Sets up |self.reimager| to expect an attempt() that returns |success|
173
Chris Masone796fcf12012-02-22 16:53:31 -0800174 @param success: the value returned by poll_job_results()
175 @param ex: if not None, |ex| is raised by get_jobs()
Chris Masone6fed6462011-10-20 16:36:43 -0700176 @return a FakeJob configured with appropriate expectations
177 """
178 canary = FakeJob()
179 self.mox.StubOutWithMock(self.reimager, '_ensure_version_label')
Chris Masone8b7cd422012-02-22 13:16:11 -0800180 self.reimager._ensure_version_label(mox.StrContains(self._BUILD))
Chris Masone6fed6462011-10-20 16:36:43 -0700181
182 self.mox.StubOutWithMock(self.reimager, '_schedule_reimage_job')
Chris Masone8b7cd422012-02-22 13:16:11 -0800183 self.reimager._schedule_reimage_job(self._BUILD,
Chris Masone6fed6462011-10-20 16:36:43 -0700184 self._NUM,
185 self._BOARD).AndReturn(canary)
186 if success is not None:
187 self.mox.StubOutWithMock(self.reimager, '_report_results')
188 self.reimager._report_results(canary, mox.IgnoreArg())
189
190 self.afe.get_jobs(id=canary.id, not_yet_run=True).AndReturn([])
Chris Masone796fcf12012-02-22 16:53:31 -0800191 if ex is not None:
192 self.afe.get_jobs(id=canary.id, finished=True).AndRaise(ex)
193 else:
194 self.afe.get_jobs(id=canary.id, finished=True).AndReturn([canary])
195 self.afe.poll_job_results(mox.IgnoreArg(),
196 canary, 0).AndReturn(success)
Chris Masone6fed6462011-10-20 16:36:43 -0700197
198 return canary
199
200
201 def testSuccessfulReimage(self):
202 """Should attempt a reimage and record success."""
203 canary = self.expect_attempt(True)
204
205 rjob = self.mox.CreateMock(base_job.base_job)
206 rjob.record('START', mox.IgnoreArg(), mox.IgnoreArg())
207 rjob.record('END GOOD', mox.IgnoreArg(), mox.IgnoreArg())
208 self.mox.ReplayAll()
Chris Masone8b7cd422012-02-22 13:16:11 -0800209 self.reimager.attempt(self._BUILD, self._BOARD, rjob.record)
Chris Masone6fed6462011-10-20 16:36:43 -0700210
211
212 def testFailedReimage(self):
213 """Should attempt a reimage and record failure."""
214 canary = self.expect_attempt(False)
215
216 rjob = self.mox.CreateMock(base_job.base_job)
217 rjob.record('START', mox.IgnoreArg(), mox.IgnoreArg())
218 rjob.record('END FAIL', mox.IgnoreArg(), mox.IgnoreArg())
219 self.mox.ReplayAll()
Chris Masone8b7cd422012-02-22 13:16:11 -0800220 self.reimager.attempt(self._BUILD, self._BOARD, rjob.record)
Chris Masone6fed6462011-10-20 16:36:43 -0700221
222
223 def testReimageThatNeverHappened(self):
224 """Should attempt a reimage and record that it didn't run."""
225 canary = self.expect_attempt(None)
226
227 rjob = self.mox.CreateMock(base_job.base_job)
228 rjob.record('START', mox.IgnoreArg(), mox.IgnoreArg())
229 rjob.record('FAIL', mox.IgnoreArg(), canary.name, mox.IgnoreArg())
230 rjob.record('END FAIL', mox.IgnoreArg(), mox.IgnoreArg())
231 self.mox.ReplayAll()
Chris Masone8b7cd422012-02-22 13:16:11 -0800232 self.reimager.attempt(self._BUILD, self._BOARD, rjob.record)
Chris Masone6fed6462011-10-20 16:36:43 -0700233
234
Chris Masone796fcf12012-02-22 16:53:31 -0800235 def testReimageThatRaised(self):
236 """Should attempt a reimage that raises an exception and record that."""
237 ex_message = 'Oh no!'
238 canary = self.expect_attempt(None, Exception(ex_message))
239
240 rjob = self.mox.CreateMock(base_job.base_job)
241 rjob.record('START', mox.IgnoreArg(), mox.IgnoreArg())
242 rjob.record('END ERROR', mox.IgnoreArg(), mox.IgnoreArg(), ex_message)
243 self.mox.ReplayAll()
244 self.reimager.attempt(self._BUILD, self._BOARD, rjob.record)
245
246
Chris Masone6fed6462011-10-20 16:36:43 -0700247class SuiteTest(mox.MoxTestBase):
248 """Unit tests for dynamic_suite.Suite.
249
Chris Masone8b7cd422012-02-22 13:16:11 -0800250 @var _BUILD: fake build
Chris Masone6fed6462011-10-20 16:36:43 -0700251 @var _TAG: fake suite tag
252 """
253
Chris Masone8b7cd422012-02-22 13:16:11 -0800254 _BUILD = 'build'
255 _TAG = 'suite_tag'
Chris Masone6fed6462011-10-20 16:36:43 -0700256
257
258 def setUp(self):
259 class FakeControlData(object):
260 """A fake parsed control file data structure."""
261 def __init__(self, data, expr=False):
262 self.string = 'text-' + data
263 self.name = 'name-' + data
264 self.data = data
265 self.test_type = 'Client'
266 self.experimental = expr
267
268
269 super(SuiteTest, self).setUp()
270 self.afe = self.mox.CreateMock(frontend.AFE)
271 self.tko = self.mox.CreateMock(frontend.TKO)
272
273 self.tmpdir = tempfile.mkdtemp(suffix=type(self).__name__)
274
275 self.getter = self.mox.CreateMock(control_file_getter.ControlFileGetter)
276
277 self.files = {'one': FakeControlData('data_one', expr=True),
278 'two': FakeControlData('data_two'),
279 'three': FakeControlData('data_three')}
280
281
282 def tearDown(self):
283 super(SuiteTest, self).tearDown()
284 shutil.rmtree(self.tmpdir, ignore_errors=True)
285
286
287 def expect_control_file_parsing(self):
288 """Expect an attempt to parse the 'control files' in |self.files|."""
289 self.getter.get_control_file_list().AndReturn(self.files.keys())
290 self.mox.StubOutWithMock(control_data, 'parse_control_string')
291 for file, data in self.files.iteritems():
292 self.getter.get_control_file_contents(file).AndReturn(data.string)
293 control_data.parse_control_string(
294 data.string, raise_warnings=True).AndReturn(data)
295
296
297 def testFindAndParseStableTests(self):
298 """Should find only non-experimental tests that match a predicate."""
299 self.expect_control_file_parsing()
300 self.mox.ReplayAll()
301
302 predicate = lambda d: d.text == self.files['two'].string
303 tests = dynamic_suite.Suite.find_and_parse_tests(self.getter, predicate)
304 self.assertEquals(len(tests), 1)
305 self.assertEquals(tests[0], self.files['two'])
306
307
308 def testFindAndParseTests(self):
309 """Should find all tests that match a predicate."""
310 self.expect_control_file_parsing()
311 self.mox.ReplayAll()
312
313 predicate = lambda d: d.text != self.files['two'].string
314 tests = dynamic_suite.Suite.find_and_parse_tests(self.getter,
315 predicate,
316 add_experimental=True)
317 self.assertEquals(len(tests), 2)
318 self.assertTrue(self.files['one'] in tests)
319 self.assertTrue(self.files['three'] in tests)
320
321
322 def mock_control_file_parsing(self):
323 """Fake out find_and_parse_tests(), returning content from |self.files|.
324 """
325 for test in self.files.values():
326 test.text = test.string # mimic parsing.
327 self.mox.StubOutWithMock(dynamic_suite.Suite, 'find_and_parse_tests')
328 dynamic_suite.Suite.find_and_parse_tests(
329 mox.IgnoreArg(),
330 mox.IgnoreArg(),
331 add_experimental=True).AndReturn(self.files.values())
332
333
334 def testStableUnstableFilter(self):
335 """Should distinguish between experimental and stable tests."""
336 self.mock_control_file_parsing()
337 self.mox.ReplayAll()
338 suite = dynamic_suite.Suite.create_from_name(self._TAG, self.tmpdir,
Chris Masoned6f38c82012-02-22 14:53:42 -0800339 afe=self.afe, tko=self.tko)
Chris Masone6fed6462011-10-20 16:36:43 -0700340
341 self.assertTrue(self.files['one'] in suite.tests)
342 self.assertTrue(self.files['two'] in suite.tests)
343 self.assertTrue(self.files['one'] in suite.unstable_tests())
344 self.assertTrue(self.files['two'] in suite.stable_tests())
345 self.assertFalse(self.files['one'] in suite.stable_tests())
346 self.assertFalse(self.files['two'] in suite.unstable_tests())
347
348
349 def expect_job_scheduling(self, add_experimental):
350 """Expect jobs to be scheduled for 'tests' in |self.files|.
351
352 @param add_experimental: expect jobs for experimental tests as well.
353 """
354 for test in self.files.values():
355 if not add_experimental and test.experimental:
356 continue
357 self.afe.create_job(
358 control_file=test.text,
Chris Masone8b7cd422012-02-22 13:16:11 -0800359 name=mox.And(mox.StrContains(self._BUILD),
Chris Masone6fed6462011-10-20 16:36:43 -0700360 mox.StrContains(test.name)),
361 control_type=mox.IgnoreArg(),
Chris Masone8b7cd422012-02-22 13:16:11 -0800362 meta_hosts=[dynamic_suite.VERSION_PREFIX + self._BUILD],
Scott Zawalskie5bb1c52012-02-29 13:15:50 -0500363 dependencies=[]).AndReturn(FakeJob())
Chris Masone6fed6462011-10-20 16:36:43 -0700364
365
366 def testScheduleTests(self):
367 """Should schedule stable and experimental tests with the AFE."""
368 self.mock_control_file_parsing()
369 self.expect_job_scheduling(add_experimental=True)
370
371 self.mox.ReplayAll()
Chris Masone8b7cd422012-02-22 13:16:11 -0800372 suite = dynamic_suite.Suite.create_from_name(self._TAG, self._BUILD,
Chris Masoned6f38c82012-02-22 14:53:42 -0800373 afe=self.afe, tko=self.tko)
Chris Masone8b7cd422012-02-22 13:16:11 -0800374 suite.schedule()
Chris Masone6fed6462011-10-20 16:36:43 -0700375
376
Scott Zawalski9ece6532012-02-28 14:10:47 -0500377 def testScheduleTestsAndRecord(self):
378 """Should schedule stable and experimental tests with the AFE."""
379 self.mock_control_file_parsing()
380 self.mox.ReplayAll()
381 suite = dynamic_suite.Suite.create_from_name(self._TAG, self._BUILD,
382 afe=self.afe, tko=self.tko,
383 results_dir=self.tmpdir)
384 self.mox.ResetAll()
385 self.expect_job_scheduling(add_experimental=True)
386 self.mox.StubOutWithMock(suite, '_record_scheduled_jobs')
387 suite._record_scheduled_jobs()
388 self.mox.ReplayAll()
389 suite.schedule()
Scott Zawalskie5bb1c52012-02-29 13:15:50 -0500390 for job in suite._jobs:
391 self.assertTrue(hasattr(job, 'test_name'))
Scott Zawalski9ece6532012-02-28 14:10:47 -0500392
393
Chris Masone6fed6462011-10-20 16:36:43 -0700394 def testScheduleStableTests(self):
395 """Should schedule only stable tests with the AFE."""
396 self.mock_control_file_parsing()
397 self.expect_job_scheduling(add_experimental=False)
398
399 self.mox.ReplayAll()
Chris Masone8b7cd422012-02-22 13:16:11 -0800400 suite = dynamic_suite.Suite.create_from_name(self._TAG, self._BUILD,
Chris Masoned6f38c82012-02-22 14:53:42 -0800401 afe=self.afe, tko=self.tko)
Chris Masone8b7cd422012-02-22 13:16:11 -0800402 suite.schedule(add_experimental=False)
Chris Masone6fed6462011-10-20 16:36:43 -0700403
404
405 def expect_result_gathering(self, job):
406 self.afe.get_jobs(id=job.id, finished=True).AndReturn(job)
407 entries = map(lambda s: s.entry, job.statuses)
408 self.afe.run('get_host_queue_entries',
409 job=job.id).AndReturn(entries)
410 if True not in map(lambda e: 'aborted' in e and e['aborted'], entries):
411 self.tko.get_status_counts(job=job.id).AndReturn(job.statuses)
412
413
Chris Masonefef21382012-01-17 11:16:32 -0800414 def _createSuiteWithMockedTestsAndControlFiles(self):
415 """Create a Suite, using mocked tests and control file contents.
416
417 @return Suite object, after mocking out behavior needed to create it.
418 """
Chris Masonefef21382012-01-17 11:16:32 -0800419 self.expect_control_file_parsing()
420 self.mox.ReplayAll()
Scott Zawalski9ece6532012-02-28 14:10:47 -0500421 suite = dynamic_suite.Suite.create_from_name(self._TAG, self._BUILD,
Chris Masoned6f38c82012-02-22 14:53:42 -0800422 self.getter, self.afe,
423 self.tko)
Chris Masonefef21382012-01-17 11:16:32 -0800424 self.mox.ResetAll()
425 return suite
426
427
Chris Masone6fed6462011-10-20 16:36:43 -0700428 def testWaitForResults(self):
429 """Should gather status and return records for job summaries."""
430 class FakeStatus(object):
431 """Fake replacement for server-side job status objects.
432
433 @var status: 'GOOD', 'FAIL', 'ERROR', etc.
434 @var test_name: name of the test this is status for
435 @var reason: reason for failure, if any
436 @var aborted: present and True if the job was aborted. Optional.
437 """
438 def __init__(self, code, name, reason, aborted=None):
439 self.status = code
440 self.test_name = name
441 self.reason = reason
442 self.entry = {}
443 if aborted:
444 self.entry['aborted'] = True
445
446 def equals_record(self, args):
447 """Compares this object to a recorded status."""
448 return self._equals_record(*args)
449
Chris Masone2ef1d4e2011-12-20 11:06:53 -0800450 def _equals_record(self, status, subdir, name, reason=None):
Chris Masone6fed6462011-10-20 16:36:43 -0700451 """Compares this object and fields of recorded status."""
452 if 'aborted' in self.entry and self.entry['aborted']:
453 return status == 'ABORT'
454 return (self.status == status and
455 self.test_name == name and
456 self.reason == reason)
457
Chris Masonefef21382012-01-17 11:16:32 -0800458 suite = self._createSuiteWithMockedTestsAndControlFiles()
Chris Masone6fed6462011-10-20 16:36:43 -0700459
460 jobs = [FakeJob(0, [FakeStatus('GOOD', 'T0', ''),
461 FakeStatus('GOOD', 'T1', '')]),
462 FakeJob(1, [FakeStatus('ERROR', 'T0', 'err', False),
463 FakeStatus('GOOD', 'T1', '')]),
464 FakeJob(2, [FakeStatus('TEST_NA', 'T0', 'no')]),
465 FakeJob(2, [FakeStatus('FAIL', 'T0', 'broken')]),
466 FakeJob(3, [FakeStatus('ERROR', 'T0', 'gah', True)])]
467 # To simulate a job that isn't ready the first time we check.
468 self.afe.get_jobs(id=jobs[0].id, finished=True).AndReturn([])
469 # Expect all the rest of the jobs to be good to go the first time.
470 for job in jobs[1:]:
471 self.expect_result_gathering(job)
472 # Then, expect job[0] to be ready.
473 self.expect_result_gathering(jobs[0])
474 # Expect us to poll twice.
475 self.mox.StubOutWithMock(time, 'sleep')
476 time.sleep(5)
477 time.sleep(5)
478 self.mox.ReplayAll()
479
Chris Masone6fed6462011-10-20 16:36:43 -0700480 suite._jobs = list(jobs)
Scott Zawalskiab25bd62012-02-10 18:29:12 -0500481 results = [result for result in suite.wait_for_results()]
Chris Masone6fed6462011-10-20 16:36:43 -0700482 for job in jobs:
483 for status in job.statuses:
484 self.assertTrue(True in map(status.equals_record, results))
485
486
487 def testRunAndWaitSuccess(self):
488 """Should record successful results."""
Chris Masonefef21382012-01-17 11:16:32 -0800489 suite = self._createSuiteWithMockedTestsAndControlFiles()
Chris Masone6fed6462011-10-20 16:36:43 -0700490
Chris Masonefef21382012-01-17 11:16:32 -0800491 results = [('GOOD', None, 'good'), ('FAIL', None, 'bad', 'reason')]
Chris Masone6fed6462011-10-20 16:36:43 -0700492 recorder = self.mox.CreateMock(base_job.base_job)
Scott Zawalskiab25bd62012-02-10 18:29:12 -0500493 recorder.record('INFO', None, 'Start %s' % self._TAG)
Chris Masone6fed6462011-10-20 16:36:43 -0700494 for result in results:
Scott Zawalskiab25bd62012-02-10 18:29:12 -0500495 status = result[0]
496 test_name = result[2]
497 recorder.record('START', None, test_name)
Chris Masone6fed6462011-10-20 16:36:43 -0700498 recorder.record(*result).InAnyOrder('results')
Scott Zawalskiab25bd62012-02-10 18:29:12 -0500499 recorder.record('END %s' % status, None, test_name)
Chris Masone6fed6462011-10-20 16:36:43 -0700500
Chris Masone6fed6462011-10-20 16:36:43 -0700501 self.mox.StubOutWithMock(suite, 'schedule')
Chris Masone8b7cd422012-02-22 13:16:11 -0800502 suite.schedule(True)
Chris Masone6fed6462011-10-20 16:36:43 -0700503 self.mox.StubOutWithMock(suite, 'wait_for_results')
504 suite.wait_for_results().AndReturn(results)
505 self.mox.ReplayAll()
506
Chris Masone8b7cd422012-02-22 13:16:11 -0800507 suite.run_and_wait(recorder.record, True)
Chris Masone6fed6462011-10-20 16:36:43 -0700508
509
510 def testRunAndWaitFailure(self):
511 """Should record failure to gather results."""
Chris Masonefef21382012-01-17 11:16:32 -0800512 suite = self._createSuiteWithMockedTestsAndControlFiles()
513
Chris Masone6fed6462011-10-20 16:36:43 -0700514 recorder = self.mox.CreateMock(base_job.base_job)
Scott Zawalskiab25bd62012-02-10 18:29:12 -0500515 recorder.record('INFO', None, 'Start %s' % self._TAG)
516 recorder.record('FAIL', None, self._TAG,
517 mox.StrContains('waiting'))
Chris Masone6fed6462011-10-20 16:36:43 -0700518
Chris Masone6fed6462011-10-20 16:36:43 -0700519 self.mox.StubOutWithMock(suite, 'schedule')
Chris Masone8b7cd422012-02-22 13:16:11 -0800520 suite.schedule(True)
Chris Masone6fed6462011-10-20 16:36:43 -0700521 self.mox.StubOutWithMock(suite, 'wait_for_results')
522 suite.wait_for_results().AndRaise(Exception())
523 self.mox.ReplayAll()
524
Chris Masone8b7cd422012-02-22 13:16:11 -0800525 suite.run_and_wait(recorder.record, True)
Chris Masone6fed6462011-10-20 16:36:43 -0700526
527
528 def testRunAndWaitScheduleFailure(self):
Chris Masonefef21382012-01-17 11:16:32 -0800529 """Should record failure to schedule jobs."""
530 suite = self._createSuiteWithMockedTestsAndControlFiles()
531
Chris Masone6fed6462011-10-20 16:36:43 -0700532 recorder = self.mox.CreateMock(base_job.base_job)
Scott Zawalskiab25bd62012-02-10 18:29:12 -0500533 recorder.record('INFO', None, 'Start %s' % self._TAG)
534 recorder.record('FAIL', None, self._TAG,
535 mox.StrContains('scheduling'))
Chris Masone6fed6462011-10-20 16:36:43 -0700536
Chris Masone6fed6462011-10-20 16:36:43 -0700537 self.mox.StubOutWithMock(suite, 'schedule')
Chris Masone8b7cd422012-02-22 13:16:11 -0800538 suite.schedule(True).AndRaise(Exception())
Chris Masone6fed6462011-10-20 16:36:43 -0700539 self.mox.ReplayAll()
540
Chris Masone8b7cd422012-02-22 13:16:11 -0800541 suite.run_and_wait(recorder.record, True)
Chris Masone6fed6462011-10-20 16:36:43 -0700542
543
544if __name__ == '__main__':
545 unittest.main()