You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
371 lines
15 KiB
371 lines
15 KiB
#!/usr/bin/python2
|
|
|
|
import datetime, time, unittest
|
|
|
|
import common
|
|
from autotest_lib.client.common_lib import utils
|
|
from autotest_lib.tko.parsers import version_1
|
|
|
|
|
|
class test_status_line(unittest.TestCase):
|
|
"""Tests for status lines."""
|
|
|
|
statuses = ['GOOD', 'WARN', 'FAIL', 'ABORT']
|
|
|
|
|
|
def test_handles_start(self):
|
|
"""Tests that START is handled properly."""
|
|
line = version_1.status_line(0, 'START', '----', 'test',
|
|
'', {})
|
|
self.assertEquals(line.type, 'START')
|
|
self.assertEquals(line.status, None)
|
|
|
|
|
|
def test_handles_info(self):
|
|
"""Tests that INFO is handled properly."""
|
|
line = version_1.status_line(0, 'INFO', '----', '----',
|
|
'', {})
|
|
self.assertEquals(line.type, 'INFO')
|
|
self.assertEquals(line.status, None)
|
|
|
|
|
|
def test_handles_status(self):
|
|
"""Tests that STATUS is handled properly."""
|
|
for stat in self.statuses:
|
|
line = version_1.status_line(0, stat, '----', 'test',
|
|
'', {})
|
|
self.assertEquals(line.type, 'STATUS')
|
|
self.assertEquals(line.status, stat)
|
|
|
|
|
|
def test_handles_endstatus(self):
|
|
"""Tests that END is handled properly."""
|
|
for stat in self.statuses:
|
|
line = version_1.status_line(0, 'END ' + stat, '----',
|
|
'test', '', {})
|
|
self.assertEquals(line.type, 'END')
|
|
self.assertEquals(line.status, stat)
|
|
|
|
|
|
def test_fails_on_bad_status(self):
|
|
"""Tests that an exception is raised on a bad status."""
|
|
for stat in self.statuses:
|
|
self.assertRaises(AssertionError,
|
|
version_1.status_line, 0,
|
|
'BAD ' + stat, '----', 'test',
|
|
'', {})
|
|
|
|
|
|
def test_saves_all_fields(self):
|
|
"""Tests that all fields are saved."""
|
|
line = version_1.status_line(5, 'GOOD', 'subdir_name',
|
|
'test_name', 'my reason here',
|
|
{'key1': 'value',
|
|
'key2': 'another value',
|
|
'key3': 'value3'})
|
|
self.assertEquals(line.indent, 5)
|
|
self.assertEquals(line.status, 'GOOD')
|
|
self.assertEquals(line.subdir, 'subdir_name')
|
|
self.assertEquals(line.testname, 'test_name')
|
|
self.assertEquals(line.reason, 'my reason here')
|
|
self.assertEquals(line.optional_fields,
|
|
{'key1': 'value', 'key2': 'another value',
|
|
'key3': 'value3'})
|
|
|
|
|
|
def test_parses_blank_subdir(self):
|
|
"""Tests that a blank subdirectory is parsed properly."""
|
|
line = version_1.status_line(0, 'GOOD', '----', 'test',
|
|
'', {})
|
|
self.assertEquals(line.subdir, None)
|
|
|
|
|
|
def test_parses_blank_testname(self):
|
|
"""Tests that a blank test name is parsed properly."""
|
|
line = version_1.status_line(0, 'GOOD', 'subdir', '----',
|
|
'', {})
|
|
self.assertEquals(line.testname, None)
|
|
|
|
|
|
def test_parse_line_smoketest(self):
|
|
"""Runs a parse line smoke test."""
|
|
input_data = ('\t\t\tGOOD\t----\t----\t'
|
|
'field1=val1\tfield2=val2\tTest Passed')
|
|
line = version_1.status_line.parse_line(input_data)
|
|
self.assertEquals(line.indent, 3)
|
|
self.assertEquals(line.type, 'STATUS')
|
|
self.assertEquals(line.status, 'GOOD')
|
|
self.assertEquals(line.subdir, None)
|
|
self.assertEquals(line.testname, None)
|
|
self.assertEquals(line.reason, 'Test Passed')
|
|
self.assertEquals(line.optional_fields,
|
|
{'field1': 'val1', 'field2': 'val2'})
|
|
|
|
def test_parse_line_handles_newline(self):
|
|
"""Tests that newlines are handled properly."""
|
|
input_data = ('\t\tGOOD\t----\t----\t'
|
|
'field1=val1\tfield2=val2\tNo newline here!')
|
|
for suffix in ('', '\n'):
|
|
line = version_1.status_line.parse_line(input_data +
|
|
suffix)
|
|
self.assertEquals(line.indent, 2)
|
|
self.assertEquals(line.type, 'STATUS')
|
|
self.assertEquals(line.status, 'GOOD')
|
|
self.assertEquals(line.subdir, None)
|
|
self.assertEquals(line.testname, None)
|
|
self.assertEquals(line.reason, 'No newline here!')
|
|
self.assertEquals(line.optional_fields,
|
|
{'field1': 'val1',
|
|
'field2': 'val2'})
|
|
|
|
|
|
def test_parse_line_fails_on_untabbed_lines(self):
|
|
"""Tests that untabbed lines do not parse."""
|
|
input_data = ' GOOD\trandom\tfields\tof text'
|
|
line = version_1.status_line.parse_line(input_data)
|
|
self.assertEquals(line, None)
|
|
line = version_1.status_line.parse_line(input_data.lstrip())
|
|
self.assertEquals(line.indent, 0)
|
|
self.assertEquals(line.type, 'STATUS')
|
|
self.assertEquals(line.status, 'GOOD')
|
|
self.assertEquals(line.subdir, 'random')
|
|
self.assertEquals(line.testname, 'fields')
|
|
self.assertEquals(line.reason, 'of text')
|
|
self.assertEquals(line.optional_fields, {})
|
|
|
|
|
|
def test_parse_line_fails_on_incomplete_lines(self):
|
|
"""Tests that incomplete lines do not parse."""
|
|
input_data = '\t\tGOOD\tfield\tsecond field'
|
|
complete_data = input_data + '\tneeded last field'
|
|
line = version_1.status_line.parse_line(input_data)
|
|
self.assertEquals(line, None)
|
|
line = version_1.status_line.parse_line(complete_data)
|
|
self.assertEquals(line.indent, 2)
|
|
self.assertEquals(line.type, 'STATUS')
|
|
self.assertEquals(line.status, 'GOOD')
|
|
self.assertEquals(line.subdir, 'field')
|
|
self.assertEquals(line.testname, 'second field')
|
|
self.assertEquals(line.reason, 'needed last field')
|
|
self.assertEquals(line.optional_fields, {})
|
|
|
|
|
|
def test_good_reboot_passes_success_test(self):
|
|
"""Tests good reboot statuses."""
|
|
line = version_1.status_line(0, 'NOSTATUS', None, 'reboot',
|
|
'reboot success', {})
|
|
self.assertEquals(line.is_successful_reboot('GOOD'), True)
|
|
self.assertEquals(line.is_successful_reboot('WARN'), True)
|
|
|
|
|
|
def test_bad_reboot_passes_success_test(self):
|
|
"""Tests bad reboot statuses."""
|
|
line = version_1.status_line(0, 'NOSTATUS', None, 'reboot',
|
|
'reboot success', {})
|
|
self.assertEquals(line.is_successful_reboot('FAIL'), False)
|
|
self.assertEquals(line.is_successful_reboot('ABORT'), False)
|
|
|
|
|
|
def test_get_kernel_returns_kernel_plus_patches(self):
|
|
"""Tests that get_kernel returns the appropriate info."""
|
|
line = version_1.status_line(0, 'GOOD', 'subdir', 'testname',
|
|
'reason text',
|
|
{'kernel': '2.6.24-rc40',
|
|
'patch0': 'first_patch 0 0',
|
|
'patch1': 'another_patch 0 0'})
|
|
kern = line.get_kernel()
|
|
kernel_hash = utils.hash('md5', '2.6.24-rc40,0,0').hexdigest()
|
|
self.assertEquals(kern.base, '2.6.24-rc40')
|
|
self.assertEquals(kern.patches[0].spec, 'first_patch')
|
|
self.assertEquals(kern.patches[1].spec, 'another_patch')
|
|
self.assertEquals(len(kern.patches), 2)
|
|
self.assertEquals(kern.kernel_hash, kernel_hash)
|
|
|
|
|
|
def test_get_kernel_ignores_out_of_sequence_patches(self):
|
|
"""Tests that get_kernel ignores patches that are out of sequence."""
|
|
line = version_1.status_line(0, 'GOOD', 'subdir', 'testname',
|
|
'reason text',
|
|
{'kernel': '2.6.24-rc40',
|
|
'patch0': 'first_patch 0 0',
|
|
'patch2': 'another_patch 0 0'})
|
|
kern = line.get_kernel()
|
|
kernel_hash = utils.hash('md5', '2.6.24-rc40,0').hexdigest()
|
|
self.assertEquals(kern.base, '2.6.24-rc40')
|
|
self.assertEquals(kern.patches[0].spec, 'first_patch')
|
|
self.assertEquals(len(kern.patches), 1)
|
|
self.assertEquals(kern.kernel_hash, kernel_hash)
|
|
|
|
|
|
def test_get_kernel_returns_unknown_with_no_kernel(self):
|
|
"""Tests that a missing kernel is handled properly."""
|
|
line = version_1.status_line(0, 'GOOD', 'subdir', 'testname',
|
|
'reason text',
|
|
{'patch0': 'first_patch 0 0',
|
|
'patch2': 'another_patch 0 0'})
|
|
kern = line.get_kernel()
|
|
self.assertEquals(kern.base, 'UNKNOWN')
|
|
self.assertEquals(kern.patches, [])
|
|
self.assertEquals(kern.kernel_hash, 'UNKNOWN')
|
|
|
|
|
|
def test_get_timestamp_returns_timestamp_field(self):
|
|
"""Tests that get_timestamp returns the expected info."""
|
|
timestamp = datetime.datetime(1970, 1, 1, 4, 30)
|
|
timestamp -= datetime.timedelta(seconds=time.timezone)
|
|
line = version_1.status_line(0, 'GOOD', 'subdir', 'testname',
|
|
'reason text',
|
|
{'timestamp': '16200'})
|
|
self.assertEquals(timestamp, line.get_timestamp())
|
|
|
|
|
|
def test_get_timestamp_returns_none_on_missing_field(self):
|
|
"""Tests that get_timestamp returns None if no timestamp exists."""
|
|
line = version_1.status_line(0, 'GOOD', 'subdir', 'testname',
|
|
'reason text', {})
|
|
self.assertEquals(None, line.get_timestamp())
|
|
|
|
|
|
class iteration_parse_line_into_dicts(unittest.TestCase):
|
|
"""Tests for parsing iteration keyvals into dictionaries."""
|
|
|
|
def parse_line(self, line):
|
|
"""
|
|
Invokes parse_line_into_dicts with two empty dictionaries.
|
|
|
|
@param line: The line to parse.
|
|
|
|
@return A 2-tuple representing the filled-in attr and perf dictionaries,
|
|
respectively.
|
|
|
|
"""
|
|
attr, perf = {}, {}
|
|
version_1.iteration.parse_line_into_dicts(line, attr, perf)
|
|
return attr, perf
|
|
|
|
|
|
def test_perf_entry(self):
|
|
"""Tests a basic perf keyval line."""
|
|
result = self.parse_line('perf-val{perf}=-173')
|
|
self.assertEqual(({}, {'perf-val': -173}), result)
|
|
|
|
|
|
def test_attr_entry(self):
|
|
"""Tests a basic attr keyval line."""
|
|
result = self.parse_line('attr-val{attr}=173')
|
|
self.assertEqual(({'attr-val': '173'}, {}), result)
|
|
|
|
|
|
def test_untagged_is_perf(self):
|
|
"""Tests that an untagged keyval is considered to be perf by default."""
|
|
result = self.parse_line('untagged=-678.5e5')
|
|
self.assertEqual(({}, {'untagged': -678.5e5}), result)
|
|
|
|
|
|
def test_invalid_tag_ignored(self):
|
|
"""Tests that invalid tags are ignored."""
|
|
result = self.parse_line('bad-tag{invalid}=56')
|
|
self.assertEqual(({}, {}), result)
|
|
|
|
|
|
def test_non_numeric_perf_ignored(self):
|
|
"""Tests that non-numeric perf values are ignored."""
|
|
result = self.parse_line('perf-val{perf}=FooBar')
|
|
self.assertEqual(({}, {}), result)
|
|
|
|
|
|
def test_non_numeric_untagged_ignored(self):
|
|
"""Tests that non-numeric untagged keyvals are ignored."""
|
|
result = self.parse_line('untagged=FooBar')
|
|
self.assertEqual(({}, {}), result)
|
|
|
|
|
|
class perf_value_iteration_parse_line_into_dict(unittest.TestCase):
|
|
"""Tests for parsing perf value iterations into a dictionary."""
|
|
|
|
def parse_line(self, line):
|
|
"""
|
|
Invokes parse_line_into_dict with a line to parse.
|
|
|
|
@param line: The string line to parse.
|
|
|
|
@return A dictionary containing the information parsed from the line.
|
|
|
|
"""
|
|
return version_1.perf_value_iteration.parse_line_into_dict(line)
|
|
|
|
def test_invalid_json(self):
|
|
"""Tests that a non-JSON line is handled properly."""
|
|
result = self.parse_line('{"invalid_json" "string"}')
|
|
self.assertEqual(result, {})
|
|
|
|
def test_single_value_int(self):
|
|
"""Tests that a single integer value is parsed properly."""
|
|
result = self.parse_line('{"value": 7}')
|
|
self.assertEqual(result, {'value': 7, 'stddev': 0})
|
|
|
|
def test_single_value_float(self):
|
|
"""Tests that a single float value is parsed properly."""
|
|
result = self.parse_line('{"value": 1.298}')
|
|
self.assertEqual(result, {'value': 1.298, 'stddev': 0})
|
|
|
|
def test_value_list_int(self):
|
|
"""Tests that an integer list is parsed properly."""
|
|
result = self.parse_line('{"value": [10, 20, 30]}')
|
|
self.assertEqual(result, {'value': 20.0, 'stddev': 10.0})
|
|
|
|
def test_value_list_float(self):
|
|
"""Tests that a float list is parsed properly."""
|
|
result = self.parse_line('{"value": [2.0, 3.0, 4.0]}')
|
|
self.assertEqual(result, {'value': 3.0, 'stddev': 1.0})
|
|
|
|
|
|
class DummyAbortTestCase(unittest.TestCase):
|
|
"""Tests for the make_dummy_abort function."""
|
|
|
|
def setUp(self):
|
|
self.indent = 3
|
|
self.subdir = "subdir"
|
|
self.testname = 'testname'
|
|
self.timestamp = 1220565792
|
|
self.reason = 'Job aborted unexpectedly'
|
|
|
|
|
|
def test_make_dummy_abort_with_timestamp(self):
|
|
"""Tests make_dummy_abort with a timestamp specified."""
|
|
abort = version_1.parser.make_dummy_abort(
|
|
self.indent, self.subdir, self.testname, self.timestamp,
|
|
self.reason)
|
|
self.assertEquals(
|
|
abort, '%sEND ABORT\t%s\t%s\ttimestamp=%d\t%s' % (
|
|
'\t' * self.indent, self.subdir, self.testname, self.timestamp,
|
|
self.reason))
|
|
|
|
def test_make_dummy_abort_with_no_subdir(self):
|
|
"""Tests make_dummy_abort with no subdir specified."""
|
|
abort= version_1.parser.make_dummy_abort(
|
|
self.indent, None, self.testname, self.timestamp, self.reason)
|
|
self.assertEquals(
|
|
abort, '%sEND ABORT\t----\t%s\ttimestamp=%d\t%s' % (
|
|
'\t' * self.indent, self.testname, self.timestamp, self.reason))
|
|
|
|
def test_make_dummy_abort_with_no_testname(self):
|
|
"""Tests make_dummy_abort with no testname specified."""
|
|
abort= version_1.parser.make_dummy_abort(
|
|
self.indent, self.subdir, None, self.timestamp, self.reason)
|
|
self.assertEquals(
|
|
abort, '%sEND ABORT\t%s\t----\ttimestamp=%d\t%s' % (
|
|
'\t' * self.indent, self.subdir, self.timestamp, self.reason))
|
|
|
|
def test_make_dummy_abort_no_timestamp(self):
|
|
"""Tests make_dummy_abort with no timestamp specified."""
|
|
abort = version_1.parser.make_dummy_abort(
|
|
self.indent, self.subdir, self.testname, None, self.reason)
|
|
self.assertEquals(
|
|
abort, '%sEND ABORT\t%s\t%s\t%s' % (
|
|
'\t' * self.indent, self.subdir, self.testname, self.reason))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|