1fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone#!/usr/bin/python
2fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone#
3fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
4fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone# Use of this source code is governed by a BSD-style license that can be
5fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone# found in the LICENSE file.
6fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
72d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone"""Unit tests for site_utils/timed_event.py."""
8fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
99f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shiimport collections, datetime, mox, unittest
10fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
11c7bcf8bf70d6e40aa4d37528f75b5a98b0f7a00eAlex Miller# driver must be imported first due to circular imports in base_event and task
12c7bcf8bf70d6e40aa4d37528f75b5a98b0f7a00eAlex Millerimport driver  # pylint: disable-msg=W0611
139f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shiimport base_event, forgiving_config_parser
1493f51d4da152538007d5b44a2dc9d2bbb1fe3429Chris Masoneimport manifest_versions, task, timed_event
15fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
16fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
17013859b492bf4f5b304e31be3300789443eee33eChris Masoneclass TimedEventTestBase(mox.MoxTestBase):
18013859b492bf4f5b304e31be3300789443eee33eChris Masone    """Base class for TimedEvent unit test classes."""
19fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
20fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
21fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    def setUp(self):
22013859b492bf4f5b304e31be3300789443eee33eChris Masone        super(TimedEventTestBase, self).setUp()
232d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        self.mox.StubOutWithMock(timed_event.TimedEvent, '_now')
245bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone        self.mv = self.mox.CreateMock(manifest_versions.ManifestVersions)
25fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
26fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
27fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    def BaseTime(self):
28013859b492bf4f5b304e31be3300789443eee33eChris Masone        """Return the TimedEvent trigger-time as a datetime instance."""
29fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        raise NotImplementedError()
30fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
31fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
325bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone    def CreateEvent(self):
33013859b492bf4f5b304e31be3300789443eee33eChris Masone        """Return an instance of the TimedEvent subclass being tested."""
34fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        raise NotImplementedError()
35fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
36fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
37fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    def TimeBefore(self, now):
38fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        """Return a datetime that's before |now|."""
39fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        raise NotImplementedError()
40fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
41fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
42fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    def TimeLaterThan(self, now):
43fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        """Return a datetime that's later than |now|."""
44fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        raise NotImplementedError()
45fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
46fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
47fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    def doTestDeadlineInFuture(self):
48fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        fake_now = self.TimeBefore(self.BaseTime())
492d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        timed_event.TimedEvent._now().MultipleTimes().AndReturn(fake_now)
50fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        self.mox.ReplayAll()
51fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
525bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone        t = self.CreateEvent()  # Deadline gets set for a future time.
532d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        self.assertFalse(t.ShouldHandle())
54fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        self.mox.VerifyAll()
55fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
56fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        self.mox.ResetAll()
57fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        fake_now = self.TimeLaterThan(fake_now)  # Jump past that future time.
582d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        timed_event.TimedEvent._now().MultipleTimes().AndReturn(fake_now)
59fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        self.mox.ReplayAll()
602d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        self.assertTrue(t.ShouldHandle())
61fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
62fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
63fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    def doTestDeadlineIsNow(self):
64fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        """We happened to create the trigger at the exact right time."""
652d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        timed_event.TimedEvent._now().MultipleTimes().AndReturn(self.BaseTime())
66fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        self.mox.ReplayAll()
675bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone        to_test = self.CreateEvent()
682d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        self.assertTrue(to_test.ShouldHandle())
69fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
70fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
71fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    def doTestTOCTOU(self):
72fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        """Even if deadline passes during initialization, trigger must fire."""
73fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        init_now = self.BaseTime() - datetime.timedelta(seconds=1)
74fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        fire_now = self.BaseTime() + datetime.timedelta(seconds=1)
752d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        timed_event.TimedEvent._now().AndReturn(init_now)
769f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        timed_event.TimedEvent._now().MultipleTimes().AndReturn(fire_now)
77fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        self.mox.ReplayAll()
78fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
795bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone        t = self.CreateEvent()  # Deadline gets set for later tonight...
80fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        # ...but has passed by the time we get around to firing.
812d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        self.assertTrue(t.ShouldHandle())
82fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
83fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
849f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi    def doTestDeadlineUpdate(self, days_to_jump, hours_to_jump=0):
85e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone        fake_now = self.TimeBefore(self.BaseTime())
86e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone        timed_event.TimedEvent._now().MultipleTimes().AndReturn(fake_now)
87e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone        self.mox.ReplayAll()
88e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone
89e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone        nightly = self.CreateEvent()  # Deadline gets set for tonight.
90e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone        self.assertFalse(nightly.ShouldHandle())
91e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone        self.mox.VerifyAll()
92e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone
93e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone        self.mox.ResetAll()
94e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone        fake_now = self.TimeLaterThan(self.BaseTime())  # Jump past deadline.
95e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone        timed_event.TimedEvent._now().MultipleTimes().AndReturn(fake_now)
96e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone        self.mox.ReplayAll()
97e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone
98e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone        self.assertTrue(nightly.ShouldHandle())
999f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        nightly.UpdateCriteria()  # Deadline moves to an hour later
100e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone        self.assertFalse(nightly.ShouldHandle())
101e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone        self.mox.VerifyAll()
102e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone
103e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone        self.mox.ResetAll()
1049f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        # Jump past deadline.
1059f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        fake_now += datetime.timedelta(days=days_to_jump, hours=hours_to_jump)
106e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone        timed_event.TimedEvent._now().MultipleTimes().AndReturn(fake_now)
107e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone        self.mox.ReplayAll()
108e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone        self.assertTrue(nightly.ShouldHandle())
109e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone
110e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone
1115bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone    def doTestGetBranchBuilds(self, days):
1125bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone        board = 'faux_board'
1135bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone        branch_manifests = {('factory','16'): ['last16'],
1145bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone                            ('release','17'): ['first17', 'last17']}
11533ea03b85c3f3b40be2813b4e5a87c8a2f3e9f8dFang Deng        since_date = self.BaseTime() - datetime.timedelta(days=days)
11633ea03b85c3f3b40be2813b4e5a87c8a2f3e9f8dFang Deng        self.mv.ManifestsSinceDate(since_date, board).AndReturn(
11733ea03b85c3f3b40be2813b4e5a87c8a2f3e9f8dFang Deng                branch_manifests)
1185bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone        timed_event.TimedEvent._now().MultipleTimes().AndReturn(self.BaseTime())
1195bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone        self.mox.ReplayAll()
120d17d185d7abd68584f3756a89a7475a5b6109f34Chris Masone        branch_builds = self.CreateEvent().GetBranchBuildsForBoard(board)
1215bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone        for (type, milestone), manifests in branch_manifests.iteritems():
1225bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone            build = None
12367f06d6003bb11f03f925810272f595d79dce44aChris Masone            if type in task.BARE_BRANCHES:
1249ee3eca81228c4479e4b1b0af11d9b69547b1ca7Chris Masone                self.assertEquals(len(branch_builds[type]), 1)
1259ee3eca81228c4479e4b1b0af11d9b69547b1ca7Chris Masone                build = branch_builds[type][0]
1265bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone                self.assertTrue(build.startswith('%s-%s' % (board, type)))
1275bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone            else:
1289ee3eca81228c4479e4b1b0af11d9b69547b1ca7Chris Masone                self.assertEquals(len(branch_builds[milestone]), 1)
1299ee3eca81228c4479e4b1b0af11d9b69547b1ca7Chris Masone                build = branch_builds[milestone][0]
1305bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone                self.assertTrue(build.startswith('%s-release' % board))
1319ee3eca81228c4479e4b1b0af11d9b69547b1ca7Chris Masone            self.assertTrue('R%s-%s' % (milestone, manifests[-1]) in build)
1325bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone
1335bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone
134013859b492bf4f5b304e31be3300789443eee33eChris Masoneclass NightlyTest(TimedEventTestBase):
135fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    """Unit tests for Weekly.
136fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    """
137fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
138fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
139fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    def setUp(self):
140fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        super(NightlyTest, self).setUp()
141fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
142fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
143fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    def BaseTime(self):
1449f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        return datetime.datetime(2012, 1, 1, 0, 0)
145fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
146fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
1475bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone    def CreateEvent(self):
1482d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        """Return an instance of timed_event.Nightly."""
1499f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        return timed_event.Nightly(self.mv, False)
1502d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone
1512d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone
1522d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone    def testCreateFromConfig(self):
1532d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        """Test that creating from config is equivalent to using constructor."""
1542d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        config = forgiving_config_parser.ForgivingConfigParser()
15593f51d4da152538007d5b44a2dc9d2bbb1fe3429Chris Masone        section = base_event.SectionName(timed_event.Nightly.KEYWORD)
1562d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        config.add_section(section)
1572d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone
1582d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        timed_event.TimedEvent._now().MultipleTimes().AndReturn(self.BaseTime())
1592d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        self.mox.ReplayAll()
1602d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone
16193f51d4da152538007d5b44a2dc9d2bbb1fe3429Chris Masone        self.assertEquals(self.CreateEvent(),
16293f51d4da152538007d5b44a2dc9d2bbb1fe3429Chris Masone                          timed_event.Nightly.CreateFromConfig(config, self.mv))
1632d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone
1642d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone
1652d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone    def testCreateFromEmptyConfig(self):
1662d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        """Test that creating from empty config uses defaults."""
1672d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        config = forgiving_config_parser.ForgivingConfigParser()
1682d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone
1692d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        timed_event.TimedEvent._now().MultipleTimes().AndReturn(self.BaseTime())
1702d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        self.mox.ReplayAll()
1712d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone
1722d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        self.assertEquals(
1739f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi            timed_event.Nightly(self.mv, False),
17493f51d4da152538007d5b44a2dc9d2bbb1fe3429Chris Masone            timed_event.Nightly.CreateFromConfig(config, self.mv))
175fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
176fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
17799d32b8031c21e1142a4b828729fb756ee668bfeChris Masone    def testCreateFromAlwaysHandleConfig(self):
17899d32b8031c21e1142a4b828729fb756ee668bfeChris Masone        """Test that creating with always_handle works as intended."""
17999d32b8031c21e1142a4b828729fb756ee668bfeChris Masone        config = forgiving_config_parser.ForgivingConfigParser()
18099d32b8031c21e1142a4b828729fb756ee668bfeChris Masone        section = base_event.SectionName(timed_event.Nightly.KEYWORD)
18199d32b8031c21e1142a4b828729fb756ee668bfeChris Masone        config.add_section(section)
18299d32b8031c21e1142a4b828729fb756ee668bfeChris Masone        config.set(section, 'always_handle', 'True')
18399d32b8031c21e1142a4b828729fb756ee668bfeChris Masone
18499d32b8031c21e1142a4b828729fb756ee668bfeChris Masone        timed_event.TimedEvent._now().MultipleTimes().AndReturn(self.BaseTime())
18599d32b8031c21e1142a4b828729fb756ee668bfeChris Masone        self.mox.ReplayAll()
18699d32b8031c21e1142a4b828729fb756ee668bfeChris Masone
18799d32b8031c21e1142a4b828729fb756ee668bfeChris Masone        event = timed_event.Nightly.CreateFromConfig(config, self.mv)
18899d32b8031c21e1142a4b828729fb756ee668bfeChris Masone        self.assertTrue(event.ShouldHandle())
18999d32b8031c21e1142a4b828729fb756ee668bfeChris Masone
19099d32b8031c21e1142a4b828729fb756ee668bfeChris Masone
191075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone    def testMerge(self):
192075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        """Test that Merge() works when the deadline time of day changes."""
193075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        timed_event.TimedEvent._now().MultipleTimes().AndReturn(self.BaseTime())
194075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        self.mox.ReplayAll()
195075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone
1969f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        old = timed_event.Nightly(self.mv, False)
1979f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        new = timed_event.Nightly(self.mv, False)
198075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        old.Merge(new)
199075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        self.assertEquals(old._deadline, new._deadline)
200075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone
201075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone
202075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone    def testSkipMerge(self):
203075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        """Test that deadline is unchanged when time of day is unchanged."""
204075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        timed_event.TimedEvent._now().MultipleTimes().AndReturn(self.BaseTime())
205075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        self.mox.ReplayAll()
206075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone
2079f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        old = timed_event.Nightly(self.mv, False)
2089f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        new = timed_event.Nightly(self.mv, False)
209075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        new._deadline += datetime.timedelta(days=1)
210075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        self.assertNotEquals(old._deadline, new._deadline)
211075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        saved_deadline = old._deadline
212075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        old.Merge(new)
213075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        self.assertEquals(saved_deadline, old._deadline)
214075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone
215075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone
216fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    def testDeadlineInPast(self):
217fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        """Ensure we work if the deadline aready passed today."""
2189f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        fake_now = self.BaseTime() + datetime.timedelta(hours=0.5)
2192d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        timed_event.TimedEvent._now().MultipleTimes().AndReturn(fake_now)
220fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        self.mox.ReplayAll()
221fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
2225bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone        nightly = self.CreateEvent()  # Deadline gets set for tomorrow night.
2232d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        self.assertFalse(nightly.ShouldHandle())
224fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        self.mox.VerifyAll()
225fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
226fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        self.mox.ResetAll()
227fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        fake_now += datetime.timedelta(days=1)  # Jump to tomorrow night.
2282d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        timed_event.TimedEvent._now().MultipleTimes().AndReturn(fake_now)
229fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        self.mox.ReplayAll()
2302d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        self.assertTrue(nightly.ShouldHandle())
231fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
232fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
233fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    def TimeBefore(self, now):
2349f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        return now - datetime.timedelta(minutes=1)
235fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
236fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
237fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    def TimeLaterThan(self, now):
2389f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        return now + datetime.timedelta(hours=0.5)
239fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
240fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
241fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    def testDeadlineInFuture(self):
242fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        """Ensure we work if the deadline is later today."""
243fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        self.doTestDeadlineInFuture()
244fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
245fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
246fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    def testDeadlineIsNow(self):
247fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        """We happened to create the trigger at the exact right time."""
248fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        self.doTestDeadlineIsNow()
249fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
250fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
251fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    def testTOCTOU(self):
252fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        """Even if deadline passes during initialization, trigger must fire."""
253fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        self.doTestTOCTOU()
254fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
255fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
256e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone    def testDeadlineUpdate(self):
257e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone        """Ensure we update the deadline correctly."""
2589f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        self.doTestDeadlineUpdate(days_to_jump=0, hours_to_jump=1)
259e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone
260e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone
2619b1534252f52030b8ec0e480afcf502db39f4936xixuan    #def testGetBranchBuilds(self):
2629b1534252f52030b8ec0e480afcf502db39f4936xixuan    #    """Ensure Nightly gets most recent builds in last day."""
2639b1534252f52030b8ec0e480afcf502db39f4936xixuan    #    self.doTestGetBranchBuilds(days=1)
2645bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone
2655bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone
2669f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi    def testFilterTasks(self):
2679f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        """Test FilterTasks function can filter tasks by current hour."""
2689f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        Task = collections.namedtuple('Task', 'hour')
2699f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        task_1 = Task(hour=0)
2709f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        task_2 = Task(hour=10)
2719f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        task_3 = Task(hour=11)
2729f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        timed_event.TimedEvent._now().MultipleTimes().AndReturn(self.BaseTime())
2739f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        self.mox.ReplayAll()
2749f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        event = self.CreateEvent()
2759f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        event.tasks = set([task_1, task_2, task_3])
2769f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi        self.assertEquals([task_1], event.FilterTasks())
2779f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi
2789f256d91d378cdc0bbffa607ef3572f006d0b0dcDan Shi
279013859b492bf4f5b304e31be3300789443eee33eChris Masoneclass WeeklyTest(TimedEventTestBase):
280fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    """Unit tests for Weekly.
281fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
282fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    @var _HOUR: The time of night to use in these unit tests.
283fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    """
284fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
2852d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone    _HOUR = 22
286fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
287fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
288fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    def setUp(self):
289fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        super(WeeklyTest, self).setUp()
290fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
291fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
292fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    def BaseTime(self):
293fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        basetime = datetime.datetime(2012, 1, 1, self._HOUR)
294fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        return basetime
295fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
296fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
2975bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone    def CreateEvent(self):
2982d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        """Return an instance of timed_event.Weekly."""
299ce1f20a4e96037420687565df3fce7a218120a16Dan Shi        return timed_event.Weekly(self.mv, False, self._HOUR)
3002d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone
3012d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone
3022d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone    def testCreateFromConfig(self):
3032d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        """Test that creating from config is equivalent to using constructor."""
3042d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        config = forgiving_config_parser.ForgivingConfigParser()
30593f51d4da152538007d5b44a2dc9d2bbb1fe3429Chris Masone        section = base_event.SectionName(timed_event.Weekly.KEYWORD)
3062d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        config.add_section(section)
3072d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        config.set(section, 'hour', '%d' % self._HOUR)
3082d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone
3092d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        timed_event.TimedEvent._now().MultipleTimes().AndReturn(self.BaseTime())
3102d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        self.mox.ReplayAll()
3112d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone
31293f51d4da152538007d5b44a2dc9d2bbb1fe3429Chris Masone        self.assertEquals(self.CreateEvent(),
31393f51d4da152538007d5b44a2dc9d2bbb1fe3429Chris Masone                          timed_event.Weekly.CreateFromConfig(config, self.mv))
314fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
315fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
316075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone    def testMergeDueToTimeChange(self):
317075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        """Test that Merge() works when the deadline time of day changes."""
318075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        timed_event.TimedEvent._now().MultipleTimes().AndReturn(self.BaseTime())
319075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        self.mox.ReplayAll()
320075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone
321ce1f20a4e96037420687565df3fce7a218120a16Dan Shi        old = timed_event.Weekly(self.mv, False, self._HOUR)
322ce1f20a4e96037420687565df3fce7a218120a16Dan Shi        new = timed_event.Weekly(self.mv, False, self._HOUR + 1)
323075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        self.assertNotEquals(old._deadline, new._deadline)
324075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        old.Merge(new)
325075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        self.assertEquals(old._deadline, new._deadline)
326075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone
327075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone
328075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone    def testSkipMerge(self):
329075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        """Test that deadline is unchanged when only the week is changed."""
330075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        timed_event.TimedEvent._now().MultipleTimes().AndReturn(self.BaseTime())
331075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        self.mox.ReplayAll()
332075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone
333ce1f20a4e96037420687565df3fce7a218120a16Dan Shi        old = timed_event.Weekly(self.mv, False, self._HOUR)
334ce1f20a4e96037420687565df3fce7a218120a16Dan Shi        new = timed_event.Weekly(self.mv, False, self._HOUR)
335075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        new._deadline += datetime.timedelta(days=7)
336075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        self.assertNotEquals(old._deadline, new._deadline)
337075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        saved_deadline = old._deadline
338075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        old.Merge(new)
339075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone        self.assertEquals(saved_deadline, old._deadline)
340075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone
341075aafa4c4508d73087f62189e5cf339ca15dc2eChris Masone
342fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    def testDeadlineInPast(self):
343fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        """Ensure we work if the deadline already passed this week."""
344ce1f20a4e96037420687565df3fce7a218120a16Dan Shi        fake_now = self.BaseTime() + datetime.timedelta(days=0.5)
3452d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        timed_event.TimedEvent._now().MultipleTimes().AndReturn(fake_now)
346fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        self.mox.ReplayAll()
347fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
3485bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone        weekly = self.CreateEvent()  # Deadline gets set for next week.
3492d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        self.assertFalse(weekly.ShouldHandle())
350fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        self.mox.VerifyAll()
351fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
352fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        self.mox.ResetAll()
353fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        fake_now += datetime.timedelta(days=1)  # Jump to tomorrow.
3542d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        timed_event.TimedEvent._now().MultipleTimes().AndReturn(fake_now)
355fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        self.mox.ReplayAll()
356ce1f20a4e96037420687565df3fce7a218120a16Dan Shi        self.assertTrue(weekly.ShouldHandle())
357fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        self.mox.VerifyAll()
358fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
359fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        self.mox.ResetAll()
360fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        fake_now += datetime.timedelta(days=7)  # Jump to next week.
3612d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        timed_event.TimedEvent._now().MultipleTimes().AndReturn(fake_now)
362fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        self.mox.ReplayAll()
3632d61ca263d3e571b19604ea4c9d7b55d83c28405Chris Masone        self.assertTrue(weekly.ShouldHandle())
364fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
365fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
366fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    def TimeBefore(self, now):
367ce1f20a4e96037420687565df3fce7a218120a16Dan Shi        return now - datetime.timedelta(days=0.5)
368fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
369fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
370fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    def TimeLaterThan(self, now):
371ce1f20a4e96037420687565df3fce7a218120a16Dan Shi        return now + datetime.timedelta(days=0.5)
372fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
373fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
374fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    def testDeadlineInFuture(self):
375fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        """Ensure we work if the deadline is later this week."""
376fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        self.doTestDeadlineInFuture()
377fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
378fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
379fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    def testDeadlineIsNow(self):
380fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        """We happened to create the trigger at the exact right time."""
381fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        self.doTestDeadlineIsNow()
382fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
383fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
384fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone    def testTOCTOU(self):
385fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        """Even if deadline passes during initialization, trigger must fire."""
386fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone        self.doTestTOCTOU()
387fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
388fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone
389e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone    def testDeadlineUpdate(self):
390e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone        """Ensure we update the deadline correctly."""
391ce1f20a4e96037420687565df3fce7a218120a16Dan Shi        self.doTestDeadlineUpdate(days_to_jump=1)
392e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone
393e8bebaf10711ca802d40c0b7f412e3910999159eChris Masone
3949b1534252f52030b8ec0e480afcf502db39f4936xixuan    #def testGetBranchBuilds(self):
3959b1534252f52030b8ec0e480afcf502db39f4936xixuan    #    """Ensure Weekly gets most recent builds in last 7 days."""
3969b1534252f52030b8ec0e480afcf502db39f4936xixuan    #    self.doTestGetBranchBuilds(days=7)
3975bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone
3985bde7dc7d8b0608feb43491d5ac648d11c890f54Chris Masone
399ce1f20a4e96037420687565df3fce7a218120a16Dan Shi    def testFilterTasks(self):
400ce1f20a4e96037420687565df3fce7a218120a16Dan Shi        """Test FilterTasks function can filter tasks by current day."""
401ce1f20a4e96037420687565df3fce7a218120a16Dan Shi        Task = collections.namedtuple('Task', 'day')
402ce1f20a4e96037420687565df3fce7a218120a16Dan Shi        task_1 = Task(day=6)
403ce1f20a4e96037420687565df3fce7a218120a16Dan Shi        task_2 = Task(day=2)
404ce1f20a4e96037420687565df3fce7a218120a16Dan Shi        task_3 = Task(day=5)
405ce1f20a4e96037420687565df3fce7a218120a16Dan Shi        timed_event.TimedEvent._now().MultipleTimes().AndReturn(self.BaseTime())
406ce1f20a4e96037420687565df3fce7a218120a16Dan Shi        self.mox.ReplayAll()
407ce1f20a4e96037420687565df3fce7a218120a16Dan Shi        event = self.CreateEvent()
408ce1f20a4e96037420687565df3fce7a218120a16Dan Shi        event.tasks = set([task_1, task_2, task_3])
409ce1f20a4e96037420687565df3fce7a218120a16Dan Shi        self.assertEquals([task_1], event.FilterTasks())
410ce1f20a4e96037420687565df3fce7a218120a16Dan Shi
411ce1f20a4e96037420687565df3fce7a218120a16Dan Shi
412fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masoneif __name__ == '__main__':
413fad911ada4f6126280765f15204eaf8b3b4bc437Chris Masone  unittest.main()
414