blob: ee742020e867fef31dd1063b329b3fe918ae12fe [file] [log] [blame]
Xixuan Wu40998892017-08-29 14:32:26 -07001# Copyright 2017 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Module for trigger_receiver unittests."""
Xixuan Wu09962902018-12-11 10:49:27 -08006# pylint: disable=g-missing-super-call
Xixuan Wu40998892017-08-29 14:32:26 -07007
8import datetime
9import os
10import unittest
11
Xixuan Wuc6819012019-05-23 11:34:59 -070012import build_lib
Xixuan Wu40998892017-08-29 14:32:26 -070013import config_reader
14import datastore_client
15import file_getter
16import mock
Xixuan Wu51bb7102019-03-18 14:51:44 -070017import task_config_reader
Craig Bergstrom58263d32018-04-26 14:11:35 -060018import task_executor
Xixuan Wu40998892017-08-29 14:32:26 -070019import time_converter
20import trigger_receiver
21
Craig Bergstrom58263d32018-04-26 14:11:35 -060022from google.appengine.api import taskqueue
Xixuan Wu40998892017-08-29 14:32:26 -070023from google.appengine.ext import ndb
24from google.appengine.ext import testbed
25
26# Ensure that SUITE_SCHEDULER_CONFIG_FILE is read only once.
27_SUITE_CONFIG_READER = config_reader.ConfigReader(
Xixuan Wu26d06e02017-09-20 14:50:28 -070028 file_getter.TEST_SUITE_SCHEDULER_CONFIG_FILE)
Xixuan Wu40998892017-08-29 14:32:26 -070029
30
31def now_generator(start_time, interval_min=30, last_days=7):
32 """A datetime.datetime.now generator.
33
34 The generator will generate 'now' from start_time till start_time+last_days
35 for every interval_min.
36
37 Args:
38 start_time: A datetime.datetime object representing the initial value of
39 the 'now'.
40 interval_min: The interval minutes between current 'now' and next 'now.
41 last_days: Representing how many days this generator will last.
42
43 Yields:
44 a datetime.datetime object to mock the current time.
45 """
46 cur_time = start_time
47 end_time = start_time + datetime.timedelta(days=last_days)
48 while cur_time < end_time:
49 yield cur_time
50 cur_time += datetime.timedelta(minutes=interval_min)
51
52
Xixuan Wu09962902018-12-11 10:49:27 -080053def _should_schedule_timed_task(last_now, now):
54 """Check whether timed (weekly/nightly) task should be scheduled.
Xixuan Wu40998892017-08-29 14:32:26 -070055
Xixuan Wu09962902018-12-11 10:49:27 -080056 A timed task should be schduled when next hour is coming.
Xixuan Wu40998892017-08-29 14:32:26 -070057
58 Args:
Xixuan Wu09962902018-12-11 10:49:27 -080059 last_now: the last time to check if timed task should be scheduled
Xixuan Wu40998892017-08-29 14:32:26 -070060 or not.
Xixuan Wu09962902018-12-11 10:49:27 -080061 now: the current time to check if timed task should be scheduled.
Xixuan Wu40998892017-08-29 14:32:26 -070062
63 Returns:
64 a boolean indicating whether there will be nightly tasks scheduled.
65 """
66 if last_now is not None and last_now.hour != now.hour:
67 return True
68
69 return False
70
71
Xixuan Wu40998892017-08-29 14:32:26 -070072def _should_schedule_new_build_task(last_now, now):
73 """Check whether weekly task should be scheduled.
74
75 A new_build task should be schduled when there're new builds between last
76 check and this check.
77
78 Args:
79 last_now: the last time to check if new_build task should be scheduled.
80 now: the current time to check if new_build task should be scheduled.
81
82 Returns:
83 a boolean indicating whether there will be new_build tasks scheduled.
84 """
85 if last_now is not None and last_now != now:
86 return True
87
88 return False
89
90
Xixuan Wuc6819012019-05-23 11:34:59 -070091class FakeBuildClient(object):
92 """Mock rest_client.BuildBucketBigqueryClient."""
93
Xinan Lin8b291982019-12-16 10:03:56 -080094 def __init__(self):
95 self.firmware_builds_called = 0
96
Xinan Lin71eeeb02020-03-10 17:37:12 -070097 def get_passed_builds(self, earliest, latest, event_type):
Xinan Linea1efcb2019-12-30 23:46:42 -080098 """Mock get_passed_builds."""
99 del earliest # unused
100 del latest # unused
Xinan Lin71eeeb02020-03-10 17:37:12 -0700101 del event_type #unused
Xixuan Wuc6819012019-05-23 11:34:59 -0700102 return [
103 build_lib.BuildInfo(
104 'link', None, '62', '9868.0.0', 'link-release'),
105 build_lib.BuildInfo(
106 'zako', None, '62', '9868.0.0', 'zako-release'),
107 build_lib.BuildInfo('samus-kernelnext', None, '62',
108 '9868.0.0', 'samus-kernelnext-release'),
109 build_lib.BuildInfo(
110 'reef', None, '62', '1234.0.0', 'reef-release'),
111 build_lib.BuildInfo(
112 'coral', 'santa', '62', '9868.0.0', 'coral-release'),
113 build_lib.BuildInfo(
114 'coral', 'astronaut', '62', '9868.0.0', 'coral-release'),
115 build_lib.BuildInfo(
116 'coral', 'lava', '62', '9868.0.0', 'coral-release'),
117 ]
118
Xinan Lin71eeeb02020-03-10 17:37:12 -0700119 def get_relaxed_passed_builds(self, earliest, latest, event_type):
Xinan Linea1efcb2019-12-30 23:46:42 -0800120 """Mock get_relaxed_pased_builds."""
121 del earliest # unused
122 del latest # unused
Xinan Lin71eeeb02020-03-10 17:37:12 -0700123 del event_type #unused
Xinan Linae7d6372019-09-12 14:42:10 -0700124 return [
125 build_lib.BuildInfo('grunt', None, '63', '9968.0.0', 'grunt-release'),
126 build_lib.BuildInfo('nami', None, '62', '9867.0.0', 'nami-release'),
127 build_lib.BuildInfo('nami', 'akali', '62', '9868.0.0', 'nami-release'),
128 build_lib.BuildInfo('nami', 'bard', '62', '9866.0.0', 'nami-release'),
129 ]
Xixuan Wuc6819012019-05-23 11:34:59 -0700130
Xinan Lin028f9582019-12-11 10:55:33 -0800131 def get_latest_passed_firmware_builds(self):
132 """Mock get_passed_firmware_builds."""
Xinan Lin8b291982019-12-16 10:03:56 -0800133 self.firmware_builds_called += 1
Xinan Lin028f9582019-12-11 10:55:33 -0800134 return [
135 ['cros', 'fake_board', ('gs://chromeos-image-archive/'
136 'fake_board-release/R30-6182.0.0-rc2/'
137 'fake_board')],
138 ['firmware', 'fake_board', ('gs://chromeos-image-archive/'
139 'firmware-fake_board-12345.67.'
140 'A-firmwarebranch/RFoo-1.0.0-b1e234567')],
Xinan Lin8b291982019-12-16 10:03:56 -0800141 ['firmware', 'zako', ('gs://chromeos-image-archive/'
142 'firmware-zako-12345.67.'
143 'A-firmwarebranch/RFoo-1.0.0-b1e234567')],
Xinan Lin028f9582019-12-11 10:55:33 -0800144 ]
145
Xixuan Wuc6819012019-05-23 11:34:59 -0700146
Xixuan Wu40998892017-08-29 14:32:26 -0700147class FakeAndroidBuildRestClient(object):
148 """Mock rest_client.AndroidBuildRestClient."""
149
150 def get_latest_build_id(self, branch, target):
151 """Mock rest_client.AndroidBuildRestClient.get_latest_build_id."""
152 del branch, target # unused
153 return '100'
154
155
156class FakeLabConfig(object):
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700157 """Mock config_reader.LabConfig."""
Xixuan Wu40998892017-08-29 14:32:26 -0700158
159 def get_android_board_list(self):
160 """Mock config_reader.LabConfig.get_android_board_list."""
161 return ('android-angler', 'android-bullhead')
162
Xixuan Wu6fb16272017-10-19 13:16:00 -0700163 def get_cros_board_list(self):
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700164 """Mock config_reader.LabConfig.get_cros_board_list."""
Xixuan Wua41efa22019-05-17 14:28:04 -0700165 return ('grunt', 'link', 'peppy', 'daisy', 'zako', 'samus-kernelnext',
Xinan Linae7d6372019-09-12 14:42:10 -0700166 'coral', 'reef', 'nami')
Xixuan Wu6fb16272017-10-19 13:16:00 -0700167
Xixuan Wu40998892017-08-29 14:32:26 -0700168 def get_firmware_ro_build_list(self, release_board):
169 """Mock config_reader.LabConfig.get_firmware_ro_build_list."""
170 del release_board # unused
171 return 'firmware1,firmware2'
172
C Shapiro7f24a002017-12-05 14:25:09 -0700173 def get_cros_model_map(self):
174 """Mock config_reader.LabConfig.get_cros_model_map."""
Xixuan Wua41efa22019-05-17 14:28:04 -0700175 return {
176 'coral': ['santa', 'astronaut'],
177 'reef': ['electro'],
Xinan Linae7d6372019-09-12 14:42:10 -0700178 'nami': ['akali', 'bard'],
Xixuan Wua41efa22019-05-17 14:28:04 -0700179 }
C Shapiro7f24a002017-12-05 14:25:09 -0700180
Xixuan Wu40998892017-08-29 14:32:26 -0700181
Xixuan Wu008ee832017-10-12 16:59:34 -0700182class TriggerReceiverBaseTestCase(unittest.TestCase):
Xixuan Wu40998892017-08-29 14:32:26 -0700183
184 def setUp(self):
185 self.testbed = testbed.Testbed()
186 self.testbed.activate()
187 self.addCleanup(self.testbed.deactivate)
188
189 self.testbed.init_datastore_v3_stub()
190 self.testbed.init_memcache_stub()
191 ndb.get_context().clear_cache()
192 self.testbed.init_taskqueue_stub(
193 root_path=os.path.join(os.path.dirname(__file__)))
194 self.taskqueue_stub = self.testbed.get_stub(
195 testbed.TASKQUEUE_SERVICE_NAME)
196
Xixuan Wuc6819012019-05-23 11:34:59 -0700197 mock_build_client = mock.patch('rest_client.BuildBucketBigqueryClient')
198 self._mock_build_client = mock_build_client.start()
199 self.addCleanup(mock_build_client.stop)
200
Xixuan Wu40998892017-08-29 14:32:26 -0700201 mock_android_client = mock.patch('rest_client.AndroidBuildRestClient')
202 self._mock_android_client = mock_android_client.start()
203 self.addCleanup(mock_android_client.stop)
204
Xixuan Wu40998892017-08-29 14:32:26 -0700205 mock_lab_config = mock.patch('config_reader.LabConfig')
206 self._mock_lab_config = mock_lab_config.start()
207 self.addCleanup(mock_lab_config.stop)
208
209 mock_utc_now = mock.patch('time_converter.utc_now')
210 self._mock_utc_now = mock_utc_now.start()
211 self.addCleanup(mock_utc_now.stop)
212
Xixuan Wuc6819012019-05-23 11:34:59 -0700213 self._mock_build_client.return_value = FakeBuildClient()
Xixuan Wu40998892017-08-29 14:32:26 -0700214 self._mock_android_client.return_value = FakeAndroidBuildRestClient()
Xixuan Wu40998892017-08-29 14:32:26 -0700215 self._mock_lab_config.return_value = FakeLabConfig()
216
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700217 board_family_patcher = mock.patch(
218 'build_lib.get_board_family_mapping_from_gs')
219 board_family_getter = board_family_patcher.start()
220 board_family_getter.return_value = {
221 'nyan': ['nyan', 'nyan_blaze', 'nyan_big'],
222 'ivybridge': ['link', 'link_freon']}
223 self.addCleanup(board_family_patcher.stop)
224
Xixuan Wu008ee832017-10-12 16:59:34 -0700225
226class TriggerReceiverFakeConfigTestCase(TriggerReceiverBaseTestCase):
227
228 _TEST_PST_HOUR = 20
229 _TEST_PST_DAY = 4 # Friday
230 _TEST_EVENT_PST_HOUR = 13
231
232 _FAKE_NIGHTLY_TASK_NAME = 'fake_nightly_task'
233 _FAKE_WEEKLY_TASK_NAME = 'fake_weekly_task'
234
235 def setUp(self):
236 super(TriggerReceiverFakeConfigTestCase, self).setUp()
237
238 self.fake_config = config_reader.ConfigReader(None)
239 self._add_nightly_tasks(self.fake_config)
240 self._add_weekly_tasks(self.fake_config)
241
242 self.fake_config_with_settings = config_reader.ConfigReader(None)
243 self._add_weekly_tasks(self.fake_config_with_settings)
244 self._add_weekly_params(self.fake_config_with_settings)
245
246 mock_config_reader = mock.patch('config_reader.ConfigReader')
247 self._mock_config_reader = mock_config_reader.start()
248 self.addCleanup(mock_config_reader.stop)
249
250 def _add_nightly_tasks(self, fake_config):
251 fake_config.add_section(self._FAKE_NIGHTLY_TASK_NAME)
252 fake_config.set(self._FAKE_NIGHTLY_TASK_NAME, 'suite', 'fake_suite')
253 fake_config.set(self._FAKE_NIGHTLY_TASK_NAME, 'run_on', 'nightly')
254 fake_config.set(self._FAKE_NIGHTLY_TASK_NAME, 'hour',
255 str(self._TEST_PST_HOUR))
256
257 def _add_weekly_tasks(self, fake_config):
258 fake_config.add_section(self._FAKE_WEEKLY_TASK_NAME)
259 fake_config.set(self._FAKE_WEEKLY_TASK_NAME, 'suite', 'fake_suite')
260 fake_config.set(self._FAKE_WEEKLY_TASK_NAME, 'run_on', 'weekly')
261 fake_config.set(self._FAKE_WEEKLY_TASK_NAME, 'day', str(self._TEST_PST_DAY))
262
263 def _add_weekly_params(self, fake_config):
Xixuan Wu51bb7102019-03-18 14:51:44 -0700264 weekly_section_name = task_config_reader.EVENT_CLASSES[
265 'weekly'].section_name()
Xixuan Wu008ee832017-10-12 16:59:34 -0700266 fake_config.add_section(weekly_section_name)
267 fake_config.set(weekly_section_name, 'hour', str(self._TEST_EVENT_PST_HOUR))
268
269 def testInitializeTriggerReceiverWithNightlyEvent(self):
270 """Test nightly event can be handled on right hour."""
271 # A task with hour=20 should be scheduled at 20:00 in PST everyday, which
272 # is 3:00/4:00 in UTC everyday.
273 self._mock_config_reader.return_value = self.fake_config
274 given_utc_hour = time_converter.convert_time_info(
275 time_converter.TimeInfo(None, self._TEST_PST_HOUR)).hour
276 utc_now = datetime.datetime(2017, 8, 6, given_utc_hour,
277 tzinfo=time_converter.UTC_TZ)
278 last_exec_client = datastore_client.LastExecutionRecordStore()
279 last_exec_client.set_last_execute_time(
280 'nightly', utc_now - datetime.timedelta(hours=1))
281 self._mock_utc_now.return_value = utc_now
282
283 suite_trigger = trigger_receiver.TriggerReceiver()
284 suite_trigger.cron()
285 self.assertTrue(suite_trigger.events['nightly'].should_handle)
286 self.assertEqual(len(suite_trigger.event_results['nightly']), 1)
287 self.assertEqual(suite_trigger.event_results['nightly'][0],
288 self._FAKE_NIGHTLY_TASK_NAME)
289
290 def testInitializeTriggerReceiverWithWeeklyEventWithoutEventHour(self):
291 """Test weekly event without event settings can be handled on right day."""
292 # A task with day=4 (Friday) and default event_hour (23) should be
293 # scheduled at Friday 23:00 in PST, which is Saturday 6:00 or 7:00 in UTC.
294 self._mock_config_reader.return_value = self.fake_config
295 given_utc_hour = time_converter.convert_time_info(
296 time_converter.TimeInfo(
297 self._TEST_PST_DAY,
Xixuan Wu51bb7102019-03-18 14:51:44 -0700298 task_config_reader.EVENT_CLASSES['weekly'].DEFAULT_PST_HOUR)).hour
Xixuan Wu008ee832017-10-12 16:59:34 -0700299 utc_now = datetime.datetime(2017, 10, 14, given_utc_hour,
300 tzinfo=time_converter.UTC_TZ)
301 last_exec_client = datastore_client.LastExecutionRecordStore()
302 last_exec_client.set_last_execute_time(
303 'weekly', utc_now - datetime.timedelta(days=1))
304 self._mock_utc_now.return_value = utc_now
305
306 suite_trigger = trigger_receiver.TriggerReceiver()
307 suite_trigger.cron()
308 self.assertTrue(suite_trigger.events['weekly'].should_handle)
309 self.assertEqual(len(suite_trigger.event_results['weekly']), 1)
310 self.assertEqual(suite_trigger.event_results['weekly'][0],
311 self._FAKE_WEEKLY_TASK_NAME)
312
313 def testInitializeTriggerReceiverWithWeeklyEventWithEventHour(self):
314 """Test weekly event with event settings can be handled on right day."""
315 # A task with day=4 (Friday) and event_hour=13 should be scheduled at
316 # Friday 13:00 in PST, which is Friday 20:00 or 21:00 in UTC.
317 self._mock_config_reader.return_value = self.fake_config_with_settings
318 given_utc_time_info = time_converter.convert_time_info(
319 time_converter.TimeInfo(self._TEST_PST_DAY, self._TEST_EVENT_PST_HOUR))
320
321 # Set the current time as a Friday 20:00 or 21:00 in UTC.
322 utc_now = datetime.datetime(2017, 10, 13, given_utc_time_info.hour,
323 tzinfo=time_converter.UTC_TZ)
324 last_exec_client = datastore_client.LastExecutionRecordStore()
325 last_exec_client.set_last_execute_time(
326 'weekly', utc_now - datetime.timedelta(days=1))
327 self._mock_utc_now.return_value = utc_now
328
329 suite_trigger = trigger_receiver.TriggerReceiver()
330 suite_trigger.cron()
331 self.assertTrue(suite_trigger.events['weekly'].should_handle)
332 self.assertEqual(len(suite_trigger.event_results['weekly']), 1)
333 self.assertEqual(suite_trigger.event_results['weekly'][0],
334 self._FAKE_WEEKLY_TASK_NAME)
335
336
Craig Bergstrom58263d32018-04-26 14:11:35 -0600337class TriggerReceiverFakeBuildTestCase(TriggerReceiverBaseTestCase):
338 """Test the new_build functionality."""
339
Craig Bergstrom58263d32018-04-26 14:11:35 -0600340 def setUp(self):
341 """Set up for a test."""
342 super(TriggerReceiverFakeBuildTestCase, self).setUp()
343
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700344 self._prepare()
345
346 def _prepare(self):
Craig Bergstrom58263d32018-04-26 14:11:35 -0600347 self.fake_config = config_reader.ConfigReader(None)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600348 mock_config_reader = mock.patch('config_reader.ConfigReader')
349 self._mock_config_reader = mock_config_reader.start()
350 self.addCleanup(mock_config_reader.stop)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600351
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700352 # Set last execution time for new_build events.
353 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600354 last_exec_client = datastore_client.LastExecutionRecordStore()
355 last_exec_client.set_last_execute_time(
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700356 'new_build', utc_now - datetime.timedelta(hours=1))
Craig Bergstrom58263d32018-04-26 14:11:35 -0600357 self._mock_utc_now.return_value = utc_now
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700358
359 def testNewBuildForHWTestSanityRequired(self):
360 """Test the new_build functionality."""
361 # Construct a fake config with only_hwtest_sanity_required.
362 fsnbt_name = 'FakeStrictNewBuildTask'
363 self.fake_config.add_section(fsnbt_name)
364 self.fake_config.set(fsnbt_name, 'run_on', 'new_build')
365 self.fake_config.set(fsnbt_name, 'suite', 'fake_suite_base')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700366 self.fake_config.set(fsnbt_name, 'boards', 'link, zako, grunt')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700367 frnbt_name = 'FakeRelaxedNewBuildTask'
368 self.fake_config.add_section(frnbt_name)
369 self.fake_config.set(frnbt_name, 'run_on', 'new_build')
370 self.fake_config.set(frnbt_name, 'suite', 'fake_suite_relaxed')
371 self.fake_config.set(frnbt_name, 'only_hwtest_sanity_required', 'True')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700372 self.fake_config.set(frnbt_name, 'boards', 'link, zako, grunt')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700373
374 self._mock_config_reader.return_value = self.fake_config
Craig Bergstrom58263d32018-04-26 14:11:35 -0600375
376 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600377 suite_trigger = trigger_receiver.TriggerReceiver()
378 suite_trigger.cron()
379
380 # Validate that the expected tests got kicked off.
Craig Bergstrom58263d32018-04-26 14:11:35 -0600381 self.assertEqual(len(suite_trigger.event_results), 1)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600382 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000383 # 2 for strict passed builds, 3 for relaxed builds.
384 self.assertEqual(len(tasks), 5)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600385
386 # The number of builds that matched the base (success) Task.
387 count_base = 0
388 # The number of builds that matched the relaxed Task.
389 count_relaxed = 0
390 for task in tasks:
391 if 'fake_suite_base' in task.payload:
392 # Make sure it matched the expected build only.
Craig Bergstrom58263d32018-04-26 14:11:35 -0600393 self.assertNotIn('grunt-release', task.payload)
394 count_base += 1
395
396 if 'fake_suite_relaxed' in task.payload:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600397 count_relaxed += 1
398
399 # Make each case matched precisely one event.
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000400 self.assertEqual(2, count_base)
401 self.assertEqual(3, count_relaxed)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600402
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700403 def testNewBuildWithExistingBoardFamilies(self):
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700404 """Test the new_build suite with an existing board family."""
405 link_suite = 'FakeLinkNewBuildTask'
406 self.fake_config.add_section(link_suite)
407 self.fake_config.set(link_suite, 'run_on', 'new_build')
408 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700409 self.fake_config.set(link_suite, 'board_families', 'ivybridge')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700410 self._mock_config_reader.return_value = self.fake_config
411
412 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
413 suite_trigger = trigger_receiver.TriggerReceiver()
414 suite_trigger.cron()
415
416 self.assertEqual(len(suite_trigger.event_results), 1)
417 self.assertEqual(suite_trigger.event_results['new_build'],
418 [link_suite])
419 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
420 self.assertEqual(len(tasks), 1)
421 self.assertIn('link-release', tasks[0].payload)
422
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700423 def testNewBuildWithExistingBoardFamiliesAndBoards(self):
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700424 """Test the new_build suite with an existing board family."""
425 link_suite = 'FakeLinkNewBuildTask'
426 self.fake_config.add_section(link_suite)
427 self.fake_config.set(link_suite, 'run_on', 'new_build')
428 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700429 self.fake_config.set(link_suite, 'board_families', 'ivybridge')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700430 self.fake_config.set(link_suite, 'boards', 'asuka, paine, banon')
431 self._mock_config_reader.return_value = self.fake_config
432
433 suite_trigger = trigger_receiver.TriggerReceiver()
434 suite_trigger.cron()
435
436 self.assertEqual(len(suite_trigger.event_results), 1)
437 self.assertEqual(suite_trigger.event_results['new_build'],
438 [link_suite])
439 boards = suite_trigger.events['new_build'].task_list[0].boards
440 self.assertIn('asuka', boards)
441 self.assertIn('link', boards)
442
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700443 def testNewBuildWithNonExistingBoardFamilies(self):
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700444 """Test the new_build suite with an non-existing board family."""
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700445 nyan_suite = 'FakeNonExistBoardFamiliesNewBuildTask'
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700446 self.fake_config.add_section(nyan_suite)
447 self.fake_config.set(nyan_suite, 'run_on', 'new_build')
448 self.fake_config.set(nyan_suite, 'suite', 'fake_suite_base')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700449 self.fake_config.set(nyan_suite, 'board_families', 'nyan')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700450 self._mock_config_reader.return_value = self.fake_config
451
452 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
453 suite_trigger = trigger_receiver.TriggerReceiver()
454 suite_trigger.cron()
455
456 self.assertEqual(len(suite_trigger.event_results), 1)
457 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
458 self.assertEqual(len(tasks), 0)
459
460 def testNewBuildWithNonSpecifiedBoardFamily(self):
461 """Test the new_build suite with an non-specified board family."""
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700462 normal_suite = 'FakeBoardFamiliesNewBuildTask'
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700463 self.fake_config.add_section(normal_suite)
464 self.fake_config.set(normal_suite, 'run_on', 'new_build')
465 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700466 self.fake_config.set(normal_suite, 'boards', 'link, zako')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700467 self._mock_config_reader.return_value = self.fake_config
468
469 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
470 suite_trigger = trigger_receiver.TriggerReceiver()
471 suite_trigger.cron()
472
473 self.assertEqual(len(suite_trigger.event_results), 1)
474 self.assertEqual(suite_trigger.event_results['new_build'],
475 [normal_suite])
476 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000477 self.assertEqual(len(tasks), 2)
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700478
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700479 def testNewBuildExcludingExistingBoardFamilies(self):
480 """Test the new_build suite excluding an existing board family."""
481 link_suite = 'FakeLinkNewBuildTask'
482 self.fake_config.add_section(link_suite)
483 self.fake_config.set(link_suite, 'run_on', 'new_build')
484 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
485 self.fake_config.set(link_suite, 'exclude_board_families', 'ivybridge')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700486 self.fake_config.set(link_suite, 'boards', 'link, zako')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700487 self._mock_config_reader.return_value = self.fake_config
488
489 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
490 suite_trigger = trigger_receiver.TriggerReceiver()
491 suite_trigger.cron()
492
493 self.assertEqual(len(suite_trigger.event_results), 1)
494 self.assertEqual(suite_trigger.event_results['new_build'],
495 [link_suite])
496 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
497 self.assertEqual(len(tasks), 1)
498 self.assertNotIn('link-release', tasks[0].payload)
499 self.assertIn('zako-release', tasks[0].payload)
500
501 def testNewBuildExcludingExistingBoardFamiliesAndBoards(self):
502 """Test the new_build suite with an existing board family."""
503 link_suite = 'FakeLinkNewBuildTask'
504 self.fake_config.add_section(link_suite)
505 self.fake_config.set(link_suite, 'run_on', 'new_build')
506 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
507 self.fake_config.set(link_suite, 'exclude_board_families', 'ivybridge')
Xixuan Wua41efa22019-05-17 14:28:04 -0700508 self.fake_config.set(link_suite, 'exclude_boards',
Xinan Lin09a628a2019-11-01 17:20:27 -0700509 'asuka, paine, banon, coral, reef, nami, samus-kernelnext')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700510 self._mock_config_reader.return_value = self.fake_config
511
512 suite_trigger = trigger_receiver.TriggerReceiver()
513 suite_trigger.cron()
514
515 self.assertEqual(len(suite_trigger.event_results), 1)
516 self.assertEqual(suite_trigger.event_results['new_build'],
517 [link_suite])
518 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
519 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
Xinan Lin09a628a2019-11-01 17:20:27 -0700520 self.assertEqual(len(tasks), 1)
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700521 self.assertNotIn('link-release', tasks[0].payload)
522 self.assertNotIn('asuka-release', tasks[0].payload)
523 self.assertIn('zako-release', tasks[0].payload)
524
525 def testNewBuildExcludingNonExistingBoardFamilies(self):
526 """Test the new_build suite excluding an non-existing board family."""
527 nyan_suite = 'FakeNonExistExcludeBoardFamiliesNewBuildTask'
528 self.fake_config.add_section(nyan_suite)
529 self.fake_config.set(nyan_suite, 'run_on', 'new_build')
530 self.fake_config.set(nyan_suite, 'suite', 'fake_suite_base')
531 self.fake_config.set(nyan_suite, 'exclude_board_families', 'nyan')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700532 self.fake_config.set(nyan_suite, 'boards', 'link, zako')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700533 self._mock_config_reader.return_value = self.fake_config
534
535 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
536 suite_trigger = trigger_receiver.TriggerReceiver()
537 suite_trigger.cron()
538
539 self.assertEqual(len(suite_trigger.event_results), 1)
540 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
541 self.assertEqual(len(tasks), 2)
542
543 def testNewBuildWithBoardExcludeBoardCollision(self):
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700544 """Test the case that the same board in boards and exclude_boards."""
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700545 normal_suite = 'FakeBoardExludingBoardCollisionNewBuildTask'
546 self.fake_config.add_section(normal_suite)
547 self.fake_config.set(normal_suite, 'run_on', 'new_build')
548 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
549 self.fake_config.set(normal_suite, 'boards', 'zako, asuka')
550 self.fake_config.set(normal_suite, 'exclude_boards', 'asuka')
551 self._mock_config_reader.return_value = self.fake_config
552
553 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
554 suite_trigger = trigger_receiver.TriggerReceiver()
555 suite_trigger.cron()
556
557 self.assertEqual(len(suite_trigger.event_results), 1)
558 self.assertEqual(suite_trigger.event_results['new_build'],
559 [normal_suite])
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700560 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
561 self.assertEqual(len(tasks), 1)
562 self.assertNotIn('asuka-release', tasks[0].payload)
563 self.assertIn('zako-release', tasks[0].payload)
564
Xixuan Wub4b2f412019-05-03 11:22:31 -0700565 def testNewBuildWithKernelnext(self):
566 """Test the case that suites run with board-kernelnext build."""
567 normal_suite = 'FakeKernelnextSuite'
568 self.fake_config.add_section(normal_suite)
569 self.fake_config.set(normal_suite, 'run_on', 'new_build')
570 self.fake_config.set(normal_suite, 'suite', 'fake-suite')
571 self.fake_config.set(normal_suite, 'pool', 'suites')
572 self.fake_config.set(normal_suite, 'boards', 'samus-kernelnext')
573 self._mock_config_reader.return_value = self.fake_config
574
Xixuan Wub4b2f412019-05-03 11:22:31 -0700575 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
576 suite_trigger = trigger_receiver.TriggerReceiver()
577 suite_trigger.cron()
578
579 self.assertEqual(len(suite_trigger.event_results), 1)
580 self.assertEqual(suite_trigger.event_results['new_build'],
581 [normal_suite])
582 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
583 self.assertEqual(len(tasks), 1)
584 # Board should be 'samus'.
585 self.assertIn('&board=samus&', tasks[0].payload)
586 # Build should be 'samus-kernelnext-release***'.
587 self.assertIn('cros_version=samus-kernelnext-release', tasks[0].payload)
588
Xixuan Wua41efa22019-05-17 14:28:04 -0700589 def testNewBuildWithModels(self):
590 """Test the new_build suite with an existing models entry."""
591 normal_suite = 'FakeModelsNewBuildTask'
592 self.fake_config.add_section(normal_suite)
593 self.fake_config.set(normal_suite, 'run_on', 'new_build')
594 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
595 self.fake_config.set(normal_suite, 'models', 'coral_lava, coral_santa')
596 self.fake_config.set(normal_suite, 'boards', 'coral')
597 self._mock_config_reader.return_value = self.fake_config
598
599 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
600 suite_trigger = trigger_receiver.TriggerReceiver()
601 suite_trigger.cron()
602
603 self.assertEqual(len(suite_trigger.event_results), 1)
604 self.assertEqual(suite_trigger.event_results['new_build'],
605 [normal_suite])
606 self.assertIn('new_build', suite_trigger.event_results)
607 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
608 self.assertEqual(len(tasks), 1)
609 self.assertNotIn('model=astronaut', tasks[0].payload)
610 self.assertIn('model=santa', tasks[0].payload)
611
Xinan Linae7d6372019-09-12 14:42:10 -0700612 def testNewBuildWithModelsForHWTestSanityRequired(self):
613 """Test the new_build suite with an existing models entry."""
614 normal_suite = 'FakeModelsNewBuildTask'
615 self.fake_config.add_section(normal_suite)
616 self.fake_config.set(normal_suite, 'run_on', 'new_build')
617 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
618 self.fake_config.set(normal_suite, 'models', 'nami_akali, nami_bard')
619 self.fake_config.set(normal_suite, 'boards', 'nami')
620 self.fake_config.set(normal_suite, 'only_hwtest_sanity_required', 'True')
621 self._mock_config_reader.return_value = self.fake_config
622
623 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
624 suite_trigger = trigger_receiver.TriggerReceiver()
625 suite_trigger.cron()
626
627 self.assertEqual(len(suite_trigger.event_results), 1)
628 self.assertEqual(suite_trigger.event_results['new_build'],
629 [normal_suite])
630 self.assertIn('new_build', suite_trigger.event_results)
631 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
632 self.assertEqual(len(tasks), 2)
633 self.assertIn('model=akali', tasks[0].payload)
634 self.assertIn('9868.0.0', tasks[0].payload)
635 self.assertIn('model=bard', tasks[1].payload)
636 self.assertIn('9867.0.0', tasks[1].payload)
637
Xixuan Wua41efa22019-05-17 14:28:04 -0700638 def testNewBuildWithExcludeModels(self):
639 """Test the new_build suite with an existing exclude_models entry."""
640 normal_suite = 'FakeExludingModelsNewBuildTask'
641 self.fake_config.add_section(normal_suite)
642 self.fake_config.set(normal_suite, 'run_on', 'new_build')
643 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
644 self.fake_config.set(normal_suite, 'exclude_models',
645 'coral_lava, coral_santa')
646 self.fake_config.set(normal_suite, 'boards', 'coral')
647 self._mock_config_reader.return_value = self.fake_config
648
649 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
650 suite_trigger = trigger_receiver.TriggerReceiver()
651 suite_trigger.cron()
652
653 self.assertEqual(len(suite_trigger.event_results), 1)
654 self.assertEqual(suite_trigger.event_results['new_build'],
655 [normal_suite])
656 self.assertIn('new_build', suite_trigger.event_results)
657 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
658 self.assertEqual(len(tasks), 1)
659 self.assertNotIn('model=santa', tasks[0].payload)
660 self.assertIn('model=astronaut', tasks[0].payload)
661
662 def testNewBuildWithModelsExcludeModels(self):
663 """Test the new_build suite with models and exclude_models entry."""
664 normal_suite = 'FakeModelsExcludeModelsNewBuildTask'
665 self.fake_config.add_section(normal_suite)
666 self.fake_config.set(normal_suite, 'run_on', 'new_build')
667 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
668 self.fake_config.set(normal_suite, 'models', 'coral_santa, coral_astronaut')
669 self.fake_config.set(normal_suite, 'exclude_models',
670 'coral_lava, coral_santa')
671 self.fake_config.set(normal_suite, 'boards', 'coral')
672 self._mock_config_reader.return_value = self.fake_config
673
674 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
675 suite_trigger = trigger_receiver.TriggerReceiver()
676 suite_trigger.cron()
677
678 self.assertEqual(len(suite_trigger.event_results), 1)
679 self.assertEqual(suite_trigger.event_results['new_build'],
680 [normal_suite])
681 self.assertIn('new_build', suite_trigger.event_results)
682 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
683 self.assertEqual(len(tasks), 1)
684 self.assertNotIn('model=santa', tasks[0].payload)
685 self.assertIn('model=astronaut', tasks[0].payload)
686
687 def testNewBuildWithNoModelListAndModelBuild(self):
688 """Test the new_build suite with models and empty board_model mapping."""
689 normal_suite = 'FakeModelsExcludeModelsNewBuildTask'
690 self.fake_config.add_section(normal_suite)
691 self.fake_config.set(normal_suite, 'run_on', 'new_build')
692 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
693 self.fake_config.set(normal_suite, 'boards', 'coral')
694 self._mock_config_reader.return_value = self.fake_config
695
696 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
697 suite_trigger = trigger_receiver.TriggerReceiver()
698 suite_trigger.cron()
699
700 self.assertIn('new_build', suite_trigger.event_results)
701 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
702 # Verify that coral-release is not kicked off on model lava as lava is not
703 # listed in cros_model_map.
704 self.assertEqual(len(tasks), 2)
705 self.assertNotIn('lava', tasks[0].payload)
706 self.assertNotIn('lava', tasks[1].payload)
707
708 def testNewBuildWithNoModelListAndNoModelBuild(self):
709 """Test the new_build suite with models and empty board_model mapping."""
710 normal_suite = 'FakeModelsExcludeModelsNewBuildTask'
711 self.fake_config.add_section(normal_suite)
712 self.fake_config.set(normal_suite, 'run_on', 'new_build')
713 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
714 self.fake_config.set(normal_suite, 'boards', 'reef')
715 self._mock_config_reader.return_value = self.fake_config
716
717 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
718 suite_trigger = trigger_receiver.TriggerReceiver()
719 suite_trigger.cron()
720
721 self.assertIn('new_build', suite_trigger.event_results)
722 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
723 # Verify that reef-release is kicked off on reef models.
724 self.assertEqual(len(tasks), 1)
725 self.assertIn('model=electro', tasks[0].payload)
726
C Shapiro09108252019-08-01 14:52:52 -0500727 def testNewBuildWithAnyModel(self):
728 """Test the new_build suite with any_model option set."""
729 normal_suite = 'FakeAnyModelNewBuildTask'
730 self.fake_config.add_section(normal_suite)
731 self.fake_config.set(normal_suite, 'run_on', 'new_build')
732 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
733 self.fake_config.set(normal_suite, 'any_model', 'True')
734 self.fake_config.set(normal_suite, 'boards', 'coral')
735 self._mock_config_reader.return_value = self.fake_config
736
737 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
738 suite_trigger = trigger_receiver.TriggerReceiver()
739 suite_trigger.cron()
740
741 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
742 self.assertEqual(len(tasks), 1)
743 self.assertIn('model=None', tasks[0].payload)
744
Xinan Lin8b291982019-12-16 10:03:56 -0800745 def testNewBuildWithFirmwareTask(self):
746 """Test the new_build suite with firmware option set."""
747 # Construct a fake config with firmware build.
748 fsnbt_name = 'FakeStrictNewBuildTask'
749 self.fake_config.add_section(fsnbt_name)
750 self.fake_config.set(fsnbt_name, 'run_on', 'new_build')
751 self.fake_config.set(fsnbt_name, 'suite', 'fake_suite_base')
752 self.fake_config.set(fsnbt_name, 'boards', 'zako')
753 self.fake_config.set(fsnbt_name, 'firmware_ro_build_spec', 'firmware')
754 self.fake_config.set(fsnbt_name, 'test_source', 'cros')
755 self._mock_config_reader.return_value = self.fake_config
756
757 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
758 suite_trigger = trigger_receiver.TriggerReceiver()
759 some_event = suite_trigger.events['new_build']
760 suite_trigger.cron()
761
762 # The firmware query has run for once.
763 self.assertEqual(suite_trigger._build_client.firmware_builds_called, 1)
764 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
765 self.assertEqual(len(tasks), 1)
766 self.assertIn('firmware-zako-12345.67', tasks[0].payload)
767
768
769 def testNewBuildWithoutFirmwareTask(self):
770 """Test the event skips fetch the firmware builds."""
771 # Construct a fake config without firmware build.
772 fsnbt_name = 'FakeStrictNewBuildTask'
773 self.fake_config.add_section(fsnbt_name)
774 self.fake_config.set(fsnbt_name, 'run_on', 'new_build')
775 self.fake_config.set(fsnbt_name, 'suite', 'fake_suite_base')
776 self.fake_config.set(fsnbt_name, 'boards', 'zako')
777 self._mock_config_reader.return_value = self.fake_config
778
779 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
780 suite_trigger = trigger_receiver.TriggerReceiver()
781 suite_trigger.cron()
782
783 # The firmware query was not called.
784 self.assertEqual(suite_trigger._build_client.firmware_builds_called, 0)
785 # Validate that the expected tests got kicked off.
786 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
787 self.assertEqual(len(tasks), 1)
788
Craig Bergstrom58263d32018-04-26 14:11:35 -0600789
Xixuan Wu008ee832017-10-12 16:59:34 -0700790class TriggerReceiverRealConfigTestCase(TriggerReceiverBaseTestCase):
791
792 def setUp(self):
793 super(TriggerReceiverRealConfigTestCase, self).setUp()
794 mock_config_reader = mock.patch('config_reader.ConfigReader')
795 self._mock_config_reader = mock_config_reader.start()
796 self.addCleanup(mock_config_reader.stop)
797 self._mock_config_reader.return_value = _SUITE_CONFIG_READER
798
799 def _get_ground_truth_task_list_from_config(self):
800 """Get the ground truth of to-be-scheduled task list from config file."""
801 self._mock_utc_now.return_value = datetime.datetime.now(
802 time_converter.UTC_TZ)
Xixuan Wu51bb7102019-03-18 14:51:44 -0700803 task_config = task_config_reader.TaskConfig(_SUITE_CONFIG_READER)
Xixuan Wu008ee832017-10-12 16:59:34 -0700804 tasks = {}
Xixuan Wu51bb7102019-03-18 14:51:44 -0700805 for keyword, klass in task_config_reader.EVENT_CLASSES.iteritems():
Xixuan Wu008ee832017-10-12 16:59:34 -0700806 new_event = klass(
807 task_config.get_event_setting(klass.section_name()), None)
808 new_event.set_task_list(
809 task_config.get_tasks_by_keyword(klass.KEYWORD)['tasks'])
810 tasks[keyword] = new_event.task_list
811
812 return tasks
813
Xixuan Wu40998892017-08-29 14:32:26 -0700814 def testCronWithoutLastExec(self):
815 """Test the first round of cron can be successfully executed."""
816 self._mock_utc_now.return_value = datetime.datetime.now(
817 time_converter.UTC_TZ)
818 suite_trigger = trigger_receiver.TriggerReceiver()
819 suite_trigger.cron()
820 self.assertFalse(suite_trigger.events['nightly'].should_handle)
821 self.assertFalse(suite_trigger.events['weekly'].should_handle)
822 self.assertFalse(suite_trigger.events['new_build'].should_handle)
823
824 self.assertEqual(suite_trigger.event_results, {})
825
826 def testCronTriggerNightly(self):
827 """Test nightly event is read with available nightly last_exec_time."""
828 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
829 last_exec_client = datastore_client.LastExecutionRecordStore()
830 last_exec_client.set_last_execute_time(
831 'nightly', utc_now - datetime.timedelta(hours=1))
832 self._mock_utc_now.return_value = utc_now
833 suite_trigger = trigger_receiver.TriggerReceiver()
834 self.assertTrue(suite_trigger.events['nightly'].should_handle)
835 self.assertFalse(suite_trigger.events['weekly'].should_handle)
836 self.assertFalse(suite_trigger.events['new_build'].should_handle)
837
Xixuan Wu33179672017-09-12 11:44:04 -0700838 def testCronTriggerNightlyOutdated(self):
839 """Test nightly event is read with available nightly last_exec_time."""
840 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
841 last_exec_client = datastore_client.LastExecutionRecordStore()
842 last_exec_client.set_last_execute_time(
843 'nightly', utc_now - datetime.timedelta(days=3))
844 self._mock_utc_now.return_value = utc_now
845 suite_trigger = trigger_receiver.TriggerReceiver()
846 self.assertFalse(suite_trigger.events['nightly'].should_handle)
847
848 def testCronTriggerWeeklyOutdated(self):
849 """Test weekly event is read with available weekly last_exec_time."""
850 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
851 last_exec_client = datastore_client.LastExecutionRecordStore()
852 last_exec_client.set_last_execute_time(
853 'weekly', utc_now - datetime.timedelta(days=8))
854 self._mock_utc_now.return_value = utc_now
855 suite_trigger = trigger_receiver.TriggerReceiver()
856 self.assertFalse(suite_trigger.events['weekly'].should_handle)
857
Xixuan Wu40998892017-08-29 14:32:26 -0700858 def testCronForWeeks(self):
859 """Ensure cron job can be successfully scheduled for several weeks."""
Xixuan Wu008ee832017-10-12 16:59:34 -0700860 all_tasks = self._get_ground_truth_task_list_from_config()
Xixuan Wu40998892017-08-29 14:32:26 -0700861 last_now = None
862
863 for now in now_generator(datetime.datetime.now(time_converter.UTC_TZ)):
864 self._mock_utc_now.return_value = now
865 suite_trigger = trigger_receiver.TriggerReceiver()
Xixuan Wu5451a662017-10-17 10:57:40 -0700866 with mock.patch('task.Task.schedule', return_value=True):
867 suite_trigger.cron()
Xixuan Wu40998892017-08-29 14:32:26 -0700868
Xixuan Wu40998892017-08-29 14:32:26 -0700869 should_scheduled_nightly_tasks = [
Xixuan Wu09962902018-12-11 10:49:27 -0800870 t.name for t in all_tasks['nightly'] if t.hour == now.hour]
Xixuan Wu008ee832017-10-12 16:59:34 -0700871
Xixuan Wu09962902018-12-11 10:49:27 -0800872 if (_should_schedule_timed_task(last_now, now) and
Xixuan Wu40998892017-08-29 14:32:26 -0700873 should_scheduled_nightly_tasks):
874 self.assertEqual(suite_trigger.event_results['nightly'],
875 should_scheduled_nightly_tasks)
876 else:
877 self.assertNotIn('nightly', suite_trigger.event_results.keys())
878
879 # Verify weekly tasks
880 should_scheduled_weekly_tasks = [
881 t.name for t in all_tasks['weekly']
Xixuan Wu09962902018-12-11 10:49:27 -0800882 if now.weekday() == t.day and now.hour == t.hour]
883 if (_should_schedule_timed_task(last_now, now) and
Xixuan Wu40998892017-08-29 14:32:26 -0700884 should_scheduled_weekly_tasks):
885 self.assertEqual(suite_trigger.event_results['weekly'],
886 should_scheduled_weekly_tasks)
887 else:
888 self.assertNotIn('weekly', suite_trigger.event_results.keys())
889
890 # Verify new_build tasks
891 should_scheduled_new_build_tasks = [
892 t.name for t in all_tasks['new_build']]
893 if (_should_schedule_new_build_task(last_now, now) and
894 should_scheduled_new_build_tasks):
895 self.assertEqual(suite_trigger.event_results['new_build'],
896 should_scheduled_new_build_tasks)
897 else:
898 self.assertNotIn('new_build', suite_trigger.event_results.keys())
899
900 last_now = now
901
902
903if __name__ == '__main__':
904 unittest.main()