162 lines
6.1 KiB
Python
Executable File
162 lines
6.1 KiB
Python
Executable File
#!/usr/bin/env python2
|
|
#
|
|
# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
# pylint: disable-msg=C0111
|
|
|
|
"""Unit tests for server/cros/dynamic_suite/job_status.py."""
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import print_function
|
|
|
|
import mox
|
|
import os
|
|
import shutil
|
|
import six
|
|
from six.moves import map
|
|
from six.moves import range
|
|
import tempfile
|
|
import time
|
|
import unittest
|
|
|
|
import common
|
|
|
|
from autotest_lib.server import frontend
|
|
from autotest_lib.server.cros.dynamic_suite import host_spec
|
|
from autotest_lib.server.cros.dynamic_suite import job_status
|
|
from autotest_lib.server.cros.dynamic_suite.fakes import FakeJob
|
|
from autotest_lib.server.cros.dynamic_suite.fakes import FakeStatus
|
|
|
|
|
|
DEFAULT_WAITTIMEOUT_MINS = 60 * 4
|
|
|
|
|
|
class StatusTest(mox.MoxTestBase):
|
|
"""Unit tests for job_status.Status.
|
|
"""
|
|
|
|
|
|
def setUp(self):
|
|
super(StatusTest, self).setUp()
|
|
self.afe = self.mox.CreateMock(frontend.AFE)
|
|
self.tko = self.mox.CreateMock(frontend.TKO)
|
|
|
|
self.tmpdir = tempfile.mkdtemp(suffix=type(self).__name__)
|
|
|
|
|
|
def tearDown(self):
|
|
super(StatusTest, self).tearDown()
|
|
shutil.rmtree(self.tmpdir, ignore_errors=True)
|
|
|
|
|
|
def expect_yield_job_entries(self, job):
|
|
entries = [s.entry for s in job.statuses]
|
|
self.afe.run('get_host_queue_entries',
|
|
job=job.id).AndReturn(entries)
|
|
if True not in ['aborted' in e and e['aborted'] for e in entries]:
|
|
self.tko.get_job_test_statuses_from_db(job.id).AndReturn(
|
|
job.statuses)
|
|
|
|
|
|
def testJobResultWaiter(self):
|
|
"""Should gather status and return records for job summaries."""
|
|
jobs = [FakeJob(0, [FakeStatus('GOOD', 'T0', ''),
|
|
FakeStatus('GOOD', 'T1', '')]),
|
|
FakeJob(1, [FakeStatus('ERROR', 'T0', 'err', False),
|
|
FakeStatus('GOOD', 'T1', '')]),
|
|
FakeJob(2, [FakeStatus('TEST_NA', 'T0', 'no')]),
|
|
FakeJob(3, [FakeStatus('FAIL', 'T0', 'broken')]),
|
|
FakeJob(4, [FakeStatus('ERROR', 'SERVER_JOB', 'server error'),
|
|
FakeStatus('GOOD', 'T0', '')]),]
|
|
# TODO: Write a better test for the case where we yield
|
|
# results for aborts vs cannot yield results because of
|
|
# a premature abort. Currently almost all client aborts
|
|
# have been converted to failures, and when aborts do happen
|
|
# they result in server job failures for which we always
|
|
# want results.
|
|
# FakeJob(5, [FakeStatus('ERROR', 'T0', 'gah', True)]),
|
|
# The next job shouldn't be recorded in the results.
|
|
# FakeJob(6, [FakeStatus('GOOD', 'SERVER_JOB', '')])]
|
|
for status in jobs[4].statuses:
|
|
status.entry['job'] = {'name': 'broken_infra_job'}
|
|
|
|
job_id_set = set([job.id for job in jobs])
|
|
yield_values = [
|
|
[jobs[1]],
|
|
[jobs[0], jobs[2]],
|
|
jobs[3:6]
|
|
]
|
|
self.mox.StubOutWithMock(time, 'sleep')
|
|
for yield_this in yield_values:
|
|
self.afe.get_jobs(id__in=list(job_id_set),
|
|
finished=True).AndReturn(yield_this)
|
|
for job in yield_this:
|
|
self.expect_yield_job_entries(job)
|
|
job_id_set.remove(job.id)
|
|
time.sleep(mox.IgnoreArg())
|
|
self.mox.ReplayAll()
|
|
|
|
waiter = job_status.JobResultWaiter(self.afe, self.tko)
|
|
waiter.add_jobs(jobs)
|
|
results = [result for result in waiter.wait_for_results()]
|
|
for job in jobs[:6]: # the 'GOOD' SERVER_JOB shouldn't be there.
|
|
for status in job.statuses:
|
|
self.assertTrue(True in list(map(status.equals_record, results)))
|
|
|
|
|
|
def testYieldSubdir(self):
|
|
"""Make sure subdir are properly set for test and non-test status."""
|
|
job_tag = '0-owner/172.33.44.55'
|
|
job_name = 'broken_infra_job'
|
|
job = FakeJob(0, [FakeStatus('ERROR', 'SERVER_JOB', 'server error',
|
|
subdir='---', job_tag=job_tag),
|
|
FakeStatus('GOOD', 'T0', '',
|
|
subdir='T0.subdir', job_tag=job_tag)],
|
|
parent_job_id=54321)
|
|
for status in job.statuses:
|
|
status.entry['job'] = {'name': job_name}
|
|
self.expect_yield_job_entries(job)
|
|
self.mox.ReplayAll()
|
|
results = list(job_status._yield_job_results(self.afe, self.tko, job))
|
|
for i in range(len(results)):
|
|
result = results[i]
|
|
if result.test_name.endswith('SERVER_JOB'):
|
|
expected_name = '%s_%s' % (job_name, job.statuses[i].test_name)
|
|
expected_subdir = job_tag
|
|
else:
|
|
expected_name = job.statuses[i].test_name
|
|
expected_subdir = os.path.join(job_tag, job.statuses[i].subdir)
|
|
self.assertEqual(results[i].test_name, expected_name)
|
|
self.assertEqual(results[i].subdir, expected_subdir)
|
|
|
|
|
|
def _prepareForReporting(self, results):
|
|
def callable(x):
|
|
pass
|
|
|
|
record_entity = self.mox.CreateMock(callable)
|
|
group = self.mox.CreateMock(host_spec.HostGroup)
|
|
|
|
statuses = {}
|
|
all_bad = True not in six.itervalues(results)
|
|
for hostname, result in six.iteritems(results):
|
|
status = self.mox.CreateMock(job_status.Status)
|
|
status.record_all(record_entity).InAnyOrder('recording')
|
|
status.is_good().InAnyOrder('recording').AndReturn(result)
|
|
if not result:
|
|
status.test_name = 'test'
|
|
if not all_bad:
|
|
status.override_status('WARN').InAnyOrder('recording')
|
|
else:
|
|
group.mark_host_success(hostname).InAnyOrder('recording')
|
|
statuses[hostname] = status
|
|
|
|
return (statuses, group, record_entity)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|