普通文本  |  297行  |  10.41 KB

#!/usr/bin/python
#
# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import datetime, unittest

import mox

import common
# This must come before the import of complete_failures in order to use the
# in memory database.
from autotest_lib.frontend import setup_django_readonly_environment
from autotest_lib.frontend import setup_test_environment
import complete_failures
from autotest_lib.client.common_lib import mail
from autotest_lib.frontend.tko import models
from django import test


GOOD_STATUS_IDX = 6

# See complte_failurs_functional_tests.py for why we need this.
class MockDatetime(datetime.datetime):
    """Used to mock out parts of datetime.datetime."""
    pass


class EmailAboutTestFailureTests(mox.MoxTestBase):
    """
    Tests that emails are sent about failed tests.
    """
    def setUp(self):
        super(EmailAboutTestFailureTests, self).setUp()

        # We need to mock out the send function in all tests or else the
        # emails will be sent out during tests.
        self.mox.StubOutWithMock(mail, 'send')

        self._orig_too_long = complete_failures._DAYS_TO_BE_FAILING_TOO_LONG


    def tearDown(self):
        complete_failures._DAYS_TO_BE_FAILING_TOO_LONG = self._orig_too_long
        super(EmailAboutTestFailureTests, self).tearDown()


    def test_email_sent_about_all_failed_tests(self):
        """Test that the email report mentions all the failed_tests."""
        complete_failures._DAYS_TO_BE_FAILING_TOO_LONG = 60

        mail.send(
                'chromeos-test-health@google.com',
                ['chromeos-lab-infrastructure@google.com'],
                [],
                'Long Failing Tests',
                '1/1 tests have been failing for at least %d days.\n'
                'They are the following:\n\ntest'
                    % complete_failures._DAYS_TO_BE_FAILING_TOO_LONG)

        failures = ['test']
        all_tests = set(failures)

        self.mox.ReplayAll()
        complete_failures.email_about_test_failure(failures, all_tests)


    def test_email_has_test_names_sorted_alphabetically(self):
        """Test that the email report has entries sorted alphabetically."""
        complete_failures._DAYS_TO_BE_FAILING_TOO_LONG = 60

        mail.send(
                'chromeos-test-health@google.com',
                ['chromeos-lab-infrastructure@google.com'],
                [],
                'Long Failing Tests',
                '2/2 tests have been failing for at least %d days.\n'
                'They are the following:\n\ntest1\ntest2'
                    % complete_failures._DAYS_TO_BE_FAILING_TOO_LONG)

        # We use an OrderedDict to gurantee that the elements would be out of
        # order if we did a simple traversal.
        failures = ['test2', 'test1']
        all_tests = set(failures)

        self.mox.ReplayAll()
        complete_failures.email_about_test_failure(failures, all_tests)


    def test_email_count_of_total_number_of_tests(self):
        """Test that the email report displays total number of tests."""
        complete_failures._DAYS_TO_BE_FAILING_TOO_LONG = 60

        mail.send(
                'chromeos-test-health@google.com',
                ['chromeos-lab-infrastructure@google.com'],
                [],
                'Long Failing Tests',
                '1/2 tests have been failing for at least %d days.\n'
                'They are the following:\n\ntest'
                    % complete_failures._DAYS_TO_BE_FAILING_TOO_LONG)

        failures = ['test']
        all_tests = set(failures) | {'not_failure'}

        self.mox.ReplayAll()
        complete_failures.email_about_test_failure(failures, all_tests)


class IsValidTestNameTests(test.TestCase):
    """Tests the is_valid_test_name function."""

    def test_returns_true_for_valid_test_name(self):
        """Test that a valid test name returns True."""
        name = 'TestName.TestName'
        self.assertTrue(complete_failures.is_valid_test_name(name))


    def test_returns_false_if_name_has_slash_in_it(self):
        """Test that a name with a slash in it returns False."""
        name = 'path/to/test'
        self.assertFalse(complete_failures.is_valid_test_name(name))


    def test_returns_false_for_try_new_image_entries(self):
        """Test that a name that starts with try_new_image returns False."""
        name = 'try_new_image-blah'
        self.assertFalse(complete_failures.is_valid_test_name(name))


class PrepareLastPassesTests(test.TestCase):
    """Tests the prepare_last_passes function."""

    def setUp(self):
        super(PrepareLastPassesTests, self).setUp()

    def tearDown(self):
        super(PrepareLastPassesTests, self).tearDown()

    def test_does_not_return_invalid_test_names(self):
        """Tests that tests with invalid test names are not returned."""
        results = complete_failures.prepare_last_passes(['invalid_test/name'])

        self.assertEqual(results, {})


class GetRecentlyRanTestNamesTests(mox.MoxTestBase, test.TestCase):
    """Tests the get_recently_ran_test_names function."""

    def setUp(self):
        super(GetRecentlyRanTestNamesTests, self).setUp()
        self.mox.StubOutWithMock(MockDatetime, 'today')
        self.datetime = datetime.datetime
        datetime.datetime = MockDatetime
        setup_test_environment.set_up()
        self._orig_cutoff = complete_failures._DAYS_NOT_RUNNING_CUTOFF


    def tearDown(self):
        datetime.datetime = self.datetime
        complete_failures._DAYS_NOT_RUNNING_CUTOFF = self._orig_cutoff
        setup_test_environment.tear_down()
        super(GetRecentlyRanTestNamesTests, self).tearDown()


    def test_return_all_recently_ran_tests(self):
        """Test that the function does as it says it does."""
        job = models.Job(job_idx=1)
        kernel = models.Kernel(kernel_idx=1)
        machine = models.Machine(machine_idx=1)
        success_status = models.Status(status_idx=GOOD_STATUS_IDX)

        recent = models.Test(job=job, status=success_status,
                             kernel=kernel, machine=machine,
                             test='recent',
                             started_time=self.datetime(2012, 1, 1))
        recent.save()
        old = models.Test(job=job, status=success_status,
                          kernel=kernel, machine=machine,
                          test='old',
                          started_time=self.datetime(2011, 1, 2))
        old.save()

        datetime.datetime.today().AndReturn(self.datetime(2012, 1, 4))
        complete_failures._DAYS_NOT_RUNNING_CUTOFF = 60

        self.mox.ReplayAll()
        results = complete_failures.get_recently_ran_test_names()

        self.assertEqual(set(results), set(['recent']))


    def test_returns_no_duplicate_names(self):
        """Test that each test name appears only once."""
        job = models.Job(job_idx=1)
        kernel = models.Kernel(kernel_idx=1)
        machine = models.Machine(machine_idx=1)
        success_status = models.Status(status_idx=GOOD_STATUS_IDX)

        test = models.Test(job=job, status=success_status,
                           kernel=kernel, machine=machine,
                           test='test',
                           started_time=self.datetime(2012, 1, 1))
        test.save()
        duplicate = models.Test(job=job, status=success_status,
                                kernel=kernel, machine=machine,
                                test='test',
                                started_time=self.datetime(2012, 1, 2))
        duplicate.save()

        datetime.datetime.today().AndReturn(self.datetime(2012, 1, 3))
        complete_failures._DAYS_NOT_RUNNING_CUTOFF = 60

        self.mox.ReplayAll()
        results = complete_failures.get_recently_ran_test_names()

        self.assertEqual(len(results), 1)


class GetTestsToAnalyzeTests(mox.MoxTestBase):
    """Tests the get_tests_to_analyze function."""

    def test_returns_recent_test_names(self):
        """Test should return all the test names in the database."""

        recent_tests = {'passing_test', 'failing_test'}
        last_passes = {'passing_test': datetime.datetime(2012, 1 ,1),
                       'old_passing_test': datetime.datetime(2011, 1, 1)}

        results = complete_failures.get_tests_to_analyze(recent_tests,
                                                         last_passes)

        self.assertEqual(results,
                         {'passing_test': datetime.datetime(2012, 1, 1),
                          'failing_test': datetime.datetime.min})


    def test_returns_failing_tests_with_min_datetime(self):
        """Test that never-passed tests are paired with datetime.min."""

        recent_tests = {'test'}
        last_passes = {}

        self.mox.ReplayAll()
        results = complete_failures.get_tests_to_analyze(recent_tests,
                                                         last_passes)

        self.assertEqual(results, {'test': datetime.datetime.min})


class FilterOutGoodTestsTests(mox.MoxTestBase):
    """Tests the filter_our_good_tests function."""

    def setUp(self):
        super(FilterOutGoodTestsTests, self).setUp()
        self.mox.StubOutWithMock(MockDatetime, 'today')
        self.datetime = datetime.datetime
        datetime.datetime = MockDatetime
        self._orig_too_long = complete_failures._DAYS_TO_BE_FAILING_TOO_LONG


    def tearDown(self):
        datetime.datetime = self.datetime
        complete_failures._DAYS_TO_BE_FAILING_TOO_LONG = self._orig_too_long
        super(FilterOutGoodTestsTests, self).tearDown()


    def test_remove_all_tests_that_have_passed_recently_enough(self):
        """Test that all recently passing tests are not returned."""

        complete_failures._DAYS_TO_BE_FAILING_TOO_LONG = 10
        datetime.datetime.today().AndReturn(self.datetime(2012, 1, 21))

        self.mox.ReplayAll()
        result = complete_failures.filter_out_good_tests(
                {'test': self.datetime(2012, 1, 20)})

        self.assertEqual(result, [])


    def test_keep_all_tests_that_have_not_passed_recently_enough(self):
        """Test that the tests that have not recently passed are returned."""

        complete_failures._DAYS_TO_BE_FAILING_TOO_LONG = 10
        datetime.datetime.today().AndReturn(self.datetime(2012, 1, 21))

        self.mox.ReplayAll()
        result = complete_failures.filter_out_good_tests(
                {'test': self.datetime(2012, 1, 10)})

        self.assertEqual(result, ['test'])


if __name__ == '__main__':
    unittest.main()