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
7#!/usr/bin/python
8#
9# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
10# Use of this source code is governed by a BSD-style license that can be
11# found in the LICENSE file.
12
13import datetime, unittest
14
15import mox
16
17import common
18# This must come before the import of complete_failures in order to use the
19# in memory database.
20from autotest_lib.frontend import setup_django_readonly_environment
21from autotest_lib.frontend import setup_test_environment
22import complete_failures
23from autotest_lib.client.common_lib import mail
24from autotest_lib.frontend.tko import models
25from django import test
26
27
28GOOD_STATUS_IDX = 6
29FAIL_STATUS_IDX = 4
30
31ERROR_STATUS = models.Status(status_idx=2, word='ERROR')
32ABORT_STATUS = models.Status(status_idx=3, word='ABORT')
33FAIL_STATUS = models.Status(status_idx=4, word='FAIL')
34WARN_STATUS = models.Status(status_idx=5, word='WARN')
35GOOD_STATUS = models.Status(status_idx=6, word='GOOD')
36ALERT_STATUS = models.Status(status_idx=7, word='ALERT')
37
38
39def add_statuses():
40    """
41    Save the statuses to the in-memory database.
42
43    These normally exist in the database and the code expects them. However, the
44    normal test database setup does not do this for us.
45    """
46    ERROR_STATUS.save()
47    ABORT_STATUS.save()
48    FAIL_STATUS.save()
49    WARN_STATUS.save()
50    GOOD_STATUS.save()
51    ALERT_STATUS.save()
52
53
54# During the tests there is a point where Django does a type check on
55# datetime.datetime. Unfortunately this means when datetime is mocked out,
56# horrible failures happen when Django tries to do this check. The solution
57# chosen is to create a pure Python class that inheirits from datetime.datetime
58# so that the today class method can be directly mocked out. It is necesarry
59# to mock out datetime.datetime completely as it a C class and so cannot have
60# parts of itself mocked out.
61class MockDatetime(datetime.datetime):
62    """Used to mock out parts of datetime.datetime."""
63    pass
64
65
66class CompleteFailuresFunctionalTests(mox.MoxTestBase, test.TestCase):
67    """
68    Does a functional test of the complete_failures script.
69
70    This uses an in-memory database but everything else is a full run.
71
72    """
73
74    def setUp(self):
75        super(CompleteFailuresFunctionalTests, self).setUp()
76        setup_test_environment.set_up()
77        add_statuses()
78        # All of our tests will involve mocking out the datetime.today() class
79        # method.
80        self.mox.StubOutWithMock(MockDatetime, 'today')
81        self.datetime = datetime.datetime
82        datetime.datetime = MockDatetime
83        # We need to mock out the send function in all tests or else the
84        # emails will be sent out during tests.
85        self.mox.StubOutWithMock(mail, 'send')
86
87        self._orignal_too_late = complete_failures._DAYS_TO_BE_FAILING_TOO_LONG
88
89
90    def tearDown(self):
91        complete_failures._DAYS_TO_BE_FAILING_TOO_LONG = self._orignal_too_late
92        datetime.datetime = self.datetime
93        setup_test_environment.tear_down()
94        super(CompleteFailuresFunctionalTests, self).tearDown()
95
96
97    def test(self):
98        """Does a basic test of as much of the system as possible."""
99        job = models.Job(job_idx=1)
100        kernel = models.Kernel(kernel_idx=1)
101        machine = models.Machine(machine_idx=1)
102        success_status = models.Status(status_idx=GOOD_STATUS_IDX)
103        fail_status = models.Status(status_idx=FAIL_STATUS_IDX)
104
105        old_passing_test = models.Test(job=job, status=success_status,
106                                       kernel=kernel, machine=machine,
107                                       test='test1',
108                                       started_time=self.datetime(2012, 1, 1))
109        old_passing_test.save()
110        failing_test = models.Test(job=job, status=fail_status,
111                                   kernel=kernel, machine=machine,
112                                   test='test2',
113                                   started_time=self.datetime(2012,1,1))
114        failing_test.save()
115        good_test = models.Test(job=job, status=success_status,
116                                kernel=kernel, machine=machine,
117                                test='test3',
118                                started_time=self.datetime(2012, 1, 20))
119        good_test.save()
120
121        complete_failures._DAYS_TO_BE_FAILING_TOO_LONG = 10
122        MockDatetime.today().AndReturn(self.datetime(2012, 1, 21))
123        MockDatetime.today().AndReturn(self.datetime(2012, 1, 21))
124        mail.send('chromeos-test-health@google.com',
125                  ['chromeos-lab-infrastructure@google.com'],
126                  [],
127                  'Long Failing Tests',
128                  '2/3 tests have been failing for at least %d days.\n'
129                  'They are the following:\n\ntest1\ntest2'
130                  % complete_failures._DAYS_TO_BE_FAILING_TOO_LONG)
131
132        self.mox.ReplayAll()
133        complete_failures.main()
134
135
136if __name__ == '__main__':
137    unittest.main()
138