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