blob: db3c8aabd380621ffef49719b24acd1623ca4c04 [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
Xinan Lincfa41012020-04-08 13:22:03 -07008import constants
Xixuan Wu40998892017-08-29 14:32:26 -07009import datetime
10import os
11import unittest
12
Xixuan Wuc6819012019-05-23 11:34:59 -070013import build_lib
Xixuan Wu40998892017-08-29 14:32:26 -070014import config_reader
15import datastore_client
16import file_getter
17import mock
Xixuan Wu51bb7102019-03-18 14:51:44 -070018import task_config_reader
Craig Bergstrom58263d32018-04-26 14:11:35 -060019import task_executor
Xixuan Wu40998892017-08-29 14:32:26 -070020import time_converter
21import trigger_receiver
22
Craig Bergstrom58263d32018-04-26 14:11:35 -060023from google.appengine.api import taskqueue
Xixuan Wu40998892017-08-29 14:32:26 -070024from google.appengine.ext import ndb
25from google.appengine.ext import testbed
26
27# Ensure that SUITE_SCHEDULER_CONFIG_FILE is read only once.
28_SUITE_CONFIG_READER = config_reader.ConfigReader(
Xixuan Wu26d06e02017-09-20 14:50:28 -070029 file_getter.TEST_SUITE_SCHEDULER_CONFIG_FILE)
Xixuan Wu40998892017-08-29 14:32:26 -070030
31
32def now_generator(start_time, interval_min=30, last_days=7):
33 """A datetime.datetime.now generator.
34
35 The generator will generate 'now' from start_time till start_time+last_days
36 for every interval_min.
37
38 Args:
39 start_time: A datetime.datetime object representing the initial value of
40 the 'now'.
41 interval_min: The interval minutes between current 'now' and next 'now.
42 last_days: Representing how many days this generator will last.
43
44 Yields:
45 a datetime.datetime object to mock the current time.
46 """
47 cur_time = start_time
48 end_time = start_time + datetime.timedelta(days=last_days)
49 while cur_time < end_time:
50 yield cur_time
51 cur_time += datetime.timedelta(minutes=interval_min)
52
53
Xixuan Wu09962902018-12-11 10:49:27 -080054def _should_schedule_timed_task(last_now, now):
55 """Check whether timed (weekly/nightly) task should be scheduled.
Xixuan Wu40998892017-08-29 14:32:26 -070056
Xixuan Wu09962902018-12-11 10:49:27 -080057 A timed task should be schduled when next hour is coming.
Xixuan Wu40998892017-08-29 14:32:26 -070058
59 Args:
Xixuan Wu09962902018-12-11 10:49:27 -080060 last_now: the last time to check if timed task should be scheduled
Xixuan Wu40998892017-08-29 14:32:26 -070061 or not.
Xixuan Wu09962902018-12-11 10:49:27 -080062 now: the current time to check if timed task should be scheduled.
Xixuan Wu40998892017-08-29 14:32:26 -070063
64 Returns:
65 a boolean indicating whether there will be nightly tasks scheduled.
66 """
67 if last_now is not None and last_now.hour != now.hour:
68 return True
69
70 return False
71
72
Xixuan Wu40998892017-08-29 14:32:26 -070073def _should_schedule_new_build_task(last_now, now):
74 """Check whether weekly task should be scheduled.
75
76 A new_build task should be schduled when there're new builds between last
77 check and this check.
78
79 Args:
80 last_now: the last time to check if new_build task should be scheduled.
81 now: the current time to check if new_build task should be scheduled.
82
83 Returns:
84 a boolean indicating whether there will be new_build tasks scheduled.
85 """
86 if last_now is not None and last_now != now:
87 return True
88
89 return False
90
91
Xinan Lincfa41012020-04-08 13:22:03 -070092def _get_current_min(now):
93 """A helper to truncate the given time to minute."""
94 return datetime.datetime(
95 now.year,
96 now.month,
97 now.day,
98 now.hour,
99 now.minute,
100 tzinfo=time_converter.UTC_TZ)
101
102
Xixuan Wuc6819012019-05-23 11:34:59 -0700103class FakeBuildClient(object):
104 """Mock rest_client.BuildBucketBigqueryClient."""
105
Xinan Lin8b291982019-12-16 10:03:56 -0800106 def __init__(self):
107 self.firmware_builds_called = 0
108
Xinan Lin71eeeb02020-03-10 17:37:12 -0700109 def get_passed_builds(self, earliest, latest, event_type):
Xinan Linea1efcb2019-12-30 23:46:42 -0800110 """Mock get_passed_builds."""
111 del earliest # unused
112 del latest # unused
Xinan Lin71eeeb02020-03-10 17:37:12 -0700113 del event_type #unused
Xixuan Wuc6819012019-05-23 11:34:59 -0700114 return [
115 build_lib.BuildInfo(
116 'link', None, '62', '9868.0.0', 'link-release'),
117 build_lib.BuildInfo(
118 'zako', None, '62', '9868.0.0', 'zako-release'),
119 build_lib.BuildInfo('samus-kernelnext', None, '62',
120 '9868.0.0', 'samus-kernelnext-release'),
121 build_lib.BuildInfo(
122 'reef', None, '62', '1234.0.0', 'reef-release'),
123 build_lib.BuildInfo(
124 'coral', 'santa', '62', '9868.0.0', 'coral-release'),
125 build_lib.BuildInfo(
126 'coral', 'astronaut', '62', '9868.0.0', 'coral-release'),
127 build_lib.BuildInfo(
128 'coral', 'lava', '62', '9868.0.0', 'coral-release'),
129 ]
130
Xinan Lin71eeeb02020-03-10 17:37:12 -0700131 def get_relaxed_passed_builds(self, earliest, latest, event_type):
Xinan Linea1efcb2019-12-30 23:46:42 -0800132 """Mock get_relaxed_pased_builds."""
133 del earliest # unused
134 del latest # unused
Xinan Lin71eeeb02020-03-10 17:37:12 -0700135 del event_type #unused
Xinan Linae7d6372019-09-12 14:42:10 -0700136 return [
137 build_lib.BuildInfo('grunt', None, '63', '9968.0.0', 'grunt-release'),
138 build_lib.BuildInfo('nami', None, '62', '9867.0.0', 'nami-release'),
139 build_lib.BuildInfo('nami', 'akali', '62', '9868.0.0', 'nami-release'),
140 build_lib.BuildInfo('nami', 'bard', '62', '9866.0.0', 'nami-release'),
141 ]
Xixuan Wuc6819012019-05-23 11:34:59 -0700142
Xinan Lin028f9582019-12-11 10:55:33 -0800143 def get_latest_passed_firmware_builds(self):
144 """Mock get_passed_firmware_builds."""
Xinan Lin8b291982019-12-16 10:03:56 -0800145 self.firmware_builds_called += 1
Xinan Lin028f9582019-12-11 10:55:33 -0800146 return [
147 ['cros', 'fake_board', ('gs://chromeos-image-archive/'
148 'fake_board-release/R30-6182.0.0-rc2/'
149 'fake_board')],
150 ['firmware', 'fake_board', ('gs://chromeos-image-archive/'
151 'firmware-fake_board-12345.67.'
152 'A-firmwarebranch/RFoo-1.0.0-b1e234567')],
Xinan Lin8b291982019-12-16 10:03:56 -0800153 ['firmware', 'zako', ('gs://chromeos-image-archive/'
154 'firmware-zako-12345.67.'
155 'A-firmwarebranch/RFoo-1.0.0-b1e234567')],
Xinan Lin028f9582019-12-11 10:55:33 -0800156 ]
157
Xixuan Wuc6819012019-05-23 11:34:59 -0700158
Xixuan Wu40998892017-08-29 14:32:26 -0700159class FakeAndroidBuildRestClient(object):
160 """Mock rest_client.AndroidBuildRestClient."""
161
162 def get_latest_build_id(self, branch, target):
163 """Mock rest_client.AndroidBuildRestClient.get_latest_build_id."""
164 del branch, target # unused
165 return '100'
166
167
168class FakeLabConfig(object):
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700169 """Mock config_reader.LabConfig."""
Xixuan Wu40998892017-08-29 14:32:26 -0700170
171 def get_android_board_list(self):
172 """Mock config_reader.LabConfig.get_android_board_list."""
173 return ('android-angler', 'android-bullhead')
174
Xixuan Wu6fb16272017-10-19 13:16:00 -0700175 def get_cros_board_list(self):
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700176 """Mock config_reader.LabConfig.get_cros_board_list."""
Xixuan Wua41efa22019-05-17 14:28:04 -0700177 return ('grunt', 'link', 'peppy', 'daisy', 'zako', 'samus-kernelnext',
Xinan Linae7d6372019-09-12 14:42:10 -0700178 'coral', 'reef', 'nami')
Xixuan Wu6fb16272017-10-19 13:16:00 -0700179
Xixuan Wu40998892017-08-29 14:32:26 -0700180 def get_firmware_ro_build_list(self, release_board):
181 """Mock config_reader.LabConfig.get_firmware_ro_build_list."""
182 del release_board # unused
183 return 'firmware1,firmware2'
184
C Shapiro7f24a002017-12-05 14:25:09 -0700185 def get_cros_model_map(self):
186 """Mock config_reader.LabConfig.get_cros_model_map."""
Xixuan Wua41efa22019-05-17 14:28:04 -0700187 return {
188 'coral': ['santa', 'astronaut'],
189 'reef': ['electro'],
Xinan Linae7d6372019-09-12 14:42:10 -0700190 'nami': ['akali', 'bard'],
Xixuan Wua41efa22019-05-17 14:28:04 -0700191 }
C Shapiro7f24a002017-12-05 14:25:09 -0700192
Xixuan Wu40998892017-08-29 14:32:26 -0700193
Xixuan Wu008ee832017-10-12 16:59:34 -0700194class TriggerReceiverBaseTestCase(unittest.TestCase):
Xixuan Wu40998892017-08-29 14:32:26 -0700195
196 def setUp(self):
197 self.testbed = testbed.Testbed()
198 self.testbed.activate()
199 self.addCleanup(self.testbed.deactivate)
200
201 self.testbed.init_datastore_v3_stub()
202 self.testbed.init_memcache_stub()
203 ndb.get_context().clear_cache()
204 self.testbed.init_taskqueue_stub(
205 root_path=os.path.join(os.path.dirname(__file__)))
206 self.taskqueue_stub = self.testbed.get_stub(
207 testbed.TASKQUEUE_SERVICE_NAME)
208
Xixuan Wuc6819012019-05-23 11:34:59 -0700209 mock_build_client = mock.patch('rest_client.BuildBucketBigqueryClient')
210 self._mock_build_client = mock_build_client.start()
211 self.addCleanup(mock_build_client.stop)
212
Xixuan Wu40998892017-08-29 14:32:26 -0700213 mock_android_client = mock.patch('rest_client.AndroidBuildRestClient')
214 self._mock_android_client = mock_android_client.start()
215 self.addCleanup(mock_android_client.stop)
216
Xixuan Wu40998892017-08-29 14:32:26 -0700217 mock_lab_config = mock.patch('config_reader.LabConfig')
218 self._mock_lab_config = mock_lab_config.start()
219 self.addCleanup(mock_lab_config.stop)
220
221 mock_utc_now = mock.patch('time_converter.utc_now')
222 self._mock_utc_now = mock_utc_now.start()
223 self.addCleanup(mock_utc_now.stop)
224
Xixuan Wuc6819012019-05-23 11:34:59 -0700225 self._mock_build_client.return_value = FakeBuildClient()
Xixuan Wu40998892017-08-29 14:32:26 -0700226 self._mock_android_client.return_value = FakeAndroidBuildRestClient()
Xixuan Wu40998892017-08-29 14:32:26 -0700227 self._mock_lab_config.return_value = FakeLabConfig()
228
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700229 board_family_patcher = mock.patch(
230 'build_lib.get_board_family_mapping_from_gs')
231 board_family_getter = board_family_patcher.start()
232 board_family_getter.return_value = {
233 'nyan': ['nyan', 'nyan_blaze', 'nyan_big'],
234 'ivybridge': ['link', 'link_freon']}
235 self.addCleanup(board_family_patcher.stop)
236
Xixuan Wu008ee832017-10-12 16:59:34 -0700237
238class TriggerReceiverFakeConfigTestCase(TriggerReceiverBaseTestCase):
239
240 _TEST_PST_HOUR = 20
241 _TEST_PST_DAY = 4 # Friday
242 _TEST_EVENT_PST_HOUR = 13
243
244 _FAKE_NIGHTLY_TASK_NAME = 'fake_nightly_task'
245 _FAKE_WEEKLY_TASK_NAME = 'fake_weekly_task'
246
247 def setUp(self):
248 super(TriggerReceiverFakeConfigTestCase, self).setUp()
249
250 self.fake_config = config_reader.ConfigReader(None)
251 self._add_nightly_tasks(self.fake_config)
252 self._add_weekly_tasks(self.fake_config)
253
254 self.fake_config_with_settings = config_reader.ConfigReader(None)
255 self._add_weekly_tasks(self.fake_config_with_settings)
256 self._add_weekly_params(self.fake_config_with_settings)
257
258 mock_config_reader = mock.patch('config_reader.ConfigReader')
259 self._mock_config_reader = mock_config_reader.start()
260 self.addCleanup(mock_config_reader.stop)
261
262 def _add_nightly_tasks(self, fake_config):
263 fake_config.add_section(self._FAKE_NIGHTLY_TASK_NAME)
264 fake_config.set(self._FAKE_NIGHTLY_TASK_NAME, 'suite', 'fake_suite')
265 fake_config.set(self._FAKE_NIGHTLY_TASK_NAME, 'run_on', 'nightly')
266 fake_config.set(self._FAKE_NIGHTLY_TASK_NAME, 'hour',
267 str(self._TEST_PST_HOUR))
268
269 def _add_weekly_tasks(self, fake_config):
270 fake_config.add_section(self._FAKE_WEEKLY_TASK_NAME)
271 fake_config.set(self._FAKE_WEEKLY_TASK_NAME, 'suite', 'fake_suite')
272 fake_config.set(self._FAKE_WEEKLY_TASK_NAME, 'run_on', 'weekly')
273 fake_config.set(self._FAKE_WEEKLY_TASK_NAME, 'day', str(self._TEST_PST_DAY))
274
275 def _add_weekly_params(self, fake_config):
Xixuan Wu51bb7102019-03-18 14:51:44 -0700276 weekly_section_name = task_config_reader.EVENT_CLASSES[
277 'weekly'].section_name()
Xixuan Wu008ee832017-10-12 16:59:34 -0700278 fake_config.add_section(weekly_section_name)
279 fake_config.set(weekly_section_name, 'hour', str(self._TEST_EVENT_PST_HOUR))
280
281 def testInitializeTriggerReceiverWithNightlyEvent(self):
282 """Test nightly event can be handled on right hour."""
283 # A task with hour=20 should be scheduled at 20:00 in PST everyday, which
284 # is 3:00/4:00 in UTC everyday.
285 self._mock_config_reader.return_value = self.fake_config
286 given_utc_hour = time_converter.convert_time_info(
287 time_converter.TimeInfo(None, self._TEST_PST_HOUR)).hour
288 utc_now = datetime.datetime(2017, 8, 6, given_utc_hour,
289 tzinfo=time_converter.UTC_TZ)
290 last_exec_client = datastore_client.LastExecutionRecordStore()
291 last_exec_client.set_last_execute_time(
292 'nightly', utc_now - datetime.timedelta(hours=1))
293 self._mock_utc_now.return_value = utc_now
294
295 suite_trigger = trigger_receiver.TriggerReceiver()
296 suite_trigger.cron()
297 self.assertTrue(suite_trigger.events['nightly'].should_handle)
298 self.assertEqual(len(suite_trigger.event_results['nightly']), 1)
299 self.assertEqual(suite_trigger.event_results['nightly'][0],
300 self._FAKE_NIGHTLY_TASK_NAME)
301
302 def testInitializeTriggerReceiverWithWeeklyEventWithoutEventHour(self):
303 """Test weekly event without event settings can be handled on right day."""
304 # A task with day=4 (Friday) and default event_hour (23) should be
305 # scheduled at Friday 23:00 in PST, which is Saturday 6:00 or 7:00 in UTC.
306 self._mock_config_reader.return_value = self.fake_config
307 given_utc_hour = time_converter.convert_time_info(
308 time_converter.TimeInfo(
309 self._TEST_PST_DAY,
Xixuan Wu51bb7102019-03-18 14:51:44 -0700310 task_config_reader.EVENT_CLASSES['weekly'].DEFAULT_PST_HOUR)).hour
Xixuan Wu008ee832017-10-12 16:59:34 -0700311 utc_now = datetime.datetime(2017, 10, 14, given_utc_hour,
312 tzinfo=time_converter.UTC_TZ)
313 last_exec_client = datastore_client.LastExecutionRecordStore()
314 last_exec_client.set_last_execute_time(
315 'weekly', utc_now - datetime.timedelta(days=1))
316 self._mock_utc_now.return_value = utc_now
317
318 suite_trigger = trigger_receiver.TriggerReceiver()
319 suite_trigger.cron()
320 self.assertTrue(suite_trigger.events['weekly'].should_handle)
321 self.assertEqual(len(suite_trigger.event_results['weekly']), 1)
322 self.assertEqual(suite_trigger.event_results['weekly'][0],
323 self._FAKE_WEEKLY_TASK_NAME)
324
325 def testInitializeTriggerReceiverWithWeeklyEventWithEventHour(self):
326 """Test weekly event with event settings can be handled on right day."""
327 # A task with day=4 (Friday) and event_hour=13 should be scheduled at
328 # Friday 13:00 in PST, which is Friday 20:00 or 21:00 in UTC.
329 self._mock_config_reader.return_value = self.fake_config_with_settings
330 given_utc_time_info = time_converter.convert_time_info(
331 time_converter.TimeInfo(self._TEST_PST_DAY, self._TEST_EVENT_PST_HOUR))
332
333 # Set the current time as a Friday 20:00 or 21:00 in UTC.
334 utc_now = datetime.datetime(2017, 10, 13, given_utc_time_info.hour,
335 tzinfo=time_converter.UTC_TZ)
336 last_exec_client = datastore_client.LastExecutionRecordStore()
337 last_exec_client.set_last_execute_time(
338 'weekly', utc_now - datetime.timedelta(days=1))
339 self._mock_utc_now.return_value = utc_now
340
341 suite_trigger = trigger_receiver.TriggerReceiver()
342 suite_trigger.cron()
343 self.assertTrue(suite_trigger.events['weekly'].should_handle)
344 self.assertEqual(len(suite_trigger.event_results['weekly']), 1)
345 self.assertEqual(suite_trigger.event_results['weekly'][0],
346 self._FAKE_WEEKLY_TASK_NAME)
347
348
Craig Bergstrom58263d32018-04-26 14:11:35 -0600349class TriggerReceiverFakeBuildTestCase(TriggerReceiverBaseTestCase):
350 """Test the new_build functionality."""
351
Craig Bergstrom58263d32018-04-26 14:11:35 -0600352 def setUp(self):
353 """Set up for a test."""
354 super(TriggerReceiverFakeBuildTestCase, self).setUp()
355
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700356 self._prepare()
357
358 def _prepare(self):
Craig Bergstrom58263d32018-04-26 14:11:35 -0600359 self.fake_config = config_reader.ConfigReader(None)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600360 mock_config_reader = mock.patch('config_reader.ConfigReader')
361 self._mock_config_reader = mock_config_reader.start()
362 self.addCleanup(mock_config_reader.stop)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600363
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700364 # Set last execution time for new_build events.
365 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600366 last_exec_client = datastore_client.LastExecutionRecordStore()
367 last_exec_client.set_last_execute_time(
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700368 'new_build', utc_now - datetime.timedelta(hours=1))
Craig Bergstrom58263d32018-04-26 14:11:35 -0600369 self._mock_utc_now.return_value = utc_now
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700370
371 def testNewBuildForHWTestSanityRequired(self):
372 """Test the new_build functionality."""
373 # Construct a fake config with only_hwtest_sanity_required.
374 fsnbt_name = 'FakeStrictNewBuildTask'
375 self.fake_config.add_section(fsnbt_name)
376 self.fake_config.set(fsnbt_name, 'run_on', 'new_build')
377 self.fake_config.set(fsnbt_name, 'suite', 'fake_suite_base')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700378 self.fake_config.set(fsnbt_name, 'boards', 'link, zako, grunt')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700379 frnbt_name = 'FakeRelaxedNewBuildTask'
380 self.fake_config.add_section(frnbt_name)
381 self.fake_config.set(frnbt_name, 'run_on', 'new_build')
382 self.fake_config.set(frnbt_name, 'suite', 'fake_suite_relaxed')
383 self.fake_config.set(frnbt_name, 'only_hwtest_sanity_required', 'True')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700384 self.fake_config.set(frnbt_name, 'boards', 'link, zako, grunt')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700385
386 self._mock_config_reader.return_value = self.fake_config
Craig Bergstrom58263d32018-04-26 14:11:35 -0600387
388 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600389 suite_trigger = trigger_receiver.TriggerReceiver()
390 suite_trigger.cron()
391
392 # Validate that the expected tests got kicked off.
Craig Bergstrom58263d32018-04-26 14:11:35 -0600393 self.assertEqual(len(suite_trigger.event_results), 1)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600394 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000395 # 2 for strict passed builds, 3 for relaxed builds.
396 self.assertEqual(len(tasks), 5)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600397
398 # The number of builds that matched the base (success) Task.
399 count_base = 0
400 # The number of builds that matched the relaxed Task.
401 count_relaxed = 0
402 for task in tasks:
403 if 'fake_suite_base' in task.payload:
404 # Make sure it matched the expected build only.
Craig Bergstrom58263d32018-04-26 14:11:35 -0600405 self.assertNotIn('grunt-release', task.payload)
406 count_base += 1
407
408 if 'fake_suite_relaxed' in task.payload:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600409 count_relaxed += 1
410
411 # Make each case matched precisely one event.
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000412 self.assertEqual(2, count_base)
413 self.assertEqual(3, count_relaxed)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600414
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700415 def testNewBuildWithExistingBoardFamilies(self):
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700416 """Test the new_build suite with an existing board family."""
417 link_suite = 'FakeLinkNewBuildTask'
418 self.fake_config.add_section(link_suite)
419 self.fake_config.set(link_suite, 'run_on', 'new_build')
420 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700421 self.fake_config.set(link_suite, 'board_families', 'ivybridge')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700422 self._mock_config_reader.return_value = self.fake_config
423
424 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
425 suite_trigger = trigger_receiver.TriggerReceiver()
426 suite_trigger.cron()
427
428 self.assertEqual(len(suite_trigger.event_results), 1)
429 self.assertEqual(suite_trigger.event_results['new_build'],
430 [link_suite])
431 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
432 self.assertEqual(len(tasks), 1)
433 self.assertIn('link-release', tasks[0].payload)
434
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700435 def testNewBuildWithExistingBoardFamiliesAndBoards(self):
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700436 """Test the new_build suite with an existing board family."""
437 link_suite = 'FakeLinkNewBuildTask'
438 self.fake_config.add_section(link_suite)
439 self.fake_config.set(link_suite, 'run_on', 'new_build')
440 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700441 self.fake_config.set(link_suite, 'board_families', 'ivybridge')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700442 self.fake_config.set(link_suite, 'boards', 'asuka, paine, banon')
443 self._mock_config_reader.return_value = self.fake_config
444
445 suite_trigger = trigger_receiver.TriggerReceiver()
446 suite_trigger.cron()
447
448 self.assertEqual(len(suite_trigger.event_results), 1)
449 self.assertEqual(suite_trigger.event_results['new_build'],
450 [link_suite])
451 boards = suite_trigger.events['new_build'].task_list[0].boards
452 self.assertIn('asuka', boards)
453 self.assertIn('link', boards)
454
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700455 def testNewBuildWithNonExistingBoardFamilies(self):
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700456 """Test the new_build suite with an non-existing board family."""
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700457 nyan_suite = 'FakeNonExistBoardFamiliesNewBuildTask'
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700458 self.fake_config.add_section(nyan_suite)
459 self.fake_config.set(nyan_suite, 'run_on', 'new_build')
460 self.fake_config.set(nyan_suite, 'suite', 'fake_suite_base')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700461 self.fake_config.set(nyan_suite, 'board_families', 'nyan')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700462 self._mock_config_reader.return_value = self.fake_config
463
464 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
465 suite_trigger = trigger_receiver.TriggerReceiver()
466 suite_trigger.cron()
467
468 self.assertEqual(len(suite_trigger.event_results), 1)
469 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
470 self.assertEqual(len(tasks), 0)
471
472 def testNewBuildWithNonSpecifiedBoardFamily(self):
473 """Test the new_build suite with an non-specified board family."""
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700474 normal_suite = 'FakeBoardFamiliesNewBuildTask'
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700475 self.fake_config.add_section(normal_suite)
476 self.fake_config.set(normal_suite, 'run_on', 'new_build')
477 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700478 self.fake_config.set(normal_suite, 'boards', 'link, zako')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700479 self._mock_config_reader.return_value = self.fake_config
480
481 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
482 suite_trigger = trigger_receiver.TriggerReceiver()
483 suite_trigger.cron()
484
485 self.assertEqual(len(suite_trigger.event_results), 1)
486 self.assertEqual(suite_trigger.event_results['new_build'],
487 [normal_suite])
488 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000489 self.assertEqual(len(tasks), 2)
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700490
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700491 def testNewBuildExcludingExistingBoardFamilies(self):
492 """Test the new_build suite excluding an existing board family."""
493 link_suite = 'FakeLinkNewBuildTask'
494 self.fake_config.add_section(link_suite)
495 self.fake_config.set(link_suite, 'run_on', 'new_build')
496 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
497 self.fake_config.set(link_suite, 'exclude_board_families', 'ivybridge')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700498 self.fake_config.set(link_suite, 'boards', 'link, zako')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700499 self._mock_config_reader.return_value = self.fake_config
500
501 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
502 suite_trigger = trigger_receiver.TriggerReceiver()
503 suite_trigger.cron()
504
505 self.assertEqual(len(suite_trigger.event_results), 1)
506 self.assertEqual(suite_trigger.event_results['new_build'],
507 [link_suite])
508 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
509 self.assertEqual(len(tasks), 1)
510 self.assertNotIn('link-release', tasks[0].payload)
511 self.assertIn('zako-release', tasks[0].payload)
512
513 def testNewBuildExcludingExistingBoardFamiliesAndBoards(self):
514 """Test the new_build suite with an existing board family."""
515 link_suite = 'FakeLinkNewBuildTask'
516 self.fake_config.add_section(link_suite)
517 self.fake_config.set(link_suite, 'run_on', 'new_build')
518 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
519 self.fake_config.set(link_suite, 'exclude_board_families', 'ivybridge')
Xixuan Wua41efa22019-05-17 14:28:04 -0700520 self.fake_config.set(link_suite, 'exclude_boards',
Xinan Lin09a628a2019-11-01 17:20:27 -0700521 'asuka, paine, banon, coral, reef, nami, samus-kernelnext')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700522 self._mock_config_reader.return_value = self.fake_config
523
524 suite_trigger = trigger_receiver.TriggerReceiver()
525 suite_trigger.cron()
526
527 self.assertEqual(len(suite_trigger.event_results), 1)
528 self.assertEqual(suite_trigger.event_results['new_build'],
529 [link_suite])
530 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
531 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
Xinan Lin09a628a2019-11-01 17:20:27 -0700532 self.assertEqual(len(tasks), 1)
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700533 self.assertNotIn('link-release', tasks[0].payload)
534 self.assertNotIn('asuka-release', tasks[0].payload)
535 self.assertIn('zako-release', tasks[0].payload)
536
537 def testNewBuildExcludingNonExistingBoardFamilies(self):
538 """Test the new_build suite excluding an non-existing board family."""
539 nyan_suite = 'FakeNonExistExcludeBoardFamiliesNewBuildTask'
540 self.fake_config.add_section(nyan_suite)
541 self.fake_config.set(nyan_suite, 'run_on', 'new_build')
542 self.fake_config.set(nyan_suite, 'suite', 'fake_suite_base')
543 self.fake_config.set(nyan_suite, 'exclude_board_families', 'nyan')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700544 self.fake_config.set(nyan_suite, 'boards', 'link, zako')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700545 self._mock_config_reader.return_value = self.fake_config
546
547 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
548 suite_trigger = trigger_receiver.TriggerReceiver()
549 suite_trigger.cron()
550
551 self.assertEqual(len(suite_trigger.event_results), 1)
552 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
553 self.assertEqual(len(tasks), 2)
554
555 def testNewBuildWithBoardExcludeBoardCollision(self):
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700556 """Test the case that the same board in boards and exclude_boards."""
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700557 normal_suite = 'FakeBoardExludingBoardCollisionNewBuildTask'
558 self.fake_config.add_section(normal_suite)
559 self.fake_config.set(normal_suite, 'run_on', 'new_build')
560 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
561 self.fake_config.set(normal_suite, 'boards', 'zako, asuka')
562 self.fake_config.set(normal_suite, 'exclude_boards', 'asuka')
563 self._mock_config_reader.return_value = self.fake_config
564
565 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
566 suite_trigger = trigger_receiver.TriggerReceiver()
567 suite_trigger.cron()
568
569 self.assertEqual(len(suite_trigger.event_results), 1)
570 self.assertEqual(suite_trigger.event_results['new_build'],
571 [normal_suite])
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700572 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
573 self.assertEqual(len(tasks), 1)
574 self.assertNotIn('asuka-release', tasks[0].payload)
575 self.assertIn('zako-release', tasks[0].payload)
576
Xixuan Wub4b2f412019-05-03 11:22:31 -0700577 def testNewBuildWithKernelnext(self):
578 """Test the case that suites run with board-kernelnext build."""
579 normal_suite = 'FakeKernelnextSuite'
580 self.fake_config.add_section(normal_suite)
581 self.fake_config.set(normal_suite, 'run_on', 'new_build')
582 self.fake_config.set(normal_suite, 'suite', 'fake-suite')
583 self.fake_config.set(normal_suite, 'pool', 'suites')
584 self.fake_config.set(normal_suite, 'boards', 'samus-kernelnext')
585 self._mock_config_reader.return_value = self.fake_config
586
Xixuan Wub4b2f412019-05-03 11:22:31 -0700587 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
588 suite_trigger = trigger_receiver.TriggerReceiver()
589 suite_trigger.cron()
590
591 self.assertEqual(len(suite_trigger.event_results), 1)
592 self.assertEqual(suite_trigger.event_results['new_build'],
593 [normal_suite])
594 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
595 self.assertEqual(len(tasks), 1)
596 # Board should be 'samus'.
597 self.assertIn('&board=samus&', tasks[0].payload)
598 # Build should be 'samus-kernelnext-release***'.
599 self.assertIn('cros_version=samus-kernelnext-release', tasks[0].payload)
600
Xixuan Wua41efa22019-05-17 14:28:04 -0700601 def testNewBuildWithModels(self):
602 """Test the new_build suite with an existing models entry."""
603 normal_suite = 'FakeModelsNewBuildTask'
604 self.fake_config.add_section(normal_suite)
605 self.fake_config.set(normal_suite, 'run_on', 'new_build')
606 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
607 self.fake_config.set(normal_suite, 'models', 'coral_lava, coral_santa')
608 self.fake_config.set(normal_suite, 'boards', 'coral')
609 self._mock_config_reader.return_value = self.fake_config
610
611 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
612 suite_trigger = trigger_receiver.TriggerReceiver()
613 suite_trigger.cron()
614
615 self.assertEqual(len(suite_trigger.event_results), 1)
616 self.assertEqual(suite_trigger.event_results['new_build'],
617 [normal_suite])
618 self.assertIn('new_build', suite_trigger.event_results)
619 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
620 self.assertEqual(len(tasks), 1)
621 self.assertNotIn('model=astronaut', tasks[0].payload)
622 self.assertIn('model=santa', tasks[0].payload)
623
Xinan Linae7d6372019-09-12 14:42:10 -0700624 def testNewBuildWithModelsForHWTestSanityRequired(self):
625 """Test the new_build suite with an existing models entry."""
626 normal_suite = 'FakeModelsNewBuildTask'
627 self.fake_config.add_section(normal_suite)
628 self.fake_config.set(normal_suite, 'run_on', 'new_build')
629 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
630 self.fake_config.set(normal_suite, 'models', 'nami_akali, nami_bard')
631 self.fake_config.set(normal_suite, 'boards', 'nami')
632 self.fake_config.set(normal_suite, 'only_hwtest_sanity_required', 'True')
633 self._mock_config_reader.return_value = self.fake_config
634
635 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
636 suite_trigger = trigger_receiver.TriggerReceiver()
637 suite_trigger.cron()
638
639 self.assertEqual(len(suite_trigger.event_results), 1)
640 self.assertEqual(suite_trigger.event_results['new_build'],
641 [normal_suite])
642 self.assertIn('new_build', suite_trigger.event_results)
643 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
644 self.assertEqual(len(tasks), 2)
645 self.assertIn('model=akali', tasks[0].payload)
646 self.assertIn('9868.0.0', tasks[0].payload)
647 self.assertIn('model=bard', tasks[1].payload)
648 self.assertIn('9867.0.0', tasks[1].payload)
649
Xixuan Wua41efa22019-05-17 14:28:04 -0700650 def testNewBuildWithExcludeModels(self):
651 """Test the new_build suite with an existing exclude_models entry."""
652 normal_suite = 'FakeExludingModelsNewBuildTask'
653 self.fake_config.add_section(normal_suite)
654 self.fake_config.set(normal_suite, 'run_on', 'new_build')
655 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
656 self.fake_config.set(normal_suite, 'exclude_models',
657 'coral_lava, coral_santa')
658 self.fake_config.set(normal_suite, 'boards', 'coral')
659 self._mock_config_reader.return_value = self.fake_config
660
661 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
662 suite_trigger = trigger_receiver.TriggerReceiver()
663 suite_trigger.cron()
664
665 self.assertEqual(len(suite_trigger.event_results), 1)
666 self.assertEqual(suite_trigger.event_results['new_build'],
667 [normal_suite])
668 self.assertIn('new_build', suite_trigger.event_results)
669 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
670 self.assertEqual(len(tasks), 1)
671 self.assertNotIn('model=santa', tasks[0].payload)
672 self.assertIn('model=astronaut', tasks[0].payload)
673
674 def testNewBuildWithModelsExcludeModels(self):
675 """Test the new_build suite with models and exclude_models entry."""
676 normal_suite = 'FakeModelsExcludeModelsNewBuildTask'
677 self.fake_config.add_section(normal_suite)
678 self.fake_config.set(normal_suite, 'run_on', 'new_build')
679 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
680 self.fake_config.set(normal_suite, 'models', 'coral_santa, coral_astronaut')
681 self.fake_config.set(normal_suite, 'exclude_models',
682 'coral_lava, coral_santa')
683 self.fake_config.set(normal_suite, 'boards', 'coral')
684 self._mock_config_reader.return_value = self.fake_config
685
686 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
687 suite_trigger = trigger_receiver.TriggerReceiver()
688 suite_trigger.cron()
689
690 self.assertEqual(len(suite_trigger.event_results), 1)
691 self.assertEqual(suite_trigger.event_results['new_build'],
692 [normal_suite])
693 self.assertIn('new_build', suite_trigger.event_results)
694 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
695 self.assertEqual(len(tasks), 1)
696 self.assertNotIn('model=santa', tasks[0].payload)
697 self.assertIn('model=astronaut', tasks[0].payload)
698
699 def testNewBuildWithNoModelListAndModelBuild(self):
700 """Test the new_build suite with models and empty board_model mapping."""
701 normal_suite = 'FakeModelsExcludeModelsNewBuildTask'
702 self.fake_config.add_section(normal_suite)
703 self.fake_config.set(normal_suite, 'run_on', 'new_build')
704 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
705 self.fake_config.set(normal_suite, 'boards', 'coral')
706 self._mock_config_reader.return_value = self.fake_config
707
708 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
709 suite_trigger = trigger_receiver.TriggerReceiver()
710 suite_trigger.cron()
711
712 self.assertIn('new_build', suite_trigger.event_results)
713 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
714 # Verify that coral-release is not kicked off on model lava as lava is not
715 # listed in cros_model_map.
716 self.assertEqual(len(tasks), 2)
717 self.assertNotIn('lava', tasks[0].payload)
718 self.assertNotIn('lava', tasks[1].payload)
719
720 def testNewBuildWithNoModelListAndNoModelBuild(self):
721 """Test the new_build suite with models and empty board_model mapping."""
722 normal_suite = 'FakeModelsExcludeModelsNewBuildTask'
723 self.fake_config.add_section(normal_suite)
724 self.fake_config.set(normal_suite, 'run_on', 'new_build')
725 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
726 self.fake_config.set(normal_suite, 'boards', 'reef')
727 self._mock_config_reader.return_value = self.fake_config
728
729 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
730 suite_trigger = trigger_receiver.TriggerReceiver()
731 suite_trigger.cron()
732
733 self.assertIn('new_build', suite_trigger.event_results)
734 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
735 # Verify that reef-release is kicked off on reef models.
736 self.assertEqual(len(tasks), 1)
737 self.assertIn('model=electro', tasks[0].payload)
738
C Shapiro09108252019-08-01 14:52:52 -0500739 def testNewBuildWithAnyModel(self):
740 """Test the new_build suite with any_model option set."""
741 normal_suite = 'FakeAnyModelNewBuildTask'
742 self.fake_config.add_section(normal_suite)
743 self.fake_config.set(normal_suite, 'run_on', 'new_build')
744 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
745 self.fake_config.set(normal_suite, 'any_model', 'True')
746 self.fake_config.set(normal_suite, 'boards', 'coral')
747 self._mock_config_reader.return_value = self.fake_config
748
749 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
750 suite_trigger = trigger_receiver.TriggerReceiver()
751 suite_trigger.cron()
752
753 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
754 self.assertEqual(len(tasks), 1)
755 self.assertIn('model=None', tasks[0].payload)
756
Xinan Lin8b291982019-12-16 10:03:56 -0800757 def testNewBuildWithFirmwareTask(self):
758 """Test the new_build suite with firmware option set."""
759 # Construct a fake config with firmware build.
760 fsnbt_name = 'FakeStrictNewBuildTask'
761 self.fake_config.add_section(fsnbt_name)
762 self.fake_config.set(fsnbt_name, 'run_on', 'new_build')
763 self.fake_config.set(fsnbt_name, 'suite', 'fake_suite_base')
764 self.fake_config.set(fsnbt_name, 'boards', 'zako')
765 self.fake_config.set(fsnbt_name, 'firmware_ro_build_spec', 'firmware')
766 self.fake_config.set(fsnbt_name, 'test_source', 'cros')
767 self._mock_config_reader.return_value = self.fake_config
768
769 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
770 suite_trigger = trigger_receiver.TriggerReceiver()
771 some_event = suite_trigger.events['new_build']
772 suite_trigger.cron()
773
774 # The firmware query has run for once.
775 self.assertEqual(suite_trigger._build_client.firmware_builds_called, 1)
776 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
777 self.assertEqual(len(tasks), 1)
778 self.assertIn('firmware-zako-12345.67', tasks[0].payload)
779
780
781 def testNewBuildWithoutFirmwareTask(self):
782 """Test the event skips fetch the firmware builds."""
783 # Construct a fake config without firmware build.
784 fsnbt_name = 'FakeStrictNewBuildTask'
785 self.fake_config.add_section(fsnbt_name)
786 self.fake_config.set(fsnbt_name, 'run_on', 'new_build')
787 self.fake_config.set(fsnbt_name, 'suite', 'fake_suite_base')
788 self.fake_config.set(fsnbt_name, 'boards', 'zako')
789 self._mock_config_reader.return_value = self.fake_config
790
791 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
792 suite_trigger = trigger_receiver.TriggerReceiver()
793 suite_trigger.cron()
794
795 # The firmware query was not called.
796 self.assertEqual(suite_trigger._build_client.firmware_builds_called, 0)
797 # Validate that the expected tests got kicked off.
798 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
799 self.assertEqual(len(tasks), 1)
800
Craig Bergstrom58263d32018-04-26 14:11:35 -0600801
Xixuan Wu008ee832017-10-12 16:59:34 -0700802class TriggerReceiverRealConfigTestCase(TriggerReceiverBaseTestCase):
803
804 def setUp(self):
805 super(TriggerReceiverRealConfigTestCase, self).setUp()
806 mock_config_reader = mock.patch('config_reader.ConfigReader')
807 self._mock_config_reader = mock_config_reader.start()
808 self.addCleanup(mock_config_reader.stop)
809 self._mock_config_reader.return_value = _SUITE_CONFIG_READER
810
811 def _get_ground_truth_task_list_from_config(self):
812 """Get the ground truth of to-be-scheduled task list from config file."""
813 self._mock_utc_now.return_value = datetime.datetime.now(
814 time_converter.UTC_TZ)
Xixuan Wu51bb7102019-03-18 14:51:44 -0700815 task_config = task_config_reader.TaskConfig(_SUITE_CONFIG_READER)
Xixuan Wu008ee832017-10-12 16:59:34 -0700816 tasks = {}
Xixuan Wu51bb7102019-03-18 14:51:44 -0700817 for keyword, klass in task_config_reader.EVENT_CLASSES.iteritems():
Xixuan Wu008ee832017-10-12 16:59:34 -0700818 new_event = klass(
819 task_config.get_event_setting(klass.section_name()), None)
820 new_event.set_task_list(
821 task_config.get_tasks_by_keyword(klass.KEYWORD)['tasks'])
822 tasks[keyword] = new_event.task_list
823
824 return tasks
825
Xinan Lincfa41012020-04-08 13:22:03 -0700826 def testEventShouldScanNewBuildFromSinceDateToTargetDate(self):
827 """Test the event should scan new builds from last_exec to target_exec."""
828 _utc_now = datetime.datetime.now(time_converter.UTC_TZ)
829 # utc_now() should be called only 3 times for the creation of Weekly,
830 # Nightly or New_Build event.
831 self._mock_utc_now.side_effect = [_utc_now, _utc_now, _utc_now]
832 target_exec_utc = _get_current_min(_utc_now)
833 since_date = target_exec_utc - datetime.timedelta(hours=1)
834 last_exec_client = datastore_client.LastExecutionRecordStore()
835 last_exec_client.set_last_execute_time('new_build', since_date)
836 delay_minutes = datetime.timedelta(
837 minutes=constants.BaseEvent.DELAY_MINUTES)
838 with mock.patch(
839 'build_lib.get_cros_builds',
840 return_value=({}, {})) as mock_get_cros_builds:
841 suite_trigger = trigger_receiver.TriggerReceiver()
842 suite_trigger.cron()
843 # The new CrOS builds we fetched should be created within
844 # the specified time span.
845 mock_get_cros_builds.assert_called_once_with(
846 mock.ANY, mock.ANY, since_date - delay_minutes,
847 target_exec_utc - delay_minutes, 'new_build')
848
Xixuan Wu40998892017-08-29 14:32:26 -0700849 def testCronWithoutLastExec(self):
850 """Test the first round of cron can be successfully executed."""
851 self._mock_utc_now.return_value = datetime.datetime.now(
852 time_converter.UTC_TZ)
853 suite_trigger = trigger_receiver.TriggerReceiver()
854 suite_trigger.cron()
855 self.assertFalse(suite_trigger.events['nightly'].should_handle)
856 self.assertFalse(suite_trigger.events['weekly'].should_handle)
857 self.assertFalse(suite_trigger.events['new_build'].should_handle)
858
859 self.assertEqual(suite_trigger.event_results, {})
860
861 def testCronTriggerNightly(self):
862 """Test nightly event is read with available nightly last_exec_time."""
863 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
864 last_exec_client = datastore_client.LastExecutionRecordStore()
865 last_exec_client.set_last_execute_time(
866 'nightly', utc_now - datetime.timedelta(hours=1))
867 self._mock_utc_now.return_value = utc_now
868 suite_trigger = trigger_receiver.TriggerReceiver()
869 self.assertTrue(suite_trigger.events['nightly'].should_handle)
870 self.assertFalse(suite_trigger.events['weekly'].should_handle)
871 self.assertFalse(suite_trigger.events['new_build'].should_handle)
872
Xixuan Wu33179672017-09-12 11:44:04 -0700873 def testCronTriggerNightlyOutdated(self):
874 """Test nightly event is read with available nightly last_exec_time."""
875 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
876 last_exec_client = datastore_client.LastExecutionRecordStore()
877 last_exec_client.set_last_execute_time(
878 'nightly', utc_now - datetime.timedelta(days=3))
879 self._mock_utc_now.return_value = utc_now
880 suite_trigger = trigger_receiver.TriggerReceiver()
881 self.assertFalse(suite_trigger.events['nightly'].should_handle)
882
883 def testCronTriggerWeeklyOutdated(self):
884 """Test weekly event is read with available weekly last_exec_time."""
885 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
886 last_exec_client = datastore_client.LastExecutionRecordStore()
887 last_exec_client.set_last_execute_time(
888 'weekly', utc_now - datetime.timedelta(days=8))
889 self._mock_utc_now.return_value = utc_now
890 suite_trigger = trigger_receiver.TriggerReceiver()
891 self.assertFalse(suite_trigger.events['weekly'].should_handle)
892
Xixuan Wu40998892017-08-29 14:32:26 -0700893 def testCronForWeeks(self):
894 """Ensure cron job can be successfully scheduled for several weeks."""
Xixuan Wu008ee832017-10-12 16:59:34 -0700895 all_tasks = self._get_ground_truth_task_list_from_config()
Xixuan Wu40998892017-08-29 14:32:26 -0700896 last_now = None
897
898 for now in now_generator(datetime.datetime.now(time_converter.UTC_TZ)):
899 self._mock_utc_now.return_value = now
900 suite_trigger = trigger_receiver.TriggerReceiver()
Xixuan Wu5451a662017-10-17 10:57:40 -0700901 with mock.patch('task.Task.schedule', return_value=True):
902 suite_trigger.cron()
Xixuan Wu40998892017-08-29 14:32:26 -0700903
Xixuan Wu40998892017-08-29 14:32:26 -0700904 should_scheduled_nightly_tasks = [
Xixuan Wu09962902018-12-11 10:49:27 -0800905 t.name for t in all_tasks['nightly'] if t.hour == now.hour]
Xixuan Wu008ee832017-10-12 16:59:34 -0700906
Xixuan Wu09962902018-12-11 10:49:27 -0800907 if (_should_schedule_timed_task(last_now, now) and
Xixuan Wu40998892017-08-29 14:32:26 -0700908 should_scheduled_nightly_tasks):
909 self.assertEqual(suite_trigger.event_results['nightly'],
910 should_scheduled_nightly_tasks)
911 else:
912 self.assertNotIn('nightly', suite_trigger.event_results.keys())
913
914 # Verify weekly tasks
915 should_scheduled_weekly_tasks = [
916 t.name for t in all_tasks['weekly']
Xixuan Wu09962902018-12-11 10:49:27 -0800917 if now.weekday() == t.day and now.hour == t.hour]
918 if (_should_schedule_timed_task(last_now, now) and
Xixuan Wu40998892017-08-29 14:32:26 -0700919 should_scheduled_weekly_tasks):
920 self.assertEqual(suite_trigger.event_results['weekly'],
921 should_scheduled_weekly_tasks)
922 else:
923 self.assertNotIn('weekly', suite_trigger.event_results.keys())
924
925 # Verify new_build tasks
926 should_scheduled_new_build_tasks = [
927 t.name for t in all_tasks['new_build']]
928 if (_should_schedule_new_build_task(last_now, now) and
929 should_scheduled_new_build_tasks):
930 self.assertEqual(suite_trigger.event_results['new_build'],
931 should_scheduled_new_build_tasks)
932 else:
933 self.assertNotIn('new_build', suite_trigger.event_results.keys())
934
935 last_now = now
936
937
938if __name__ == '__main__':
939 unittest.main()