blob: cf474df8f74a3e6d47a954fa3fb2653e5a0a7c05 [file] [log] [blame]
Fang Deng0454e632014-04-07 15:39:47 -07001#!/usr/bin/python
2# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
Allen Licc205492017-07-10 17:26:04 -07006import collections
Prashanth Ba7be2072014-07-15 15:03:21 -07007import datetime as datetime_base
8from datetime import datetime
Fang Deng0454e632014-04-07 15:39:47 -07009import mock
Prashanth Ba7be2072014-07-15 15:03:21 -070010import time
Fang Deng0454e632014-04-07 15:39:47 -070011import unittest
12
13import common
14
15from autotest_lib.server.cros.dynamic_suite import constants
16from autotest_lib.site_utils import run_suite
Xixuan Wu888ee7a2018-04-24 10:27:27 -070017from autotest_lib.site_utils import run_suite_common
Prashanth Ba7be2072014-07-15 15:03:21 -070018from autotest_lib.site_utils import diagnosis_utils
Fang Deng0454e632014-04-07 15:39:47 -070019
20
Allen Licc205492017-07-10 17:26:04 -070021class ReturnResultUnittest(unittest.TestCase):
22 """_ReturnResult tests."""
23
24 def setUp(self):
25 super(ReturnResultUnittest, self).setUp()
26 patcher = mock.patch.object(run_suite, '_RETURN_RESULTS',
27 collections.OrderedDict())
28 self.results = results = patcher.start()
29 self.addCleanup(patcher.stop)
30 results['small'] = run_suite._ReturnResult(0, 'small')
31 results['big'] = run_suite._ReturnResult(1, 'big')
32
33 patcher = mock.patch.object(run_suite, '_RETURN_RESULTS_LIST',
34 list(results.values()))
35 patcher.start()
36 self.addCleanup(patcher.stop)
37
38 def test_equal(self):
39 """Test _ReturnResult equal."""
40 self.assertEqual(self.results['small'], self.results['small'])
41
42 def test_unequal(self):
43 """Test _ReturnResult unequal."""
44 self.assertNotEqual(self.results['big'], self.results['small'])
45
46 def test_greater_than(self):
47 """Test _ReturnResult greater than."""
48 self.assertGreater(self.results['big'], self.results['small'])
49
50 def test_bitwise_or(self):
51 """Test _ReturnResult bitwise or."""
52 self.assertEqual(self.results['big'],
53 self.results['big'] | self.results['small'])
54
55
Fang Deng0454e632014-04-07 15:39:47 -070056class ResultCollectorUnittest(unittest.TestCase):
57 """Runsuite unittest"""
58
Fang Dengf8503532014-06-12 18:21:55 -070059 JOB_MAX_RUNTIME_MINS = 10
60
Fang Deng0454e632014-04-07 15:39:47 -070061 def setUp(self):
62 """Set up test."""
63 self.afe = mock.MagicMock()
64 self.tko = mock.MagicMock()
65
66
67 def _build_view(self, test_idx, test_name, subdir, status, afe_job_id,
68 job_name='fake_job_name', reason='fake reason',
69 job_keyvals=None, test_started_time=None,
Fang Dengf8503532014-06-12 18:21:55 -070070 test_finished_time=None, invalidates_test_idx=None,
71 job_started_time=None, job_finished_time=None):
Fang Deng0454e632014-04-07 15:39:47 -070072 """Build a test view using the given fields.
73
74 @param test_idx: An integer representing test_idx.
75 @param test_name: A string, e.g. 'dummy_Pass'
76 @param subdir: A string representing the subdir field of the test view.
77 e.g. 'dummy_Pass'.
78 @param status: A string representing the test status.
79 e.g. 'FAIL', 'PASS'
80 @param afe_job_id: An integer representing the afe job id.
81 @param job_name: A string representing the job name.
82 @param reason: A string representing the reason field of the test view.
83 @param job_keyvals: A dictionary stroing the job keyvals.
84 @param test_started_time: A string, e.g. '2014-04-12 12:35:33'
85 @param test_finished_time: A string, e.g. '2014-04-12 12:35:33'
Fang Dengaeab6172014-05-07 17:17:04 -070086 @param invalidates_test_idx: An integer, representing the idx of the
87 test that has been retried.
Fang Dengf8503532014-06-12 18:21:55 -070088 @param job_started_time: A string, e.g. '2014-04-12 12:35:33'
89 @param job_finished_time: A string, e.g. '2014-04-12 12:35:33'
Fang Deng0454e632014-04-07 15:39:47 -070090
91 @reutrn: A dictionary representing a test view.
92
93 """
94 if job_keyvals is None:
95 job_keyvals = {}
96 return {'test_idx': test_idx, 'test_name': test_name, 'subdir':subdir,
97 'status': status, 'afe_job_id': afe_job_id,
98 'job_name': job_name, 'reason': reason,
99 'job_keyvals': job_keyvals,
100 'test_started_time': test_started_time,
Fang Dengaeab6172014-05-07 17:17:04 -0700101 'test_finished_time': test_finished_time,
Fang Dengf8503532014-06-12 18:21:55 -0700102 'invalidates_test_idx': invalidates_test_idx,
103 'job_started_time': job_started_time,
104 'job_finished_time': job_finished_time}
Fang Deng0454e632014-04-07 15:39:47 -0700105
106
David Rileydcd1a642017-03-01 23:15:08 -0800107 def _mock_tko_get_detailed_test_views(self, test_views,
108 missing_results=[]):
Fang Deng0454e632014-04-07 15:39:47 -0700109 """Mock tko method get_detailed_test_views call.
110
111 @param test_views: A list of test views that will be returned
112 by get_detailed_test_views.
113 """
114 return_values = {}
115 for v in test_views:
116 views_of_job = return_values.setdefault(
117 ('get_detailed_test_views', v['afe_job_id']), [])
118 views_of_job.append(v)
David Rileydcd1a642017-03-01 23:15:08 -0800119 for job_id in missing_results:
120 views_of_job = return_values.setdefault(
121 ('get_detailed_test_views', job_id), [])
Fang Deng0454e632014-04-07 15:39:47 -0700122
123 def side_effect(*args, **kwargs):
124 """Maps args and kwargs to the mocked return values."""
125 key = (kwargs['call'], kwargs['afe_job_id'])
126 return return_values[key]
127
128 self.tko.run = mock.MagicMock(side_effect=side_effect)
129
130
131 def _mock_afe_get_jobs(self, suite_job_id, child_job_ids):
132 """Mock afe get_jobs call.
133
134 @param suite_job_id: The afe job id of the suite job.
135 @param child_job_ids: A list of job ids of the child jobs.
136
137 """
Fang Dengf8503532014-06-12 18:21:55 -0700138 suite_job = mock.MagicMock()
139 suite_job.id = suite_job_id
140 suite_job.max_runtime_mins = 10
141 suite_job.parent_job = None
142
Fang Deng0454e632014-04-07 15:39:47 -0700143 return_values = {suite_job_id: []}
144 for job_id in child_job_ids:
145 new_job = mock.MagicMock()
146 new_job.id = job_id
David Rileydcd1a642017-03-01 23:15:08 -0800147 new_job.name = 'test.%d' % job_id
Fang Dengf8503532014-06-12 18:21:55 -0700148 new_job.max_runtime_mins = self.JOB_MAX_RUNTIME_MINS
149 new_job.parent_job = suite_job
Fang Deng0454e632014-04-07 15:39:47 -0700150 return_values[suite_job_id].append(new_job)
151
152 def side_effect(*args, **kwargs):
153 """Maps args and kwargs to the mocked return values."""
Fang Dengf8503532014-06-12 18:21:55 -0700154 if kwargs.get('id') == suite_job_id:
155 return [suite_job]
Fang Deng0454e632014-04-07 15:39:47 -0700156 return return_values[kwargs['parent_job_id']]
157
158 self.afe.get_jobs = mock.MagicMock(side_effect=side_effect)
159
160
161 def testFetchSuiteTestView(self):
162 """Test that it fetches the correct suite test views."""
163 suite_job_id = 100
Fang Dengaeab6172014-05-07 17:17:04 -0700164 suite_name = 'dummy'
165 build = 'R23-1.1.1.1'
Fang Deng0454e632014-04-07 15:39:47 -0700166 server_job_view = self._build_view(
167 10, 'SERVER_JOB', '----', 'GOOD', suite_job_id)
168 test_to_ignore = self._build_view(
169 11, 'dummy_Pass', '101-user/host/dummy_Pass',
170 'GOOD', suite_job_id)
171 test_to_include = self._build_view(
172 12, 'dummy_Pass.bluetooth', None, 'TEST_NA', suite_job_id)
David Rileydcd1a642017-03-01 23:15:08 -0800173 test_missing = self._build_view(
174 13, 'dummy_Missing', None, 'ABORT', suite_job_id)
Fang Dengf8503532014-06-12 18:21:55 -0700175 self._mock_afe_get_jobs(suite_job_id, [])
Fang Deng0454e632014-04-07 15:39:47 -0700176 self._mock_tko_get_detailed_test_views(
David Rileydcd1a642017-03-01 23:15:08 -0800177 [server_job_view, test_to_ignore, test_to_include,
178 test_missing])
Fang Deng0454e632014-04-07 15:39:47 -0700179 collector = run_suite.ResultCollector(
180 'fake_server', self.afe, self.tko,
Richard Barnetteed5115a2018-09-12 17:12:54 -0700181 build=build, suite_name=suite_name,
Allen Li0b675b62017-07-05 13:38:04 -0700182 suite_job_id=suite_job_id,
183 return_code_function=run_suite._ReturnCodeComputer())
David Rileydcd1a642017-03-01 23:15:08 -0800184 collector._missing_results = {
185 test_missing['test_name']: [14, 15],
186 }
Fang Deng0454e632014-04-07 15:39:47 -0700187 suite_views = collector._fetch_relevant_test_views_of_suite()
188 suite_views = sorted(suite_views, key=lambda view: view['test_idx'])
Shuqian Zhaoc085abb2016-02-24 11:27:26 -0800189 # Verify that SERVER_JOB is renamed to 'Suite job'
Fang Dengaeab6172014-05-07 17:17:04 -0700190 self.assertEqual(suite_views[0].get_testname(),
Shuqian Zhaoc085abb2016-02-24 11:27:26 -0800191 run_suite.TestView.SUITE_JOB)
Fang Deng0454e632014-04-07 15:39:47 -0700192 # Verify that the test with a subidr is not included.
Fang Dengaeab6172014-05-07 17:17:04 -0700193 self.assertEqual(suite_views[0]['test_idx'], 10)
194 self.assertEqual(suite_views[1]['test_idx'], 12)
David Rileydcd1a642017-03-01 23:15:08 -0800195 self.assertEqual(suite_views[1]['afe_job_id'], suite_job_id)
196 # Verify that the test with missing results had it's AFE job id
197 # replaced.
198 self.assertEqual(suite_views[2]['test_idx'], 13)
199 self.assertEqual(suite_views[2]['afe_job_id'], 14)
Fang Deng0454e632014-04-07 15:39:47 -0700200
201
202 def testFetchTestViewOfChildJobs(self):
203 """Test that it fetches the correct child test views."""
204 build = 'lumpy-release/R36-5788.0.0'
MK Ryu977a9752014-10-21 11:58:09 -0700205 board = 'lumpy'
Fang Deng0454e632014-04-07 15:39:47 -0700206 suite_name = 'my_suite'
207 suite_job_id = 100
Fang Dengaeab6172014-05-07 17:17:04 -0700208 invalid_job_id = 101
209 invalid_job_name = '%s/%s/test_Pass' % (build, suite_name)
210 good_job_id = 102
Fang Deng0454e632014-04-07 15:39:47 -0700211 good_job_name = '%s/%s/test_Pass' % (build, suite_name)
Fang Dengaeab6172014-05-07 17:17:04 -0700212 bad_job_id = 103
Fang Deng0454e632014-04-07 15:39:47 -0700213 bad_job_name = '%s/%s/test_ServerJobFail' % (build, suite_name)
David Rileydcd1a642017-03-01 23:15:08 -0800214 missing_job_id = 104
Fang Deng0454e632014-04-07 15:39:47 -0700215
Fang Dengaeab6172014-05-07 17:17:04 -0700216 invalid_test = self._build_view(
217 19, 'test_Pass_Old', 'fake/subdir',
218 'FAIL', invalid_job_id, invalid_job_name)
Fang Deng0454e632014-04-07 15:39:47 -0700219 good_job_server_job = self._build_view(
220 20, 'SERVER_JOB', '----', 'GOOD', good_job_id, good_job_name)
221 good_job_test = self._build_view(
Fang Dengaeab6172014-05-07 17:17:04 -0700222 21, 'test_Pass', 'fake/subdir', 'GOOD',
223 good_job_id, good_job_name,
224 job_keyvals={'retry_original_job_id': invalid_job_id})
Fang Deng0454e632014-04-07 15:39:47 -0700225 bad_job_server_job = self._build_view(
226 22, 'SERVER_JOB', '----', 'FAIL', bad_job_id, bad_job_name)
227 bad_job_test = self._build_view(
228 23, 'test_ServerJobFail', 'fake/subdir', 'GOOD',
229 bad_job_id, bad_job_name)
230 self._mock_tko_get_detailed_test_views(
231 [good_job_server_job, good_job_test,
David Rileydcd1a642017-03-01 23:15:08 -0800232 bad_job_server_job, bad_job_test, invalid_test],
233 [missing_job_id])
234 self._mock_afe_get_jobs(suite_job_id,
235 [good_job_id, bad_job_id, missing_job_id])
Fang Deng0454e632014-04-07 15:39:47 -0700236 collector = run_suite.ResultCollector(
237 'fake_server', self.afe, self.tko,
Richard Barnetteed5115a2018-09-12 17:12:54 -0700238 build, suite_name, suite_job_id,
Allen Li0b675b62017-07-05 13:38:04 -0700239 return_code_function=run_suite._ReturnCodeComputer())
David Rileydcd1a642017-03-01 23:15:08 -0800240 child_views, retry_counts, missing_results = (
241 collector._fetch_test_views_of_child_jobs())
Fang Dengaeab6172014-05-07 17:17:04 -0700242 # child_views should contain tests 21, 22, 23
Fang Deng0454e632014-04-07 15:39:47 -0700243 child_views = sorted(child_views, key=lambda view: view['test_idx'])
244 # Verify that the SERVER_JOB has been renamed properly
Fang Dengaeab6172014-05-07 17:17:04 -0700245 self.assertEqual(child_views[1].get_testname(),
246 'test_ServerJobFail_SERVER_JOB')
David Rileydcd1a642017-03-01 23:15:08 -0800247 self.assertEqual(missing_results, {'test.104': [104]})
Fang Dengaeab6172014-05-07 17:17:04 -0700248 # Verify that failed SERVER_JOB and actual invalid tests are included,
249 expected = [good_job_test['test_idx'], bad_job_server_job['test_idx'],
250 bad_job_test['test_idx']]
251 child_view_ids = [v['test_idx'] for v in child_views]
252 self.assertEqual(child_view_ids, expected)
253 self.afe.get_jobs.assert_called_once_with(
254 parent_job_id=suite_job_id)
255 # Verify the retry_counts is calculated correctly
256 self.assertEqual(len(retry_counts), 1)
257 self.assertEqual(retry_counts[21], 1)
Fang Deng0454e632014-04-07 15:39:47 -0700258
259
260 def testGenerateLinks(self):
261 """Test that it generates correct web and buildbot links."""
262 suite_job_id = 100
Fang Dengaeab6172014-05-07 17:17:04 -0700263 suite_name = 'my_suite'
264 build = 'lumpy-release/R36-5788.0.0'
MK Ryu977a9752014-10-21 11:58:09 -0700265 board = 'lumpy'
Fang Dengf8503532014-06-12 18:21:55 -0700266 fake_job = mock.MagicMock()
267 fake_job.parent = suite_job_id
Dan Shi9b620c22017-10-10 10:58:37 -0700268 test_sponge_url = 'http://test_url'
269 job_keyvals = {'sponge_url': test_sponge_url}
Fang Dengaeab6172014-05-07 17:17:04 -0700270 suite_job_view = run_suite.TestView(
271 self._build_view(
Dan Shi9b620c22017-10-10 10:58:37 -0700272 20, 'Suite job', '----', 'GOOD', suite_job_id,
273 job_keyvals=job_keyvals),
Simran Basi01984f52015-10-12 15:36:45 -0700274 fake_job, suite_name, build, 'chromeos-test')
Fang Dengaeab6172014-05-07 17:17:04 -0700275 good_test = run_suite.TestView(
276 self._build_view(
Dan Shi9b620c22017-10-10 10:58:37 -0700277 21, 'test_Pass', 'fake/subdir', 'GOOD', 101,
278 job_keyvals=job_keyvals),
Simran Basi01984f52015-10-12 15:36:45 -0700279 fake_job, suite_name, build, 'chromeos-test')
Fang Dengaeab6172014-05-07 17:17:04 -0700280 bad_test = run_suite.TestView(
281 self._build_view(
Dan Shi9b620c22017-10-10 10:58:37 -0700282 23, 'test_Fail', 'fake/subdir', 'FAIL', 102,
283 job_keyvals=job_keyvals),
Simran Basi01984f52015-10-12 15:36:45 -0700284 fake_job, suite_name, build, 'chromeos-test')
Fang Deng0454e632014-04-07 15:39:47 -0700285
286 collector = run_suite.ResultCollector(
287 'fake_server', self.afe, self.tko,
Richard Barnetteed5115a2018-09-12 17:12:54 -0700288 build, suite_name, suite_job_id, user='chromeos-test',
Allen Li0b675b62017-07-05 13:38:04 -0700289 return_code_function=run_suite._ReturnCodeComputer())
Fang Deng0454e632014-04-07 15:39:47 -0700290 collector._suite_views = [suite_job_view]
291 collector._test_views = [suite_job_view, good_test, bad_test]
292 collector._max_testname_width = max(
Fang Dengaeab6172014-05-07 17:17:04 -0700293 [len(v.get_testname()) for v in collector._test_views]) + 3
Fang Deng0454e632014-04-07 15:39:47 -0700294 collector._generate_web_and_buildbot_links()
Allen Lidc2c69a2016-09-14 19:05:47 -0700295 URL_PATTERN = run_suite._URL_PATTERN
Fang Deng0454e632014-04-07 15:39:47 -0700296 # expected_web_links is list of (anchor, url) tuples we
297 # are expecting.
298 expected_web_links = [
Allen Li34613242016-09-02 11:52:34 -0700299 (v.get_testname(),
Prathmesh Prabhucd246f52018-01-03 13:45:48 -0800300 URL_PATTERN % ('http://fake_server',
301 '%s-%s' % (v['afe_job_id'], 'chromeos-test')),
Dan Shi9b620c22017-10-10 10:58:37 -0700302 test_sponge_url)
Fang Deng0454e632014-04-07 15:39:47 -0700303 for v in collector._test_views]
304 # Verify web links are generated correctly.
305 for i in range(len(collector._web_links)):
306 expect = expected_web_links[i]
307 self.assertEqual(collector._web_links[i].anchor, expect[0])
308 self.assertEqual(collector._web_links[i].url, expect[1])
Dan Shi9b620c22017-10-10 10:58:37 -0700309 self.assertEqual(collector._web_links[i].sponge_url, expect[2])
Fang Deng0454e632014-04-07 15:39:47 -0700310
311 expected_buildbot_links = [
Allen Li34613242016-09-02 11:52:34 -0700312 (v.get_testname(),
Prathmesh Prabhucd246f52018-01-03 13:45:48 -0800313 URL_PATTERN % ('http://fake_server',
314 '%s-%s' % (v['afe_job_id'], 'chromeos-test')))
Fang Deng0454e632014-04-07 15:39:47 -0700315 for v in collector._test_views if v['status'] != 'GOOD']
316 # Verify buildbot links are generated correctly.
Allen Li28be0642017-07-10 15:16:26 -0700317 for i in range(len(collector.buildbot_links)):
Fang Deng0454e632014-04-07 15:39:47 -0700318 expect = expected_buildbot_links[i]
Allen Li28be0642017-07-10 15:16:26 -0700319 self.assertEqual(collector.buildbot_links[i].anchor, expect[0])
320 self.assertEqual(collector.buildbot_links[i].url, expect[1])
321 self.assertEqual(collector.buildbot_links[i].retry_count, 0)
Shuhei Takahashi18f56492017-11-14 16:23:46 +0900322 # Assert that a retry dashboard link is created.
Simran Basi7203d4e2015-02-03 15:50:18 -0800323 self.assertNotEqual(
Shuhei Takahashi18f56492017-11-14 16:23:46 +0900324 collector.buildbot_links[i].GenerateRetryLink(), '')
David Rileya0cd1c22017-07-10 11:15:57 -0700325 self.assertNotEqual(
Shuhei Takahashi18f56492017-11-14 16:23:46 +0900326 collector.buildbot_links[i].GenerateHistoryLink(), '')
Fang Deng0454e632014-04-07 15:39:47 -0700327
328
Fang Deng5a43be62014-05-07 17:17:04 -0700329 def _end_to_end_test_helper(
330 self, include_bad_test=False, include_warn_test=False,
Allen Lie6236ec2017-07-05 12:52:36 -0700331 include_timeout_test=False,
Fang Dengaeab6172014-05-07 17:17:04 -0700332 include_self_aborted_test=False,
Fang Dengf8503532014-06-12 18:21:55 -0700333 include_aborted_by_suite_test=False,
Fang Dengaeab6172014-05-07 17:17:04 -0700334 include_good_retry=False, include_bad_retry=False,
Brian Norris58ae5162017-09-26 13:34:56 -0700335 include_good_test=True,
Fang Dengf8503532014-06-12 18:21:55 -0700336 suite_job_timed_out=False, suite_job_status='GOOD'):
Fang Deng0454e632014-04-07 15:39:47 -0700337 """A helper method for testing ResultCollector end-to-end.
338
339 This method mocks the retrieving of required test views,
340 and call ResultCollector.run() to collect the results.
341
Fang Dengaeab6172014-05-07 17:17:04 -0700342 @param include_bad_test:
343 If True, include a view of a test which has status 'FAIL'.
344 @param include_warn_test:
345 If True, include a view of a test which has status 'WARN'
Fang Dengaeab6172014-05-07 17:17:04 -0700346 @param include_timeout_test:
347 If True, include a view of a test which was aborted before
348 started.
349 @param include_self_aborted_test:
350 If True, include a view of test which was aborted after
Fang Dengf8503532014-06-12 18:21:55 -0700351 started and hit hits own timeout.
352 @param include_self_aborted_by_suite_test:
353 If True, include a view of test which was aborted after
354 started but has not hit its own timeout.
Fang Dengaeab6172014-05-07 17:17:04 -0700355 @param include_good_retry:
356 If True, include a test that passed after retry.
357 @param include_bad_retry:
358 If True, include a test that failed after retry.
Brian Norris58ae5162017-09-26 13:34:56 -0700359 @param include_good_test:
360 If True, include a test that passed. If False, pretend no tests
361 (including the parent suite job) came back with any test
362 results.
Fang Dengf8503532014-06-12 18:21:55 -0700363 @param suite_job_status: One of 'GOOD' 'FAIL' 'ABORT' 'RUNNING'
Fang Deng0454e632014-04-07 15:39:47 -0700364
Fang Dengaeab6172014-05-07 17:17:04 -0700365 @returns: A ResultCollector instance.
Fang Deng0454e632014-04-07 15:39:47 -0700366 """
367 suite_job_id = 100
368 good_job_id = 101
369 bad_job_id = 102
Fang Deng5a43be62014-05-07 17:17:04 -0700370 warn_job_id = 102
Fang Deng5a43be62014-05-07 17:17:04 -0700371 timeout_job_id = 100
372 self_aborted_job_id = 104
Fang Dengf8503532014-06-12 18:21:55 -0700373 aborted_by_suite_job_id = 105
374 good_retry_job_id = 106
375 bad_retry_job_id = 107
Fang Dengaeab6172014-05-07 17:17:04 -0700376 invalid_job_id_1 = 90
377 invalid_job_id_2 = 91
378 suite_name = 'dummy'
379 build = 'lumpy-release/R27-3888.0.0'
Fang Deng0454e632014-04-07 15:39:47 -0700380 suite_job_keyvals = {
381 constants.DOWNLOAD_STARTED_TIME: '2014-04-29 13:14:20',
382 constants.PAYLOAD_FINISHED_TIME: '2014-04-29 13:14:25',
383 constants.ARTIFACT_FINISHED_TIME: '2014-04-29 13:14:30'}
384
Fang Dengf8503532014-06-12 18:21:55 -0700385 suite_job_started_time = '2014-04-29 13:14:37'
386 if suite_job_timed_out:
387 suite_job_keyvals['aborted_by'] = 'test_user'
388 suite_job_finished_time = '2014-04-29 13:25:37'
389 suite_job_status = 'ABORT'
390 else:
391 suite_job_finished_time = '2014-04-29 13:23:37'
392
Fang Deng0454e632014-04-07 15:39:47 -0700393 server_job_view = self._build_view(
Fang Deng5a43be62014-05-07 17:17:04 -0700394 10, 'SERVER_JOB', '----', suite_job_status, suite_job_id,
Fang Deng0454e632014-04-07 15:39:47 -0700395 'lumpy-release/R27-3888.0.0-test_suites/control.dummy',
396 '', suite_job_keyvals, '2014-04-29 13:14:37',
Fang Dengf8503532014-06-12 18:21:55 -0700397 '2014-04-29 13:20:27', job_started_time=suite_job_started_time,
398 job_finished_time=suite_job_finished_time)
Fang Deng0454e632014-04-07 15:39:47 -0700399 good_test = self._build_view(
400 11, 'dummy_Pass', '101-user/host/dummy_Pass', 'GOOD',
Fang Dengaeab6172014-05-07 17:17:04 -0700401 good_job_id, 'lumpy-release/R27-3888.0.0/dummy/dummy_Pass',
Fang Deng0454e632014-04-07 15:39:47 -0700402 '', {}, '2014-04-29 13:15:35', '2014-04-29 13:15:36')
403 bad_test = self._build_view(
404 12, 'dummy_Fail.Fail', '102-user/host/dummy_Fail.Fail', 'FAIL',
Fang Dengaeab6172014-05-07 17:17:04 -0700405 bad_job_id, 'lumpy-release/R27-3888.0.0/dummy/dummy_Fail.Fail',
Fang Deng0454e632014-04-07 15:39:47 -0700406 'always fail', {}, '2014-04-29 13:16:00',
407 '2014-04-29 13:16:02')
408 warn_test = self._build_view(
Fang Deng5a43be62014-05-07 17:17:04 -0700409 13, 'dummy_Fail.Warn', '102-user/host/dummy_Fail.Warn', 'WARN',
Fang Dengaeab6172014-05-07 17:17:04 -0700410 warn_job_id, 'lumpy-release/R27-3888.0.0/dummy/dummy_Fail.Warn',
Fang Deng0454e632014-04-07 15:39:47 -0700411 'always warn', {}, '2014-04-29 13:16:00',
412 '2014-04-29 13:16:02')
Fang Deng5a43be62014-05-07 17:17:04 -0700413 timeout_test = self._build_view(
414 15, 'dummy_Timeout', '', 'ABORT',
Fang Dengaeab6172014-05-07 17:17:04 -0700415 timeout_job_id,
416 'lumpy-release/R27-3888.0.0/dummy/dummy_Timeout',
Fang Deng5a43be62014-05-07 17:17:04 -0700417 'child job did not run', {}, '2014-04-29 13:15:37',
418 '2014-04-29 13:15:38')
419 self_aborted_test = self._build_view(
420 16, 'dummy_Abort', '104-user/host/dummy_Abort', 'ABORT',
Fang Dengaeab6172014-05-07 17:17:04 -0700421 self_aborted_job_id,
422 'lumpy-release/R27-3888.0.0/dummy/dummy_Abort',
Fang Dengf8503532014-06-12 18:21:55 -0700423 'child job aborted', {'aborted_by': 'test_user'},
424 '2014-04-29 13:15:39', '2014-04-29 13:15:40',
425 job_started_time='2014-04-29 13:15:39',
426 job_finished_time='2014-04-29 13:25:40')
427 aborted_by_suite = self._build_view(
428 17, 'dummy_AbortBySuite', '105-user/host/dummy_AbortBySuite',
429 'RUNNING', aborted_by_suite_job_id,
430 'lumpy-release/R27-3888.0.0/dummy/dummy_Abort',
431 'aborted by suite', {'aborted_by': 'test_user'},
432 '2014-04-29 13:15:39', '2014-04-29 13:15:40',
433 job_started_time='2014-04-29 13:15:39',
434 job_finished_time='2014-04-29 13:15:40')
Fang Dengaeab6172014-05-07 17:17:04 -0700435 good_retry = self._build_view(
Fang Dengf8503532014-06-12 18:21:55 -0700436 18, 'dummy_RetryPass', '106-user/host/dummy_RetryPass', 'GOOD',
Fang Dengaeab6172014-05-07 17:17:04 -0700437 good_retry_job_id,
438 'lumpy-release/R27-3888.0.0/dummy/dummy_RetryPass',
439 '', {'retry_original_job_id': invalid_job_id_1},
440 '2014-04-29 13:15:37',
441 '2014-04-29 13:15:38', invalidates_test_idx=1)
442 bad_retry = self._build_view(
Fang Dengf8503532014-06-12 18:21:55 -0700443 19, 'dummy_RetryFail', '107-user/host/dummy_RetryFail', 'FAIL',
Fang Dengaeab6172014-05-07 17:17:04 -0700444 bad_retry_job_id,
445 'lumpy-release/R27-3888.0.0/dummy/dummy_RetryFail',
446 'retry failed', {'retry_original_job_id': invalid_job_id_2},
447 '2014-04-29 13:15:39', '2014-04-29 13:15:40',
448 invalidates_test_idx=2)
449 invalid_test_1 = self._build_view(
450 1, 'dummy_RetryPass', '90-user/host/dummy_RetryPass', 'GOOD',
451 invalid_job_id_1,
452 'lumpy-release/R27-3888.0.0/dummy/dummy_RetryPass',
453 'original test failed', {}, '2014-04-29 13:10:00',
454 '2014-04-29 13:10:01')
455 invalid_test_2 = self._build_view(
456 2, 'dummy_RetryFail', '91-user/host/dummy_RetryFail', 'FAIL',
457 invalid_job_id_2,
458 'lumpy-release/R27-3888.0.0/dummy/dummy_RetryFail',
459 'original test failed', {},
460 '2014-04-29 13:10:03', '2014-04-29 13:10:04')
461
Brian Norris58ae5162017-09-26 13:34:56 -0700462 test_views = []
463 child_jobs = set()
464 missing_results = []
465 if include_good_test:
466 test_views.append(server_job_view)
467 test_views.append(good_test)
468 child_jobs.add(good_job_id)
469 # Emulate missing even the parent/suite job.
470 else:
471 missing_results.append(suite_job_id)
Fang Deng0454e632014-04-07 15:39:47 -0700472 if include_bad_test:
473 test_views.append(bad_test)
Fang Deng5a43be62014-05-07 17:17:04 -0700474 child_jobs.add(bad_job_id)
Fang Deng0454e632014-04-07 15:39:47 -0700475 if include_warn_test:
476 test_views.append(warn_test)
Fang Deng5a43be62014-05-07 17:17:04 -0700477 child_jobs.add(warn_job_id)
Fang Deng5a43be62014-05-07 17:17:04 -0700478 if include_timeout_test:
479 test_views.append(timeout_test)
Fang Deng5a43be62014-05-07 17:17:04 -0700480 if include_self_aborted_test:
481 test_views.append(self_aborted_test)
482 child_jobs.add(self_aborted_job_id)
Fang Dengaeab6172014-05-07 17:17:04 -0700483 if include_good_retry:
484 test_views.extend([good_retry, invalid_test_1])
485 child_jobs.add(good_retry_job_id)
486 if include_bad_retry:
487 test_views.extend([bad_retry, invalid_test_2])
488 child_jobs.add(bad_retry_job_id)
Fang Dengf8503532014-06-12 18:21:55 -0700489 if include_aborted_by_suite_test:
490 test_views.append(aborted_by_suite)
491 child_jobs.add(aborted_by_suite_job_id)
Brian Norris58ae5162017-09-26 13:34:56 -0700492 self._mock_tko_get_detailed_test_views(test_views,
493 missing_results=missing_results)
Fang Deng0454e632014-04-07 15:39:47 -0700494 self._mock_afe_get_jobs(suite_job_id, child_jobs)
495 collector = run_suite.ResultCollector(
496 'fake_server', self.afe, self.tko,
Richard Barnetteed5115a2018-09-12 17:12:54 -0700497 'lumpy-release/R36-5788.0.0', 'dummy', suite_job_id,
Allen Li0b675b62017-07-05 13:38:04 -0700498 return_code_function=run_suite._ReturnCodeComputer())
Fang Deng0454e632014-04-07 15:39:47 -0700499 collector.run()
Brian Norris58ae5162017-09-26 13:34:56 -0700500 collector.output_results()
Fang Deng0454e632014-04-07 15:39:47 -0700501 return collector
502
503
Brian Norris58ae5162017-09-26 13:34:56 -0700504 def testEndToEndSuiteEmpty(self):
505 """Test it returns code INFRA_FAILURE when no tests report back."""
506 collector = self._end_to_end_test_helper(include_good_test=False)
507 self.assertEqual(collector.return_result.return_code,
Xixuan Wu888ee7a2018-04-24 10:27:27 -0700508 run_suite_common.RETURN_CODES.INFRA_FAILURE)
Brian Norris58ae5162017-09-26 13:34:56 -0700509
510
Fang Deng0454e632014-04-07 15:39:47 -0700511 def testEndToEndSuitePass(self):
512 """Test it returns code OK when all test pass."""
513 collector = self._end_to_end_test_helper()
Allen Licc205492017-07-10 17:26:04 -0700514 self.assertEqual(collector.return_result.return_code,
Xixuan Wu888ee7a2018-04-24 10:27:27 -0700515 run_suite_common.RETURN_CODES.OK)
Fang Deng0454e632014-04-07 15:39:47 -0700516
517
Fang Deng0454e632014-04-07 15:39:47 -0700518 def testEndToEndSuiteWarn(self):
519 """Test it returns code WARNING when there is a test that warns."""
520 collector = self._end_to_end_test_helper(include_warn_test=True)
Allen Licc205492017-07-10 17:26:04 -0700521 self.assertEqual(collector.return_result.return_code,
Xixuan Wu888ee7a2018-04-24 10:27:27 -0700522 run_suite_common.RETURN_CODES.WARNING)
Fang Deng0454e632014-04-07 15:39:47 -0700523
524
525 def testEndToEndSuiteFail(self):
526 """Test it returns code ERROR when there is a test that fails."""
Fang Deng0454e632014-04-07 15:39:47 -0700527 collector = self._end_to_end_test_helper(include_bad_test=True)
Allen Licc205492017-07-10 17:26:04 -0700528 self.assertEqual(collector.return_result.return_code,
Xixuan Wu888ee7a2018-04-24 10:27:27 -0700529 run_suite_common.RETURN_CODES.ERROR)
Fang Deng0454e632014-04-07 15:39:47 -0700530
Fang Deng0454e632014-04-07 15:39:47 -0700531
Fang Deng5a43be62014-05-07 17:17:04 -0700532 def testEndToEndSuiteJobFail(self):
533 """Test it returns code SUITE_FAILURE when only the suite job failed."""
534 collector = self._end_to_end_test_helper(suite_job_status='ABORT')
535 self.assertEqual(
Allen Licc205492017-07-10 17:26:04 -0700536 collector.return_result.return_code,
Xixuan Wu888ee7a2018-04-24 10:27:27 -0700537 run_suite_common.RETURN_CODES.INFRA_FAILURE)
Fang Deng5a43be62014-05-07 17:17:04 -0700538
539 collector = self._end_to_end_test_helper(suite_job_status='ERROR')
540 self.assertEqual(
Allen Licc205492017-07-10 17:26:04 -0700541 collector.return_result.return_code,
Xixuan Wu888ee7a2018-04-24 10:27:27 -0700542 run_suite_common.RETURN_CODES.INFRA_FAILURE)
Fang Deng5a43be62014-05-07 17:17:04 -0700543
544
Fang Dengaeab6172014-05-07 17:17:04 -0700545 def testEndToEndRetry(self):
546 """Test it returns correct code when a test was retried."""
547 collector = self._end_to_end_test_helper(include_good_retry=True)
548 self.assertEqual(
Allen Licc205492017-07-10 17:26:04 -0700549 collector.return_result.return_code,
Xixuan Wu888ee7a2018-04-24 10:27:27 -0700550 run_suite_common.RETURN_CODES.WARNING)
Fang Dengaeab6172014-05-07 17:17:04 -0700551
552 collector = self._end_to_end_test_helper(include_good_retry=True,
553 include_self_aborted_test=True)
554 self.assertEqual(
Allen Licc205492017-07-10 17:26:04 -0700555 collector.return_result.return_code,
Xixuan Wu888ee7a2018-04-24 10:27:27 -0700556 run_suite_common.RETURN_CODES.ERROR)
Fang Dengaeab6172014-05-07 17:17:04 -0700557
558 collector = self._end_to_end_test_helper(include_good_retry=True,
559 include_bad_test=True)
560 self.assertEqual(
Allen Licc205492017-07-10 17:26:04 -0700561 collector.return_result.return_code,
Xixuan Wu888ee7a2018-04-24 10:27:27 -0700562 run_suite_common.RETURN_CODES.ERROR)
Fang Dengaeab6172014-05-07 17:17:04 -0700563
564 collector = self._end_to_end_test_helper(include_bad_retry=True)
565 self.assertEqual(
Allen Licc205492017-07-10 17:26:04 -0700566 collector.return_result.return_code,
Xixuan Wu888ee7a2018-04-24 10:27:27 -0700567 run_suite_common.RETURN_CODES.ERROR)
Fang Dengaeab6172014-05-07 17:17:04 -0700568
569
Fang Deng5a43be62014-05-07 17:17:04 -0700570 def testEndToEndSuiteTimeout(self):
571 """Test it returns correct code when a child job timed out."""
Fang Dengf8503532014-06-12 18:21:55 -0700572 # a child job timed out before started, none failed.
Fang Deng5a43be62014-05-07 17:17:04 -0700573 collector = self._end_to_end_test_helper(include_timeout_test=True)
574 self.assertEqual(
Allen Licc205492017-07-10 17:26:04 -0700575 collector.return_result.return_code,
Xixuan Wu888ee7a2018-04-24 10:27:27 -0700576 run_suite_common.RETURN_CODES.SUITE_TIMEOUT)
Fang Deng5a43be62014-05-07 17:17:04 -0700577
Fang Dengf8503532014-06-12 18:21:55 -0700578 # a child job timed out before started, and one test failed.
Fang Deng5a43be62014-05-07 17:17:04 -0700579 collector = self._end_to_end_test_helper(
580 include_bad_test=True, include_timeout_test=True)
Allen Licc205492017-07-10 17:26:04 -0700581 self.assertEqual(collector.return_result.return_code,
Xixuan Wu888ee7a2018-04-24 10:27:27 -0700582 run_suite_common.RETURN_CODES.ERROR)
Fang Deng5a43be62014-05-07 17:17:04 -0700583
Fang Dengf8503532014-06-12 18:21:55 -0700584 # a child job timed out before started, and one test warned.
Fang Deng5a43be62014-05-07 17:17:04 -0700585 collector = self._end_to_end_test_helper(
586 include_warn_test=True, include_timeout_test=True)
Allen Licc205492017-07-10 17:26:04 -0700587 self.assertEqual(collector.return_result.return_code,
Xixuan Wu888ee7a2018-04-24 10:27:27 -0700588 run_suite_common.RETURN_CODES.SUITE_TIMEOUT)
Fang Dengaeab6172014-05-07 17:17:04 -0700589
Fang Dengf8503532014-06-12 18:21:55 -0700590 # a child job timed out before started, and one test was retried.
Fang Dengaeab6172014-05-07 17:17:04 -0700591 collector = self._end_to_end_test_helper(include_good_retry=True,
592 include_timeout_test=True)
Fang Deng5a43be62014-05-07 17:17:04 -0700593 self.assertEqual(
Allen Licc205492017-07-10 17:26:04 -0700594 collector.return_result.return_code,
Xixuan Wu888ee7a2018-04-24 10:27:27 -0700595 run_suite_common.RETURN_CODES.SUITE_TIMEOUT)
Fang Deng5a43be62014-05-07 17:17:04 -0700596
Fang Dengf8503532014-06-12 18:21:55 -0700597 # a child jot was aborted because suite timed out.
598 collector = self._end_to_end_test_helper(
599 include_aborted_by_suite_test=True)
600 self.assertEqual(
Prathmesh Prabhu316180c2017-12-19 16:06:44 -0800601 collector.return_result.return_code,
Xixuan Wu888ee7a2018-04-24 10:27:27 -0700602 run_suite_common.RETURN_CODES.SUITE_TIMEOUT)
Fang Dengf8503532014-06-12 18:21:55 -0700603
604 # suite job timed out.
605 collector = self._end_to_end_test_helper(suite_job_timed_out=True)
606 self.assertEqual(
Allen Licc205492017-07-10 17:26:04 -0700607 collector.return_result.return_code,
Xixuan Wu888ee7a2018-04-24 10:27:27 -0700608 run_suite_common.RETURN_CODES.SUITE_TIMEOUT)
Fang Dengf8503532014-06-12 18:21:55 -0700609
Fang Deng5a43be62014-05-07 17:17:04 -0700610
Ningning Xiabd911bd2016-04-19 14:06:03 -0700611class LogLinkUnittests(unittest.TestCase):
612 """Test the LogLink"""
613
614 def testGenerateBuildbotLinks(self):
615 """Test LogLink GenerateBuildbotLinks"""
616 log_link_a = run_suite.LogLink('mock_anchor', 'mock_server',
617 'mock_job_string',
618 bug_info=('mock_bug_id', 1),
619 reason='mock_reason',
620 retry_count=1,
621 testname='mock_testname')
622 # Generate a bug link and a log link when bug_info is present
Allen Lie082ced2016-09-14 15:19:20 -0700623 self.assertTrue(len(list(log_link_a.GenerateBuildbotLinks())) == 2)
Ningning Xiabd911bd2016-04-19 14:06:03 -0700624
625 log_link_b = run_suite.LogLink('mock_anchor', 'mock_server',
626 'mock_job_string_b',
627 reason='mock_reason',
628 retry_count=1,
629 testname='mock_testname')
630 # Generate a log link when there is no bug_info
Allen Lie082ced2016-09-14 15:19:20 -0700631 self.assertTrue(len(list(log_link_b.GenerateBuildbotLinks())) == 1)
Ningning Xiabd911bd2016-04-19 14:06:03 -0700632
633
Prashanth Ba7be2072014-07-15 15:03:21 -0700634class SimpleTimerUnittests(unittest.TestCase):
635 """Test the simple timer."""
636
637 def testPoll(self):
638 """Test polling the timer."""
639 interval_hours = 0.0001
640 t = diagnosis_utils.SimpleTimer(interval_hours=interval_hours)
641 deadline = t.deadline
642 self.assertTrue(deadline is not None and
643 t.interval_hours == interval_hours)
644 min_deadline = (datetime.now() +
645 datetime_base.timedelta(hours=interval_hours))
646 time.sleep(interval_hours * 3600)
647 self.assertTrue(t.poll())
648 self.assertTrue(t.deadline >= min_deadline)
649
650
651 def testBadInterval(self):
652 """Test a bad interval."""
653 t = diagnosis_utils.SimpleTimer(interval_hours=-1)
654 self.assertTrue(t.deadline is None and t.poll() == False)
655 t._reset()
656 self.assertTrue(t.deadline is None and t.poll() == False)
657
658
Fang Deng0454e632014-04-07 15:39:47 -0700659if __name__ == '__main__':
660 unittest.main()