blob: 7aecfc996b8be0aa2eaa4a3a545a8678217bbb29 [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 Linea1efcb2019-12-30 23:46:42 -080097 def get_passed_builds(self, earliest, latest):
98 """Mock get_passed_builds."""
99 del earliest # unused
100 del latest # unused
Xixuan Wuc6819012019-05-23 11:34:59 -0700101 return [
102 build_lib.BuildInfo(
103 'link', None, '62', '9868.0.0', 'link-release'),
104 build_lib.BuildInfo(
105 'zako', None, '62', '9868.0.0', 'zako-release'),
106 build_lib.BuildInfo('samus-kernelnext', None, '62',
107 '9868.0.0', 'samus-kernelnext-release'),
108 build_lib.BuildInfo(
109 'reef', None, '62', '1234.0.0', 'reef-release'),
110 build_lib.BuildInfo(
111 'coral', 'santa', '62', '9868.0.0', 'coral-release'),
112 build_lib.BuildInfo(
113 'coral', 'astronaut', '62', '9868.0.0', 'coral-release'),
114 build_lib.BuildInfo(
115 'coral', 'lava', '62', '9868.0.0', 'coral-release'),
116 ]
117
118 def get_latest_passed_builds(self, build_config):
Xixuan Wu6ec23e32019-05-23 11:56:02 -0700119 """Mock get_latest_passed_builds."""
Xixuan Wuc6819012019-05-23 11:34:59 -0700120 del build_config # unused
121 return build_lib.BuildInfo('link', '62', '9868.0.0', build_config)
122
Xinan Linea1efcb2019-12-30 23:46:42 -0800123 def get_relaxed_passed_builds(self, earliest, latest):
124 """Mock get_relaxed_pased_builds."""
125 del earliest # unused
126 del latest # unused
Xinan Linae7d6372019-09-12 14:42:10 -0700127 return [
128 build_lib.BuildInfo('grunt', None, '63', '9968.0.0', 'grunt-release'),
129 build_lib.BuildInfo('nami', None, '62', '9867.0.0', 'nami-release'),
130 build_lib.BuildInfo('nami', 'akali', '62', '9868.0.0', 'nami-release'),
131 build_lib.BuildInfo('nami', 'bard', '62', '9866.0.0', 'nami-release'),
132 ]
Xixuan Wuc6819012019-05-23 11:34:59 -0700133
Xinan Lin028f9582019-12-11 10:55:33 -0800134 def get_latest_passed_firmware_builds(self):
135 """Mock get_passed_firmware_builds."""
Xinan Lin8b291982019-12-16 10:03:56 -0800136 self.firmware_builds_called += 1
Xinan Lin028f9582019-12-11 10:55:33 -0800137 return [
138 ['cros', 'fake_board', ('gs://chromeos-image-archive/'
139 'fake_board-release/R30-6182.0.0-rc2/'
140 'fake_board')],
141 ['firmware', 'fake_board', ('gs://chromeos-image-archive/'
142 'firmware-fake_board-12345.67.'
143 'A-firmwarebranch/RFoo-1.0.0-b1e234567')],
Xinan Lin8b291982019-12-16 10:03:56 -0800144 ['firmware', 'zako', ('gs://chromeos-image-archive/'
145 'firmware-zako-12345.67.'
146 'A-firmwarebranch/RFoo-1.0.0-b1e234567')],
Xinan Lin028f9582019-12-11 10:55:33 -0800147 ]
148
Xixuan Wuc6819012019-05-23 11:34:59 -0700149
Xixuan Wu40998892017-08-29 14:32:26 -0700150class FakeAndroidBuildRestClient(object):
151 """Mock rest_client.AndroidBuildRestClient."""
152
153 def get_latest_build_id(self, branch, target):
154 """Mock rest_client.AndroidBuildRestClient.get_latest_build_id."""
155 del branch, target # unused
156 return '100'
157
158
159class FakeLabConfig(object):
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700160 """Mock config_reader.LabConfig."""
Xixuan Wu40998892017-08-29 14:32:26 -0700161
162 def get_android_board_list(self):
163 """Mock config_reader.LabConfig.get_android_board_list."""
164 return ('android-angler', 'android-bullhead')
165
Xixuan Wu6fb16272017-10-19 13:16:00 -0700166 def get_cros_board_list(self):
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700167 """Mock config_reader.LabConfig.get_cros_board_list."""
Xixuan Wua41efa22019-05-17 14:28:04 -0700168 return ('grunt', 'link', 'peppy', 'daisy', 'zako', 'samus-kernelnext',
Xinan Linae7d6372019-09-12 14:42:10 -0700169 'coral', 'reef', 'nami')
Xixuan Wu6fb16272017-10-19 13:16:00 -0700170
Xixuan Wu40998892017-08-29 14:32:26 -0700171 def get_firmware_ro_build_list(self, release_board):
172 """Mock config_reader.LabConfig.get_firmware_ro_build_list."""
173 del release_board # unused
174 return 'firmware1,firmware2'
175
C Shapiro7f24a002017-12-05 14:25:09 -0700176 def get_cros_model_map(self):
177 """Mock config_reader.LabConfig.get_cros_model_map."""
Xixuan Wua41efa22019-05-17 14:28:04 -0700178 return {
179 'coral': ['santa', 'astronaut'],
180 'reef': ['electro'],
Xinan Linae7d6372019-09-12 14:42:10 -0700181 'nami': ['akali', 'bard'],
Xixuan Wua41efa22019-05-17 14:28:04 -0700182 }
C Shapiro7f24a002017-12-05 14:25:09 -0700183
Xixuan Wu40998892017-08-29 14:32:26 -0700184
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700185class FakeMigrationConfig(object):
186 """Mock config_reader.MigrationConfig."""
187
Xixuan Wu1e42c752019-03-21 13:41:49 -0700188 def get_skylab_suites_dump(self):
Xixuan Wuee6b6a82019-03-21 14:28:26 -0700189 """Mock config_reader.MigrationConfig.get_skylab_suite_list."""
Xixuan Wu1e42c752019-03-21 13:41:49 -0700190 return {'suite:ent-nightly':
191 {'pool:suites':
Xixuan Wu028f6732019-04-11 14:47:42 -0700192 {'model:santa': {
193 'skylab': True,
194 'override_pool': '',
195 'override_qs_account': '',
196 },
197 'model:zako': {
198 'skylab': True,
199 'override_pool': 'QUOTA_POOL',
200 'override_qs_account': 'QUOTA_ACCOUNT',
201 }}}}
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700202
203
Xixuan Wu008ee832017-10-12 16:59:34 -0700204class TriggerReceiverBaseTestCase(unittest.TestCase):
Xixuan Wu40998892017-08-29 14:32:26 -0700205
206 def setUp(self):
207 self.testbed = testbed.Testbed()
208 self.testbed.activate()
209 self.addCleanup(self.testbed.deactivate)
210
211 self.testbed.init_datastore_v3_stub()
212 self.testbed.init_memcache_stub()
213 ndb.get_context().clear_cache()
214 self.testbed.init_taskqueue_stub(
215 root_path=os.path.join(os.path.dirname(__file__)))
216 self.taskqueue_stub = self.testbed.get_stub(
217 testbed.TASKQUEUE_SERVICE_NAME)
218
Xixuan Wuc6819012019-05-23 11:34:59 -0700219 mock_build_client = mock.patch('rest_client.BuildBucketBigqueryClient')
220 self._mock_build_client = mock_build_client.start()
221 self.addCleanup(mock_build_client.stop)
222
Xixuan Wu40998892017-08-29 14:32:26 -0700223 mock_android_client = mock.patch('rest_client.AndroidBuildRestClient')
224 self._mock_android_client = mock_android_client.start()
225 self.addCleanup(mock_android_client.stop)
226
Xixuan Wu40998892017-08-29 14:32:26 -0700227 mock_lab_config = mock.patch('config_reader.LabConfig')
228 self._mock_lab_config = mock_lab_config.start()
229 self.addCleanup(mock_lab_config.stop)
230
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700231 mock_migration_config = mock.patch('config_reader.MigrationConfig')
232 self._mock_migration_config = mock_migration_config.start()
233 self.addCleanup(mock_migration_config.stop)
234
Xixuan Wu40998892017-08-29 14:32:26 -0700235 mock_utc_now = mock.patch('time_converter.utc_now')
236 self._mock_utc_now = mock_utc_now.start()
237 self.addCleanup(mock_utc_now.stop)
238
Xixuan Wuc6819012019-05-23 11:34:59 -0700239 self._mock_build_client.return_value = FakeBuildClient()
Xixuan Wu40998892017-08-29 14:32:26 -0700240 self._mock_android_client.return_value = FakeAndroidBuildRestClient()
Xixuan Wu40998892017-08-29 14:32:26 -0700241 self._mock_lab_config.return_value = FakeLabConfig()
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700242 self._mock_migration_config.return_value = FakeMigrationConfig()
Xixuan Wu40998892017-08-29 14:32:26 -0700243
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700244 board_family_patcher = mock.patch(
245 'build_lib.get_board_family_mapping_from_gs')
246 board_family_getter = board_family_patcher.start()
247 board_family_getter.return_value = {
248 'nyan': ['nyan', 'nyan_blaze', 'nyan_big'],
249 'ivybridge': ['link', 'link_freon']}
250 self.addCleanup(board_family_patcher.stop)
251
Xixuan Wu008ee832017-10-12 16:59:34 -0700252
253class TriggerReceiverFakeConfigTestCase(TriggerReceiverBaseTestCase):
254
255 _TEST_PST_HOUR = 20
256 _TEST_PST_DAY = 4 # Friday
257 _TEST_EVENT_PST_HOUR = 13
258
259 _FAKE_NIGHTLY_TASK_NAME = 'fake_nightly_task'
260 _FAKE_WEEKLY_TASK_NAME = 'fake_weekly_task'
261
262 def setUp(self):
263 super(TriggerReceiverFakeConfigTestCase, self).setUp()
264
265 self.fake_config = config_reader.ConfigReader(None)
266 self._add_nightly_tasks(self.fake_config)
267 self._add_weekly_tasks(self.fake_config)
268
269 self.fake_config_with_settings = config_reader.ConfigReader(None)
270 self._add_weekly_tasks(self.fake_config_with_settings)
271 self._add_weekly_params(self.fake_config_with_settings)
272
273 mock_config_reader = mock.patch('config_reader.ConfigReader')
274 self._mock_config_reader = mock_config_reader.start()
275 self.addCleanup(mock_config_reader.stop)
276
277 def _add_nightly_tasks(self, fake_config):
278 fake_config.add_section(self._FAKE_NIGHTLY_TASK_NAME)
279 fake_config.set(self._FAKE_NIGHTLY_TASK_NAME, 'suite', 'fake_suite')
280 fake_config.set(self._FAKE_NIGHTLY_TASK_NAME, 'run_on', 'nightly')
281 fake_config.set(self._FAKE_NIGHTLY_TASK_NAME, 'hour',
282 str(self._TEST_PST_HOUR))
283
284 def _add_weekly_tasks(self, fake_config):
285 fake_config.add_section(self._FAKE_WEEKLY_TASK_NAME)
286 fake_config.set(self._FAKE_WEEKLY_TASK_NAME, 'suite', 'fake_suite')
287 fake_config.set(self._FAKE_WEEKLY_TASK_NAME, 'run_on', 'weekly')
288 fake_config.set(self._FAKE_WEEKLY_TASK_NAME, 'day', str(self._TEST_PST_DAY))
289
290 def _add_weekly_params(self, fake_config):
Xixuan Wu51bb7102019-03-18 14:51:44 -0700291 weekly_section_name = task_config_reader.EVENT_CLASSES[
292 'weekly'].section_name()
Xixuan Wu008ee832017-10-12 16:59:34 -0700293 fake_config.add_section(weekly_section_name)
294 fake_config.set(weekly_section_name, 'hour', str(self._TEST_EVENT_PST_HOUR))
295
296 def testInitializeTriggerReceiverWithNightlyEvent(self):
297 """Test nightly event can be handled on right hour."""
298 # A task with hour=20 should be scheduled at 20:00 in PST everyday, which
299 # is 3:00/4:00 in UTC everyday.
300 self._mock_config_reader.return_value = self.fake_config
301 given_utc_hour = time_converter.convert_time_info(
302 time_converter.TimeInfo(None, self._TEST_PST_HOUR)).hour
303 utc_now = datetime.datetime(2017, 8, 6, given_utc_hour,
304 tzinfo=time_converter.UTC_TZ)
305 last_exec_client = datastore_client.LastExecutionRecordStore()
306 last_exec_client.set_last_execute_time(
307 'nightly', utc_now - datetime.timedelta(hours=1))
308 self._mock_utc_now.return_value = utc_now
309
310 suite_trigger = trigger_receiver.TriggerReceiver()
311 suite_trigger.cron()
312 self.assertTrue(suite_trigger.events['nightly'].should_handle)
313 self.assertEqual(len(suite_trigger.event_results['nightly']), 1)
314 self.assertEqual(suite_trigger.event_results['nightly'][0],
315 self._FAKE_NIGHTLY_TASK_NAME)
316
317 def testInitializeTriggerReceiverWithWeeklyEventWithoutEventHour(self):
318 """Test weekly event without event settings can be handled on right day."""
319 # A task with day=4 (Friday) and default event_hour (23) should be
320 # scheduled at Friday 23:00 in PST, which is Saturday 6:00 or 7:00 in UTC.
321 self._mock_config_reader.return_value = self.fake_config
322 given_utc_hour = time_converter.convert_time_info(
323 time_converter.TimeInfo(
324 self._TEST_PST_DAY,
Xixuan Wu51bb7102019-03-18 14:51:44 -0700325 task_config_reader.EVENT_CLASSES['weekly'].DEFAULT_PST_HOUR)).hour
Xixuan Wu008ee832017-10-12 16:59:34 -0700326 utc_now = datetime.datetime(2017, 10, 14, given_utc_hour,
327 tzinfo=time_converter.UTC_TZ)
328 last_exec_client = datastore_client.LastExecutionRecordStore()
329 last_exec_client.set_last_execute_time(
330 'weekly', utc_now - datetime.timedelta(days=1))
331 self._mock_utc_now.return_value = utc_now
332
333 suite_trigger = trigger_receiver.TriggerReceiver()
334 suite_trigger.cron()
335 self.assertTrue(suite_trigger.events['weekly'].should_handle)
336 self.assertEqual(len(suite_trigger.event_results['weekly']), 1)
337 self.assertEqual(suite_trigger.event_results['weekly'][0],
338 self._FAKE_WEEKLY_TASK_NAME)
339
340 def testInitializeTriggerReceiverWithWeeklyEventWithEventHour(self):
341 """Test weekly event with event settings can be handled on right day."""
342 # A task with day=4 (Friday) and event_hour=13 should be scheduled at
343 # Friday 13:00 in PST, which is Friday 20:00 or 21:00 in UTC.
344 self._mock_config_reader.return_value = self.fake_config_with_settings
345 given_utc_time_info = time_converter.convert_time_info(
346 time_converter.TimeInfo(self._TEST_PST_DAY, self._TEST_EVENT_PST_HOUR))
347
348 # Set the current time as a Friday 20:00 or 21:00 in UTC.
349 utc_now = datetime.datetime(2017, 10, 13, given_utc_time_info.hour,
350 tzinfo=time_converter.UTC_TZ)
351 last_exec_client = datastore_client.LastExecutionRecordStore()
352 last_exec_client.set_last_execute_time(
353 'weekly', utc_now - datetime.timedelta(days=1))
354 self._mock_utc_now.return_value = utc_now
355
356 suite_trigger = trigger_receiver.TriggerReceiver()
357 suite_trigger.cron()
358 self.assertTrue(suite_trigger.events['weekly'].should_handle)
359 self.assertEqual(len(suite_trigger.event_results['weekly']), 1)
360 self.assertEqual(suite_trigger.event_results['weekly'][0],
361 self._FAKE_WEEKLY_TASK_NAME)
362
363
Craig Bergstrom58263d32018-04-26 14:11:35 -0600364class TriggerReceiverFakeBuildTestCase(TriggerReceiverBaseTestCase):
365 """Test the new_build functionality."""
366
Craig Bergstrom58263d32018-04-26 14:11:35 -0600367 def setUp(self):
368 """Set up for a test."""
369 super(TriggerReceiverFakeBuildTestCase, self).setUp()
370
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700371 self._prepare()
372
373 def _prepare(self):
Craig Bergstrom58263d32018-04-26 14:11:35 -0600374 self.fake_config = config_reader.ConfigReader(None)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600375 mock_config_reader = mock.patch('config_reader.ConfigReader')
376 self._mock_config_reader = mock_config_reader.start()
377 self.addCleanup(mock_config_reader.stop)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600378
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700379 # Set last execution time for new_build events.
380 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600381 last_exec_client = datastore_client.LastExecutionRecordStore()
382 last_exec_client.set_last_execute_time(
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700383 'new_build', utc_now - datetime.timedelta(hours=1))
Craig Bergstrom58263d32018-04-26 14:11:35 -0600384 self._mock_utc_now.return_value = utc_now
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700385
386 def testNewBuildForHWTestSanityRequired(self):
387 """Test the new_build functionality."""
388 # Construct a fake config with only_hwtest_sanity_required.
389 fsnbt_name = 'FakeStrictNewBuildTask'
390 self.fake_config.add_section(fsnbt_name)
391 self.fake_config.set(fsnbt_name, 'run_on', 'new_build')
392 self.fake_config.set(fsnbt_name, 'suite', 'fake_suite_base')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700393 self.fake_config.set(fsnbt_name, 'boards', 'link, zako, grunt')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700394 frnbt_name = 'FakeRelaxedNewBuildTask'
395 self.fake_config.add_section(frnbt_name)
396 self.fake_config.set(frnbt_name, 'run_on', 'new_build')
397 self.fake_config.set(frnbt_name, 'suite', 'fake_suite_relaxed')
398 self.fake_config.set(frnbt_name, 'only_hwtest_sanity_required', 'True')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700399 self.fake_config.set(frnbt_name, 'boards', 'link, zako, grunt')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700400
401 self._mock_config_reader.return_value = self.fake_config
Craig Bergstrom58263d32018-04-26 14:11:35 -0600402
403 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600404 suite_trigger = trigger_receiver.TriggerReceiver()
405 suite_trigger.cron()
406
407 # Validate that the expected tests got kicked off.
Craig Bergstrom58263d32018-04-26 14:11:35 -0600408 self.assertEqual(len(suite_trigger.event_results), 1)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600409 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000410 # 2 for strict passed builds, 3 for relaxed builds.
411 self.assertEqual(len(tasks), 5)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600412
413 # The number of builds that matched the base (success) Task.
414 count_base = 0
415 # The number of builds that matched the relaxed Task.
416 count_relaxed = 0
417 for task in tasks:
418 if 'fake_suite_base' in task.payload:
419 # Make sure it matched the expected build only.
Craig Bergstrom58263d32018-04-26 14:11:35 -0600420 self.assertNotIn('grunt-release', task.payload)
421 count_base += 1
422
423 if 'fake_suite_relaxed' in task.payload:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600424 count_relaxed += 1
425
426 # Make each case matched precisely one event.
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000427 self.assertEqual(2, count_base)
428 self.assertEqual(3, count_relaxed)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600429
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700430 def testNewBuildWithExistingBoardFamilies(self):
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700431 """Test the new_build suite with an existing board family."""
432 link_suite = 'FakeLinkNewBuildTask'
433 self.fake_config.add_section(link_suite)
434 self.fake_config.set(link_suite, 'run_on', 'new_build')
435 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700436 self.fake_config.set(link_suite, 'board_families', 'ivybridge')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700437 self._mock_config_reader.return_value = self.fake_config
438
439 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
440 suite_trigger = trigger_receiver.TriggerReceiver()
441 suite_trigger.cron()
442
443 self.assertEqual(len(suite_trigger.event_results), 1)
444 self.assertEqual(suite_trigger.event_results['new_build'],
445 [link_suite])
446 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
447 self.assertEqual(len(tasks), 1)
448 self.assertIn('link-release', tasks[0].payload)
449
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700450 def testNewBuildWithExistingBoardFamiliesAndBoards(self):
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700451 """Test the new_build suite with an existing board family."""
452 link_suite = 'FakeLinkNewBuildTask'
453 self.fake_config.add_section(link_suite)
454 self.fake_config.set(link_suite, 'run_on', 'new_build')
455 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700456 self.fake_config.set(link_suite, 'board_families', 'ivybridge')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700457 self.fake_config.set(link_suite, 'boards', 'asuka, paine, banon')
458 self._mock_config_reader.return_value = self.fake_config
459
460 suite_trigger = trigger_receiver.TriggerReceiver()
461 suite_trigger.cron()
462
463 self.assertEqual(len(suite_trigger.event_results), 1)
464 self.assertEqual(suite_trigger.event_results['new_build'],
465 [link_suite])
466 boards = suite_trigger.events['new_build'].task_list[0].boards
467 self.assertIn('asuka', boards)
468 self.assertIn('link', boards)
469
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700470 def testNewBuildWithNonExistingBoardFamilies(self):
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700471 """Test the new_build suite with an non-existing board family."""
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700472 nyan_suite = 'FakeNonExistBoardFamiliesNewBuildTask'
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700473 self.fake_config.add_section(nyan_suite)
474 self.fake_config.set(nyan_suite, 'run_on', 'new_build')
475 self.fake_config.set(nyan_suite, 'suite', 'fake_suite_base')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700476 self.fake_config.set(nyan_suite, 'board_families', 'nyan')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700477 self._mock_config_reader.return_value = self.fake_config
478
479 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
480 suite_trigger = trigger_receiver.TriggerReceiver()
481 suite_trigger.cron()
482
483 self.assertEqual(len(suite_trigger.event_results), 1)
484 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
485 self.assertEqual(len(tasks), 0)
486
487 def testNewBuildWithNonSpecifiedBoardFamily(self):
488 """Test the new_build suite with an non-specified board family."""
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700489 normal_suite = 'FakeBoardFamiliesNewBuildTask'
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700490 self.fake_config.add_section(normal_suite)
491 self.fake_config.set(normal_suite, 'run_on', 'new_build')
492 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700493 self.fake_config.set(normal_suite, 'boards', 'link, zako')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700494 self._mock_config_reader.return_value = self.fake_config
495
496 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
497 suite_trigger = trigger_receiver.TriggerReceiver()
498 suite_trigger.cron()
499
500 self.assertEqual(len(suite_trigger.event_results), 1)
501 self.assertEqual(suite_trigger.event_results['new_build'],
502 [normal_suite])
503 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000504 self.assertEqual(len(tasks), 2)
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700505
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700506 def testNewBuildExcludingExistingBoardFamilies(self):
507 """Test the new_build suite excluding an existing board family."""
508 link_suite = 'FakeLinkNewBuildTask'
509 self.fake_config.add_section(link_suite)
510 self.fake_config.set(link_suite, 'run_on', 'new_build')
511 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
512 self.fake_config.set(link_suite, 'exclude_board_families', 'ivybridge')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700513 self.fake_config.set(link_suite, 'boards', 'link, zako')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700514 self._mock_config_reader.return_value = self.fake_config
515
516 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
517 suite_trigger = trigger_receiver.TriggerReceiver()
518 suite_trigger.cron()
519
520 self.assertEqual(len(suite_trigger.event_results), 1)
521 self.assertEqual(suite_trigger.event_results['new_build'],
522 [link_suite])
523 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
524 self.assertEqual(len(tasks), 1)
525 self.assertNotIn('link-release', tasks[0].payload)
526 self.assertIn('zako-release', tasks[0].payload)
527
528 def testNewBuildExcludingExistingBoardFamiliesAndBoards(self):
529 """Test the new_build suite with an existing board family."""
530 link_suite = 'FakeLinkNewBuildTask'
531 self.fake_config.add_section(link_suite)
532 self.fake_config.set(link_suite, 'run_on', 'new_build')
533 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
534 self.fake_config.set(link_suite, 'exclude_board_families', 'ivybridge')
Xixuan Wua41efa22019-05-17 14:28:04 -0700535 self.fake_config.set(link_suite, 'exclude_boards',
Xinan Lin09a628a2019-11-01 17:20:27 -0700536 'asuka, paine, banon, coral, reef, nami, samus-kernelnext')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700537 self._mock_config_reader.return_value = self.fake_config
538
539 suite_trigger = trigger_receiver.TriggerReceiver()
540 suite_trigger.cron()
541
542 self.assertEqual(len(suite_trigger.event_results), 1)
543 self.assertEqual(suite_trigger.event_results['new_build'],
544 [link_suite])
545 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
546 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
Xinan Lin09a628a2019-11-01 17:20:27 -0700547 self.assertEqual(len(tasks), 1)
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700548 self.assertNotIn('link-release', tasks[0].payload)
549 self.assertNotIn('asuka-release', tasks[0].payload)
550 self.assertIn('zako-release', tasks[0].payload)
551
552 def testNewBuildExcludingNonExistingBoardFamilies(self):
553 """Test the new_build suite excluding an non-existing board family."""
554 nyan_suite = 'FakeNonExistExcludeBoardFamiliesNewBuildTask'
555 self.fake_config.add_section(nyan_suite)
556 self.fake_config.set(nyan_suite, 'run_on', 'new_build')
557 self.fake_config.set(nyan_suite, 'suite', 'fake_suite_base')
558 self.fake_config.set(nyan_suite, 'exclude_board_families', 'nyan')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700559 self.fake_config.set(nyan_suite, 'boards', 'link, zako')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700560 self._mock_config_reader.return_value = self.fake_config
561
562 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
563 suite_trigger = trigger_receiver.TriggerReceiver()
564 suite_trigger.cron()
565
566 self.assertEqual(len(suite_trigger.event_results), 1)
567 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
568 self.assertEqual(len(tasks), 2)
569
570 def testNewBuildWithBoardExcludeBoardCollision(self):
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700571 """Test the case that the same board in boards and exclude_boards."""
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700572 normal_suite = 'FakeBoardExludingBoardCollisionNewBuildTask'
573 self.fake_config.add_section(normal_suite)
574 self.fake_config.set(normal_suite, 'run_on', 'new_build')
575 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
576 self.fake_config.set(normal_suite, 'boards', 'zako, asuka')
577 self.fake_config.set(normal_suite, 'exclude_boards', 'asuka')
578 self._mock_config_reader.return_value = self.fake_config
579
580 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
581 suite_trigger = trigger_receiver.TriggerReceiver()
582 suite_trigger.cron()
583
584 self.assertEqual(len(suite_trigger.event_results), 1)
585 self.assertEqual(suite_trigger.event_results['new_build'],
586 [normal_suite])
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700587 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
588 self.assertEqual(len(tasks), 1)
589 self.assertNotIn('asuka-release', tasks[0].payload)
590 self.assertIn('zako-release', tasks[0].payload)
591
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700592 def testNewBuildWithSkylab(self):
593 """Test the case that suites run in skylab."""
594 normal_suite = 'FakeSkylabSuite'
595 self.fake_config.add_section(normal_suite)
596 self.fake_config.set(normal_suite, 'run_on', 'new_build')
597 self.fake_config.set(normal_suite, 'suite', 'ent-nightly')
Xixuan Wu1e42c752019-03-21 13:41:49 -0700598 self.fake_config.set(normal_suite, 'pool', 'suites')
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700599 self.fake_config.set(normal_suite, 'boards', 'zako, asuka')
600 self._mock_config_reader.return_value = self.fake_config
601
602 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
603 suite_trigger = trigger_receiver.TriggerReceiver()
604 suite_trigger.cron()
605
606 self.assertEqual(len(suite_trigger.event_results), 1)
607 self.assertEqual(suite_trigger.event_results['new_build'],
608 [normal_suite])
609 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
610 self.assertEqual(len(tasks), 1)
611 self.assertIn('is_skylab=True', tasks[0].payload)
Xixuan Wu028f6732019-04-11 14:47:42 -0700612 self.assertIn('override_pool=QUOTA_POOL', tasks[0].payload)
613 self.assertIn('override_qs_account=QUOTA_ACCOUNT', tasks[0].payload)
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700614
Xixuan Wub4b2f412019-05-03 11:22:31 -0700615 def testNewBuildWithKernelnext(self):
616 """Test the case that suites run with board-kernelnext build."""
617 normal_suite = 'FakeKernelnextSuite'
618 self.fake_config.add_section(normal_suite)
619 self.fake_config.set(normal_suite, 'run_on', 'new_build')
620 self.fake_config.set(normal_suite, 'suite', 'fake-suite')
621 self.fake_config.set(normal_suite, 'pool', 'suites')
622 self.fake_config.set(normal_suite, 'boards', 'samus-kernelnext')
623 self._mock_config_reader.return_value = self.fake_config
624
Xixuan Wub4b2f412019-05-03 11:22:31 -0700625 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
626 suite_trigger = trigger_receiver.TriggerReceiver()
627 suite_trigger.cron()
628
629 self.assertEqual(len(suite_trigger.event_results), 1)
630 self.assertEqual(suite_trigger.event_results['new_build'],
631 [normal_suite])
632 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
633 self.assertEqual(len(tasks), 1)
634 # Board should be 'samus'.
635 self.assertIn('&board=samus&', tasks[0].payload)
636 # Build should be 'samus-kernelnext-release***'.
637 self.assertIn('cros_version=samus-kernelnext-release', tasks[0].payload)
638
Xixuan Wua41efa22019-05-17 14:28:04 -0700639 def testNewBuildWithModels(self):
640 """Test the new_build suite with an existing models entry."""
641 normal_suite = 'FakeModelsNewBuildTask'
642 self.fake_config.add_section(normal_suite)
643 self.fake_config.set(normal_suite, 'run_on', 'new_build')
644 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
645 self.fake_config.set(normal_suite, 'models', '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=astronaut', tasks[0].payload)
660 self.assertIn('model=santa', tasks[0].payload)
661
Xinan Linae7d6372019-09-12 14:42:10 -0700662 def testNewBuildWithModelsForHWTestSanityRequired(self):
663 """Test the new_build suite with an existing models entry."""
664 normal_suite = 'FakeModelsNewBuildTask'
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', 'nami_akali, nami_bard')
669 self.fake_config.set(normal_suite, 'boards', 'nami')
670 self.fake_config.set(normal_suite, 'only_hwtest_sanity_required', 'True')
671 self._mock_config_reader.return_value = self.fake_config
672
673 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
674 suite_trigger = trigger_receiver.TriggerReceiver()
675 suite_trigger.cron()
676
677 self.assertEqual(len(suite_trigger.event_results), 1)
678 self.assertEqual(suite_trigger.event_results['new_build'],
679 [normal_suite])
680 self.assertIn('new_build', suite_trigger.event_results)
681 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
682 self.assertEqual(len(tasks), 2)
683 self.assertIn('model=akali', tasks[0].payload)
684 self.assertIn('9868.0.0', tasks[0].payload)
685 self.assertIn('model=bard', tasks[1].payload)
686 self.assertIn('9867.0.0', tasks[1].payload)
687
Xixuan Wua41efa22019-05-17 14:28:04 -0700688 def testNewBuildWithExcludeModels(self):
689 """Test the new_build suite with an existing exclude_models entry."""
690 normal_suite = 'FakeExludingModelsNewBuildTask'
691 self.fake_config.add_section(normal_suite)
692 self.fake_config.set(normal_suite, 'run_on', 'new_build')
693 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
694 self.fake_config.set(normal_suite, 'exclude_models',
695 'coral_lava, coral_santa')
696 self.fake_config.set(normal_suite, 'boards', 'coral')
697 self._mock_config_reader.return_value = self.fake_config
698
699 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
700 suite_trigger = trigger_receiver.TriggerReceiver()
701 suite_trigger.cron()
702
703 self.assertEqual(len(suite_trigger.event_results), 1)
704 self.assertEqual(suite_trigger.event_results['new_build'],
705 [normal_suite])
706 self.assertIn('new_build', suite_trigger.event_results)
707 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
708 self.assertEqual(len(tasks), 1)
709 self.assertNotIn('model=santa', tasks[0].payload)
710 self.assertIn('model=astronaut', tasks[0].payload)
711
712 def testNewBuildWithModelsExcludeModels(self):
713 """Test the new_build suite with models and exclude_models entry."""
714 normal_suite = 'FakeModelsExcludeModelsNewBuildTask'
715 self.fake_config.add_section(normal_suite)
716 self.fake_config.set(normal_suite, 'run_on', 'new_build')
717 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
718 self.fake_config.set(normal_suite, 'models', 'coral_santa, coral_astronaut')
719 self.fake_config.set(normal_suite, 'exclude_models',
720 'coral_lava, coral_santa')
721 self.fake_config.set(normal_suite, 'boards', 'coral')
722 self._mock_config_reader.return_value = self.fake_config
723
724 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
725 suite_trigger = trigger_receiver.TriggerReceiver()
726 suite_trigger.cron()
727
728 self.assertEqual(len(suite_trigger.event_results), 1)
729 self.assertEqual(suite_trigger.event_results['new_build'],
730 [normal_suite])
731 self.assertIn('new_build', suite_trigger.event_results)
732 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
733 self.assertEqual(len(tasks), 1)
734 self.assertNotIn('model=santa', tasks[0].payload)
735 self.assertIn('model=astronaut', tasks[0].payload)
736
737 def testNewBuildWithNoModelListAndModelBuild(self):
738 """Test the new_build suite with models and empty board_model mapping."""
739 normal_suite = 'FakeModelsExcludeModelsNewBuildTask'
740 self.fake_config.add_section(normal_suite)
741 self.fake_config.set(normal_suite, 'run_on', 'new_build')
742 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
743 self.fake_config.set(normal_suite, 'boards', 'coral')
744 self._mock_config_reader.return_value = self.fake_config
745
746 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
747 suite_trigger = trigger_receiver.TriggerReceiver()
748 suite_trigger.cron()
749
750 self.assertIn('new_build', suite_trigger.event_results)
751 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
752 # Verify that coral-release is not kicked off on model lava as lava is not
753 # listed in cros_model_map.
754 self.assertEqual(len(tasks), 2)
755 self.assertNotIn('lava', tasks[0].payload)
756 self.assertNotIn('lava', tasks[1].payload)
757
758 def testNewBuildWithNoModelListAndNoModelBuild(self):
759 """Test the new_build suite with models and empty board_model mapping."""
760 normal_suite = 'FakeModelsExcludeModelsNewBuildTask'
761 self.fake_config.add_section(normal_suite)
762 self.fake_config.set(normal_suite, 'run_on', 'new_build')
763 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
764 self.fake_config.set(normal_suite, 'boards', 'reef')
765 self._mock_config_reader.return_value = self.fake_config
766
767 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
768 suite_trigger = trigger_receiver.TriggerReceiver()
769 suite_trigger.cron()
770
771 self.assertIn('new_build', suite_trigger.event_results)
772 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
773 # Verify that reef-release is kicked off on reef models.
774 self.assertEqual(len(tasks), 1)
775 self.assertIn('model=electro', tasks[0].payload)
776
C Shapiro09108252019-08-01 14:52:52 -0500777 def testNewBuildWithAnyModel(self):
778 """Test the new_build suite with any_model option set."""
779 normal_suite = 'FakeAnyModelNewBuildTask'
780 self.fake_config.add_section(normal_suite)
781 self.fake_config.set(normal_suite, 'run_on', 'new_build')
782 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
783 self.fake_config.set(normal_suite, 'any_model', 'True')
784 self.fake_config.set(normal_suite, 'boards', 'coral')
785 self._mock_config_reader.return_value = self.fake_config
786
787 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
788 suite_trigger = trigger_receiver.TriggerReceiver()
789 suite_trigger.cron()
790
791 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
792 self.assertEqual(len(tasks), 1)
793 self.assertIn('model=None', tasks[0].payload)
794
Xinan Lin8b291982019-12-16 10:03:56 -0800795 def testNewBuildWithFirmwareTask(self):
796 """Test the new_build suite with firmware option set."""
797 # Construct a fake config with firmware build.
798 fsnbt_name = 'FakeStrictNewBuildTask'
799 self.fake_config.add_section(fsnbt_name)
800 self.fake_config.set(fsnbt_name, 'run_on', 'new_build')
801 self.fake_config.set(fsnbt_name, 'suite', 'fake_suite_base')
802 self.fake_config.set(fsnbt_name, 'boards', 'zako')
803 self.fake_config.set(fsnbt_name, 'firmware_ro_build_spec', 'firmware')
804 self.fake_config.set(fsnbt_name, 'test_source', 'cros')
805 self._mock_config_reader.return_value = self.fake_config
806
807 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
808 suite_trigger = trigger_receiver.TriggerReceiver()
809 some_event = suite_trigger.events['new_build']
810 suite_trigger.cron()
811
812 # The firmware query has run for once.
813 self.assertEqual(suite_trigger._build_client.firmware_builds_called, 1)
814 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
815 self.assertEqual(len(tasks), 1)
816 self.assertIn('firmware-zako-12345.67', tasks[0].payload)
817
818
819 def testNewBuildWithoutFirmwareTask(self):
820 """Test the event skips fetch the firmware builds."""
821 # Construct a fake config without firmware build.
822 fsnbt_name = 'FakeStrictNewBuildTask'
823 self.fake_config.add_section(fsnbt_name)
824 self.fake_config.set(fsnbt_name, 'run_on', 'new_build')
825 self.fake_config.set(fsnbt_name, 'suite', 'fake_suite_base')
826 self.fake_config.set(fsnbt_name, 'boards', 'zako')
827 self._mock_config_reader.return_value = self.fake_config
828
829 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
830 suite_trigger = trigger_receiver.TriggerReceiver()
831 suite_trigger.cron()
832
833 # The firmware query was not called.
834 self.assertEqual(suite_trigger._build_client.firmware_builds_called, 0)
835 # Validate that the expected tests got kicked off.
836 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
837 self.assertEqual(len(tasks), 1)
838
Craig Bergstrom58263d32018-04-26 14:11:35 -0600839
Xixuan Wu008ee832017-10-12 16:59:34 -0700840class TriggerReceiverRealConfigTestCase(TriggerReceiverBaseTestCase):
841
842 def setUp(self):
843 super(TriggerReceiverRealConfigTestCase, self).setUp()
844 mock_config_reader = mock.patch('config_reader.ConfigReader')
845 self._mock_config_reader = mock_config_reader.start()
846 self.addCleanup(mock_config_reader.stop)
847 self._mock_config_reader.return_value = _SUITE_CONFIG_READER
848
849 def _get_ground_truth_task_list_from_config(self):
850 """Get the ground truth of to-be-scheduled task list from config file."""
851 self._mock_utc_now.return_value = datetime.datetime.now(
852 time_converter.UTC_TZ)
Xixuan Wu51bb7102019-03-18 14:51:44 -0700853 task_config = task_config_reader.TaskConfig(_SUITE_CONFIG_READER)
Xixuan Wu008ee832017-10-12 16:59:34 -0700854 tasks = {}
Xixuan Wu51bb7102019-03-18 14:51:44 -0700855 for keyword, klass in task_config_reader.EVENT_CLASSES.iteritems():
Xixuan Wu008ee832017-10-12 16:59:34 -0700856 new_event = klass(
857 task_config.get_event_setting(klass.section_name()), None)
858 new_event.set_task_list(
859 task_config.get_tasks_by_keyword(klass.KEYWORD)['tasks'])
860 tasks[keyword] = new_event.task_list
861
862 return tasks
863
Xixuan Wu40998892017-08-29 14:32:26 -0700864 def testCronWithoutLastExec(self):
865 """Test the first round of cron can be successfully executed."""
866 self._mock_utc_now.return_value = datetime.datetime.now(
867 time_converter.UTC_TZ)
868 suite_trigger = trigger_receiver.TriggerReceiver()
869 suite_trigger.cron()
870 self.assertFalse(suite_trigger.events['nightly'].should_handle)
871 self.assertFalse(suite_trigger.events['weekly'].should_handle)
872 self.assertFalse(suite_trigger.events['new_build'].should_handle)
873
874 self.assertEqual(suite_trigger.event_results, {})
875
876 def testCronTriggerNightly(self):
877 """Test nightly event is read with available nightly last_exec_time."""
878 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
879 last_exec_client = datastore_client.LastExecutionRecordStore()
880 last_exec_client.set_last_execute_time(
881 'nightly', utc_now - datetime.timedelta(hours=1))
882 self._mock_utc_now.return_value = utc_now
883 suite_trigger = trigger_receiver.TriggerReceiver()
884 self.assertTrue(suite_trigger.events['nightly'].should_handle)
885 self.assertFalse(suite_trigger.events['weekly'].should_handle)
886 self.assertFalse(suite_trigger.events['new_build'].should_handle)
887
Xixuan Wu33179672017-09-12 11:44:04 -0700888 def testCronTriggerNightlyOutdated(self):
889 """Test nightly event is read with available nightly last_exec_time."""
890 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
891 last_exec_client = datastore_client.LastExecutionRecordStore()
892 last_exec_client.set_last_execute_time(
893 'nightly', utc_now - datetime.timedelta(days=3))
894 self._mock_utc_now.return_value = utc_now
895 suite_trigger = trigger_receiver.TriggerReceiver()
896 self.assertFalse(suite_trigger.events['nightly'].should_handle)
897
898 def testCronTriggerWeeklyOutdated(self):
899 """Test weekly event is read with available weekly last_exec_time."""
900 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
901 last_exec_client = datastore_client.LastExecutionRecordStore()
902 last_exec_client.set_last_execute_time(
903 'weekly', utc_now - datetime.timedelta(days=8))
904 self._mock_utc_now.return_value = utc_now
905 suite_trigger = trigger_receiver.TriggerReceiver()
906 self.assertFalse(suite_trigger.events['weekly'].should_handle)
907
Xixuan Wu40998892017-08-29 14:32:26 -0700908 def testCronForWeeks(self):
909 """Ensure cron job can be successfully scheduled for several weeks."""
Xixuan Wu008ee832017-10-12 16:59:34 -0700910 all_tasks = self._get_ground_truth_task_list_from_config()
Xixuan Wu40998892017-08-29 14:32:26 -0700911 last_now = None
912
913 for now in now_generator(datetime.datetime.now(time_converter.UTC_TZ)):
914 self._mock_utc_now.return_value = now
915 suite_trigger = trigger_receiver.TriggerReceiver()
Xixuan Wu5451a662017-10-17 10:57:40 -0700916 with mock.patch('task.Task.schedule', return_value=True):
917 suite_trigger.cron()
Xixuan Wu40998892017-08-29 14:32:26 -0700918
Xixuan Wu40998892017-08-29 14:32:26 -0700919 should_scheduled_nightly_tasks = [
Xixuan Wu09962902018-12-11 10:49:27 -0800920 t.name for t in all_tasks['nightly'] if t.hour == now.hour]
Xixuan Wu008ee832017-10-12 16:59:34 -0700921
Xixuan Wu09962902018-12-11 10:49:27 -0800922 if (_should_schedule_timed_task(last_now, now) and
Xixuan Wu40998892017-08-29 14:32:26 -0700923 should_scheduled_nightly_tasks):
924 self.assertEqual(suite_trigger.event_results['nightly'],
925 should_scheduled_nightly_tasks)
926 else:
927 self.assertNotIn('nightly', suite_trigger.event_results.keys())
928
929 # Verify weekly tasks
930 should_scheduled_weekly_tasks = [
931 t.name for t in all_tasks['weekly']
Xixuan Wu09962902018-12-11 10:49:27 -0800932 if now.weekday() == t.day and now.hour == t.hour]
933 if (_should_schedule_timed_task(last_now, now) and
Xixuan Wu40998892017-08-29 14:32:26 -0700934 should_scheduled_weekly_tasks):
935 self.assertEqual(suite_trigger.event_results['weekly'],
936 should_scheduled_weekly_tasks)
937 else:
938 self.assertNotIn('weekly', suite_trigger.event_results.keys())
939
940 # Verify new_build tasks
941 should_scheduled_new_build_tasks = [
942 t.name for t in all_tasks['new_build']]
943 if (_should_schedule_new_build_task(last_now, now) and
944 should_scheduled_new_build_tasks):
945 self.assertEqual(suite_trigger.event_results['new_build'],
946 should_scheduled_new_build_tasks)
947 else:
948 self.assertNotIn('new_build', suite_trigger.event_results.keys())
949
950 last_now = now
951
952
953if __name__ == '__main__':
954 unittest.main()