1#!/usr/bin/python 2# 3# Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7"""Unit tests for site_utils/deduping_scheduler.py.""" 8 9import mox 10import unittest 11 12# driver must be imported first due to circular imports in base_event and task 13import driver # pylint: disable-msg=W0611 14import deduping_scheduler 15 16import common 17from autotest_lib.client.common_lib import error 18from autotest_lib.client.common_lib import priorities 19from autotest_lib.server import frontend, site_utils 20from autotest_lib.server.cros.dynamic_suite import reporting 21 22 23class DedupingSchedulerTest(mox.MoxTestBase): 24 """Unit tests for DedupingScheduler 25 26 @var _BUILD: fake build 27 @var _BOARD: fake board to reimage 28 @var _SUITE: fake suite name 29 @var _POOL: fake machine pool name 30 """ 31 32 _BUILD = 'build' 33 _BUILDS = {'cros-version': 'build'} 34 _BOARD = 'board' 35 _SUITE = 'suite' 36 _POOL = 'pool' 37 _NUM = 2 38 _PRIORITY = priorities.Priority.POSTBUILD 39 _TIMEOUT = 24 40 _TIMEOUT_MINS = 1440 41 42 43 def setUp(self): 44 super(DedupingSchedulerTest, self).setUp() 45 self.afe = self.mox.CreateMock(frontend.AFE) 46 self.scheduler = deduping_scheduler.DedupingScheduler(afe=self.afe) 47 self.mox.StubOutWithMock(site_utils, 'check_lab_status') 48 49 50 def _SetupLabStatus(self, build, message=None): 51 """Set up to mock one call to `site_utils.check_lab_status()`. 52 53 @param build The build to expect to be passed to 54 `check_lab_status()`. 55 @param message `None` if the mocked call should return that 56 the lab status is up. Otherwise, a string for 57 the exception message. 58 59 """ 60 if message is None: 61 site_utils.check_lab_status(build) 62 else: 63 site_utils.check_lab_status(build).AndRaise( 64 site_utils.TestLabException(message)) 65 66 67 def testScheduleSuite(self): 68 """Test a successful de-dup and suite schedule.""" 69 # Lab is UP! 70 self._SetupLabStatus(self._BUILD) 71 # A similar suite has not already been scheduled. 72 self.afe.get_jobs(name__istartswith=self._BUILD, 73 name__iendswith='control.'+self._SUITE, 74 created_on__gte=mox.IgnoreArg(), 75 min_rpc_timeout=mox.IgnoreArg()).AndReturn([]) 76 # Expect an attempt to schedule; allow it to succeed. 77 self.afe.run('create_suite_job', 78 name=self._SUITE, 79 board=self._BOARD, 80 builds=self._BUILDS, 81 check_hosts=False, 82 pool=self._POOL, 83 num=self._NUM, 84 priority=self._PRIORITY, 85 test_source_build=None, 86 timeout=self._TIMEOUT, 87 max_runtime_mins=self._TIMEOUT_MINS, 88 timeout_mins=self._TIMEOUT_MINS, 89 file_bugs=False, 90 wait_for_results=False, 91 job_retry=False, 92 delay_minutes=0, 93 run_prod_code=False, 94 min_rpc_timeout=mox.IgnoreArg()).AndReturn(7) 95 self.mox.ReplayAll() 96 self.assertTrue(self.scheduler.ScheduleSuite(self._SUITE, 97 self._BOARD, 98 self._BUILD, 99 self._POOL, 100 self._NUM, 101 self._PRIORITY, 102 self._TIMEOUT)) 103 104 105 def testShouldNotScheduleSuite(self): 106 """Test a successful de-dup and avoiding scheduling the suite.""" 107 # Lab is UP! 108 self._SetupLabStatus(self._BUILD) 109 # A similar suite has already been scheduled. 110 self.afe.get_jobs( 111 name__istartswith=self._BUILD, 112 name__iendswith='control.'+self._SUITE, 113 created_on__gte=mox.IgnoreArg(), 114 min_rpc_timeout=mox.IgnoreArg()).AndReturn(['42']) 115 self.mox.ReplayAll() 116 self.assertFalse(self.scheduler.ScheduleSuite(self._SUITE, 117 self._BOARD, 118 self._BUILD, 119 self._POOL, 120 None, 121 self._PRIORITY, 122 self._TIMEOUT)) 123 124 125 def testShouldNotScheduleSuiteLabClosed(self): 126 """Test that we don't schedule when the lab is closed.""" 127 # Lab is down. :-( 128 self._SetupLabStatus(self._BUILD, 'Lab closed due to sheep.') 129 self.mox.ReplayAll() 130 self.assertFalse(self.scheduler.ScheduleSuite(self._SUITE, 131 self._BOARD, 132 self._BUILD, 133 self._POOL, 134 None, 135 self._PRIORITY, 136 self._TIMEOUT)) 137 138 139 def testForceScheduleSuite(self): 140 """Test a successful de-dup, but force scheduling the suite.""" 141 # Expect an attempt to schedule; allow it to succeed. 142 self.afe.run('create_suite_job', 143 name=self._SUITE, 144 board=self._BOARD, 145 builds=self._BUILDS, 146 check_hosts=False, 147 num=None, 148 pool=self._POOL, 149 priority=self._PRIORITY, 150 test_source_build=None, 151 timeout=self._TIMEOUT, 152 max_runtime_mins=self._TIMEOUT_MINS, 153 timeout_mins=self._TIMEOUT_MINS, 154 file_bugs=False, 155 wait_for_results=False, 156 job_retry=False, 157 delay_minutes=0, 158 run_prod_code=False, 159 min_rpc_timeout=mox.IgnoreArg()).AndReturn(7) 160 self.mox.ReplayAll() 161 self.assertTrue(self.scheduler.ScheduleSuite(self._SUITE, 162 self._BOARD, 163 self._BUILD, 164 self._POOL, 165 None, 166 self._PRIORITY, 167 self._TIMEOUT, 168 force=True)) 169 170 171 def testShouldScheduleSuiteExplodes(self): 172 """Test a failure to de-dup.""" 173 # Lab is UP! 174 self._SetupLabStatus(self._BUILD) 175 # Barf while checking for similar suites. 176 self.afe.get_jobs( 177 name__istartswith=self._BUILD, 178 name__iendswith='control.'+self._SUITE, 179 created_on__gte=mox.IgnoreArg(), 180 min_rpc_timeout=mox.IgnoreArg()).AndRaise(Exception()) 181 self.mox.ReplayAll() 182 self.assertRaises(deduping_scheduler.DedupException, 183 self.scheduler.ScheduleSuite, 184 self._SUITE, 185 self._BOARD, 186 self._BUILD, 187 self._POOL, 188 self._NUM, 189 self._PRIORITY, 190 self._TIMEOUT) 191 192 193 def testScheduleFail(self): 194 """Test a successful de-dup and failure to schedule the suite.""" 195 # Lab is UP! 196 self._SetupLabStatus(self._BUILD) 197 # A similar suite has not already been scheduled. 198 self.afe.get_jobs(name__istartswith=self._BUILD, 199 name__iendswith='control.'+self._SUITE, 200 created_on__gte=mox.IgnoreArg(), 201 min_rpc_timeout=mox.IgnoreArg()).AndReturn([]) 202 # Expect an attempt to create a job for the suite; fail it. 203 self.afe.run('create_suite_job', 204 name=self._SUITE, 205 board=self._BOARD, 206 builds=self._BUILDS, 207 check_hosts=False, 208 num=None, 209 pool=None, 210 priority=self._PRIORITY, 211 test_source_build=None, 212 timeout=self._TIMEOUT, 213 max_runtime_mins=self._TIMEOUT_MINS, 214 timeout_mins=self._TIMEOUT_MINS, 215 file_bugs=False, 216 wait_for_results=False, 217 run_prod_code=False, 218 min_rpc_timeout=mox.IgnoreArg()).AndReturn(None) 219 self.mox.ReplayAll() 220 self.assertRaises(deduping_scheduler.ScheduleException, 221 self.scheduler.ScheduleSuite, 222 self._SUITE, 223 self._BOARD, 224 self._BUILD, 225 None, 226 None, 227 self._PRIORITY, 228 self._TIMEOUT) 229 230 231 def testScheduleExplodes(self): 232 """Test a successful de-dup and barf while scheduling the suite.""" 233 # Lab is UP! 234 self._SetupLabStatus(self._BUILD) 235 # A similar suite has not already been scheduled. 236 self.afe.get_jobs(name__istartswith=self._BUILD, 237 name__iendswith='control.'+self._SUITE, 238 created_on__gte=mox.IgnoreArg(), 239 min_rpc_timeout=mox.IgnoreArg()).AndReturn([]) 240 # Expect an attempt to create a job for the suite; barf on it. 241 self.afe.run('create_suite_job', 242 name=self._SUITE, 243 board=self._BOARD, 244 builds=self._BUILDS, 245 check_hosts=False, 246 num=None, 247 pool=None, 248 priority=self._PRIORITY, 249 test_source_build=None, 250 timeout=self._TIMEOUT, 251 max_runtime_mins=self._TIMEOUT_MINS, 252 timeout_mins=self._TIMEOUT_MINS, 253 file_bugs=False, 254 wait_for_results=False, 255 run_prod_code=False, 256 min_rpc_timeout=mox.IgnoreArg()).AndRaise(Exception()) 257 self.mox.ReplayAll() 258 self.assertRaises(deduping_scheduler.ScheduleException, 259 self.scheduler.ScheduleSuite, 260 self._SUITE, 261 self._BOARD, 262 self._BUILD, 263 None, 264 None, 265 self._PRIORITY, 266 self._TIMEOUT) 267 268 269 def _SetupScheduleSuiteMocks(self, mock_bug_id): 270 """Setup mocks needed for SuiteSchedulerBug testing. 271 272 @param mock_bug_id: An integer representing a bug id that should be 273 returned by Reporter._create_bug_report 274 None if _create_bug_report is supposed to 275 fail. 276 """ 277 self.mox.StubOutWithMock(reporting.Reporter, '__init__') 278 self.mox.StubOutWithMock(reporting.Reporter, '_create_bug_report') 279 self.mox.StubOutWithMock(reporting.Reporter, '_check_tracker') 280 self.mox.StubOutWithMock(reporting.Reporter, '_find_issue_by_marker') 281 self.mox.StubOutWithMock(site_utils, 'get_sheriffs') 282 self.scheduler._file_bug = True 283 # Lab is UP! 284 self._SetupLabStatus(self._BUILD) 285 # A similar suite has not already been scheduled. 286 self.afe.get_jobs(name__istartswith=self._BUILD, 287 name__iendswith='control.'+self._SUITE, 288 created_on__gte=mox.IgnoreArg(), 289 min_rpc_timeout=mox.IgnoreArg()).AndReturn([]) 290 message = 'Control file not found.' 291 exception = error.ControlFileNotFound(message) 292 site_utils.get_sheriffs(lab_only=True).AndReturn(['deputy1', 'deputy2']) 293 self.afe.run('create_suite_job', 294 name=self._SUITE, 295 board=self._BOARD, 296 builds=self._BUILDS, 297 check_hosts=False, 298 pool=self._POOL, 299 num=self._NUM, 300 priority=self._PRIORITY, 301 test_source_build=None, 302 timeout=self._TIMEOUT, 303 max_runtime_mins=self._TIMEOUT_MINS, 304 timeout_mins=self._TIMEOUT_MINS, 305 file_bugs=False, 306 wait_for_results=False, 307 job_retry=False, 308 delay_minutes=0, 309 run_prod_code=False, 310 min_rpc_timeout=mox.IgnoreArg()).AndRaise(exception) 311 reporting.Reporter.__init__() 312 reporting.Reporter._check_tracker().AndReturn(True) 313 (reporting.Reporter._find_issue_by_marker(mox.IgnoreArg()) 314 .AndReturn(None)) 315 reporting.Reporter._create_bug_report( 316 mox.IgnoreArg(), {}, []).AndReturn(mock_bug_id) 317 318 319 def testScheduleReportsBugSuccess(self): 320 """Test that the scheduler file a bug.""" 321 self._SetupScheduleSuiteMocks(1158) 322 self.mox.ReplayAll() 323 self.assertFalse(self.scheduler.ScheduleSuite( 324 self._SUITE, self._BOARD, self._BUILD, self._POOL, 325 self._NUM, self._PRIORITY, self._TIMEOUT)) 326 self.mox.VerifyAll() 327 328 329 def testScheduleReportsBugFalse(self): 330 """Test that the scheduler failed to file a bug.""" 331 self._SetupScheduleSuiteMocks(None) 332 self.mox.ReplayAll() 333 self.assertRaises( 334 deduping_scheduler.ScheduleException, 335 self.scheduler.ScheduleSuite, 336 self._SUITE, self._BOARD, self._BUILD, self._POOL, 337 self._NUM, self._PRIORITY, self._TIMEOUT) 338 self.mox.VerifyAll() 339 340 341if __name__ == '__main__': 342 unittest.main() 343