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
41
42    def setUp(self):
43        super(DedupingSchedulerTest, self).setUp()
44        self.afe = self.mox.CreateMock(frontend.AFE)
45        self.scheduler = deduping_scheduler.DedupingScheduler(afe=self.afe)
46        self.mox.StubOutWithMock(site_utils, 'check_lab_status')
47
48
49    def _SetupLabStatus(self, build, message=None):
50        """Set up to mock one call to `site_utils.check_lab_status()`.
51
52        @param build    The build to expect to be passed to
53                        `check_lab_status()`.
54        @param message  `None` if the mocked call should return that
55                        the lab status is up.  Otherwise, a string for
56                        the exception message.
57
58        """
59        if message is None:
60            site_utils.check_lab_status(build)
61        else:
62            site_utils.check_lab_status(build).AndRaise(
63                site_utils.TestLabException(message))
64
65
66    def testScheduleSuite(self):
67        """Test a successful de-dup and suite schedule."""
68        # Lab is UP!
69        self._SetupLabStatus(self._BUILD)
70        # A similar suite has not already been scheduled.
71        self.afe.get_jobs(name__startswith=self._BUILD,
72                          name__endswith='control.'+self._SUITE,
73                          created_on__gte=mox.IgnoreArg()).AndReturn([])
74        # Expect an attempt to schedule; allow it to succeed.
75        self.afe.run('create_suite_job',
76                     name=self._SUITE,
77                     board=self._BOARD,
78                     builds=self._BUILDS,
79                     check_hosts=False,
80                     pool=self._POOL,
81                     num=self._NUM,
82                     priority=self._PRIORITY,
83                     test_source_build=None,
84                     timeout=self._TIMEOUT,
85                     file_bugs=False,
86                     wait_for_results=False,
87                     job_retry=False).AndReturn(7)
88        self.mox.ReplayAll()
89        self.assertTrue(self.scheduler.ScheduleSuite(self._SUITE,
90                                                     self._BOARD,
91                                                     self._BUILD,
92                                                     self._POOL,
93                                                     self._NUM,
94                                                     self._PRIORITY,
95                                                     self._TIMEOUT))
96
97
98    def testShouldNotScheduleSuite(self):
99        """Test a successful de-dup and avoiding scheduling the suite."""
100        # Lab is UP!
101        self._SetupLabStatus(self._BUILD)
102        # A similar suite has already been scheduled.
103        self.afe.get_jobs(
104            name__startswith=self._BUILD,
105            name__endswith='control.'+self._SUITE,
106            created_on__gte=mox.IgnoreArg()).AndReturn(['42'])
107        self.mox.ReplayAll()
108        self.assertFalse(self.scheduler.ScheduleSuite(self._SUITE,
109                                                      self._BOARD,
110                                                      self._BUILD,
111                                                      self._POOL,
112                                                      None,
113                                                      self._PRIORITY,
114                                                      self._TIMEOUT))
115
116
117    def testShouldNotScheduleSuiteLabClosed(self):
118        """Test that we don't schedule when the lab is closed."""
119        # Lab is down.  :-(
120        self._SetupLabStatus(self._BUILD, 'Lab closed due to sheep.')
121        self.mox.ReplayAll()
122        self.assertFalse(self.scheduler.ScheduleSuite(self._SUITE,
123                                                      self._BOARD,
124                                                      self._BUILD,
125                                                      self._POOL,
126                                                      None,
127                                                      self._PRIORITY,
128                                                      self._TIMEOUT))
129
130
131    def testForceScheduleSuite(self):
132        """Test a successful de-dup, but force scheduling the suite."""
133        # Expect an attempt to schedule; allow it to succeed.
134        self.afe.run('create_suite_job',
135                     name=self._SUITE,
136                     board=self._BOARD,
137                     builds=self._BUILDS,
138                     check_hosts=False,
139                     num=None,
140                     pool=self._POOL,
141                     priority=self._PRIORITY,
142                     test_source_build=None,
143                     timeout=self._TIMEOUT,
144                     file_bugs=False,
145                     wait_for_results=False,
146                     job_retry=False).AndReturn(7)
147        self.mox.ReplayAll()
148        self.assertTrue(self.scheduler.ScheduleSuite(self._SUITE,
149                                                     self._BOARD,
150                                                     self._BUILD,
151                                                     self._POOL,
152                                                     None,
153                                                     self._PRIORITY,
154                                                     self._TIMEOUT,
155                                                     force=True))
156
157
158    def testShouldScheduleSuiteExplodes(self):
159        """Test a failure to de-dup."""
160        # Lab is UP!
161        self._SetupLabStatus(self._BUILD)
162        # Barf while checking for similar suites.
163        self.afe.get_jobs(
164            name__startswith=self._BUILD,
165            name__endswith='control.'+self._SUITE,
166            created_on__gte=mox.IgnoreArg()).AndRaise(Exception())
167        self.mox.ReplayAll()
168        self.assertRaises(deduping_scheduler.DedupException,
169                          self.scheduler.ScheduleSuite,
170                          self._SUITE,
171                          self._BOARD,
172                          self._BUILD,
173                          self._POOL,
174                          self._NUM,
175                          self._PRIORITY,
176                          self._TIMEOUT)
177
178
179    def testScheduleFail(self):
180        """Test a successful de-dup and failure to schedule the suite."""
181        # Lab is UP!
182        self._SetupLabStatus(self._BUILD)
183        # A similar suite has not already been scheduled.
184        self.afe.get_jobs(name__startswith=self._BUILD,
185                          name__endswith='control.'+self._SUITE,
186                          created_on__gte=mox.IgnoreArg()).AndReturn([])
187        # Expect an attempt to create a job for the suite; fail it.
188        self.afe.run('create_suite_job',
189                     name=self._SUITE,
190                     board=self._BOARD,
191                     builds=self._BUILDS,
192                     check_hosts=False,
193                     num=None,
194                     pool=None,
195                     priority=self._PRIORITY,
196                     test_source_build=None,
197                     timeout=self._TIMEOUT,
198                     file_bugs=False,
199                     wait_for_results=False).AndReturn(None)
200        self.mox.ReplayAll()
201        self.assertRaises(deduping_scheduler.ScheduleException,
202                          self.scheduler.ScheduleSuite,
203                          self._SUITE,
204                          self._BOARD,
205                          self._BUILD,
206                          None,
207                          None,
208                          self._PRIORITY,
209                          self._TIMEOUT)
210
211
212    def testScheduleExplodes(self):
213        """Test a successful de-dup and barf while scheduling the suite."""
214        # Lab is UP!
215        self._SetupLabStatus(self._BUILD)
216        # A similar suite has not already been scheduled.
217        self.afe.get_jobs(name__startswith=self._BUILD,
218                          name__endswith='control.'+self._SUITE,
219                          created_on__gte=mox.IgnoreArg()).AndReturn([])
220        # Expect an attempt to create a job for the suite; barf on it.
221        self.afe.run('create_suite_job',
222                     name=self._SUITE,
223                     board=self._BOARD,
224                     builds=self._BUILDS,
225                     check_hosts=False,
226                     num=None,
227                     pool=None,
228                     priority=self._PRIORITY,
229                     test_source_build=None,
230                     timeout=self._TIMEOUT,
231                     file_bugs=False,
232                     wait_for_results=False).AndRaise(Exception())
233        self.mox.ReplayAll()
234        self.assertRaises(deduping_scheduler.ScheduleException,
235                          self.scheduler.ScheduleSuite,
236                          self._SUITE,
237                          self._BOARD,
238                          self._BUILD,
239                          None,
240                          None,
241                          self._PRIORITY,
242                          self._TIMEOUT)
243
244
245    def _SetupScheduleSuiteMocks(self, mock_bug_id):
246        """Setup mocks needed for SuiteSchedulerBug testing.
247
248        @param mock_bug_id: An integer representing a bug id that should be
249                            returned by Reporter._create_bug_report
250                            None if _create_bug_report is supposed to
251                            fail.
252        """
253        self.mox.StubOutWithMock(reporting.Reporter, '__init__')
254        self.mox.StubOutWithMock(reporting.Reporter, '_create_bug_report')
255        self.mox.StubOutWithMock(reporting.Reporter, '_check_tracker')
256        self.mox.StubOutWithMock(reporting.Reporter, 'find_issue_by_marker')
257        self.mox.StubOutWithMock(site_utils, 'get_sheriffs')
258        self.scheduler._file_bug = True
259        # Lab is UP!
260        self._SetupLabStatus(self._BUILD)
261        # A similar suite has not already been scheduled.
262        self.afe.get_jobs(name__startswith=self._BUILD,
263                          name__endswith='control.'+self._SUITE,
264                          created_on__gte=mox.IgnoreArg()).AndReturn([])
265        message = 'Control file not found.'
266        exception = error.ControlFileNotFound(message)
267        site_utils.get_sheriffs(lab_only=True).AndReturn(['deputy1', 'deputy2'])
268        self.afe.run('create_suite_job',
269                     name=self._SUITE,
270                     board=self._BOARD,
271                     builds=self._BUILDS,
272                     check_hosts=False,
273                     pool=self._POOL,
274                     num=self._NUM,
275                     priority=self._PRIORITY,
276                     test_source_build=None,
277                     timeout=self._TIMEOUT,
278                     file_bugs=False,
279                     wait_for_results=False,
280                     job_retry=False).AndRaise(exception)
281        reporting.Reporter.__init__()
282        reporting.Reporter._check_tracker().AndReturn(True)
283        reporting.Reporter.find_issue_by_marker(mox.IgnoreArg()).AndReturn(None)
284        reporting.Reporter._create_bug_report(
285                mox.IgnoreArg(), {}, []).AndReturn(mock_bug_id)
286
287
288    def testScheduleReportsBugSuccess(self):
289        """Test that the scheduler file a bug."""
290        self._SetupScheduleSuiteMocks(1158)
291        self.mox.ReplayAll()
292        self.assertFalse(self.scheduler.ScheduleSuite(
293                    self._SUITE, self._BOARD, self._BUILD, self._POOL,
294                    self._NUM, self._PRIORITY, self._TIMEOUT))
295        self.mox.VerifyAll()
296
297
298    def testScheduleReportsBugFalse(self):
299        """Test that the scheduler failed to file a bug."""
300        self._SetupScheduleSuiteMocks(None)
301        self.mox.ReplayAll()
302        self.assertRaises(
303                deduping_scheduler.ScheduleException,
304                self.scheduler.ScheduleSuite,
305                self._SUITE, self._BOARD, self._BUILD, self._POOL,
306                self._NUM, self._PRIORITY, self._TIMEOUT)
307        self.mox.VerifyAll()
308
309
310if __name__ == '__main__':
311    unittest.main()
312