• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/python
2#
3# Copyright (c) 2013 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
7import datetime, unittest
8
9import mox
10
11import common
12# This must come before the import of complete_failures in order to use the
13# in memory database.
14from autotest_lib.frontend import setup_django_readonly_environment
15from autotest_lib.frontend import setup_test_environment
16import complete_failures
17from autotest_lib.client.common_lib import mail
18from autotest_lib.frontend.tko import models
19from django import test
20
21
22GOOD_STATUS_IDX = 6
23
24# See complte_failurs_functional_tests.py for why we need this.
25class MockDatetime(datetime.datetime):
26    """Used to mock out parts of datetime.datetime."""
27    pass
28
29
30class EmailAboutTestFailureTests(mox.MoxTestBase):
31    """
32    Tests that emails are sent about failed tests.
33    """
34    def setUp(self):
35        super(EmailAboutTestFailureTests, self).setUp()
36
37        # We need to mock out the send function in all tests or else the
38        # emails will be sent out during tests.
39        self.mox.StubOutWithMock(mail, 'send')
40
41        self._orig_too_long = complete_failures._DAYS_TO_BE_FAILING_TOO_LONG
42
43
44    def tearDown(self):
45        complete_failures._DAYS_TO_BE_FAILING_TOO_LONG = self._orig_too_long
46        super(EmailAboutTestFailureTests, self).tearDown()
47
48
49    def test_email_sent_about_all_failed_tests(self):
50        """Test that the email report mentions all the failed_tests."""
51        complete_failures._DAYS_TO_BE_FAILING_TOO_LONG = 60
52
53        mail.send(
54                'chromeos-test-health@google.com',
55                ['chromeos-lab-infrastructure@google.com'],
56                [],
57                'Long Failing Tests',
58                '1/1 tests have been failing for at least %d days.\n'
59                'They are the following:\n\ntest'
60                    % complete_failures._DAYS_TO_BE_FAILING_TOO_LONG)
61
62        failures = ['test']
63        all_tests = set(failures)
64
65        self.mox.ReplayAll()
66        complete_failures.email_about_test_failure(failures, all_tests)
67
68
69    def test_email_has_test_names_sorted_alphabetically(self):
70        """Test that the email report has entries sorted alphabetically."""
71        complete_failures._DAYS_TO_BE_FAILING_TOO_LONG = 60
72
73        mail.send(
74                'chromeos-test-health@google.com',
75                ['chromeos-lab-infrastructure@google.com'],
76                [],
77                'Long Failing Tests',
78                '2/2 tests have been failing for at least %d days.\n'
79                'They are the following:\n\ntest1\ntest2'
80                    % complete_failures._DAYS_TO_BE_FAILING_TOO_LONG)
81
82        # We use an OrderedDict to gurantee that the elements would be out of
83        # order if we did a simple traversal.
84        failures = ['test2', 'test1']
85        all_tests = set(failures)
86
87        self.mox.ReplayAll()
88        complete_failures.email_about_test_failure(failures, all_tests)
89
90
91    def test_email_count_of_total_number_of_tests(self):
92        """Test that the email report displays total number of tests."""
93        complete_failures._DAYS_TO_BE_FAILING_TOO_LONG = 60
94
95        mail.send(
96                'chromeos-test-health@google.com',
97                ['chromeos-lab-infrastructure@google.com'],
98                [],
99                'Long Failing Tests',
100                '1/2 tests have been failing for at least %d days.\n'
101                'They are the following:\n\ntest'
102                    % complete_failures._DAYS_TO_BE_FAILING_TOO_LONG)
103
104        failures = ['test']
105        all_tests = set(failures) | {'not_failure'}
106
107        self.mox.ReplayAll()
108        complete_failures.email_about_test_failure(failures, all_tests)
109
110
111class IsValidTestNameTests(test.TestCase):
112    """Tests the is_valid_test_name function."""
113
114    def test_returns_true_for_valid_test_name(self):
115        """Test that a valid test name returns True."""
116        name = 'TestName.TestName'
117        self.assertTrue(complete_failures.is_valid_test_name(name))
118
119
120    def test_returns_false_if_name_has_slash_in_it(self):
121        """Test that a name with a slash in it returns False."""
122        name = 'path/to/test'
123        self.assertFalse(complete_failures.is_valid_test_name(name))
124
125
126    def test_returns_false_for_try_new_image_entries(self):
127        """Test that a name that starts with try_new_image returns False."""
128        name = 'try_new_image-blah'
129        self.assertFalse(complete_failures.is_valid_test_name(name))
130
131
132class PrepareLastPassesTests(test.TestCase):
133    """Tests the prepare_last_passes function."""
134
135    def setUp(self):
136        super(PrepareLastPassesTests, self).setUp()
137
138    def tearDown(self):
139        super(PrepareLastPassesTests, self).tearDown()
140
141    def test_does_not_return_invalid_test_names(self):
142        """Tests that tests with invalid test names are not returned."""
143        results = complete_failures.prepare_last_passes(['invalid_test/name'])
144
145        self.assertEqual(results, {})
146
147
148class GetRecentlyRanTestNamesTests(mox.MoxTestBase, test.TestCase):
149    """Tests the get_recently_ran_test_names function."""
150
151    def setUp(self):
152        super(GetRecentlyRanTestNamesTests, self).setUp()
153        self.mox.StubOutWithMock(MockDatetime, 'today')
154        self.datetime = datetime.datetime
155        datetime.datetime = MockDatetime
156        setup_test_environment.set_up()
157        self._orig_cutoff = complete_failures._DAYS_NOT_RUNNING_CUTOFF
158
159
160    def tearDown(self):
161        datetime.datetime = self.datetime
162        complete_failures._DAYS_NOT_RUNNING_CUTOFF = self._orig_cutoff
163        setup_test_environment.tear_down()
164        super(GetRecentlyRanTestNamesTests, self).tearDown()
165
166
167    def test_return_all_recently_ran_tests(self):
168        """Test that the function does as it says it does."""
169        job = models.Job(job_idx=1)
170        kernel = models.Kernel(kernel_idx=1)
171        machine = models.Machine(machine_idx=1)
172        success_status = models.Status(status_idx=GOOD_STATUS_IDX)
173
174        recent = models.Test(job=job, status=success_status,
175                             kernel=kernel, machine=machine,
176                             test='recent',
177                             started_time=self.datetime(2012, 1, 1))
178        recent.save()
179        old = models.Test(job=job, status=success_status,
180                          kernel=kernel, machine=machine,
181                          test='old',
182                          started_time=self.datetime(2011, 1, 2))
183        old.save()
184
185        datetime.datetime.today().AndReturn(self.datetime(2012, 1, 4))
186        complete_failures._DAYS_NOT_RUNNING_CUTOFF = 60
187
188        self.mox.ReplayAll()
189        results = complete_failures.get_recently_ran_test_names()
190
191        self.assertEqual(set(results), set(['recent']))
192
193
194    def test_returns_no_duplicate_names(self):
195        """Test that each test name appears only once."""
196        job = models.Job(job_idx=1)
197        kernel = models.Kernel(kernel_idx=1)
198        machine = models.Machine(machine_idx=1)
199        success_status = models.Status(status_idx=GOOD_STATUS_IDX)
200
201        test = models.Test(job=job, status=success_status,
202                           kernel=kernel, machine=machine,
203                           test='test',
204                           started_time=self.datetime(2012, 1, 1))
205        test.save()
206        duplicate = models.Test(job=job, status=success_status,
207                                kernel=kernel, machine=machine,
208                                test='test',
209                                started_time=self.datetime(2012, 1, 2))
210        duplicate.save()
211
212        datetime.datetime.today().AndReturn(self.datetime(2012, 1, 3))
213        complete_failures._DAYS_NOT_RUNNING_CUTOFF = 60
214
215        self.mox.ReplayAll()
216        results = complete_failures.get_recently_ran_test_names()
217
218        self.assertEqual(len(results), 1)
219
220
221class GetTestsToAnalyzeTests(mox.MoxTestBase):
222    """Tests the get_tests_to_analyze function."""
223
224    def test_returns_recent_test_names(self):
225        """Test should return all the test names in the database."""
226
227        recent_tests = {'passing_test', 'failing_test'}
228        last_passes = {'passing_test': datetime.datetime(2012, 1 ,1),
229                       'old_passing_test': datetime.datetime(2011, 1, 1)}
230
231        results = complete_failures.get_tests_to_analyze(recent_tests,
232                                                         last_passes)
233
234        self.assertEqual(results,
235                         {'passing_test': datetime.datetime(2012, 1, 1),
236                          'failing_test': datetime.datetime.min})
237
238
239    def test_returns_failing_tests_with_min_datetime(self):
240        """Test that never-passed tests are paired with datetime.min."""
241
242        recent_tests = {'test'}
243        last_passes = {}
244
245        self.mox.ReplayAll()
246        results = complete_failures.get_tests_to_analyze(recent_tests,
247                                                         last_passes)
248
249        self.assertEqual(results, {'test': datetime.datetime.min})
250
251
252class FilterOutGoodTestsTests(mox.MoxTestBase):
253    """Tests the filter_our_good_tests function."""
254
255    def setUp(self):
256        super(FilterOutGoodTestsTests, self).setUp()
257        self.mox.StubOutWithMock(MockDatetime, 'today')
258        self.datetime = datetime.datetime
259        datetime.datetime = MockDatetime
260        self._orig_too_long = complete_failures._DAYS_TO_BE_FAILING_TOO_LONG
261
262
263    def tearDown(self):
264        datetime.datetime = self.datetime
265        complete_failures._DAYS_TO_BE_FAILING_TOO_LONG = self._orig_too_long
266        super(FilterOutGoodTestsTests, self).tearDown()
267
268
269    def test_remove_all_tests_that_have_passed_recently_enough(self):
270        """Test that all recently passing tests are not returned."""
271
272        complete_failures._DAYS_TO_BE_FAILING_TOO_LONG = 10
273        datetime.datetime.today().AndReturn(self.datetime(2012, 1, 21))
274
275        self.mox.ReplayAll()
276        result = complete_failures.filter_out_good_tests(
277                {'test': self.datetime(2012, 1, 20)})
278
279        self.assertEqual(result, [])
280
281
282    def test_keep_all_tests_that_have_not_passed_recently_enough(self):
283        """Test that the tests that have not recently passed are returned."""
284
285        complete_failures._DAYS_TO_BE_FAILING_TOO_LONG = 10
286        datetime.datetime.today().AndReturn(self.datetime(2012, 1, 21))
287
288        self.mox.ReplayAll()
289        result = complete_failures.filter_out_good_tests(
290                {'test': self.datetime(2012, 1, 10)})
291
292        self.assertEqual(result, ['test'])
293
294
295if __name__ == '__main__':
296    unittest.main()
297