blob: 417d59d11373ad70854a87210c979cdd85c62248 [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
94 def get_passed_builds_since_date(self, since_date):
Xixuan Wu6ec23e32019-05-23 11:56:02 -070095 """Mock get_passed_builds_since_date."""
Xixuan Wuc6819012019-05-23 11:34:59 -070096 del since_date # unused
97 return [
98 build_lib.BuildInfo(
99 'link', None, '62', '9868.0.0', 'link-release'),
100 build_lib.BuildInfo(
101 'zako', None, '62', '9868.0.0', 'zako-release'),
102 build_lib.BuildInfo('samus-kernelnext', None, '62',
103 '9868.0.0', 'samus-kernelnext-release'),
104 build_lib.BuildInfo(
105 'reef', None, '62', '1234.0.0', 'reef-release'),
106 build_lib.BuildInfo(
107 'coral', 'santa', '62', '9868.0.0', 'coral-release'),
108 build_lib.BuildInfo(
109 'coral', 'astronaut', '62', '9868.0.0', 'coral-release'),
110 build_lib.BuildInfo(
111 'coral', 'lava', '62', '9868.0.0', 'coral-release'),
112 ]
113
114 def get_latest_passed_builds(self, build_config):
Xixuan Wu6ec23e32019-05-23 11:56:02 -0700115 """Mock get_latest_passed_builds."""
Xixuan Wuc6819012019-05-23 11:34:59 -0700116 del build_config # unused
117 return build_lib.BuildInfo('link', '62', '9868.0.0', build_config)
118
119 def get_relaxed_passed_builds_since_date(self, since_date):
Xixuan Wu6ec23e32019-05-23 11:56:02 -0700120 """Mock get_relaxed_pased_builds_since_date."""
Xixuan Wuc6819012019-05-23 11:34:59 -0700121 del since_date # unused
Xinan Linae7d6372019-09-12 14:42:10 -0700122 return [
123 build_lib.BuildInfo('grunt', None, '63', '9968.0.0', 'grunt-release'),
124 build_lib.BuildInfo('nami', None, '62', '9867.0.0', 'nami-release'),
125 build_lib.BuildInfo('nami', 'akali', '62', '9868.0.0', 'nami-release'),
126 build_lib.BuildInfo('nami', 'bard', '62', '9866.0.0', 'nami-release'),
127 ]
Xixuan Wuc6819012019-05-23 11:34:59 -0700128
Xinan Lin028f9582019-12-11 10:55:33 -0800129 def get_latest_passed_firmware_builds(self):
130 """Mock get_passed_firmware_builds."""
131 return [
132 ['cros', 'fake_board', ('gs://chromeos-image-archive/'
133 'fake_board-release/R30-6182.0.0-rc2/'
134 'fake_board')],
135 ['firmware', 'fake_board', ('gs://chromeos-image-archive/'
136 'firmware-fake_board-12345.67.'
137 'A-firmwarebranch/RFoo-1.0.0-b1e234567')],
138 ]
139
Xixuan Wuc6819012019-05-23 11:34:59 -0700140
Xixuan Wu40998892017-08-29 14:32:26 -0700141class FakeAndroidBuildRestClient(object):
142 """Mock rest_client.AndroidBuildRestClient."""
143
144 def get_latest_build_id(self, branch, target):
145 """Mock rest_client.AndroidBuildRestClient.get_latest_build_id."""
146 del branch, target # unused
147 return '100'
148
149
150class FakeLabConfig(object):
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700151 """Mock config_reader.LabConfig."""
Xixuan Wu40998892017-08-29 14:32:26 -0700152
153 def get_android_board_list(self):
154 """Mock config_reader.LabConfig.get_android_board_list."""
155 return ('android-angler', 'android-bullhead')
156
Xixuan Wu6fb16272017-10-19 13:16:00 -0700157 def get_cros_board_list(self):
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700158 """Mock config_reader.LabConfig.get_cros_board_list."""
Xixuan Wua41efa22019-05-17 14:28:04 -0700159 return ('grunt', 'link', 'peppy', 'daisy', 'zako', 'samus-kernelnext',
Xinan Linae7d6372019-09-12 14:42:10 -0700160 'coral', 'reef', 'nami')
Xixuan Wu6fb16272017-10-19 13:16:00 -0700161
Xixuan Wu40998892017-08-29 14:32:26 -0700162 def get_firmware_ro_build_list(self, release_board):
163 """Mock config_reader.LabConfig.get_firmware_ro_build_list."""
164 del release_board # unused
165 return 'firmware1,firmware2'
166
C Shapiro7f24a002017-12-05 14:25:09 -0700167 def get_cros_model_map(self):
168 """Mock config_reader.LabConfig.get_cros_model_map."""
Xixuan Wua41efa22019-05-17 14:28:04 -0700169 return {
170 'coral': ['santa', 'astronaut'],
171 'reef': ['electro'],
Xinan Linae7d6372019-09-12 14:42:10 -0700172 'nami': ['akali', 'bard'],
Xixuan Wua41efa22019-05-17 14:28:04 -0700173 }
C Shapiro7f24a002017-12-05 14:25:09 -0700174
Xixuan Wu40998892017-08-29 14:32:26 -0700175
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700176class FakeMigrationConfig(object):
177 """Mock config_reader.MigrationConfig."""
178
Xixuan Wu1e42c752019-03-21 13:41:49 -0700179 def get_skylab_suites_dump(self):
Xixuan Wuee6b6a82019-03-21 14:28:26 -0700180 """Mock config_reader.MigrationConfig.get_skylab_suite_list."""
Xixuan Wu1e42c752019-03-21 13:41:49 -0700181 return {'suite:ent-nightly':
182 {'pool:suites':
Xixuan Wu028f6732019-04-11 14:47:42 -0700183 {'model:santa': {
184 'skylab': True,
185 'override_pool': '',
186 'override_qs_account': '',
187 },
188 'model:zako': {
189 'skylab': True,
190 'override_pool': 'QUOTA_POOL',
191 'override_qs_account': 'QUOTA_ACCOUNT',
192 }}}}
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700193
194
Xixuan Wu008ee832017-10-12 16:59:34 -0700195class TriggerReceiverBaseTestCase(unittest.TestCase):
Xixuan Wu40998892017-08-29 14:32:26 -0700196
197 def setUp(self):
198 self.testbed = testbed.Testbed()
199 self.testbed.activate()
200 self.addCleanup(self.testbed.deactivate)
201
202 self.testbed.init_datastore_v3_stub()
203 self.testbed.init_memcache_stub()
204 ndb.get_context().clear_cache()
205 self.testbed.init_taskqueue_stub(
206 root_path=os.path.join(os.path.dirname(__file__)))
207 self.taskqueue_stub = self.testbed.get_stub(
208 testbed.TASKQUEUE_SERVICE_NAME)
209
Xixuan Wuc6819012019-05-23 11:34:59 -0700210 mock_build_client = mock.patch('rest_client.BuildBucketBigqueryClient')
211 self._mock_build_client = mock_build_client.start()
212 self.addCleanup(mock_build_client.stop)
213
Xixuan Wu40998892017-08-29 14:32:26 -0700214 mock_android_client = mock.patch('rest_client.AndroidBuildRestClient')
215 self._mock_android_client = mock_android_client.start()
216 self.addCleanup(mock_android_client.stop)
217
Xixuan Wu40998892017-08-29 14:32:26 -0700218 mock_lab_config = mock.patch('config_reader.LabConfig')
219 self._mock_lab_config = mock_lab_config.start()
220 self.addCleanup(mock_lab_config.stop)
221
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700222 mock_migration_config = mock.patch('config_reader.MigrationConfig')
223 self._mock_migration_config = mock_migration_config.start()
224 self.addCleanup(mock_migration_config.stop)
225
Xixuan Wu40998892017-08-29 14:32:26 -0700226 mock_utc_now = mock.patch('time_converter.utc_now')
227 self._mock_utc_now = mock_utc_now.start()
228 self.addCleanup(mock_utc_now.stop)
229
Xixuan Wuc6819012019-05-23 11:34:59 -0700230 self._mock_build_client.return_value = FakeBuildClient()
Xixuan Wu40998892017-08-29 14:32:26 -0700231 self._mock_android_client.return_value = FakeAndroidBuildRestClient()
Xixuan Wu40998892017-08-29 14:32:26 -0700232 self._mock_lab_config.return_value = FakeLabConfig()
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700233 self._mock_migration_config.return_value = FakeMigrationConfig()
Xixuan Wu40998892017-08-29 14:32:26 -0700234
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700235 board_family_patcher = mock.patch(
236 'build_lib.get_board_family_mapping_from_gs')
237 board_family_getter = board_family_patcher.start()
238 board_family_getter.return_value = {
239 'nyan': ['nyan', 'nyan_blaze', 'nyan_big'],
240 'ivybridge': ['link', 'link_freon']}
241 self.addCleanup(board_family_patcher.stop)
242
Xixuan Wu008ee832017-10-12 16:59:34 -0700243
244class TriggerReceiverFakeConfigTestCase(TriggerReceiverBaseTestCase):
245
246 _TEST_PST_HOUR = 20
247 _TEST_PST_DAY = 4 # Friday
248 _TEST_EVENT_PST_HOUR = 13
249
250 _FAKE_NIGHTLY_TASK_NAME = 'fake_nightly_task'
251 _FAKE_WEEKLY_TASK_NAME = 'fake_weekly_task'
252
253 def setUp(self):
254 super(TriggerReceiverFakeConfigTestCase, self).setUp()
255
256 self.fake_config = config_reader.ConfigReader(None)
257 self._add_nightly_tasks(self.fake_config)
258 self._add_weekly_tasks(self.fake_config)
259
260 self.fake_config_with_settings = config_reader.ConfigReader(None)
261 self._add_weekly_tasks(self.fake_config_with_settings)
262 self._add_weekly_params(self.fake_config_with_settings)
263
264 mock_config_reader = mock.patch('config_reader.ConfigReader')
265 self._mock_config_reader = mock_config_reader.start()
266 self.addCleanup(mock_config_reader.stop)
267
268 def _add_nightly_tasks(self, fake_config):
269 fake_config.add_section(self._FAKE_NIGHTLY_TASK_NAME)
270 fake_config.set(self._FAKE_NIGHTLY_TASK_NAME, 'suite', 'fake_suite')
271 fake_config.set(self._FAKE_NIGHTLY_TASK_NAME, 'run_on', 'nightly')
272 fake_config.set(self._FAKE_NIGHTLY_TASK_NAME, 'hour',
273 str(self._TEST_PST_HOUR))
274
275 def _add_weekly_tasks(self, fake_config):
276 fake_config.add_section(self._FAKE_WEEKLY_TASK_NAME)
277 fake_config.set(self._FAKE_WEEKLY_TASK_NAME, 'suite', 'fake_suite')
278 fake_config.set(self._FAKE_WEEKLY_TASK_NAME, 'run_on', 'weekly')
279 fake_config.set(self._FAKE_WEEKLY_TASK_NAME, 'day', str(self._TEST_PST_DAY))
280
281 def _add_weekly_params(self, fake_config):
Xixuan Wu51bb7102019-03-18 14:51:44 -0700282 weekly_section_name = task_config_reader.EVENT_CLASSES[
283 'weekly'].section_name()
Xixuan Wu008ee832017-10-12 16:59:34 -0700284 fake_config.add_section(weekly_section_name)
285 fake_config.set(weekly_section_name, 'hour', str(self._TEST_EVENT_PST_HOUR))
286
287 def testInitializeTriggerReceiverWithNightlyEvent(self):
288 """Test nightly event can be handled on right hour."""
289 # A task with hour=20 should be scheduled at 20:00 in PST everyday, which
290 # is 3:00/4:00 in UTC everyday.
291 self._mock_config_reader.return_value = self.fake_config
292 given_utc_hour = time_converter.convert_time_info(
293 time_converter.TimeInfo(None, self._TEST_PST_HOUR)).hour
294 utc_now = datetime.datetime(2017, 8, 6, given_utc_hour,
295 tzinfo=time_converter.UTC_TZ)
296 last_exec_client = datastore_client.LastExecutionRecordStore()
297 last_exec_client.set_last_execute_time(
298 'nightly', utc_now - datetime.timedelta(hours=1))
299 self._mock_utc_now.return_value = utc_now
300
301 suite_trigger = trigger_receiver.TriggerReceiver()
302 suite_trigger.cron()
303 self.assertTrue(suite_trigger.events['nightly'].should_handle)
304 self.assertEqual(len(suite_trigger.event_results['nightly']), 1)
305 self.assertEqual(suite_trigger.event_results['nightly'][0],
306 self._FAKE_NIGHTLY_TASK_NAME)
307
308 def testInitializeTriggerReceiverWithWeeklyEventWithoutEventHour(self):
309 """Test weekly event without event settings can be handled on right day."""
310 # A task with day=4 (Friday) and default event_hour (23) should be
311 # scheduled at Friday 23:00 in PST, which is Saturday 6:00 or 7:00 in UTC.
312 self._mock_config_reader.return_value = self.fake_config
313 given_utc_hour = time_converter.convert_time_info(
314 time_converter.TimeInfo(
315 self._TEST_PST_DAY,
Xixuan Wu51bb7102019-03-18 14:51:44 -0700316 task_config_reader.EVENT_CLASSES['weekly'].DEFAULT_PST_HOUR)).hour
Xixuan Wu008ee832017-10-12 16:59:34 -0700317 utc_now = datetime.datetime(2017, 10, 14, given_utc_hour,
318 tzinfo=time_converter.UTC_TZ)
319 last_exec_client = datastore_client.LastExecutionRecordStore()
320 last_exec_client.set_last_execute_time(
321 'weekly', utc_now - datetime.timedelta(days=1))
322 self._mock_utc_now.return_value = utc_now
323
324 suite_trigger = trigger_receiver.TriggerReceiver()
325 suite_trigger.cron()
326 self.assertTrue(suite_trigger.events['weekly'].should_handle)
327 self.assertEqual(len(suite_trigger.event_results['weekly']), 1)
328 self.assertEqual(suite_trigger.event_results['weekly'][0],
329 self._FAKE_WEEKLY_TASK_NAME)
330
331 def testInitializeTriggerReceiverWithWeeklyEventWithEventHour(self):
332 """Test weekly event with event settings can be handled on right day."""
333 # A task with day=4 (Friday) and event_hour=13 should be scheduled at
334 # Friday 13:00 in PST, which is Friday 20:00 or 21:00 in UTC.
335 self._mock_config_reader.return_value = self.fake_config_with_settings
336 given_utc_time_info = time_converter.convert_time_info(
337 time_converter.TimeInfo(self._TEST_PST_DAY, self._TEST_EVENT_PST_HOUR))
338
339 # Set the current time as a Friday 20:00 or 21:00 in UTC.
340 utc_now = datetime.datetime(2017, 10, 13, given_utc_time_info.hour,
341 tzinfo=time_converter.UTC_TZ)
342 last_exec_client = datastore_client.LastExecutionRecordStore()
343 last_exec_client.set_last_execute_time(
344 'weekly', utc_now - datetime.timedelta(days=1))
345 self._mock_utc_now.return_value = utc_now
346
347 suite_trigger = trigger_receiver.TriggerReceiver()
348 suite_trigger.cron()
349 self.assertTrue(suite_trigger.events['weekly'].should_handle)
350 self.assertEqual(len(suite_trigger.event_results['weekly']), 1)
351 self.assertEqual(suite_trigger.event_results['weekly'][0],
352 self._FAKE_WEEKLY_TASK_NAME)
353
354
Craig Bergstrom58263d32018-04-26 14:11:35 -0600355class TriggerReceiverFakeBuildTestCase(TriggerReceiverBaseTestCase):
356 """Test the new_build functionality."""
357
Craig Bergstrom58263d32018-04-26 14:11:35 -0600358 def setUp(self):
359 """Set up for a test."""
360 super(TriggerReceiverFakeBuildTestCase, self).setUp()
361
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700362 self._prepare()
363
364 def _prepare(self):
Craig Bergstrom58263d32018-04-26 14:11:35 -0600365 self.fake_config = config_reader.ConfigReader(None)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600366 mock_config_reader = mock.patch('config_reader.ConfigReader')
367 self._mock_config_reader = mock_config_reader.start()
368 self.addCleanup(mock_config_reader.stop)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600369
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700370 # Set last execution time for new_build events.
371 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600372 last_exec_client = datastore_client.LastExecutionRecordStore()
373 last_exec_client.set_last_execute_time(
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700374 'new_build', utc_now - datetime.timedelta(hours=1))
Craig Bergstrom58263d32018-04-26 14:11:35 -0600375 self._mock_utc_now.return_value = utc_now
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700376
377 def testNewBuildForHWTestSanityRequired(self):
378 """Test the new_build functionality."""
379 # Construct a fake config with only_hwtest_sanity_required.
380 fsnbt_name = 'FakeStrictNewBuildTask'
381 self.fake_config.add_section(fsnbt_name)
382 self.fake_config.set(fsnbt_name, 'run_on', 'new_build')
383 self.fake_config.set(fsnbt_name, 'suite', 'fake_suite_base')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700384 self.fake_config.set(fsnbt_name, 'boards', 'link, zako, grunt')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700385 frnbt_name = 'FakeRelaxedNewBuildTask'
386 self.fake_config.add_section(frnbt_name)
387 self.fake_config.set(frnbt_name, 'run_on', 'new_build')
388 self.fake_config.set(frnbt_name, 'suite', 'fake_suite_relaxed')
389 self.fake_config.set(frnbt_name, 'only_hwtest_sanity_required', 'True')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700390 self.fake_config.set(frnbt_name, 'boards', 'link, zako, grunt')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700391
392 self._mock_config_reader.return_value = self.fake_config
Craig Bergstrom58263d32018-04-26 14:11:35 -0600393
394 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600395 suite_trigger = trigger_receiver.TriggerReceiver()
396 suite_trigger.cron()
397
398 # Validate that the expected tests got kicked off.
Craig Bergstrom58263d32018-04-26 14:11:35 -0600399 self.assertEqual(len(suite_trigger.event_results), 1)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600400 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000401 # 2 for strict passed builds, 3 for relaxed builds.
402 self.assertEqual(len(tasks), 5)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600403
404 # The number of builds that matched the base (success) Task.
405 count_base = 0
406 # The number of builds that matched the relaxed Task.
407 count_relaxed = 0
408 for task in tasks:
409 if 'fake_suite_base' in task.payload:
410 # Make sure it matched the expected build only.
Craig Bergstrom58263d32018-04-26 14:11:35 -0600411 self.assertNotIn('grunt-release', task.payload)
412 count_base += 1
413
414 if 'fake_suite_relaxed' in task.payload:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600415 count_relaxed += 1
416
417 # Make each case matched precisely one event.
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000418 self.assertEqual(2, count_base)
419 self.assertEqual(3, count_relaxed)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600420
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700421 def testNewBuildWithExistingBoardFamilies(self):
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700422 """Test the new_build suite with an existing board family."""
423 link_suite = 'FakeLinkNewBuildTask'
424 self.fake_config.add_section(link_suite)
425 self.fake_config.set(link_suite, 'run_on', 'new_build')
426 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700427 self.fake_config.set(link_suite, 'board_families', 'ivybridge')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700428 self._mock_config_reader.return_value = self.fake_config
429
430 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
431 suite_trigger = trigger_receiver.TriggerReceiver()
432 suite_trigger.cron()
433
434 self.assertEqual(len(suite_trigger.event_results), 1)
435 self.assertEqual(suite_trigger.event_results['new_build'],
436 [link_suite])
437 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
438 self.assertEqual(len(tasks), 1)
439 self.assertIn('link-release', tasks[0].payload)
440
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700441 def testNewBuildWithExistingBoardFamiliesAndBoards(self):
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700442 """Test the new_build suite with an existing board family."""
443 link_suite = 'FakeLinkNewBuildTask'
444 self.fake_config.add_section(link_suite)
445 self.fake_config.set(link_suite, 'run_on', 'new_build')
446 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700447 self.fake_config.set(link_suite, 'board_families', 'ivybridge')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700448 self.fake_config.set(link_suite, 'boards', 'asuka, paine, banon')
449 self._mock_config_reader.return_value = self.fake_config
450
451 suite_trigger = trigger_receiver.TriggerReceiver()
452 suite_trigger.cron()
453
454 self.assertEqual(len(suite_trigger.event_results), 1)
455 self.assertEqual(suite_trigger.event_results['new_build'],
456 [link_suite])
457 boards = suite_trigger.events['new_build'].task_list[0].boards
458 self.assertIn('asuka', boards)
459 self.assertIn('link', boards)
460
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700461 def testNewBuildWithNonExistingBoardFamilies(self):
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700462 """Test the new_build suite with an non-existing board family."""
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700463 nyan_suite = 'FakeNonExistBoardFamiliesNewBuildTask'
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700464 self.fake_config.add_section(nyan_suite)
465 self.fake_config.set(nyan_suite, 'run_on', 'new_build')
466 self.fake_config.set(nyan_suite, 'suite', 'fake_suite_base')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700467 self.fake_config.set(nyan_suite, 'board_families', 'nyan')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700468 self._mock_config_reader.return_value = self.fake_config
469
470 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
471 suite_trigger = trigger_receiver.TriggerReceiver()
472 suite_trigger.cron()
473
474 self.assertEqual(len(suite_trigger.event_results), 1)
475 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
476 self.assertEqual(len(tasks), 0)
477
478 def testNewBuildWithNonSpecifiedBoardFamily(self):
479 """Test the new_build suite with an non-specified board family."""
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700480 normal_suite = 'FakeBoardFamiliesNewBuildTask'
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700481 self.fake_config.add_section(normal_suite)
482 self.fake_config.set(normal_suite, 'run_on', 'new_build')
483 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700484 self.fake_config.set(normal_suite, 'boards', 'link, zako')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700485 self._mock_config_reader.return_value = self.fake_config
486
487 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
488 suite_trigger = trigger_receiver.TriggerReceiver()
489 suite_trigger.cron()
490
491 self.assertEqual(len(suite_trigger.event_results), 1)
492 self.assertEqual(suite_trigger.event_results['new_build'],
493 [normal_suite])
494 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000495 self.assertEqual(len(tasks), 2)
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700496
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700497 def testNewBuildExcludingExistingBoardFamilies(self):
498 """Test the new_build suite excluding an existing board family."""
499 link_suite = 'FakeLinkNewBuildTask'
500 self.fake_config.add_section(link_suite)
501 self.fake_config.set(link_suite, 'run_on', 'new_build')
502 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
503 self.fake_config.set(link_suite, 'exclude_board_families', 'ivybridge')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700504 self.fake_config.set(link_suite, 'boards', 'link, zako')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700505 self._mock_config_reader.return_value = self.fake_config
506
507 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
508 suite_trigger = trigger_receiver.TriggerReceiver()
509 suite_trigger.cron()
510
511 self.assertEqual(len(suite_trigger.event_results), 1)
512 self.assertEqual(suite_trigger.event_results['new_build'],
513 [link_suite])
514 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
515 self.assertEqual(len(tasks), 1)
516 self.assertNotIn('link-release', tasks[0].payload)
517 self.assertIn('zako-release', tasks[0].payload)
518
519 def testNewBuildExcludingExistingBoardFamiliesAndBoards(self):
520 """Test the new_build suite with an existing board family."""
521 link_suite = 'FakeLinkNewBuildTask'
522 self.fake_config.add_section(link_suite)
523 self.fake_config.set(link_suite, 'run_on', 'new_build')
524 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
525 self.fake_config.set(link_suite, 'exclude_board_families', 'ivybridge')
Xixuan Wua41efa22019-05-17 14:28:04 -0700526 self.fake_config.set(link_suite, 'exclude_boards',
Xinan Lin09a628a2019-11-01 17:20:27 -0700527 'asuka, paine, banon, coral, reef, nami, samus-kernelnext')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700528 self._mock_config_reader.return_value = self.fake_config
529
530 suite_trigger = trigger_receiver.TriggerReceiver()
531 suite_trigger.cron()
532
533 self.assertEqual(len(suite_trigger.event_results), 1)
534 self.assertEqual(suite_trigger.event_results['new_build'],
535 [link_suite])
536 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
537 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
Xinan Lin09a628a2019-11-01 17:20:27 -0700538 self.assertEqual(len(tasks), 1)
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700539 self.assertNotIn('link-release', tasks[0].payload)
540 self.assertNotIn('asuka-release', tasks[0].payload)
541 self.assertIn('zako-release', tasks[0].payload)
542
543 def testNewBuildExcludingNonExistingBoardFamilies(self):
544 """Test the new_build suite excluding an non-existing board family."""
545 nyan_suite = 'FakeNonExistExcludeBoardFamiliesNewBuildTask'
546 self.fake_config.add_section(nyan_suite)
547 self.fake_config.set(nyan_suite, 'run_on', 'new_build')
548 self.fake_config.set(nyan_suite, 'suite', 'fake_suite_base')
549 self.fake_config.set(nyan_suite, 'exclude_board_families', 'nyan')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700550 self.fake_config.set(nyan_suite, 'boards', 'link, zako')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700551 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 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
559 self.assertEqual(len(tasks), 2)
560
561 def testNewBuildWithBoardExcludeBoardCollision(self):
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700562 """Test the case that the same board in boards and exclude_boards."""
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700563 normal_suite = 'FakeBoardExludingBoardCollisionNewBuildTask'
564 self.fake_config.add_section(normal_suite)
565 self.fake_config.set(normal_suite, 'run_on', 'new_build')
566 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
567 self.fake_config.set(normal_suite, 'boards', 'zako, asuka')
568 self.fake_config.set(normal_suite, 'exclude_boards', 'asuka')
569 self._mock_config_reader.return_value = self.fake_config
570
571 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
572 suite_trigger = trigger_receiver.TriggerReceiver()
573 suite_trigger.cron()
574
575 self.assertEqual(len(suite_trigger.event_results), 1)
576 self.assertEqual(suite_trigger.event_results['new_build'],
577 [normal_suite])
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700578 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
579 self.assertEqual(len(tasks), 1)
580 self.assertNotIn('asuka-release', tasks[0].payload)
581 self.assertIn('zako-release', tasks[0].payload)
582
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700583 def testNewBuildWithSkylab(self):
584 """Test the case that suites run in skylab."""
585 normal_suite = 'FakeSkylabSuite'
586 self.fake_config.add_section(normal_suite)
587 self.fake_config.set(normal_suite, 'run_on', 'new_build')
588 self.fake_config.set(normal_suite, 'suite', 'ent-nightly')
Xixuan Wu1e42c752019-03-21 13:41:49 -0700589 self.fake_config.set(normal_suite, 'pool', 'suites')
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700590 self.fake_config.set(normal_suite, 'boards', 'zako, asuka')
591 self._mock_config_reader.return_value = self.fake_config
592
593 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
594 suite_trigger = trigger_receiver.TriggerReceiver()
595 suite_trigger.cron()
596
597 self.assertEqual(len(suite_trigger.event_results), 1)
598 self.assertEqual(suite_trigger.event_results['new_build'],
599 [normal_suite])
600 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
601 self.assertEqual(len(tasks), 1)
602 self.assertIn('is_skylab=True', tasks[0].payload)
Xixuan Wu028f6732019-04-11 14:47:42 -0700603 self.assertIn('override_pool=QUOTA_POOL', tasks[0].payload)
604 self.assertIn('override_qs_account=QUOTA_ACCOUNT', tasks[0].payload)
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700605
Xixuan Wub4b2f412019-05-03 11:22:31 -0700606 def testNewBuildWithKernelnext(self):
607 """Test the case that suites run with board-kernelnext build."""
608 normal_suite = 'FakeKernelnextSuite'
609 self.fake_config.add_section(normal_suite)
610 self.fake_config.set(normal_suite, 'run_on', 'new_build')
611 self.fake_config.set(normal_suite, 'suite', 'fake-suite')
612 self.fake_config.set(normal_suite, 'pool', 'suites')
613 self.fake_config.set(normal_suite, 'boards', 'samus-kernelnext')
614 self._mock_config_reader.return_value = self.fake_config
615
Xixuan Wub4b2f412019-05-03 11:22:31 -0700616 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
617 suite_trigger = trigger_receiver.TriggerReceiver()
618 suite_trigger.cron()
619
620 self.assertEqual(len(suite_trigger.event_results), 1)
621 self.assertEqual(suite_trigger.event_results['new_build'],
622 [normal_suite])
623 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
624 self.assertEqual(len(tasks), 1)
625 # Board should be 'samus'.
626 self.assertIn('&board=samus&', tasks[0].payload)
627 # Build should be 'samus-kernelnext-release***'.
628 self.assertIn('cros_version=samus-kernelnext-release', tasks[0].payload)
629
Xixuan Wua41efa22019-05-17 14:28:04 -0700630 def testNewBuildWithModels(self):
631 """Test the new_build suite with an existing models entry."""
632 normal_suite = 'FakeModelsNewBuildTask'
633 self.fake_config.add_section(normal_suite)
634 self.fake_config.set(normal_suite, 'run_on', 'new_build')
635 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
636 self.fake_config.set(normal_suite, 'models', 'coral_lava, coral_santa')
637 self.fake_config.set(normal_suite, 'boards', 'coral')
638 self._mock_config_reader.return_value = self.fake_config
639
640 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
641 suite_trigger = trigger_receiver.TriggerReceiver()
642 suite_trigger.cron()
643
644 self.assertEqual(len(suite_trigger.event_results), 1)
645 self.assertEqual(suite_trigger.event_results['new_build'],
646 [normal_suite])
647 self.assertIn('new_build', suite_trigger.event_results)
648 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
649 self.assertEqual(len(tasks), 1)
650 self.assertNotIn('model=astronaut', tasks[0].payload)
651 self.assertIn('model=santa', tasks[0].payload)
652
Xinan Linae7d6372019-09-12 14:42:10 -0700653 def testNewBuildWithModelsForHWTestSanityRequired(self):
654 """Test the new_build suite with an existing models entry."""
655 normal_suite = 'FakeModelsNewBuildTask'
656 self.fake_config.add_section(normal_suite)
657 self.fake_config.set(normal_suite, 'run_on', 'new_build')
658 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
659 self.fake_config.set(normal_suite, 'models', 'nami_akali, nami_bard')
660 self.fake_config.set(normal_suite, 'boards', 'nami')
661 self.fake_config.set(normal_suite, 'only_hwtest_sanity_required', 'True')
662 self._mock_config_reader.return_value = self.fake_config
663
664 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
665 suite_trigger = trigger_receiver.TriggerReceiver()
666 suite_trigger.cron()
667
668 self.assertEqual(len(suite_trigger.event_results), 1)
669 self.assertEqual(suite_trigger.event_results['new_build'],
670 [normal_suite])
671 self.assertIn('new_build', suite_trigger.event_results)
672 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
673 self.assertEqual(len(tasks), 2)
674 self.assertIn('model=akali', tasks[0].payload)
675 self.assertIn('9868.0.0', tasks[0].payload)
676 self.assertIn('model=bard', tasks[1].payload)
677 self.assertIn('9867.0.0', tasks[1].payload)
678
Xixuan Wua41efa22019-05-17 14:28:04 -0700679 def testNewBuildWithExcludeModels(self):
680 """Test the new_build suite with an existing exclude_models entry."""
681 normal_suite = 'FakeExludingModelsNewBuildTask'
682 self.fake_config.add_section(normal_suite)
683 self.fake_config.set(normal_suite, 'run_on', 'new_build')
684 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
685 self.fake_config.set(normal_suite, 'exclude_models',
686 'coral_lava, coral_santa')
687 self.fake_config.set(normal_suite, 'boards', 'coral')
688 self._mock_config_reader.return_value = self.fake_config
689
690 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
691 suite_trigger = trigger_receiver.TriggerReceiver()
692 suite_trigger.cron()
693
694 self.assertEqual(len(suite_trigger.event_results), 1)
695 self.assertEqual(suite_trigger.event_results['new_build'],
696 [normal_suite])
697 self.assertIn('new_build', suite_trigger.event_results)
698 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
699 self.assertEqual(len(tasks), 1)
700 self.assertNotIn('model=santa', tasks[0].payload)
701 self.assertIn('model=astronaut', tasks[0].payload)
702
703 def testNewBuildWithModelsExcludeModels(self):
704 """Test the new_build suite with models and exclude_models entry."""
705 normal_suite = 'FakeModelsExcludeModelsNewBuildTask'
706 self.fake_config.add_section(normal_suite)
707 self.fake_config.set(normal_suite, 'run_on', 'new_build')
708 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
709 self.fake_config.set(normal_suite, 'models', 'coral_santa, coral_astronaut')
710 self.fake_config.set(normal_suite, 'exclude_models',
711 'coral_lava, coral_santa')
712 self.fake_config.set(normal_suite, 'boards', 'coral')
713 self._mock_config_reader.return_value = self.fake_config
714
715 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
716 suite_trigger = trigger_receiver.TriggerReceiver()
717 suite_trigger.cron()
718
719 self.assertEqual(len(suite_trigger.event_results), 1)
720 self.assertEqual(suite_trigger.event_results['new_build'],
721 [normal_suite])
722 self.assertIn('new_build', suite_trigger.event_results)
723 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
724 self.assertEqual(len(tasks), 1)
725 self.assertNotIn('model=santa', tasks[0].payload)
726 self.assertIn('model=astronaut', tasks[0].payload)
727
728 def testNewBuildWithNoModelListAndModelBuild(self):
729 """Test the new_build suite with models and empty board_model mapping."""
730 normal_suite = 'FakeModelsExcludeModelsNewBuildTask'
731 self.fake_config.add_section(normal_suite)
732 self.fake_config.set(normal_suite, 'run_on', 'new_build')
733 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
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 self.assertIn('new_build', suite_trigger.event_results)
742 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
743 # Verify that coral-release is not kicked off on model lava as lava is not
744 # listed in cros_model_map.
745 self.assertEqual(len(tasks), 2)
746 self.assertNotIn('lava', tasks[0].payload)
747 self.assertNotIn('lava', tasks[1].payload)
748
749 def testNewBuildWithNoModelListAndNoModelBuild(self):
750 """Test the new_build suite with models and empty board_model mapping."""
751 normal_suite = 'FakeModelsExcludeModelsNewBuildTask'
752 self.fake_config.add_section(normal_suite)
753 self.fake_config.set(normal_suite, 'run_on', 'new_build')
754 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
755 self.fake_config.set(normal_suite, 'boards', 'reef')
756 self._mock_config_reader.return_value = self.fake_config
757
758 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
759 suite_trigger = trigger_receiver.TriggerReceiver()
760 suite_trigger.cron()
761
762 self.assertIn('new_build', suite_trigger.event_results)
763 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
764 # Verify that reef-release is kicked off on reef models.
765 self.assertEqual(len(tasks), 1)
766 self.assertIn('model=electro', tasks[0].payload)
767
C Shapiro09108252019-08-01 14:52:52 -0500768 def testNewBuildWithAnyModel(self):
769 """Test the new_build suite with any_model option set."""
770 normal_suite = 'FakeAnyModelNewBuildTask'
771 self.fake_config.add_section(normal_suite)
772 self.fake_config.set(normal_suite, 'run_on', 'new_build')
773 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
774 self.fake_config.set(normal_suite, 'any_model', 'True')
775 self.fake_config.set(normal_suite, 'boards', 'coral')
776 self._mock_config_reader.return_value = self.fake_config
777
778 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
779 suite_trigger = trigger_receiver.TriggerReceiver()
780 suite_trigger.cron()
781
782 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
783 self.assertEqual(len(tasks), 1)
784 self.assertIn('model=None', tasks[0].payload)
785
Craig Bergstrom58263d32018-04-26 14:11:35 -0600786
Xixuan Wu008ee832017-10-12 16:59:34 -0700787class TriggerReceiverRealConfigTestCase(TriggerReceiverBaseTestCase):
788
789 def setUp(self):
790 super(TriggerReceiverRealConfigTestCase, self).setUp()
791 mock_config_reader = mock.patch('config_reader.ConfigReader')
792 self._mock_config_reader = mock_config_reader.start()
793 self.addCleanup(mock_config_reader.stop)
794 self._mock_config_reader.return_value = _SUITE_CONFIG_READER
795
796 def _get_ground_truth_task_list_from_config(self):
797 """Get the ground truth of to-be-scheduled task list from config file."""
798 self._mock_utc_now.return_value = datetime.datetime.now(
799 time_converter.UTC_TZ)
Xixuan Wu51bb7102019-03-18 14:51:44 -0700800 task_config = task_config_reader.TaskConfig(_SUITE_CONFIG_READER)
Xixuan Wu008ee832017-10-12 16:59:34 -0700801 tasks = {}
Xixuan Wu51bb7102019-03-18 14:51:44 -0700802 for keyword, klass in task_config_reader.EVENT_CLASSES.iteritems():
Xixuan Wu008ee832017-10-12 16:59:34 -0700803 new_event = klass(
804 task_config.get_event_setting(klass.section_name()), None)
805 new_event.set_task_list(
806 task_config.get_tasks_by_keyword(klass.KEYWORD)['tasks'])
807 tasks[keyword] = new_event.task_list
808
809 return tasks
810
Xixuan Wu40998892017-08-29 14:32:26 -0700811 def testCronWithoutLastExec(self):
812 """Test the first round of cron can be successfully executed."""
813 self._mock_utc_now.return_value = datetime.datetime.now(
814 time_converter.UTC_TZ)
815 suite_trigger = trigger_receiver.TriggerReceiver()
816 suite_trigger.cron()
817 self.assertFalse(suite_trigger.events['nightly'].should_handle)
818 self.assertFalse(suite_trigger.events['weekly'].should_handle)
819 self.assertFalse(suite_trigger.events['new_build'].should_handle)
820
821 self.assertEqual(suite_trigger.event_results, {})
822
823 def testCronTriggerNightly(self):
824 """Test nightly event is read with available nightly last_exec_time."""
825 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
826 last_exec_client = datastore_client.LastExecutionRecordStore()
827 last_exec_client.set_last_execute_time(
828 'nightly', utc_now - datetime.timedelta(hours=1))
829 self._mock_utc_now.return_value = utc_now
830 suite_trigger = trigger_receiver.TriggerReceiver()
831 self.assertTrue(suite_trigger.events['nightly'].should_handle)
832 self.assertFalse(suite_trigger.events['weekly'].should_handle)
833 self.assertFalse(suite_trigger.events['new_build'].should_handle)
834
Xixuan Wu33179672017-09-12 11:44:04 -0700835 def testCronTriggerNightlyOutdated(self):
836 """Test nightly event is read with available nightly last_exec_time."""
837 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
838 last_exec_client = datastore_client.LastExecutionRecordStore()
839 last_exec_client.set_last_execute_time(
840 'nightly', utc_now - datetime.timedelta(days=3))
841 self._mock_utc_now.return_value = utc_now
842 suite_trigger = trigger_receiver.TriggerReceiver()
843 self.assertFalse(suite_trigger.events['nightly'].should_handle)
844
845 def testCronTriggerWeeklyOutdated(self):
846 """Test weekly event is read with available weekly last_exec_time."""
847 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
848 last_exec_client = datastore_client.LastExecutionRecordStore()
849 last_exec_client.set_last_execute_time(
850 'weekly', utc_now - datetime.timedelta(days=8))
851 self._mock_utc_now.return_value = utc_now
852 suite_trigger = trigger_receiver.TriggerReceiver()
853 self.assertFalse(suite_trigger.events['weekly'].should_handle)
854
Xixuan Wu40998892017-08-29 14:32:26 -0700855 def testCronForWeeks(self):
856 """Ensure cron job can be successfully scheduled for several weeks."""
Xixuan Wu008ee832017-10-12 16:59:34 -0700857 all_tasks = self._get_ground_truth_task_list_from_config()
Xixuan Wu40998892017-08-29 14:32:26 -0700858 last_now = None
859
860 for now in now_generator(datetime.datetime.now(time_converter.UTC_TZ)):
861 self._mock_utc_now.return_value = now
862 suite_trigger = trigger_receiver.TriggerReceiver()
Xixuan Wu5451a662017-10-17 10:57:40 -0700863 with mock.patch('task.Task.schedule', return_value=True):
864 suite_trigger.cron()
Xixuan Wu40998892017-08-29 14:32:26 -0700865
Xixuan Wu40998892017-08-29 14:32:26 -0700866 should_scheduled_nightly_tasks = [
Xixuan Wu09962902018-12-11 10:49:27 -0800867 t.name for t in all_tasks['nightly'] if t.hour == now.hour]
Xixuan Wu008ee832017-10-12 16:59:34 -0700868
Xixuan Wu09962902018-12-11 10:49:27 -0800869 if (_should_schedule_timed_task(last_now, now) and
Xixuan Wu40998892017-08-29 14:32:26 -0700870 should_scheduled_nightly_tasks):
871 self.assertEqual(suite_trigger.event_results['nightly'],
872 should_scheduled_nightly_tasks)
873 else:
874 self.assertNotIn('nightly', suite_trigger.event_results.keys())
875
876 # Verify weekly tasks
877 should_scheduled_weekly_tasks = [
878 t.name for t in all_tasks['weekly']
Xixuan Wu09962902018-12-11 10:49:27 -0800879 if now.weekday() == t.day and now.hour == t.hour]
880 if (_should_schedule_timed_task(last_now, now) and
Xixuan Wu40998892017-08-29 14:32:26 -0700881 should_scheduled_weekly_tasks):
882 self.assertEqual(suite_trigger.event_results['weekly'],
883 should_scheduled_weekly_tasks)
884 else:
885 self.assertNotIn('weekly', suite_trigger.event_results.keys())
886
887 # Verify new_build tasks
888 should_scheduled_new_build_tasks = [
889 t.name for t in all_tasks['new_build']]
890 if (_should_schedule_new_build_task(last_now, now) and
891 should_scheduled_new_build_tasks):
892 self.assertEqual(suite_trigger.event_results['new_build'],
893 should_scheduled_new_build_tasks)
894 else:
895 self.assertNotIn('new_build', suite_trigger.event_results.keys())
896
897 last_now = now
898
899
900if __name__ == '__main__':
901 unittest.main()