blob: bef704da9d77c4a69cc9b42d1cfb496602af1e6f [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."""
6
7import datetime
8import os
9import unittest
10
11import cloud_sql_client
12import config_reader
13import datastore_client
14import file_getter
15import mock
Craig Bergstrom58263d32018-04-26 14:11:35 -060016import task_executor
Xixuan Wu40998892017-08-29 14:32:26 -070017import time_converter
18import trigger_receiver
19
Craig Bergstrom58263d32018-04-26 14:11:35 -060020from google.appengine.api import taskqueue
Xixuan Wu40998892017-08-29 14:32:26 -070021from google.appengine.ext import ndb
22from google.appengine.ext import testbed
23
24# Ensure that SUITE_SCHEDULER_CONFIG_FILE is read only once.
25_SUITE_CONFIG_READER = config_reader.ConfigReader(
Xixuan Wu26d06e02017-09-20 14:50:28 -070026 file_getter.TEST_SUITE_SCHEDULER_CONFIG_FILE)
Xixuan Wu40998892017-08-29 14:32:26 -070027
28
29def now_generator(start_time, interval_min=30, last_days=7):
30 """A datetime.datetime.now generator.
31
32 The generator will generate 'now' from start_time till start_time+last_days
33 for every interval_min.
34
35 Args:
36 start_time: A datetime.datetime object representing the initial value of
37 the 'now'.
38 interval_min: The interval minutes between current 'now' and next 'now.
39 last_days: Representing how many days this generator will last.
40
41 Yields:
42 a datetime.datetime object to mock the current time.
43 """
44 cur_time = start_time
45 end_time = start_time + datetime.timedelta(days=last_days)
46 while cur_time < end_time:
47 yield cur_time
48 cur_time += datetime.timedelta(minutes=interval_min)
49
50
Xixuan Wu40998892017-08-29 14:32:26 -070051def _should_schedule_nightly_task(last_now, now):
52 """Check whether nightly task should be scheduled.
53
54 A nightly task should be schduled when next hour is coming.
55
56 Args:
57 last_now: the last time to check if nightly task should be scheduled
58 or not.
59 now: the current time to check if nightly task should be scheduled.
60
61 Returns:
62 a boolean indicating whether there will be nightly tasks scheduled.
63 """
64 if last_now is not None and last_now.hour != now.hour:
65 return True
66
67 return False
68
69
70def _should_schedule_weekly_task(last_now, now, weekly_time_info):
71 """Check whether weekly task should be scheduled.
72
73 A weekly task should be schduled when it comes to the default weekly tasks
74 scheduling hour in next day.
75
76 Args:
77 last_now: the last time to check if weekly task should be scheduled
78 or not.
79 now: the current time to check if weekly task should be scheduled.
80 weekly_time_info: the default weekly tasks scheduling time info.
81
82 Returns:
83 a boolean indicating whether there will be weekly tasks scheduled.
84 """
85 if (last_now is not None and last_now.hour != now.hour and
86 now.hour == weekly_time_info.hour):
87 return True
88
89 return False
90
91
92def _should_schedule_new_build_task(last_now, now):
93 """Check whether weekly task should be scheduled.
94
95 A new_build task should be schduled when there're new builds between last
96 check and this check.
97
98 Args:
99 last_now: the last time to check if new_build task should be scheduled.
100 now: the current time to check if new_build task should be scheduled.
101
102 Returns:
103 a boolean indicating whether there will be new_build tasks scheduled.
104 """
105 if last_now is not None and last_now != now:
106 return True
107
108 return False
109
110
111class FakeCIDBClient(object):
112 """Mock cloud_sql_client.CIDBClient."""
113
114 def get_passed_builds_since_date(self, since_date):
115 """Mock cloud_sql_client.CIDBClient.get_passed_builds_since_date."""
116 del since_date # unused
117 return [cloud_sql_client.BuildInfo('link', '62', '9868.0.0',
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700118 'link-release'),
119 cloud_sql_client.BuildInfo('zako', '62', '9868.0.0',
120 'zako-release')]
Xixuan Wu40998892017-08-29 14:32:26 -0700121
122 def get_latest_passed_builds(self, build_config):
123 """Mock cloud_sql_client.CIDBClient.get_latest_passed_builds."""
124 del build_config # unused
125 return cloud_sql_client.BuildInfo('link', '62', '9868.0.0', build_config)
126
Craig Bergstrom58263d32018-04-26 14:11:35 -0600127 def get_relaxed_pased_builds_since_date(self, since_date):
128 """Mock cloud_sql_client.CIDBClient.get_relaxed_pased_builds_since_date."""
129 del since_date # unused
130 return [cloud_sql_client.BuildInfo('grunt', '63', '9968.0.0',
131 'grunt-release')]
132
Xixuan Wu40998892017-08-29 14:32:26 -0700133
134class FakeAndroidBuildRestClient(object):
135 """Mock rest_client.AndroidBuildRestClient."""
136
137 def get_latest_build_id(self, branch, target):
138 """Mock rest_client.AndroidBuildRestClient.get_latest_build_id."""
139 del branch, target # unused
140 return '100'
141
142
143class FakeLabConfig(object):
144 """Mock rest_client.AndroidBuildRestClient."""
145
146 def get_android_board_list(self):
147 """Mock config_reader.LabConfig.get_android_board_list."""
148 return ('android-angler', 'android-bullhead')
149
Xixuan Wu6fb16272017-10-19 13:16:00 -0700150 def get_cros_board_list(self):
151 """Mock config_reader.LabConfig.get_android_board_list."""
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700152 return ('grunt', 'link', 'peppy', 'daisy', 'zako')
Xixuan Wu6fb16272017-10-19 13:16:00 -0700153
Xixuan Wubb74a372018-08-21 17:37:08 -0700154 def get_skylab_board_list(self):
155 """Mock config_reader.LabConfig.get_skylab_board_list."""
156 return set(['nyan_blaze'])
157
Xixuan Wu446b8ad2018-08-23 11:25:43 -0700158 def get_skylab_suite_list(self):
159 """Mock config_reader.LabConfig.get_skylab_suite_list."""
160 return set(['ent-nightly'])
161
Xixuan Wu40998892017-08-29 14:32:26 -0700162 def get_firmware_ro_build_list(self, release_board):
163 """Mock config_reader.LabConfig.get_firmware_ro_build_list."""
164 del release_board # unused
165 return 'firmware1,firmware2'
166
C Shapiro7f24a002017-12-05 14:25:09 -0700167 def get_cros_model_map(self):
168 """Mock config_reader.LabConfig.get_cros_model_map."""
169 return {}
170
Xixuan Wu40998892017-08-29 14:32:26 -0700171
Xixuan Wu008ee832017-10-12 16:59:34 -0700172class TriggerReceiverBaseTestCase(unittest.TestCase):
Xixuan Wu40998892017-08-29 14:32:26 -0700173
174 def setUp(self):
175 self.testbed = testbed.Testbed()
176 self.testbed.activate()
177 self.addCleanup(self.testbed.deactivate)
178
179 self.testbed.init_datastore_v3_stub()
180 self.testbed.init_memcache_stub()
181 ndb.get_context().clear_cache()
182 self.testbed.init_taskqueue_stub(
183 root_path=os.path.join(os.path.dirname(__file__)))
184 self.taskqueue_stub = self.testbed.get_stub(
185 testbed.TASKQUEUE_SERVICE_NAME)
186
187 mock_cidb_client = mock.patch('cloud_sql_client.CIDBClient')
188 self._mock_cidb_client = mock_cidb_client.start()
189 self.addCleanup(mock_cidb_client.stop)
190
191 mock_android_client = mock.patch('rest_client.AndroidBuildRestClient')
192 self._mock_android_client = mock_android_client.start()
193 self.addCleanup(mock_android_client.stop)
194
Xixuan Wu40998892017-08-29 14:32:26 -0700195 mock_lab_config = mock.patch('config_reader.LabConfig')
196 self._mock_lab_config = mock_lab_config.start()
197 self.addCleanup(mock_lab_config.stop)
198
199 mock_utc_now = mock.patch('time_converter.utc_now')
200 self._mock_utc_now = mock_utc_now.start()
201 self.addCleanup(mock_utc_now.stop)
202
203 self._mock_cidb_client.return_value = FakeCIDBClient()
204 self._mock_android_client.return_value = FakeAndroidBuildRestClient()
Xixuan Wu40998892017-08-29 14:32:26 -0700205 self._mock_lab_config.return_value = FakeLabConfig()
206
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700207 board_family_patcher = mock.patch(
208 'build_lib.get_board_family_mapping_from_gs')
209 board_family_getter = board_family_patcher.start()
210 board_family_getter.return_value = {
211 'nyan': ['nyan', 'nyan_blaze', 'nyan_big'],
212 'ivybridge': ['link', 'link_freon']}
213 self.addCleanup(board_family_patcher.stop)
214
Xixuan Wu008ee832017-10-12 16:59:34 -0700215
216class TriggerReceiverFakeConfigTestCase(TriggerReceiverBaseTestCase):
217
218 _TEST_PST_HOUR = 20
219 _TEST_PST_DAY = 4 # Friday
220 _TEST_EVENT_PST_HOUR = 13
221
222 _FAKE_NIGHTLY_TASK_NAME = 'fake_nightly_task'
223 _FAKE_WEEKLY_TASK_NAME = 'fake_weekly_task'
224
225 def setUp(self):
226 super(TriggerReceiverFakeConfigTestCase, self).setUp()
227
228 self.fake_config = config_reader.ConfigReader(None)
229 self._add_nightly_tasks(self.fake_config)
230 self._add_weekly_tasks(self.fake_config)
231
232 self.fake_config_with_settings = config_reader.ConfigReader(None)
233 self._add_weekly_tasks(self.fake_config_with_settings)
234 self._add_weekly_params(self.fake_config_with_settings)
235
236 mock_config_reader = mock.patch('config_reader.ConfigReader')
237 self._mock_config_reader = mock_config_reader.start()
238 self.addCleanup(mock_config_reader.stop)
239
240 def _add_nightly_tasks(self, fake_config):
241 fake_config.add_section(self._FAKE_NIGHTLY_TASK_NAME)
242 fake_config.set(self._FAKE_NIGHTLY_TASK_NAME, 'suite', 'fake_suite')
243 fake_config.set(self._FAKE_NIGHTLY_TASK_NAME, 'run_on', 'nightly')
244 fake_config.set(self._FAKE_NIGHTLY_TASK_NAME, 'hour',
245 str(self._TEST_PST_HOUR))
246
247 def _add_weekly_tasks(self, fake_config):
248 fake_config.add_section(self._FAKE_WEEKLY_TASK_NAME)
249 fake_config.set(self._FAKE_WEEKLY_TASK_NAME, 'suite', 'fake_suite')
250 fake_config.set(self._FAKE_WEEKLY_TASK_NAME, 'run_on', 'weekly')
251 fake_config.set(self._FAKE_WEEKLY_TASK_NAME, 'day', str(self._TEST_PST_DAY))
252
253 def _add_weekly_params(self, fake_config):
254 weekly_section_name = config_reader.EVENT_CLASSES['weekly'].section_name()
255 fake_config.add_section(weekly_section_name)
256 fake_config.set(weekly_section_name, 'hour', str(self._TEST_EVENT_PST_HOUR))
257
258 def testInitializeTriggerReceiverWithNightlyEvent(self):
259 """Test nightly event can be handled on right hour."""
260 # A task with hour=20 should be scheduled at 20:00 in PST everyday, which
261 # is 3:00/4:00 in UTC everyday.
262 self._mock_config_reader.return_value = self.fake_config
263 given_utc_hour = time_converter.convert_time_info(
264 time_converter.TimeInfo(None, self._TEST_PST_HOUR)).hour
265 utc_now = datetime.datetime(2017, 8, 6, given_utc_hour,
266 tzinfo=time_converter.UTC_TZ)
267 last_exec_client = datastore_client.LastExecutionRecordStore()
268 last_exec_client.set_last_execute_time(
269 'nightly', utc_now - datetime.timedelta(hours=1))
270 self._mock_utc_now.return_value = utc_now
271
272 suite_trigger = trigger_receiver.TriggerReceiver()
273 suite_trigger.cron()
274 self.assertTrue(suite_trigger.events['nightly'].should_handle)
275 self.assertEqual(len(suite_trigger.event_results['nightly']), 1)
276 self.assertEqual(suite_trigger.event_results['nightly'][0],
277 self._FAKE_NIGHTLY_TASK_NAME)
278
279 def testInitializeTriggerReceiverWithWeeklyEventWithoutEventHour(self):
280 """Test weekly event without event settings can be handled on right day."""
281 # A task with day=4 (Friday) and default event_hour (23) should be
282 # scheduled at Friday 23:00 in PST, which is Saturday 6:00 or 7:00 in UTC.
283 self._mock_config_reader.return_value = self.fake_config
284 given_utc_hour = time_converter.convert_time_info(
285 time_converter.TimeInfo(
286 self._TEST_PST_DAY,
287 config_reader.EVENT_CLASSES['weekly'].DEFAULT_PST_HOUR)).hour
288 utc_now = datetime.datetime(2017, 10, 14, given_utc_hour,
289 tzinfo=time_converter.UTC_TZ)
290 last_exec_client = datastore_client.LastExecutionRecordStore()
291 last_exec_client.set_last_execute_time(
292 'weekly', utc_now - datetime.timedelta(days=1))
293 self._mock_utc_now.return_value = utc_now
294
295 suite_trigger = trigger_receiver.TriggerReceiver()
296 suite_trigger.cron()
297 self.assertTrue(suite_trigger.events['weekly'].should_handle)
298 self.assertEqual(len(suite_trigger.event_results['weekly']), 1)
299 self.assertEqual(suite_trigger.event_results['weekly'][0],
300 self._FAKE_WEEKLY_TASK_NAME)
301
302 def testInitializeTriggerReceiverWithWeeklyEventWithEventHour(self):
303 """Test weekly event with event settings can be handled on right day."""
304 # A task with day=4 (Friday) and event_hour=13 should be scheduled at
305 # Friday 13:00 in PST, which is Friday 20:00 or 21:00 in UTC.
306 self._mock_config_reader.return_value = self.fake_config_with_settings
307 given_utc_time_info = time_converter.convert_time_info(
308 time_converter.TimeInfo(self._TEST_PST_DAY, self._TEST_EVENT_PST_HOUR))
309
310 # Set the current time as a Friday 20:00 or 21:00 in UTC.
311 utc_now = datetime.datetime(2017, 10, 13, given_utc_time_info.hour,
312 tzinfo=time_converter.UTC_TZ)
313 last_exec_client = datastore_client.LastExecutionRecordStore()
314 last_exec_client.set_last_execute_time(
315 'weekly', utc_now - datetime.timedelta(days=1))
316 self._mock_utc_now.return_value = utc_now
317
318 suite_trigger = trigger_receiver.TriggerReceiver()
319 suite_trigger.cron()
320 self.assertTrue(suite_trigger.events['weekly'].should_handle)
321 self.assertEqual(len(suite_trigger.event_results['weekly']), 1)
322 self.assertEqual(suite_trigger.event_results['weekly'][0],
323 self._FAKE_WEEKLY_TASK_NAME)
324
325
Craig Bergstrom58263d32018-04-26 14:11:35 -0600326class TriggerReceiverFakeBuildTestCase(TriggerReceiverBaseTestCase):
327 """Test the new_build functionality."""
328
Craig Bergstrom58263d32018-04-26 14:11:35 -0600329 def setUp(self):
330 """Set up for a test."""
331 super(TriggerReceiverFakeBuildTestCase, self).setUp()
332
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700333 self._prepare()
334
335 def _prepare(self):
Craig Bergstrom58263d32018-04-26 14:11:35 -0600336 self.fake_config = config_reader.ConfigReader(None)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600337 mock_config_reader = mock.patch('config_reader.ConfigReader')
338 self._mock_config_reader = mock_config_reader.start()
339 self.addCleanup(mock_config_reader.stop)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600340
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700341 # Set last execution time for new_build events.
342 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600343 last_exec_client = datastore_client.LastExecutionRecordStore()
344 last_exec_client.set_last_execute_time(
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700345 'new_build', utc_now - datetime.timedelta(hours=1))
Craig Bergstrom58263d32018-04-26 14:11:35 -0600346 self._mock_utc_now.return_value = utc_now
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700347
348 def testNewBuildForHWTestSanityRequired(self):
349 """Test the new_build functionality."""
350 # Construct a fake config with only_hwtest_sanity_required.
351 fsnbt_name = 'FakeStrictNewBuildTask'
352 self.fake_config.add_section(fsnbt_name)
353 self.fake_config.set(fsnbt_name, 'run_on', 'new_build')
354 self.fake_config.set(fsnbt_name, 'suite', 'fake_suite_base')
355 frnbt_name = 'FakeRelaxedNewBuildTask'
356 self.fake_config.add_section(frnbt_name)
357 self.fake_config.set(frnbt_name, 'run_on', 'new_build')
358 self.fake_config.set(frnbt_name, 'suite', 'fake_suite_relaxed')
359 self.fake_config.set(frnbt_name, 'only_hwtest_sanity_required', 'True')
360
361 self._mock_config_reader.return_value = self.fake_config
Craig Bergstrom58263d32018-04-26 14:11:35 -0600362
363 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600364 suite_trigger = trigger_receiver.TriggerReceiver()
365 suite_trigger.cron()
366
367 # Validate that the expected tests got kicked off.
Craig Bergstrom58263d32018-04-26 14:11:35 -0600368 self.assertEqual(len(suite_trigger.event_results), 1)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600369 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700370 self.assertEqual(len(tasks), 3)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600371
372 # The number of builds that matched the base (success) Task.
373 count_base = 0
374 # The number of builds that matched the relaxed Task.
375 count_relaxed = 0
376 for task in tasks:
377 if 'fake_suite_base' in task.payload:
378 # Make sure it matched the expected build only.
Craig Bergstrom58263d32018-04-26 14:11:35 -0600379 self.assertNotIn('grunt-release', task.payload)
380 count_base += 1
381
382 if 'fake_suite_relaxed' in task.payload:
383 self.assertIn('grunt-release', task.payload)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600384 count_relaxed += 1
385
386 # Make each case matched precisely one event.
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700387 self.assertEqual(2, count_base)
Craig Bergstrom58263d32018-04-26 14:11:35 -0600388 self.assertEqual(1, count_relaxed)
389
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700390 def testNewBuildWithExistingBoardFamilies(self):
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700391 """Test the new_build suite with an existing board family."""
392 link_suite = 'FakeLinkNewBuildTask'
393 self.fake_config.add_section(link_suite)
394 self.fake_config.set(link_suite, 'run_on', 'new_build')
395 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700396 self.fake_config.set(link_suite, 'board_families', 'ivybridge')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700397 self._mock_config_reader.return_value = self.fake_config
398
399 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
400 suite_trigger = trigger_receiver.TriggerReceiver()
401 suite_trigger.cron()
402
403 self.assertEqual(len(suite_trigger.event_results), 1)
404 self.assertEqual(suite_trigger.event_results['new_build'],
405 [link_suite])
406 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
407 self.assertEqual(len(tasks), 1)
408 self.assertIn('link-release', tasks[0].payload)
409
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700410 def testNewBuildWithExistingBoardFamiliesAndBoards(self):
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700411 """Test the new_build suite with an existing board family."""
412 link_suite = 'FakeLinkNewBuildTask'
413 self.fake_config.add_section(link_suite)
414 self.fake_config.set(link_suite, 'run_on', 'new_build')
415 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700416 self.fake_config.set(link_suite, 'board_families', 'ivybridge')
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700417 self.fake_config.set(link_suite, 'boards', 'asuka, paine, banon')
418 self._mock_config_reader.return_value = self.fake_config
419
420 suite_trigger = trigger_receiver.TriggerReceiver()
421 suite_trigger.cron()
422
423 self.assertEqual(len(suite_trigger.event_results), 1)
424 self.assertEqual(suite_trigger.event_results['new_build'],
425 [link_suite])
426 boards = suite_trigger.events['new_build'].task_list[0].boards
427 self.assertIn('asuka', boards)
428 self.assertIn('link', boards)
429
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700430 def testNewBuildWithNonExistingBoardFamilies(self):
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700431 """Test the new_build suite with an non-existing board family."""
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700432 nyan_suite = 'FakeNonExistBoardFamiliesNewBuildTask'
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700433 self.fake_config.add_section(nyan_suite)
434 self.fake_config.set(nyan_suite, 'run_on', 'new_build')
435 self.fake_config.set(nyan_suite, 'suite', 'fake_suite_base')
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700436 self.fake_config.set(nyan_suite, 'board_families', 'nyan')
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 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
445 self.assertEqual(len(tasks), 0)
446
447 def testNewBuildWithNonSpecifiedBoardFamily(self):
448 """Test the new_build suite with an non-specified board family."""
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700449 normal_suite = 'FakeBoardFamiliesNewBuildTask'
Xixuan Wu244e0ec2018-05-23 14:49:55 -0700450 self.fake_config.add_section(normal_suite)
451 self.fake_config.set(normal_suite, 'run_on', 'new_build')
452 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
453 self._mock_config_reader.return_value = self.fake_config
454
455 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
456 suite_trigger = trigger_receiver.TriggerReceiver()
457 suite_trigger.cron()
458
459 self.assertEqual(len(suite_trigger.event_results), 1)
460 self.assertEqual(suite_trigger.event_results['new_build'],
461 [normal_suite])
462 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
463 self.assertEqual(len(tasks), 2)
464
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700465 def testNewBuildExcludingExistingBoardFamilies(self):
466 """Test the new_build suite excluding an existing board family."""
467 link_suite = 'FakeLinkNewBuildTask'
468 self.fake_config.add_section(link_suite)
469 self.fake_config.set(link_suite, 'run_on', 'new_build')
470 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
471 self.fake_config.set(link_suite, 'exclude_board_families', 'ivybridge')
472 self._mock_config_reader.return_value = self.fake_config
473
474 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
475 suite_trigger = trigger_receiver.TriggerReceiver()
476 suite_trigger.cron()
477
478 self.assertEqual(len(suite_trigger.event_results), 1)
479 self.assertEqual(suite_trigger.event_results['new_build'],
480 [link_suite])
481 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
482 self.assertEqual(len(tasks), 1)
483 self.assertNotIn('link-release', tasks[0].payload)
484 self.assertIn('zako-release', tasks[0].payload)
485
486 def testNewBuildExcludingExistingBoardFamiliesAndBoards(self):
487 """Test the new_build suite with an existing board family."""
488 link_suite = 'FakeLinkNewBuildTask'
489 self.fake_config.add_section(link_suite)
490 self.fake_config.set(link_suite, 'run_on', 'new_build')
491 self.fake_config.set(link_suite, 'suite', 'fake_suite_base')
492 self.fake_config.set(link_suite, 'exclude_board_families', 'ivybridge')
493 self.fake_config.set(link_suite, 'exclude_boards', 'asuka, paine, banon')
494 self._mock_config_reader.return_value = self.fake_config
495
496 suite_trigger = trigger_receiver.TriggerReceiver()
497 suite_trigger.cron()
498
499 self.assertEqual(len(suite_trigger.event_results), 1)
500 self.assertEqual(suite_trigger.event_results['new_build'],
501 [link_suite])
502 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
503 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
504 self.assertNotIn('link-release', tasks[0].payload)
505 self.assertNotIn('asuka-release', tasks[0].payload)
506 self.assertIn('zako-release', tasks[0].payload)
507
508 def testNewBuildExcludingNonExistingBoardFamilies(self):
509 """Test the new_build suite excluding an non-existing board family."""
510 nyan_suite = 'FakeNonExistExcludeBoardFamiliesNewBuildTask'
511 self.fake_config.add_section(nyan_suite)
512 self.fake_config.set(nyan_suite, 'run_on', 'new_build')
513 self.fake_config.set(nyan_suite, 'suite', 'fake_suite_base')
514 self.fake_config.set(nyan_suite, 'exclude_board_families', 'nyan')
515 self._mock_config_reader.return_value = self.fake_config
516
517 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
518 suite_trigger = trigger_receiver.TriggerReceiver()
519 suite_trigger.cron()
520
521 self.assertEqual(len(suite_trigger.event_results), 1)
522 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
523 self.assertEqual(len(tasks), 2)
524
525 def testNewBuildWithBoardExcludeBoardCollision(self):
526 """Test the new_build suite specified same board in boards and
527 exclude_boards."""
528 normal_suite = 'FakeBoardExludingBoardCollisionNewBuildTask'
529 self.fake_config.add_section(normal_suite)
530 self.fake_config.set(normal_suite, 'run_on', 'new_build')
531 self.fake_config.set(normal_suite, 'suite', 'fake_suite_base')
532 self.fake_config.set(normal_suite, 'boards', 'zako, asuka')
533 self.fake_config.set(normal_suite, 'exclude_boards', 'asuka')
534 self._mock_config_reader.return_value = self.fake_config
535
536 queue = taskqueue.Queue(task_executor.SUITES_QUEUE)
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 [normal_suite])
543 # self.assertIn('new_build', suite_trigger.event_results)
544 tasks = queue.lease_tasks(3600, 10, deadline=0.5)
545 self.assertEqual(len(tasks), 1)
546 self.assertNotIn('asuka-release', tasks[0].payload)
547 self.assertIn('zako-release', tasks[0].payload)
548
Craig Bergstrom58263d32018-04-26 14:11:35 -0600549
Xixuan Wu008ee832017-10-12 16:59:34 -0700550class TriggerReceiverRealConfigTestCase(TriggerReceiverBaseTestCase):
551
552 def setUp(self):
553 super(TriggerReceiverRealConfigTestCase, self).setUp()
554 mock_config_reader = mock.patch('config_reader.ConfigReader')
555 self._mock_config_reader = mock_config_reader.start()
556 self.addCleanup(mock_config_reader.stop)
557 self._mock_config_reader.return_value = _SUITE_CONFIG_READER
558
559 def _get_ground_truth_task_list_from_config(self):
560 """Get the ground truth of to-be-scheduled task list from config file."""
561 self._mock_utc_now.return_value = datetime.datetime.now(
562 time_converter.UTC_TZ)
563 task_config = config_reader.TaskConfig(_SUITE_CONFIG_READER)
564 tasks = {}
565 for keyword, klass in config_reader.EVENT_CLASSES.iteritems():
566 new_event = klass(
567 task_config.get_event_setting(klass.section_name()), None)
568 new_event.set_task_list(
569 task_config.get_tasks_by_keyword(klass.KEYWORD)['tasks'])
570 tasks[keyword] = new_event.task_list
571
572 return tasks
573
Xixuan Wu40998892017-08-29 14:32:26 -0700574 def testCronWithoutLastExec(self):
575 """Test the first round of cron can be successfully executed."""
576 self._mock_utc_now.return_value = datetime.datetime.now(
577 time_converter.UTC_TZ)
578 suite_trigger = trigger_receiver.TriggerReceiver()
579 suite_trigger.cron()
580 self.assertFalse(suite_trigger.events['nightly'].should_handle)
581 self.assertFalse(suite_trigger.events['weekly'].should_handle)
582 self.assertFalse(suite_trigger.events['new_build'].should_handle)
583
584 self.assertEqual(suite_trigger.event_results, {})
585
586 def testCronTriggerNightly(self):
587 """Test nightly event is read with available nightly last_exec_time."""
588 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
589 last_exec_client = datastore_client.LastExecutionRecordStore()
590 last_exec_client.set_last_execute_time(
591 'nightly', utc_now - datetime.timedelta(hours=1))
592 self._mock_utc_now.return_value = utc_now
593 suite_trigger = trigger_receiver.TriggerReceiver()
594 self.assertTrue(suite_trigger.events['nightly'].should_handle)
595 self.assertFalse(suite_trigger.events['weekly'].should_handle)
596 self.assertFalse(suite_trigger.events['new_build'].should_handle)
597
Xixuan Wu33179672017-09-12 11:44:04 -0700598 def testCronTriggerNightlyOutdated(self):
599 """Test nightly event is read with available nightly last_exec_time."""
600 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
601 last_exec_client = datastore_client.LastExecutionRecordStore()
602 last_exec_client.set_last_execute_time(
603 'nightly', utc_now - datetime.timedelta(days=3))
604 self._mock_utc_now.return_value = utc_now
605 suite_trigger = trigger_receiver.TriggerReceiver()
606 self.assertFalse(suite_trigger.events['nightly'].should_handle)
607
608 def testCronTriggerWeeklyOutdated(self):
609 """Test weekly event is read with available weekly last_exec_time."""
610 utc_now = datetime.datetime.now(time_converter.UTC_TZ)
611 last_exec_client = datastore_client.LastExecutionRecordStore()
612 last_exec_client.set_last_execute_time(
613 'weekly', utc_now - datetime.timedelta(days=8))
614 self._mock_utc_now.return_value = utc_now
615 suite_trigger = trigger_receiver.TriggerReceiver()
616 self.assertFalse(suite_trigger.events['weekly'].should_handle)
617
Xixuan Wu40998892017-08-29 14:32:26 -0700618 def testCronForWeeks(self):
619 """Ensure cron job can be successfully scheduled for several weeks."""
Xixuan Wu008ee832017-10-12 16:59:34 -0700620 all_tasks = self._get_ground_truth_task_list_from_config()
621 nightly_time_info = time_converter.convert_time_info(
Xixuan Wu40998892017-08-29 14:32:26 -0700622 time_converter.TimeInfo(
623 config_reader.EVENT_CLASSES['nightly'].DEFAULT_PST_DAY,
624 config_reader.EVENT_CLASSES['nightly'].DEFAULT_PST_HOUR))
Xixuan Wu008ee832017-10-12 16:59:34 -0700625 weekly_time_info = time_converter.convert_time_info(
Xixuan Wu40998892017-08-29 14:32:26 -0700626 time_converter.TimeInfo(
627 config_reader.EVENT_CLASSES['weekly'].DEFAULT_PST_DAY,
628 config_reader.EVENT_CLASSES['weekly'].DEFAULT_PST_HOUR))
629 last_now = None
630
631 for now in now_generator(datetime.datetime.now(time_converter.UTC_TZ)):
632 self._mock_utc_now.return_value = now
633 suite_trigger = trigger_receiver.TriggerReceiver()
Xixuan Wu5451a662017-10-17 10:57:40 -0700634 with mock.patch('task.Task.schedule', return_value=True):
635 suite_trigger.cron()
Xixuan Wu40998892017-08-29 14:32:26 -0700636
Xixuan Wu40998892017-08-29 14:32:26 -0700637 should_scheduled_nightly_tasks = [
638 t.name for t in all_tasks['nightly']
639 if (t.hour is not None and t.hour == now.hour) or
640 (t.hour is None and now.hour == nightly_time_info.hour)]
Xixuan Wu008ee832017-10-12 16:59:34 -0700641
Xixuan Wu40998892017-08-29 14:32:26 -0700642 if (_should_schedule_nightly_task(last_now, now) and
643 should_scheduled_nightly_tasks):
644 self.assertEqual(suite_trigger.event_results['nightly'],
645 should_scheduled_nightly_tasks)
646 else:
647 self.assertNotIn('nightly', suite_trigger.event_results.keys())
648
649 # Verify weekly tasks
650 should_scheduled_weekly_tasks = [
651 t.name for t in all_tasks['weekly']
652 if (t.day is not None and now.weekday() == t.day) or
653 (t.day is None and now.weekday() == weekly_time_info.weekday)]
654 if (_should_schedule_weekly_task(last_now, now, weekly_time_info) and
655 should_scheduled_weekly_tasks):
656 self.assertEqual(suite_trigger.event_results['weekly'],
657 should_scheduled_weekly_tasks)
658 else:
659 self.assertNotIn('weekly', suite_trigger.event_results.keys())
660
661 # Verify new_build tasks
662 should_scheduled_new_build_tasks = [
663 t.name for t in all_tasks['new_build']]
664 if (_should_schedule_new_build_task(last_now, now) and
665 should_scheduled_new_build_tasks):
666 self.assertEqual(suite_trigger.event_results['new_build'],
667 should_scheduled_new_build_tasks)
668 else:
669 self.assertNotIn('new_build', suite_trigger.event_results.keys())
670
671 last_now = now
672
673
674if __name__ == '__main__':
675 unittest.main()