1*9c5db199SXin Li#!/usr/bin/python3 2*9c5db199SXin Li 3*9c5db199SXin Lifrom autotest_lib.tko import models 4*9c5db199SXin Liimport datetime, time, unittest, mock 5*9c5db199SXin Li 6*9c5db199SXin Liimport common 7*9c5db199SXin Lifrom autotest_lib.client.common_lib import utils 8*9c5db199SXin Lifrom autotest_lib.tko.parsers import version_1 9*9c5db199SXin Li 10*9c5db199SXin Li 11*9c5db199SXin Liclass test_status_line(unittest.TestCase): 12*9c5db199SXin Li """Tests for status lines.""" 13*9c5db199SXin Li 14*9c5db199SXin Li statuses = ['GOOD', 'WARN', 'FAIL', 'ABORT'] 15*9c5db199SXin Li 16*9c5db199SXin Li 17*9c5db199SXin Li def test_handles_start(self): 18*9c5db199SXin Li """Tests that START is handled properly.""" 19*9c5db199SXin Li line = version_1.status_line(0, 'START', '----', 'test', 20*9c5db199SXin Li '', {}) 21*9c5db199SXin Li self.assertEquals(line.type, 'START') 22*9c5db199SXin Li self.assertEquals(line.status, None) 23*9c5db199SXin Li 24*9c5db199SXin Li 25*9c5db199SXin Li def test_handles_info(self): 26*9c5db199SXin Li """Tests that INFO is handled properly.""" 27*9c5db199SXin Li line = version_1.status_line(0, 'INFO', '----', '----', 28*9c5db199SXin Li '', {}) 29*9c5db199SXin Li self.assertEquals(line.type, 'INFO') 30*9c5db199SXin Li self.assertEquals(line.status, None) 31*9c5db199SXin Li 32*9c5db199SXin Li 33*9c5db199SXin Li def test_handles_status(self): 34*9c5db199SXin Li """Tests that STATUS is handled properly.""" 35*9c5db199SXin Li for stat in self.statuses: 36*9c5db199SXin Li line = version_1.status_line(0, stat, '----', 'test', 37*9c5db199SXin Li '', {}) 38*9c5db199SXin Li self.assertEquals(line.type, 'STATUS') 39*9c5db199SXin Li self.assertEquals(line.status, stat) 40*9c5db199SXin Li 41*9c5db199SXin Li 42*9c5db199SXin Li def test_handles_endstatus(self): 43*9c5db199SXin Li """Tests that END is handled properly.""" 44*9c5db199SXin Li for stat in self.statuses: 45*9c5db199SXin Li line = version_1.status_line(0, 'END ' + stat, '----', 46*9c5db199SXin Li 'test', '', {}) 47*9c5db199SXin Li self.assertEquals(line.type, 'END') 48*9c5db199SXin Li self.assertEquals(line.status, stat) 49*9c5db199SXin Li 50*9c5db199SXin Li 51*9c5db199SXin Li def test_fails_on_bad_status(self): 52*9c5db199SXin Li """Tests that an exception is raised on a bad status.""" 53*9c5db199SXin Li for stat in self.statuses: 54*9c5db199SXin Li self.assertRaises(AssertionError, 55*9c5db199SXin Li version_1.status_line, 0, 56*9c5db199SXin Li 'BAD ' + stat, '----', 'test', 57*9c5db199SXin Li '', {}) 58*9c5db199SXin Li 59*9c5db199SXin Li 60*9c5db199SXin Li def test_saves_all_fields(self): 61*9c5db199SXin Li """Tests that all fields are saved.""" 62*9c5db199SXin Li line = version_1.status_line(5, 'GOOD', 'subdir_name', 63*9c5db199SXin Li 'test_name', 'my reason here', 64*9c5db199SXin Li {'key1': 'value', 65*9c5db199SXin Li 'key2': 'another value', 66*9c5db199SXin Li 'key3': 'value3'}) 67*9c5db199SXin Li self.assertEquals(line.indent, 5) 68*9c5db199SXin Li self.assertEquals(line.status, 'GOOD') 69*9c5db199SXin Li self.assertEquals(line.subdir, 'subdir_name') 70*9c5db199SXin Li self.assertEquals(line.testname, 'test_name') 71*9c5db199SXin Li self.assertEquals(line.reason, 'my reason here') 72*9c5db199SXin Li self.assertEquals(line.optional_fields, 73*9c5db199SXin Li {'key1': 'value', 'key2': 'another value', 74*9c5db199SXin Li 'key3': 'value3'}) 75*9c5db199SXin Li 76*9c5db199SXin Li 77*9c5db199SXin Li def test_parses_blank_subdir(self): 78*9c5db199SXin Li """Tests that a blank subdirectory is parsed properly.""" 79*9c5db199SXin Li line = version_1.status_line(0, 'GOOD', '----', 'test', 80*9c5db199SXin Li '', {}) 81*9c5db199SXin Li self.assertEquals(line.subdir, None) 82*9c5db199SXin Li 83*9c5db199SXin Li 84*9c5db199SXin Li def test_parses_blank_testname(self): 85*9c5db199SXin Li """Tests that a blank test name is parsed properly.""" 86*9c5db199SXin Li line = version_1.status_line(0, 'GOOD', 'subdir', '----', 87*9c5db199SXin Li '', {}) 88*9c5db199SXin Li self.assertEquals(line.testname, None) 89*9c5db199SXin Li 90*9c5db199SXin Li 91*9c5db199SXin Li def test_parse_line_smoketest(self): 92*9c5db199SXin Li """Runs a parse line smoke test.""" 93*9c5db199SXin Li input_data = ('\t\t\tGOOD\t----\t----\t' 94*9c5db199SXin Li 'field1=val1\tfield2=val2\tTest Passed') 95*9c5db199SXin Li line = version_1.status_line.parse_line(input_data) 96*9c5db199SXin Li self.assertEquals(line.indent, 3) 97*9c5db199SXin Li self.assertEquals(line.type, 'STATUS') 98*9c5db199SXin Li self.assertEquals(line.status, 'GOOD') 99*9c5db199SXin Li self.assertEquals(line.subdir, None) 100*9c5db199SXin Li self.assertEquals(line.testname, None) 101*9c5db199SXin Li self.assertEquals(line.reason, 'Test Passed') 102*9c5db199SXin Li self.assertEquals(line.optional_fields, 103*9c5db199SXin Li {'field1': 'val1', 'field2': 'val2'}) 104*9c5db199SXin Li 105*9c5db199SXin Li def test_parse_line_handles_newline(self): 106*9c5db199SXin Li """Tests that newlines are handled properly.""" 107*9c5db199SXin Li input_data = ('\t\tGOOD\t----\t----\t' 108*9c5db199SXin Li 'field1=val1\tfield2=val2\tNo newline here!') 109*9c5db199SXin Li for suffix in ('', '\n'): 110*9c5db199SXin Li line = version_1.status_line.parse_line(input_data + 111*9c5db199SXin Li suffix) 112*9c5db199SXin Li self.assertEquals(line.indent, 2) 113*9c5db199SXin Li self.assertEquals(line.type, 'STATUS') 114*9c5db199SXin Li self.assertEquals(line.status, 'GOOD') 115*9c5db199SXin Li self.assertEquals(line.subdir, None) 116*9c5db199SXin Li self.assertEquals(line.testname, None) 117*9c5db199SXin Li self.assertEquals(line.reason, 'No newline here!') 118*9c5db199SXin Li self.assertEquals(line.optional_fields, 119*9c5db199SXin Li {'field1': 'val1', 120*9c5db199SXin Li 'field2': 'val2'}) 121*9c5db199SXin Li 122*9c5db199SXin Li 123*9c5db199SXin Li def test_parse_line_fails_on_untabbed_lines(self): 124*9c5db199SXin Li """Tests that untabbed lines do not parse.""" 125*9c5db199SXin Li input_data = ' GOOD\trandom\tfields\tof text' 126*9c5db199SXin Li line = version_1.status_line.parse_line(input_data) 127*9c5db199SXin Li self.assertEquals(line, None) 128*9c5db199SXin Li line = version_1.status_line.parse_line(input_data.lstrip()) 129*9c5db199SXin Li self.assertEquals(line.indent, 0) 130*9c5db199SXin Li self.assertEquals(line.type, 'STATUS') 131*9c5db199SXin Li self.assertEquals(line.status, 'GOOD') 132*9c5db199SXin Li self.assertEquals(line.subdir, 'random') 133*9c5db199SXin Li self.assertEquals(line.testname, 'fields') 134*9c5db199SXin Li self.assertEquals(line.reason, 'of text') 135*9c5db199SXin Li self.assertEquals(line.optional_fields, {}) 136*9c5db199SXin Li 137*9c5db199SXin Li 138*9c5db199SXin Li def test_parse_line_fails_on_incomplete_lines(self): 139*9c5db199SXin Li """Tests that incomplete lines do not parse.""" 140*9c5db199SXin Li input_data = '\t\tGOOD\tfield\tsecond field' 141*9c5db199SXin Li complete_data = input_data + '\tneeded last field' 142*9c5db199SXin Li line = version_1.status_line.parse_line(input_data) 143*9c5db199SXin Li self.assertEquals(line, None) 144*9c5db199SXin Li line = version_1.status_line.parse_line(complete_data) 145*9c5db199SXin Li self.assertEquals(line.indent, 2) 146*9c5db199SXin Li self.assertEquals(line.type, 'STATUS') 147*9c5db199SXin Li self.assertEquals(line.status, 'GOOD') 148*9c5db199SXin Li self.assertEquals(line.subdir, 'field') 149*9c5db199SXin Li self.assertEquals(line.testname, 'second field') 150*9c5db199SXin Li self.assertEquals(line.reason, 'needed last field') 151*9c5db199SXin Li self.assertEquals(line.optional_fields, {}) 152*9c5db199SXin Li 153*9c5db199SXin Li 154*9c5db199SXin Li def test_good_reboot_passes_success_test(self): 155*9c5db199SXin Li """Tests good reboot statuses.""" 156*9c5db199SXin Li line = version_1.status_line(0, 'NOSTATUS', None, 'reboot', 157*9c5db199SXin Li 'reboot success', {}) 158*9c5db199SXin Li self.assertEquals(line.is_successful_reboot('GOOD'), True) 159*9c5db199SXin Li self.assertEquals(line.is_successful_reboot('WARN'), True) 160*9c5db199SXin Li 161*9c5db199SXin Li 162*9c5db199SXin Li def test_bad_reboot_passes_success_test(self): 163*9c5db199SXin Li """Tests bad reboot statuses.""" 164*9c5db199SXin Li line = version_1.status_line(0, 'NOSTATUS', None, 'reboot', 165*9c5db199SXin Li 'reboot success', {}) 166*9c5db199SXin Li self.assertEquals(line.is_successful_reboot('FAIL'), False) 167*9c5db199SXin Li self.assertEquals(line.is_successful_reboot('ABORT'), False) 168*9c5db199SXin Li 169*9c5db199SXin Li 170*9c5db199SXin Li def test_get_kernel_returns_kernel_plus_patches(self): 171*9c5db199SXin Li """Tests that get_kernel returns the appropriate info.""" 172*9c5db199SXin Li line = version_1.status_line(0, 'GOOD', 'subdir', 'testname', 173*9c5db199SXin Li 'reason text', 174*9c5db199SXin Li {'kernel': '2.6.24-rc40', 175*9c5db199SXin Li 'patch0': 'first_patch 0 0', 176*9c5db199SXin Li 'patch1': 'another_patch 0 0'}) 177*9c5db199SXin Li kern = line.get_kernel() 178*9c5db199SXin Li kernel_hash = utils.hash('md5', '2.6.24-rc40,0,0').hexdigest() 179*9c5db199SXin Li self.assertEquals(kern.base, '2.6.24-rc40') 180*9c5db199SXin Li self.assertEquals(kern.patches[0].spec, 'first_patch') 181*9c5db199SXin Li self.assertEquals(kern.patches[1].spec, 'another_patch') 182*9c5db199SXin Li self.assertEquals(len(kern.patches), 2) 183*9c5db199SXin Li self.assertEquals(kern.kernel_hash, kernel_hash) 184*9c5db199SXin Li 185*9c5db199SXin Li 186*9c5db199SXin Li def test_get_kernel_ignores_out_of_sequence_patches(self): 187*9c5db199SXin Li """Tests that get_kernel ignores patches that are out of sequence.""" 188*9c5db199SXin Li line = version_1.status_line(0, 'GOOD', 'subdir', 'testname', 189*9c5db199SXin Li 'reason text', 190*9c5db199SXin Li {'kernel': '2.6.24-rc40', 191*9c5db199SXin Li 'patch0': 'first_patch 0 0', 192*9c5db199SXin Li 'patch2': 'another_patch 0 0'}) 193*9c5db199SXin Li kern = line.get_kernel() 194*9c5db199SXin Li kernel_hash = utils.hash('md5', '2.6.24-rc40,0').hexdigest() 195*9c5db199SXin Li self.assertEquals(kern.base, '2.6.24-rc40') 196*9c5db199SXin Li self.assertEquals(kern.patches[0].spec, 'first_patch') 197*9c5db199SXin Li self.assertEquals(len(kern.patches), 1) 198*9c5db199SXin Li self.assertEquals(kern.kernel_hash, kernel_hash) 199*9c5db199SXin Li 200*9c5db199SXin Li 201*9c5db199SXin Li def test_get_kernel_returns_unknown_with_no_kernel(self): 202*9c5db199SXin Li """Tests that a missing kernel is handled properly.""" 203*9c5db199SXin Li line = version_1.status_line(0, 'GOOD', 'subdir', 'testname', 204*9c5db199SXin Li 'reason text', 205*9c5db199SXin Li {'patch0': 'first_patch 0 0', 206*9c5db199SXin Li 'patch2': 'another_patch 0 0'}) 207*9c5db199SXin Li kern = line.get_kernel() 208*9c5db199SXin Li self.assertEquals(kern.base, 'UNKNOWN') 209*9c5db199SXin Li self.assertEquals(kern.patches, []) 210*9c5db199SXin Li self.assertEquals(kern.kernel_hash, 'UNKNOWN') 211*9c5db199SXin Li 212*9c5db199SXin Li 213*9c5db199SXin Li def test_get_timestamp_returns_timestamp_field(self): 214*9c5db199SXin Li """Tests that get_timestamp returns the expected info.""" 215*9c5db199SXin Li timestamp = datetime.datetime(1970, 1, 1, 4, 30) 216*9c5db199SXin Li timestamp -= datetime.timedelta(seconds=time.timezone) 217*9c5db199SXin Li line = version_1.status_line(0, 'GOOD', 'subdir', 'testname', 218*9c5db199SXin Li 'reason text', 219*9c5db199SXin Li {'timestamp': '16200'}) 220*9c5db199SXin Li self.assertEquals(timestamp, line.get_timestamp()) 221*9c5db199SXin Li 222*9c5db199SXin Li 223*9c5db199SXin Li def test_get_timestamp_returns_none_on_missing_field(self): 224*9c5db199SXin Li """Tests that get_timestamp returns None if no timestamp exists.""" 225*9c5db199SXin Li line = version_1.status_line(0, 'GOOD', 'subdir', 'testname', 226*9c5db199SXin Li 'reason text', {}) 227*9c5db199SXin Li self.assertEquals(None, line.get_timestamp()) 228*9c5db199SXin Li 229*9c5db199SXin Li 230*9c5db199SXin Liclass iteration_parse_line_into_dicts(unittest.TestCase): 231*9c5db199SXin Li """Tests for parsing iteration keyvals into dictionaries.""" 232*9c5db199SXin Li 233*9c5db199SXin Li def parse_line(self, line): 234*9c5db199SXin Li """ 235*9c5db199SXin Li Invokes parse_line_into_dicts with two empty dictionaries. 236*9c5db199SXin Li 237*9c5db199SXin Li @param line: The line to parse. 238*9c5db199SXin Li 239*9c5db199SXin Li @return A 2-tuple representing the filled-in attr and perf dictionaries, 240*9c5db199SXin Li respectively. 241*9c5db199SXin Li 242*9c5db199SXin Li """ 243*9c5db199SXin Li attr, perf = {}, {} 244*9c5db199SXin Li version_1.iteration.parse_line_into_dicts(line, attr, perf) 245*9c5db199SXin Li return attr, perf 246*9c5db199SXin Li 247*9c5db199SXin Li 248*9c5db199SXin Li def test_perf_entry(self): 249*9c5db199SXin Li """Tests a basic perf keyval line.""" 250*9c5db199SXin Li result = self.parse_line('perf-val{perf}=-173') 251*9c5db199SXin Li self.assertEqual(({}, {'perf-val': -173}), result) 252*9c5db199SXin Li 253*9c5db199SXin Li 254*9c5db199SXin Li def test_attr_entry(self): 255*9c5db199SXin Li """Tests a basic attr keyval line.""" 256*9c5db199SXin Li result = self.parse_line('attr-val{attr}=173') 257*9c5db199SXin Li self.assertEqual(({'attr-val': '173'}, {}), result) 258*9c5db199SXin Li 259*9c5db199SXin Li 260*9c5db199SXin Li def test_untagged_is_perf(self): 261*9c5db199SXin Li """Tests that an untagged keyval is considered to be perf by default.""" 262*9c5db199SXin Li result = self.parse_line('untagged=-678.5e5') 263*9c5db199SXin Li self.assertEqual(({}, {'untagged': -678.5e5}), result) 264*9c5db199SXin Li 265*9c5db199SXin Li 266*9c5db199SXin Li def test_invalid_tag_ignored(self): 267*9c5db199SXin Li """Tests that invalid tags are ignored.""" 268*9c5db199SXin Li result = self.parse_line('bad-tag{invalid}=56') 269*9c5db199SXin Li self.assertEqual(({}, {}), result) 270*9c5db199SXin Li 271*9c5db199SXin Li 272*9c5db199SXin Li def test_non_numeric_perf_ignored(self): 273*9c5db199SXin Li """Tests that non-numeric perf values are ignored.""" 274*9c5db199SXin Li result = self.parse_line('perf-val{perf}=FooBar') 275*9c5db199SXin Li self.assertEqual(({}, {}), result) 276*9c5db199SXin Li 277*9c5db199SXin Li 278*9c5db199SXin Li def test_non_numeric_untagged_ignored(self): 279*9c5db199SXin Li """Tests that non-numeric untagged keyvals are ignored.""" 280*9c5db199SXin Li result = self.parse_line('untagged=FooBar') 281*9c5db199SXin Li self.assertEqual(({}, {}), result) 282*9c5db199SXin Li 283*9c5db199SXin Li 284*9c5db199SXin Liclass perf_value_iteration_parse_line_into_dict(unittest.TestCase): 285*9c5db199SXin Li """Tests for parsing perf value iterations into a dictionary.""" 286*9c5db199SXin Li 287*9c5db199SXin Li def parse_line(self, line): 288*9c5db199SXin Li """ 289*9c5db199SXin Li Invokes parse_line_into_dict with a line to parse. 290*9c5db199SXin Li 291*9c5db199SXin Li @param line: The string line to parse. 292*9c5db199SXin Li 293*9c5db199SXin Li @return A dictionary containing the information parsed from the line. 294*9c5db199SXin Li 295*9c5db199SXin Li """ 296*9c5db199SXin Li return version_1.perf_value_iteration.parse_line_into_dict(line) 297*9c5db199SXin Li 298*9c5db199SXin Li def test_invalid_json(self): 299*9c5db199SXin Li """Tests that a non-JSON line is handled properly.""" 300*9c5db199SXin Li result = self.parse_line('{"invalid_json" "string"}') 301*9c5db199SXin Li self.assertEqual(result, {}) 302*9c5db199SXin Li 303*9c5db199SXin Li def test_single_value_int(self): 304*9c5db199SXin Li """Tests that a single integer value is parsed properly.""" 305*9c5db199SXin Li result = self.parse_line('{"value": 7}') 306*9c5db199SXin Li self.assertEqual(result, {'value': 7, 'stddev': 0}) 307*9c5db199SXin Li 308*9c5db199SXin Li def test_single_value_float(self): 309*9c5db199SXin Li """Tests that a single float value is parsed properly.""" 310*9c5db199SXin Li result = self.parse_line('{"value": 1.298}') 311*9c5db199SXin Li self.assertEqual(result, {'value': 1.298, 'stddev': 0}) 312*9c5db199SXin Li 313*9c5db199SXin Li def test_value_list_int(self): 314*9c5db199SXin Li """Tests that an integer list is parsed properly.""" 315*9c5db199SXin Li result = self.parse_line('{"value": [10, 20, 30]}') 316*9c5db199SXin Li self.assertEqual(result, {'value': 20.0, 'stddev': 10.0}) 317*9c5db199SXin Li 318*9c5db199SXin Li def test_value_list_float(self): 319*9c5db199SXin Li """Tests that a float list is parsed properly.""" 320*9c5db199SXin Li result = self.parse_line('{"value": [2.0, 3.0, 4.0]}') 321*9c5db199SXin Li self.assertEqual(result, {'value': 3.0, 'stddev': 1.0}) 322*9c5db199SXin Li 323*9c5db199SXin Li 324*9c5db199SXin Liclass DummyAbortTestCase(unittest.TestCase): 325*9c5db199SXin Li """Tests for the make_stub_abort function.""" 326*9c5db199SXin Li 327*9c5db199SXin Li def setUp(self): 328*9c5db199SXin Li self.indent = 3 329*9c5db199SXin Li self.subdir = "subdir" 330*9c5db199SXin Li self.testname = 'testname' 331*9c5db199SXin Li self.timestamp = 1220565792 332*9c5db199SXin Li self.reason = 'Job aborted unexpectedly' 333*9c5db199SXin Li 334*9c5db199SXin Li 335*9c5db199SXin Li def test_make_stub_abort_with_timestamp(self): 336*9c5db199SXin Li """Tests make_stub_abort with a timestamp specified.""" 337*9c5db199SXin Li abort = version_1.parser.make_stub_abort( 338*9c5db199SXin Li self.indent, self.subdir, self.testname, self.timestamp, 339*9c5db199SXin Li self.reason) 340*9c5db199SXin Li self.assertEquals( 341*9c5db199SXin Li abort, '%sEND ABORT\t%s\t%s\ttimestamp=%d\t%s' % ( 342*9c5db199SXin Li '\t' * self.indent, self.subdir, self.testname, self.timestamp, 343*9c5db199SXin Li self.reason)) 344*9c5db199SXin Li 345*9c5db199SXin Li def test_make_stub_abort_with_no_subdir(self): 346*9c5db199SXin Li """Tests make_stub_abort with no subdir specified.""" 347*9c5db199SXin Li abort= version_1.parser.make_stub_abort( 348*9c5db199SXin Li self.indent, None, self.testname, self.timestamp, self.reason) 349*9c5db199SXin Li self.assertEquals( 350*9c5db199SXin Li abort, '%sEND ABORT\t----\t%s\ttimestamp=%d\t%s' % ( 351*9c5db199SXin Li '\t' * self.indent, self.testname, self.timestamp, self.reason)) 352*9c5db199SXin Li 353*9c5db199SXin Li def test_make_stub_abort_with_no_testname(self): 354*9c5db199SXin Li """Tests make_stub_abort with no testname specified.""" 355*9c5db199SXin Li abort= version_1.parser.make_stub_abort( 356*9c5db199SXin Li self.indent, self.subdir, None, self.timestamp, self.reason) 357*9c5db199SXin Li self.assertEquals( 358*9c5db199SXin Li abort, '%sEND ABORT\t%s\t----\ttimestamp=%d\t%s' % ( 359*9c5db199SXin Li '\t' * self.indent, self.subdir, self.timestamp, self.reason)) 360*9c5db199SXin Li 361*9c5db199SXin Li def test_make_stub_abort_no_timestamp(self): 362*9c5db199SXin Li """Tests make_stub_abort with no timestamp specified.""" 363*9c5db199SXin Li abort = version_1.parser.make_stub_abort( 364*9c5db199SXin Li self.indent, self.subdir, self.testname, None, self.reason) 365*9c5db199SXin Li self.assertEquals( 366*9c5db199SXin Li abort, '%sEND ABORT\t%s\t%s\t%s' % ( 367*9c5db199SXin Li '\t' * self.indent, self.subdir, self.testname, self.reason)) 368*9c5db199SXin Li 369*9c5db199SXin Li 370*9c5db199SXin Liclass test_parse_file(unittest.TestCase): 371*9c5db199SXin Li """Tests for parsing a status.log file.""" 372*9c5db199SXin Li 373*9c5db199SXin Li class fake_job(models.job): 374*9c5db199SXin Li """Fake job object.""" 375*9c5db199SXin Li 376*9c5db199SXin Li def exit_status(self): 377*9c5db199SXin Li """Fake exit_status method.""" 378*9c5db199SXin Li return 'FAIL' 379*9c5db199SXin Li 380*9c5db199SXin Li @staticmethod 381*9c5db199SXin Li def _parse_host_keyval(job_dir, hostname): 382*9c5db199SXin Li return {} 383*9c5db199SXin Li 384*9c5db199SXin Li @mock.patch.object(models.test, 'parse_host_keyval', _parse_host_keyval) 385*9c5db199SXin Li def test_top_level_fail_with_reason(self): 386*9c5db199SXin Li """Tests that a status.log with a FAIL keeps the reason.""" 387*9c5db199SXin Li job = self.fake_job('dir', 'user', 'label', 'machine', None, None, 388*9c5db199SXin Li None, None, None, None, None, None) 389*9c5db199SXin Li parser = version_1.parser() 390*9c5db199SXin Li parser.start(job) 391*9c5db199SXin Li tests = parser.end([ 392*9c5db199SXin Li 'FAIL\t----\t----\ttimestamp=1615249387\tlocaltime=Mar 09 00:23:07\tThis is the reason.' 393*9c5db199SXin Li ]) 394*9c5db199SXin Li self.assertEquals(tests[0].status, 'FAIL') 395*9c5db199SXin Li self.assertEquals(tests[0].reason, 'This is the reason.') 396*9c5db199SXin Li 397*9c5db199SXin Li 398*9c5db199SXin Liif __name__ == '__main__': 399*9c5db199SXin Li unittest.main() 400