blob: 6da40e946ce7f3dafea08bc573e5998b574ed2de [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
Xixuan Wuc6819012019-05-23 11:34:59 -070097 def get_passed_builds_since_date(self, since_date):
Xixuan Wu6ec23e32019-05-23 11:56:02 -070098 """Mock get_passed_builds_since_date."""
Xixuan Wuc6819012019-05-23 11:34:59 -070099 del since_date # unused
100 return [
101 build_lib.BuildInfo(
102 'link', None, '62', '9868.0.0', 'link-release'),
103 build_lib.BuildInfo(
104 'zako', None, '62', '9868.0.0', 'zako-release'),
105 build_lib.BuildInfo('samus-kernelnext', None, '62',
106 '9868.0.0', 'samus-kernelnext-release'),
107 build_lib.BuildInfo(
108 'reef', None, '62', '1234.0.0', 'reef-release'),
109 build_lib.BuildInfo(
110 'coral', 'santa', '62', '9868.0.0', 'coral-release'),
111 build_lib.BuildInfo(
112 'coral', 'astronaut', '62', '9868.0.0', 'coral-release'),
113 build_lib.BuildInfo(
114 'coral', 'lava', '62', '9868.0.0', 'coral-release'),
115 ]
116
117 def get_latest_passed_builds(self, build_config):
Xixuan Wu6ec23e32019-05-23 11:56:02 -0700118 """Mock get_latest_passed_builds."""
Xixuan Wuc6819012019-05-23 11:34:59 -0700119 del build_config # unused
120 return build_lib.BuildInfo('link', '62', '9868.0.0', build_config)
121
122 def get_relaxed_passed_builds_since_date(self, since_date):
Xixuan Wu6ec23e32019-05-23 11:56:02 -0700123 """Mock get_relaxed_pased_builds_since_date."""
Xixuan Wuc6819012019-05-23 11:34:59 -0700124 del since_date # unused
Xinan Linae7d6372019-09-12 14:42:10 -0700125 return [
126 build_lib.BuildInfo('grunt', None, '63', '9968.0.0', 'grunt-release'),
127 build_lib.BuildInfo('nami', None, '62', '9867.0.0', 'nami-release'),
128 build_lib.BuildInfo('nami', 'akali', '62', '9868.0.0', 'nami-release'),
129 build_lib.BuildInfo('nami', 'bard', '62', '9866.0.0', 'nami-release'),
130 ]
Xixuan Wuc6819012019-05-23 11:34:59 -0700131
Xinan Lin028f9582019-12-11 10:55:33 -0800132 def get_latest_passed_firmware_builds(self):
133 """Mock get_passed_firmware_builds."""
Xinan Lin8b291982019-12-16 10:03:56 -0800134 self.firmware_builds_called += 1
Xinan Lin028f9582019-12-11 10:55:33 -0800135 return [
136 ['cros', 'fake_board', ('gs://chromeos-image-archive/'
137 'fake_board-release/R30-6182.0.0-rc2/'
138 'fake_board')],
139 ['firmware', 'fake_board', ('gs://chromeos-image-archive/'
140 'firmware-fake_board-12345.67.'
141 'A-firmwarebranch/RFoo-1.0.0-b1e234567')],
Xinan Lin8b291982019-12-16 10:03:56 -0800142 ['firmware', 'zako', ('gs://chromeos-image-archive/'
143 'firmware-zako-12345.67.'
144 'A-firmwarebranch/RFoo-1.0.0-b1e234567')],
Xinan Lin028f9582019-12-11 10:55:33 -0800145 ]
146
Xixuan Wuc6819012019-05-23 11:34:59 -0700147
Xixuan Wu40998892017-08-29 14:32:26 -0700148class FakeAndroidBuildRestClient(object):
149 """Mock rest_client.AndroidBuildRestClient."""
150
151 def get_latest_build_id(self, branch, target):
152 """Mock rest_client.AndroidBuildRestClient.get_latest_build_id."""
153 del branch, target # unused
154 return '100'
155
156
157class FakeLabConfig(object):
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700158 """Mock config_reader.LabConfig."""
Xixuan Wu40998892017-08-29 14:32:26 -0700159
160 def get_android_board_list(self):
161 """Mock config_reader.LabConfig.get_android_board_list."""
162 return ('android-angler', 'android-bullhead')
163
Xixuan Wu6fb16272017-10-19 13:16:00 -0700164 def get_cros_board_list(self):
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700165 """Mock config_reader.LabConfig.get_cros_board_list."""
Xixuan Wua41efa22019-05-17 14:28:04 -0700166 return ('grunt', 'link', 'peppy', 'daisy', 'zako', 'samus-kernelnext',
Xinan Linae7d6372019-09-12 14:42:10 -0700167 'coral', 'reef', 'nami')
Xixuan Wu6fb16272017-10-19 13:16:00 -0700168
Xixuan Wu40998892017-08-29 14:32:26 -0700169 def get_firmware_ro_build_list(self, release_board):
170 """Mock config_reader.LabConfig.get_firmware_ro_build_list."""
171 del release_board # unused
172 return 'firmware1,firmware2'
173
C Shapiro7f24a002017-12-05 14:25:09 -0700174 def get_cros_model_map(self):
175 """Mock config_reader.LabConfig.get_cros_model_map."""
Xixuan Wua41efa22019-05-17 14:28:04 -0700176 return {
177 'coral': ['santa', 'astronaut'],
178 'reef': ['electro'],
Xinan Linae7d6372019-09-12 14:42:10 -0700179 'nami': ['akali', 'bard'],
Xixuan Wua41efa22019-05-17 14:28:04 -0700180 }
C Shapiro7f24a002017-12-05 14:25:09 -0700181
Xixuan Wu40998892017-08-29 14:32:26 -0700182
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700183class FakeMigrationConfig(object):
184 """Mock config_reader.MigrationConfig."""
185
Xixuan Wu1e42c752019-03-21 13:41:49 -0700186 def get_skylab_suites_dump(self):
Xixuan Wuee6b6a82019-03-21 14:28:26 -0700187 """Mock config_reader.MigrationConfig.get_skylab_suite_list."""
Xixuan Wu1e42c752019-03-21 13:41:49 -0700188 return {'suite:ent-nightly':
189 {'pool:suites':
Xixuan Wu028f6732019-04-11 14:47:42 -0700190 {'model:santa': {
191 'skylab': True,
192 'override_pool': '',
193 'override_qs_account': '',
194 },
195 'model:zako': {
196 'skylab': True,
197 'override_pool': 'QUOTA_POOL',
198 'override_qs_account': 'QUOTA_ACCOUNT',
199 }}}}
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700200
201
Xixuan Wu008ee832017-10-12 16:59:34 -0700202class TriggerReceiverBaseTestCase(unittest.TestCase):
Xixuan Wu40998892017-08-29 14:32:26 -0700203
204 def setUp(self):
205 self.testbed = testbed.Testbed()
206 self.testbed.activate()
207 self.addCleanup(self.testbed.deactivate)
208
209 self.testbed.init_datastore_v3_stub()
210 self.testbed.init_memcache_stub()
211 ndb.get_context().clear_cache()
212 self.testbed.init_taskqueue_stub(
213 root_path=os.path.join(os.path.dirname(__file__)))
214 self.taskqueue_stub = self.testbed.get_stub(
215 testbed.TASKQUEUE_SERVICE_NAME)
216
Xixuan Wuc6819012019-05-23 11:34:59 -0700217 mock_build_client = mock.patch('rest_client.BuildBucketBigqueryClient')
218 self._mock_build_client = mock_build_client.start()
219 self.addCleanup(mock_build_client.stop)
220
Xixuan Wu40998892017-08-29 14:32:26 -0700221 mock_android_client = mock.patch('rest_client.AndroidBuildRestClient')
222 self._mock_android_client = mock_android_client.start()
223 self.addCleanup(mock_android_client.stop)
224
Xixuan Wu40998892017-08-29 14:32:26 -0700225 mock_lab_config = mock.patch('config_reader.LabConfig')
226 self._mock_lab_config = mock_lab_config.start()
227 self.addCleanup(mock_lab_config.stop)
228
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700229 mock_migration_config = mock.patch('config_reader.MigrationConfig')
230 self._mock_migration_config = mock_migration_config.start()
231 self.addCleanup(mock_migration_config.stop)
232
Xixuan Wu40998892017-08-29 14:32:26 -0700233 mock_utc_now = mock.patch('time_converter.utc_now')
234 self._mock_utc_now = mock_utc_now.start()
235 self.addCleanup(mock_utc_now.stop)
236
Xixuan Wuc6819012019-05-23 11:34:59 -0700237 self._mock_build_client.return_value = FakeBuildClient()
Xixuan Wu40998892017-08-29 14:32:26 -0700238 self._mock_android_client.return_value = FakeAndroidBuildRestClient()
Xixuan Wu40998892017-08-29 14:32:26 -0700239 self._mock_lab_config.return_value = FakeLabConfig()
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700240 self._mock_migration_config.return_value = FakeMigrationConfig()
Xixuan Wu40998892017-08-29 14:32:26 -0700241
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700242 board_family_patcher = mock.patch(
243 'build_lib.get_board_family_mapping_from_gs')
244 board_family_getter = board_family_patcher.start()
245 board_family_getter.return_value = {
246 'nyan': ['nyan', 'nyan_blaze', 'nyan_big'],
247 'ivybridge': ['link', 'link_freon']}
248 self.addCleanup(board_family_patcher.stop)
249
Xixuan Wu008ee832017-10-12 16:59:34 -0700250
251class TriggerReceiverFakeConfigTestCase(TriggerReceiverBaseTestCase):
252
253 _TEST_PST_HOUR = 20
254 _TEST_PST_DAY = 4 # Friday
255 _TEST_EVENT_PST_HOUR = 13
256
257 _FAKE_NIGHTLY_TASK_NAME = 'fake_nightly_task'
258 _FAKE_WEEKLY_TASK_NAME = 'fake_weekly_task'
259
260 def setUp(self):
261 super(TriggerReceiverFakeConfigTestCase, self).setUp()
262
263 self.fake_config = config_reader.ConfigReader(None)
264 self._add_nightly_tasks(self.fake_config)
265 self._add_weekly_tasks(self.fake_config)
266
267 self.fake_config_with_settings = config_reader.ConfigReader(None)
268 self._add_weekly_tasks(self.fake_config_with_settings)
269 self._add_weekly_params(self.fake_config_with_settings)
270
271 mock_config_reader = mock.patch('config_reader.ConfigReader')
272 self._mock_config_reader = mock_config_reader.start()
273 self.addCleanup(mock_config_reader.stop)
274
275 def _add_nightly_tasks(self, fake_config):
276 fake_config.add_section(self._FAKE_NIGHTLY_TASK_NAME)
277 fake_config.set(self._FAKE_NIGHTLY_TASK_NAME, 'suite', 'fake_suite')
278 fake_config.set(self._FAKE_NIGHTLY_TASK_NAME, 'run_on', 'nightly')
279 fake_config.set(self._FAKE_NIGHTLY_TASK_NAME, 'hour',
280 str(self._TEST_PST_HOUR))
281
282 def _add_weekly_tasks(self, fake_config):
283 fake_config.add_section(self._FAKE_WEEKLY_TASK_NAME)
284 fake_config.set(self._FAKE_WEEKLY_TASK_NAME, 'suite', 'fake_suite')
285 fake_config.set(self._FAKE_WEEKLY_TASK_NAME, 'run_on', 'weekly')
286 fake_config.set(self._FAKE_WEEKLY_TASK_NAME, 'day', str(self._TEST_PST_DAY))
287
288 def _add_weekly_params(self, fake_config):
Xixuan Wu51bb7102019-03-18 14:51:44 -0700289 weekly_section_name = task_config_reader.EVENT_CLASSES[
290 'weekly'].section_name()
Xixuan Wu008ee832017-10-12 16:59:34 -0700291 fake_config.add_section(weekly_section_name)
292 fake_config.set(weekly_section_name, 'hour', str(self._TEST_EVENT_PST_HOUR))
293
294 def testInitializeTriggerReceiverWithNightlyEvent(self):
295 """Test nightly event can be handled on right hour."""
296 # A task with hour=20 should be scheduled at 20:00 in PST everyday, which
297 # is 3:00/4:00 in UTC everyday.
298 self._mock_config_reader.return_value = self.fake_config
299 given_utc_hour = time_converter.convert_time_info(
300 time_converter.TimeInfo(None, self._TEST_PST_HOUR)).hour
301 utc_now = datetime.datetime(2017, 8, 6, given_utc_hour,
302 tzinfo=time_converter.UTC_TZ)
303 last_exec_client = datastore_client.LastExecutionRecordStore()
304 last_exec_client.set_last_execute_time(
305 'nightly', utc_now - datetime.timedelta(hours=1))
306 self._mock_utc_now.return_value = utc_now
307
308 suite_trigger = trigger_receiver.TriggerReceiver()
309 suite_trigger.cron()
310 self.assertTrue(suite_trigger.events['nightly'].should_handle)
311 self.assertEqual(len(suite_trigger.event_results['nightly']), 1)
312 self.assertEqual(suite_trigger.event_results['nightly'][0],
313 self._FAKE_NIGHTLY_TASK_NAME)
314
315 def testInitializeTriggerReceiverWithWeeklyEventWithoutEventHour(self):
316 """Test weekly event without event settings can be handled on right day."""
317 # A task with day=4 (Friday) and default event_hour (23) should be
318 # scheduled at Friday 23:00 in PST, which is Saturday 6:00 or 7:00 in UTC.
319 self._mock_config_reader.return_value = self.fake_config
320 given_utc_hour = time_converter.convert_time_info(
321 time_converter.TimeInfo(
322 self._TEST_PST_DAY,
Xixuan Wu51bb7102019-03-18 14:51:44 -0700323 task_config_reader.EVENT_CLASSES['weekly'].DEFAULT_PST_HOUR)).hour
Xixuan Wu008ee832017-10-12 16:59:34 -0700324 utc_now = datetime.datetime(2017, 10, 14, given_utc_hour,
325 tzinfo=time_converter.UTC_TZ)
326 last_exec_client = datastore_client.LastExecutionRecordStore()
327 last_exec_client.set_last_execute_time(
328 'weekly', utc_now - datetime.timedelta(days=1))
329 self._mock_utc_now.return_value = utc_now
330
331 suite_trigger = trigger_receiver.TriggerReceiver()
332 suite_trigger.cron()
333 self.assertTrue(suite_trigger.events['weekly'].should_handle)
334 self.assertEqual(len(suite_trigger.event_results['weekly']), 1)
335 self.assertEqual(suite_trigger.event_results['weekly'][0],
336 self._FAKE_WEEKLY_TASK_NAME)
337
338 def testInitializeTriggerReceiverWithWeeklyEventWithEventHour(self):
339 """Test weekly event with event settings can be handled on right day."""
340 # A task with day=4 (Friday) and event_hour=13 should be scheduled at
341 # Friday 13:00 in PST, which is Friday 20:00 or 21:00 in UTC.
342 self._mock_config_reader.return_value = self.fake_config_with_settings
343 given_utc_time_info = time_converter.convert_time_info(
344 time_converter.TimeInfo(self._TEST_PST_DAY, self._TEST_EVENT_PST_HOUR))
345
346 # Set the current time as a Friday 20:00 or 21:00 in UTC.
347 utc_now = datetime.datetime(2017, 10, 13, given_utc_time_info.hour,
348 tzinfo=time_converter.UTC_TZ)
349 last_exec_client = datastore_client.LastExecutionRecordStore()
350 last_exec_client.set_last_execute_time(
351 'weekly', utc_now - datetime.timedelta(days=1))
352 self._mock_utc_now.return_value = utc_now
353
354 suite_trigger = trigger_receiver.TriggerReceiver()
355 suite_trigger.cron()
356 self.assertTrue(suite_trigger.events['weekly'].should_handle)
357 self.assertEqual(len(suite_trigger.event_results['weekly']), 1)
358 self.assertEqual(suite_trigger.event_results['weekly'][0],
359 self._FAKE_WEEKLY_TASK_NAME)
360
361
Craig Bergstrom58263d32018-04-26 14:11:35 -0600362class TriggerReceiverFakeBuildTestCase(TriggerReceiverBaseTestCase):
363 """Test the new_build functionality."""
364
Craig Bergstrom58263d32018-04-26 14:11:35 -0600365 def setUp(self):
366 """Set up for a test."""
367 super(TriggerReceiverFakeBuildTestCase, self).setUp()
368
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700369 self._prepare()
370
371 def _prepare(self):
Craig Bergstrom58263d32018-04-26 14:11:35 -0600372 self.fake_config = config_reader.ConfigReader(None)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600373 mock_config_reader = mock.patch('config_reader.ConfigReader')
374 self._mock_config_reader = mock_config_reader.start()
375 self.addCleanup(mock_config_reader.stop)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600376
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700377 # Set last execution time for new_build events.
378 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600379 last_exec_client = datastore_client.LastExecutionRecordStore()
380 last_exec_client.set_last_execute_time(
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700381 'new_build', utc_now - datetime.timedelta(hours=1))
Craig Bergstrom58263d32018-04-26 14:11:35 -0600382 self._mock_utc_now.return_value = utc_now
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700383
384 def testNewBuildForHWTestSanityRequired(self):
385 """Test the new_build functionality."""
386 # Construct a fake config with only_hwtest_sanity_required.
387 fsnbt_name = 'FakeStrictNewBuildTask'
388 self.fake_config.add_section(fsnbt_name)
389 self.fake_config.set(fsnbt_name, 'run_on', 'new_build')
390 self.fake_config.set(fsnbt_name, 'suite', 'fake_suite_base')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700391 self.fake_config.set(fsnbt_name, 'boards', 'link, zako, grunt')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700392 frnbt_name = 'FakeRelaxedNewBuildTask'
393 self.fake_config.add_section(frnbt_name)
394 self.fake_config.set(frnbt_name, 'run_on', 'new_build')
395 self.fake_config.set(frnbt_name, 'suite', 'fake_suite_relaxed')
396 self.fake_config.set(frnbt_name, 'only_hwtest_sanity_required', 'True')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700397 self.fake_config.set(frnbt_name, 'boards', 'link, zako, grunt')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700398
399 self._mock_config_reader.return_value = self.fake_config
Craig Bergstrom58263d32018-04-26 14:11:35 -0600400
401 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600402 suite_trigger = trigger_receiver.TriggerReceiver()
403 suite_trigger.cron()
404
405 # Validate that the expected tests got kicked off.
Craig Bergstrom58263d32018-04-26 14:11:35 -0600406 self.assertEqual(len(suite_trigger.event_results), 1)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600407 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000408 # 2 for strict passed builds, 3 for relaxed builds.
409 self.assertEqual(len(tasks), 5)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600410
411 # The number of builds that matched the base (success) Task.
412 count_base = 0
413 # The number of builds that matched the relaxed Task.
414 count_relaxed = 0
415 for task in tasks:
416 if 'fake_suite_base' in task.payload:
417 # Make sure it matched the expected build only.
Craig Bergstrom58263d32018-04-26 14:11:35 -0600418 self.assertNotIn('grunt-release', task.payload)
419 count_base += 1
420
421 if 'fake_suite_relaxed' in task.payload:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600422 count_relaxed += 1
423
424 # Make each case matched precisely one event.
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000425 self.assertEqual(2, count_base)
426 self.assertEqual(3, count_relaxed)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600427
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700428 def testNewBuildWithExistingBoardFamilies(self):
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700429 """Test the new_build suite with an existing board family."""
430 link_suite = 'FakeLinkNewBuildTask'
431 self.fake_config.add_section(link_suite)
432 self.fake_config.set(link_suite, 'run_on', 'new_build')
433 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700434 self.fake_config.set(link_suite, 'board_families', 'ivybridge')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700435 self._mock_config_reader.return_value = self.fake_config
436
437 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
438 suite_trigger = trigger_receiver.TriggerReceiver()
439 suite_trigger.cron()
440
441 self.assertEqual(len(suite_trigger.event_results), 1)
442 self.assertEqual(suite_trigger.event_results['new_build'],
443 [link_suite])
444 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
445 self.assertEqual(len(tasks), 1)
446 self.assertIn('link-release', tasks[0].payload)
447
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700448 def testNewBuildWithExistingBoardFamiliesAndBoards(self):
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700449 """Test the new_build suite with an existing board family."""
450 link_suite = 'FakeLinkNewBuildTask'
451 self.fake_config.add_section(link_suite)
452 self.fake_config.set(link_suite, 'run_on', 'new_build')
453 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700454 self.fake_config.set(link_suite, 'board_families', 'ivybridge')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700455 self.fake_config.set(link_suite, 'boards', 'asuka, paine, banon')
456 self._mock_config_reader.return_value = self.fake_config
457
458 suite_trigger = trigger_receiver.TriggerReceiver()
459 suite_trigger.cron()
460
461 self.assertEqual(len(suite_trigger.event_results), 1)
462 self.assertEqual(suite_trigger.event_results['new_build'],
463 [link_suite])
464 boards = suite_trigger.events['new_build'].task_list[0].boards
465 self.assertIn('asuka', boards)
466 self.assertIn('link', boards)
467
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700468 def testNewBuildWithNonExistingBoardFamilies(self):
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700469 """Test the new_build suite with an non-existing board family."""
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700470 nyan_suite = 'FakeNonExistBoardFamiliesNewBuildTask'
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700471 self.fake_config.add_section(nyan_suite)
472 self.fake_config.set(nyan_suite, 'run_on', 'new_build')
473 self.fake_config.set(nyan_suite, 'suite', 'fake_suite_base')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700474 self.fake_config.set(nyan_suite, 'board_families', 'nyan')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700475 self._mock_config_reader.return_value = self.fake_config
476
477 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
478 suite_trigger = trigger_receiver.TriggerReceiver()
479 suite_trigger.cron()
480
481 self.assertEqual(len(suite_trigger.event_results), 1)
482 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
483 self.assertEqual(len(tasks), 0)
484
485 def testNewBuildWithNonSpecifiedBoardFamily(self):
486 """Test the new_build suite with an non-specified board family."""
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700487 normal_suite = 'FakeBoardFamiliesNewBuildTask'
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700488 self.fake_config.add_section(normal_suite)
489 self.fake_config.set(normal_suite, 'run_on', 'new_build')
490 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700491 self.fake_config.set(normal_suite, 'boards', 'link, zako')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700492 self._mock_config_reader.return_value = self.fake_config
493
494 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
495 suite_trigger = trigger_receiver.TriggerReceiver()
496 suite_trigger.cron()
497
498 self.assertEqual(len(suite_trigger.event_results), 1)
499 self.assertEqual(suite_trigger.event_results['new_build'],
500 [normal_suite])
501 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
Harpreet Grewalbbbb7de2019-02-05 19:35:03 +0000502 self.assertEqual(len(tasks), 2)
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700503
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700504 def testNewBuildExcludingExistingBoardFamilies(self):
505 """Test the new_build suite excluding an existing board family."""
506 link_suite = 'FakeLinkNewBuildTask'
507 self.fake_config.add_section(link_suite)
508 self.fake_config.set(link_suite, 'run_on', 'new_build')
509 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
510 self.fake_config.set(link_suite, 'exclude_board_families', 'ivybridge')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700511 self.fake_config.set(link_suite, 'boards', 'link, zako')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700512 self._mock_config_reader.return_value = self.fake_config
513
514 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
515 suite_trigger = trigger_receiver.TriggerReceiver()
516 suite_trigger.cron()
517
518 self.assertEqual(len(suite_trigger.event_results), 1)
519 self.assertEqual(suite_trigger.event_results['new_build'],
520 [link_suite])
521 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
522 self.assertEqual(len(tasks), 1)
523 self.assertNotIn('link-release', tasks[0].payload)
524 self.assertIn('zako-release', tasks[0].payload)
525
526 def testNewBuildExcludingExistingBoardFamiliesAndBoards(self):
527 """Test the new_build suite with an existing board family."""
528 link_suite = 'FakeLinkNewBuildTask'
529 self.fake_config.add_section(link_suite)
530 self.fake_config.set(link_suite, 'run_on', 'new_build')
531 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
532 self.fake_config.set(link_suite, 'exclude_board_families', 'ivybridge')
Xixuan Wua41efa22019-05-17 14:28:04 -0700533 self.fake_config.set(link_suite, 'exclude_boards',
Xinan Lin09a628a2019-11-01 17:20:27 -0700534 'asuka, paine, banon, coral, reef, nami, samus-kernelnext')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700535 self._mock_config_reader.return_value = self.fake_config
536
537 suite_trigger = trigger_receiver.TriggerReceiver()
538 suite_trigger.cron()
539
540 self.assertEqual(len(suite_trigger.event_results), 1)
541 self.assertEqual(suite_trigger.event_results['new_build'],
542 [link_suite])
543 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
544 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
Xinan Lin09a628a2019-11-01 17:20:27 -0700545 self.assertEqual(len(tasks), 1)
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700546 self.assertNotIn('link-release', tasks[0].payload)
547 self.assertNotIn('asuka-release', tasks[0].payload)
548 self.assertIn('zako-release', tasks[0].payload)
549
550 def testNewBuildExcludingNonExistingBoardFamilies(self):
551 """Test the new_build suite excluding an non-existing board family."""
552 nyan_suite = 'FakeNonExistExcludeBoardFamiliesNewBuildTask'
553 self.fake_config.add_section(nyan_suite)
554 self.fake_config.set(nyan_suite, 'run_on', 'new_build')
555 self.fake_config.set(nyan_suite, 'suite', 'fake_suite_base')
556 self.fake_config.set(nyan_suite, 'exclude_board_families', 'nyan')
Xixuan Wub4b2f412019-05-03 11:22:31 -0700557 self.fake_config.set(nyan_suite, 'boards', 'link, zako')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700558 self._mock_config_reader.return_value = self.fake_config
559
560 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
561 suite_trigger = trigger_receiver.TriggerReceiver()
562 suite_trigger.cron()
563
564 self.assertEqual(len(suite_trigger.event_results), 1)
565 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
566 self.assertEqual(len(tasks), 2)
567
568 def testNewBuildWithBoardExcludeBoardCollision(self):
Xixuan Wu8d2f2862018-08-28 16:48:04 -0700569 """Test the case that the same board in boards and exclude_boards."""
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700570 normal_suite = 'FakeBoardExludingBoardCollisionNewBuildTask'
571 self.fake_config.add_section(normal_suite)
572 self.fake_config.set(normal_suite, 'run_on', 'new_build')
573 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
574 self.fake_config.set(normal_suite, 'boards', 'zako, asuka')
575 self.fake_config.set(normal_suite, 'exclude_boards', 'asuka')
576 self._mock_config_reader.return_value = self.fake_config
577
578 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
579 suite_trigger = trigger_receiver.TriggerReceiver()
580 suite_trigger.cron()
581
582 self.assertEqual(len(suite_trigger.event_results), 1)
583 self.assertEqual(suite_trigger.event_results['new_build'],
584 [normal_suite])
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700585 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
586 self.assertEqual(len(tasks), 1)
587 self.assertNotIn('asuka-release', tasks[0].payload)
588 self.assertIn('zako-release', tasks[0].payload)
589
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700590 def testNewBuildWithSkylab(self):
591 """Test the case that suites run in skylab."""
592 normal_suite = 'FakeSkylabSuite'
593 self.fake_config.add_section(normal_suite)
594 self.fake_config.set(normal_suite, 'run_on', 'new_build')
595 self.fake_config.set(normal_suite, 'suite', 'ent-nightly')
Xixuan Wu1e42c752019-03-21 13:41:49 -0700596 self.fake_config.set(normal_suite, 'pool', 'suites')
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700597 self.fake_config.set(normal_suite, 'boards', 'zako, asuka')
598 self._mock_config_reader.return_value = self.fake_config
599
600 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
601 suite_trigger = trigger_receiver.TriggerReceiver()
602 suite_trigger.cron()
603
604 self.assertEqual(len(suite_trigger.event_results), 1)
605 self.assertEqual(suite_trigger.event_results['new_build'],
606 [normal_suite])
607 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
608 self.assertEqual(len(tasks), 1)
609 self.assertIn('is_skylab=True', tasks[0].payload)
Xixuan Wu028f6732019-04-11 14:47:42 -0700610 self.assertIn('override_pool=QUOTA_POOL', tasks[0].payload)
611 self.assertIn('override_qs_account=QUOTA_ACCOUNT', tasks[0].payload)
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700612
Xixuan Wub4b2f412019-05-03 11:22:31 -0700613 def testNewBuildWithKernelnext(self):
614 """Test the case that suites run with board-kernelnext build."""
615 normal_suite = 'FakeKernelnextSuite'
616 self.fake_config.add_section(normal_suite)
617 self.fake_config.set(normal_suite, 'run_on', 'new_build')
618 self.fake_config.set(normal_suite, 'suite', 'fake-suite')
619 self.fake_config.set(normal_suite, 'pool', 'suites')
620 self.fake_config.set(normal_suite, 'boards', 'samus-kernelnext')
621 self._mock_config_reader.return_value = self.fake_config
622
Xixuan Wub4b2f412019-05-03 11:22:31 -0700623 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
624 suite_trigger = trigger_receiver.TriggerReceiver()
625 suite_trigger.cron()
626
627 self.assertEqual(len(suite_trigger.event_results), 1)
628 self.assertEqual(suite_trigger.event_results['new_build'],
629 [normal_suite])
630 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
631 self.assertEqual(len(tasks), 1)
632 # Board should be 'samus'.
633 self.assertIn('&board=samus&', tasks[0].payload)
634 # Build should be 'samus-kernelnext-release***'.
635 self.assertIn('cros_version=samus-kernelnext-release', tasks[0].payload)
636
Xixuan Wua41efa22019-05-17 14:28:04 -0700637 def testNewBuildWithModels(self):
638 """Test the new_build suite with an existing models entry."""
639 normal_suite = 'FakeModelsNewBuildTask'
640 self.fake_config.add_section(normal_suite)
641 self.fake_config.set(normal_suite, 'run_on', 'new_build')
642 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
643 self.fake_config.set(normal_suite, 'models', 'coral_lava, coral_santa')
644 self.fake_config.set(normal_suite, 'boards', 'coral')
645 self._mock_config_reader.return_value = self.fake_config
646
647 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
648 suite_trigger = trigger_receiver.TriggerReceiver()
649 suite_trigger.cron()
650
651 self.assertEqual(len(suite_trigger.event_results), 1)
652 self.assertEqual(suite_trigger.event_results['new_build'],
653 [normal_suite])
654 self.assertIn('new_build', suite_trigger.event_results)
655 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
656 self.assertEqual(len(tasks), 1)
657 self.assertNotIn('model=astronaut', tasks[0].payload)
658 self.assertIn('model=santa', tasks[0].payload)
659
Xinan Linae7d6372019-09-12 14:42:10 -0700660 def testNewBuildWithModelsForHWTestSanityRequired(self):
661 """Test the new_build suite with an existing models entry."""
662 normal_suite = 'FakeModelsNewBuildTask'
663 self.fake_config.add_section(normal_suite)
664 self.fake_config.set(normal_suite, 'run_on', 'new_build')
665 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
666 self.fake_config.set(normal_suite, 'models', 'nami_akali, nami_bard')
667 self.fake_config.set(normal_suite, 'boards', 'nami')
668 self.fake_config.set(normal_suite, 'only_hwtest_sanity_required', 'True')
669 self._mock_config_reader.return_value = self.fake_config
670
671 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
672 suite_trigger = trigger_receiver.TriggerReceiver()
673 suite_trigger.cron()
674
675 self.assertEqual(len(suite_trigger.event_results), 1)
676 self.assertEqual(suite_trigger.event_results['new_build'],
677 [normal_suite])
678 self.assertIn('new_build', suite_trigger.event_results)
679 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
680 self.assertEqual(len(tasks), 2)
681 self.assertIn('model=akali', tasks[0].payload)
682 self.assertIn('9868.0.0', tasks[0].payload)
683 self.assertIn('model=bard', tasks[1].payload)
684 self.assertIn('9867.0.0', tasks[1].payload)
685
Xixuan Wua41efa22019-05-17 14:28:04 -0700686 def testNewBuildWithExcludeModels(self):
687 """Test the new_build suite with an existing exclude_models entry."""
688 normal_suite = 'FakeExludingModelsNewBuildTask'
689 self.fake_config.add_section(normal_suite)
690 self.fake_config.set(normal_suite, 'run_on', 'new_build')
691 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
692 self.fake_config.set(normal_suite, 'exclude_models',
693 'coral_lava, coral_santa')
694 self.fake_config.set(normal_suite, 'boards', 'coral')
695 self._mock_config_reader.return_value = self.fake_config
696
697 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
698 suite_trigger = trigger_receiver.TriggerReceiver()
699 suite_trigger.cron()
700
701 self.assertEqual(len(suite_trigger.event_results), 1)
702 self.assertEqual(suite_trigger.event_results['new_build'],
703 [normal_suite])
704 self.assertIn('new_build', suite_trigger.event_results)
705 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
706 self.assertEqual(len(tasks), 1)
707 self.assertNotIn('model=santa', tasks[0].payload)
708 self.assertIn('model=astronaut', tasks[0].payload)
709
710 def testNewBuildWithModelsExcludeModels(self):
711 """Test the new_build suite with models and exclude_models entry."""
712 normal_suite = 'FakeModelsExcludeModelsNewBuildTask'
713 self.fake_config.add_section(normal_suite)
714 self.fake_config.set(normal_suite, 'run_on', 'new_build')
715 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
716 self.fake_config.set(normal_suite, 'models', 'coral_santa, coral_astronaut')
717 self.fake_config.set(normal_suite, 'exclude_models',
718 'coral_lava, coral_santa')
719 self.fake_config.set(normal_suite, 'boards', 'coral')
720 self._mock_config_reader.return_value = self.fake_config
721
722 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
723 suite_trigger = trigger_receiver.TriggerReceiver()
724 suite_trigger.cron()
725
726 self.assertEqual(len(suite_trigger.event_results), 1)
727 self.assertEqual(suite_trigger.event_results['new_build'],
728 [normal_suite])
729 self.assertIn('new_build', suite_trigger.event_results)
730 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
731 self.assertEqual(len(tasks), 1)
732 self.assertNotIn('model=santa', tasks[0].payload)
733 self.assertIn('model=astronaut', tasks[0].payload)
734
735 def testNewBuildWithNoModelListAndModelBuild(self):
736 """Test the new_build suite with models and empty board_model mapping."""
737 normal_suite = 'FakeModelsExcludeModelsNewBuildTask'
738 self.fake_config.add_section(normal_suite)
739 self.fake_config.set(normal_suite, 'run_on', 'new_build')
740 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
741 self.fake_config.set(normal_suite, 'boards', 'coral')
742 self._mock_config_reader.return_value = self.fake_config
743
744 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
745 suite_trigger = trigger_receiver.TriggerReceiver()
746 suite_trigger.cron()
747
748 self.assertIn('new_build', suite_trigger.event_results)
749 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
750 # Verify that coral-release is not kicked off on model lava as lava is not
751 # listed in cros_model_map.
752 self.assertEqual(len(tasks), 2)
753 self.assertNotIn('lava', tasks[0].payload)
754 self.assertNotIn('lava', tasks[1].payload)
755
756 def testNewBuildWithNoModelListAndNoModelBuild(self):
757 """Test the new_build suite with models and empty board_model mapping."""
758 normal_suite = 'FakeModelsExcludeModelsNewBuildTask'
759 self.fake_config.add_section(normal_suite)
760 self.fake_config.set(normal_suite, 'run_on', 'new_build')
761 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
762 self.fake_config.set(normal_suite, 'boards', 'reef')
763 self._mock_config_reader.return_value = self.fake_config
764
765 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
766 suite_trigger = trigger_receiver.TriggerReceiver()
767 suite_trigger.cron()
768
769 self.assertIn('new_build', suite_trigger.event_results)
770 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
771 # Verify that reef-release is kicked off on reef models.
772 self.assertEqual(len(tasks), 1)
773 self.assertIn('model=electro', tasks[0].payload)
774
C Shapiro09108252019-08-01 14:52:52 -0500775 def testNewBuildWithAnyModel(self):
776 """Test the new_build suite with any_model option set."""
777 normal_suite = 'FakeAnyModelNewBuildTask'
778 self.fake_config.add_section(normal_suite)
779 self.fake_config.set(normal_suite, 'run_on', 'new_build')
780 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
781 self.fake_config.set(normal_suite, 'any_model', 'True')
782 self.fake_config.set(normal_suite, 'boards', 'coral')
783 self._mock_config_reader.return_value = self.fake_config
784
785 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
786 suite_trigger = trigger_receiver.TriggerReceiver()
787 suite_trigger.cron()
788
789 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
790 self.assertEqual(len(tasks), 1)
791 self.assertIn('model=None', tasks[0].payload)
792
Xinan Lin8b291982019-12-16 10:03:56 -0800793 def testNewBuildWithFirmwareTask(self):
794 """Test the new_build suite with firmware option set."""
795 # Construct a fake config with firmware build.
796 fsnbt_name = 'FakeStrictNewBuildTask'
797 self.fake_config.add_section(fsnbt_name)
798 self.fake_config.set(fsnbt_name, 'run_on', 'new_build')
799 self.fake_config.set(fsnbt_name, 'suite', 'fake_suite_base')
800 self.fake_config.set(fsnbt_name, 'boards', 'zako')
801 self.fake_config.set(fsnbt_name, 'firmware_ro_build_spec', 'firmware')
802 self.fake_config.set(fsnbt_name, 'test_source', 'cros')
803 self._mock_config_reader.return_value = self.fake_config
804
805 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
806 suite_trigger = trigger_receiver.TriggerReceiver()
807 some_event = suite_trigger.events['new_build']
808 suite_trigger.cron()
809
810 # The firmware query has run for once.
811 self.assertEqual(suite_trigger._build_client.firmware_builds_called, 1)
812 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
813 self.assertEqual(len(tasks), 1)
814 self.assertIn('firmware-zako-12345.67', tasks[0].payload)
815
816
817 def testNewBuildWithoutFirmwareTask(self):
818 """Test the event skips fetch the firmware builds."""
819 # Construct a fake config without firmware build.
820 fsnbt_name = 'FakeStrictNewBuildTask'
821 self.fake_config.add_section(fsnbt_name)
822 self.fake_config.set(fsnbt_name, 'run_on', 'new_build')
823 self.fake_config.set(fsnbt_name, 'suite', 'fake_suite_base')
824 self.fake_config.set(fsnbt_name, 'boards', 'zako')
825 self._mock_config_reader.return_value = self.fake_config
826
827 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
828 suite_trigger = trigger_receiver.TriggerReceiver()
829 suite_trigger.cron()
830
831 # The firmware query was not called.
832 self.assertEqual(suite_trigger._build_client.firmware_builds_called, 0)
833 # Validate that the expected tests got kicked off.
834 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
835 self.assertEqual(len(tasks), 1)
836
Craig Bergstrom58263d32018-04-26 14:11:35 -0600837
Xixuan Wu008ee832017-10-12 16:59:34 -0700838class TriggerReceiverRealConfigTestCase(TriggerReceiverBaseTestCase):
839
840 def setUp(self):
841 super(TriggerReceiverRealConfigTestCase, self).setUp()
842 mock_config_reader = mock.patch('config_reader.ConfigReader')
843 self._mock_config_reader = mock_config_reader.start()
844 self.addCleanup(mock_config_reader.stop)
845 self._mock_config_reader.return_value = _SUITE_CONFIG_READER
846
847 def _get_ground_truth_task_list_from_config(self):
848 """Get the ground truth of to-be-scheduled task list from config file."""
849 self._mock_utc_now.return_value = datetime.datetime.now(
850 time_converter.UTC_TZ)
Xixuan Wu51bb7102019-03-18 14:51:44 -0700851 task_config = task_config_reader.TaskConfig(_SUITE_CONFIG_READER)
Xixuan Wu008ee832017-10-12 16:59:34 -0700852 tasks = {}
Xixuan Wu51bb7102019-03-18 14:51:44 -0700853 for keyword, klass in task_config_reader.EVENT_CLASSES.iteritems():
Xixuan Wu008ee832017-10-12 16:59:34 -0700854 new_event = klass(
855 task_config.get_event_setting(klass.section_name()), None)
856 new_event.set_task_list(
857 task_config.get_tasks_by_keyword(klass.KEYWORD)['tasks'])
858 tasks[keyword] = new_event.task_list
859
860 return tasks
861
Xixuan Wu40998892017-08-29 14:32:26 -0700862 def testCronWithoutLastExec(self):
863 """Test the first round of cron can be successfully executed."""
864 self._mock_utc_now.return_value = datetime.datetime.now(
865 time_converter.UTC_TZ)
866 suite_trigger = trigger_receiver.TriggerReceiver()
867 suite_trigger.cron()
868 self.assertFalse(suite_trigger.events['nightly'].should_handle)
869 self.assertFalse(suite_trigger.events['weekly'].should_handle)
870 self.assertFalse(suite_trigger.events['new_build'].should_handle)
871
872 self.assertEqual(suite_trigger.event_results, {})
873
874 def testCronTriggerNightly(self):
875 """Test nightly event is read with available nightly last_exec_time."""
876 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
877 last_exec_client = datastore_client.LastExecutionRecordStore()
878 last_exec_client.set_last_execute_time(
879 'nightly', utc_now - datetime.timedelta(hours=1))
880 self._mock_utc_now.return_value = utc_now
881 suite_trigger = trigger_receiver.TriggerReceiver()
882 self.assertTrue(suite_trigger.events['nightly'].should_handle)
883 self.assertFalse(suite_trigger.events['weekly'].should_handle)
884 self.assertFalse(suite_trigger.events['new_build'].should_handle)
885
Xixuan Wu33179672017-09-12 11:44:04 -0700886 def testCronTriggerNightlyOutdated(self):
887 """Test nightly event is read with available nightly last_exec_time."""
888 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
889 last_exec_client = datastore_client.LastExecutionRecordStore()
890 last_exec_client.set_last_execute_time(
891 'nightly', utc_now - datetime.timedelta(days=3))
892 self._mock_utc_now.return_value = utc_now
893 suite_trigger = trigger_receiver.TriggerReceiver()
894 self.assertFalse(suite_trigger.events['nightly'].should_handle)
895
896 def testCronTriggerWeeklyOutdated(self):
897 """Test weekly event is read with available weekly last_exec_time."""
898 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
899 last_exec_client = datastore_client.LastExecutionRecordStore()
900 last_exec_client.set_last_execute_time(
901 'weekly', utc_now - datetime.timedelta(days=8))
902 self._mock_utc_now.return_value = utc_now
903 suite_trigger = trigger_receiver.TriggerReceiver()
904 self.assertFalse(suite_trigger.events['weekly'].should_handle)
905
Xixuan Wu40998892017-08-29 14:32:26 -0700906 def testCronForWeeks(self):
907 """Ensure cron job can be successfully scheduled for several weeks."""
Xixuan Wu008ee832017-10-12 16:59:34 -0700908 all_tasks = self._get_ground_truth_task_list_from_config()
Xixuan Wu40998892017-08-29 14:32:26 -0700909 last_now = None
910
911 for now in now_generator(datetime.datetime.now(time_converter.UTC_TZ)):
912 self._mock_utc_now.return_value = now
913 suite_trigger = trigger_receiver.TriggerReceiver()
Xixuan Wu5451a662017-10-17 10:57:40 -0700914 with mock.patch('task.Task.schedule', return_value=True):
915 suite_trigger.cron()
Xixuan Wu40998892017-08-29 14:32:26 -0700916
Xixuan Wu40998892017-08-29 14:32:26 -0700917 should_scheduled_nightly_tasks = [
Xixuan Wu09962902018-12-11 10:49:27 -0800918 t.name for t in all_tasks['nightly'] if t.hour == now.hour]
Xixuan Wu008ee832017-10-12 16:59:34 -0700919
Xixuan Wu09962902018-12-11 10:49:27 -0800920 if (_should_schedule_timed_task(last_now, now) and
Xixuan Wu40998892017-08-29 14:32:26 -0700921 should_scheduled_nightly_tasks):
922 self.assertEqual(suite_trigger.event_results['nightly'],
923 should_scheduled_nightly_tasks)
924 else:
925 self.assertNotIn('nightly', suite_trigger.event_results.keys())
926
927 # Verify weekly tasks
928 should_scheduled_weekly_tasks = [
929 t.name for t in all_tasks['weekly']
Xixuan Wu09962902018-12-11 10:49:27 -0800930 if now.weekday() == t.day and now.hour == t.hour]
931 if (_should_schedule_timed_task(last_now, now) and
Xixuan Wu40998892017-08-29 14:32:26 -0700932 should_scheduled_weekly_tasks):
933 self.assertEqual(suite_trigger.event_results['weekly'],
934 should_scheduled_weekly_tasks)
935 else:
936 self.assertNotIn('weekly', suite_trigger.event_results.keys())
937
938 # Verify new_build tasks
939 should_scheduled_new_build_tasks = [
940 t.name for t in all_tasks['new_build']]
941 if (_should_schedule_new_build_task(last_now, now) and
942 should_scheduled_new_build_tasks):
943 self.assertEqual(suite_trigger.event_results['new_build'],
944 should_scheduled_new_build_tasks)
945 else:
946 self.assertNotIn('new_build', suite_trigger.event_results.keys())
947
948 last_now = now
949
950
951if __name__ == '__main__':
952 unittest.main()