Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(53)

Side by Side Diff: scripts/master/unittests/floating_builder_test.py

Issue 2250443002: Update floating builder logic, add to "chromiumos" (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/build.git@master
Patch Set: Pylint fixes. Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « scripts/master/floating_builder.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """ Source file for floating builder testcases."""
7
8 import calendar
9 import datetime
10 import itertools
11 import os
12 import time
13 import unittest
14
15 import test_env # pylint: disable=W0611,W0403
16
17 import mock
18
19 from master import floating_builder as fb
20
21
22 def _to_timestamp(dt):
23 # Calculate the offset between local timezone and UTC.
24 current_time = time.mktime(dt.timetuple())
25 offset = (datetime.datetime.fromtimestamp(current_time) -
26 datetime.datetime.utcfromtimestamp(current_time))
27
28 return calendar.timegm((dt - offset).timetuple())
29
30
31 class _FakeSlaveStatus(object):
32 def __init__(self, name):
33 self.name = name
34 self.connect_times = []
35 self.last_message_received = None
36
37 def lastMessageReceived(self):
38 return self.last_message_received
39
40
41 class _FakeSlave(object):
42 def __init__(self, slavename):
43 self.slavename = slavename
44 self.slave_status = None
45 self.offline = False
46
47 def _set_last_seen(self, now, **kwargs):
48 td = datetime.timedelta(**kwargs)
49 self.slave_status = _FakeSlaveStatus(self.slavename)
50 self.slave_status.last_message_received = _to_timestamp(now + td)
51
52 def __str__(self):
53 return self.slavename
54
55
56 class _FakeBuilder(object):
57
58 def __init__(self, name, slaves):
59 self.name = name
60 self._all_slaves = slaves
61
62 self.botmaster = mock.MagicMock()
63 self.builder_status = mock.MagicMock()
64 self.builder_status.getSlaves.side_effect = lambda: [
65 s.slave_status for s in self._all_slaves
66 if s.slave_status]
67
68 self._online_slaves = ()
69 self._busy_slaves = ()
70
71 def __repr__(self):
72 return self.name
73
74 @property
75 def slaves(self):
76 return [_FakeSlaveBuilder(s, self)
77 for s in self._all_slaves
78 if s.slavename in self._online_slaves]
79
80 @property
81 def slavebuilders(self):
82 """Returns the list of slavebuilders that would be handed to
83 NextSlaveFunc.
84
85 This is the set of slaves that are available for scheduling. We derive
86 this by returning all slaves that are both online and not busy.
87 """
88 return self._get_slave_builders(lambda s:
89 s.slavename in self._online_slaves and
90 s.slavename not in self._busy_slaves)
91
92 def _get_slave_builders(self, fn):
93 return [_FakeSlaveBuilder(slave, self)
94 for slave in self._all_slaves
95 if fn(slave)]
96
97 def set_online_slaves(self, *slavenames):
98 self._online_slaves = set(slavenames)
99
100 def set_busy_slaves(self, *slavenames):
101 self._busy_slaves = set(slavenames)
102
103
104 class _FakeSlaveBuilder(object):
105
106 def __init__(self, slave, builder):
107 self.slave = slave
108 self.builder = builder
109
110 def __repr__(self):
111 return '{%s/%s}' % (self.builder.name, self.slave.slavename)
112
113
114 class FloatingBuilderTest(unittest.TestCase):
115
116 def setUp(self):
117 self._mocks = (
118 mock.patch('master.floating_builder._get_now'),
119 mock.patch('master.floating_builder.PokeBuilderTimer.reset'),
120 )
121 for patcher in self._mocks:
122 patcher.start()
123
124 # Mock current date/time.
125 self.now = datetime.datetime(2016, 1, 1, 8, 0, 0) # 1/1/2016 @8:00
126 fb._get_now.return_value = self.now
127
128 # Mock PokeBuilderTimer to record when the poke builder was set, but not
129 # actually schedule any reactor magic.
130 self.poke_delta = None
131 def record_poke_delta(delta):
132 self.poke_delta = delta
133 fb.PokeBuilderTimer.reset.side_effect = record_poke_delta
134
135 self._slaves = dict((s, _FakeSlave(s)) for s in (
136 'primary-a', 'primary-b', 'floating-a', 'floating-b',
137 ))
138
139 self.builder = _FakeBuilder(
140 'Test Builder',
141 [s[1] for s in sorted(self._slaves.iteritems())],
142 )
143
144 def tearDown(self):
145 for patcher in reversed(self._mocks):
146 patcher.stop()
147
148 def testPrimaryBuilderIsSelectedWhenAvailable(self):
149 fs = fb.FloatingSet()
150 fs.AddPrimary('primary-a')
151 fs.AddFloating('floating-a', 'floating-b')
152
153 self.builder.set_online_slaves('primary-a', 'floating-a', 'floating-b')
154
155 fnsf = fs.NextSlaveFunc(datetime.timedelta(seconds=10))
156 nsb = fnsf(self.builder, self.builder.slavebuilders)
157 self.assertIsNotNone(nsb)
158 self.assertEqual(nsb.slave.slavename, 'primary-a')
159
160 def testPrimaryBuilderIsSelectedWhenOneIsAvailableAndOneIsBusy(self):
161 fs = fb.FloatingSet()
162 fs.AddPrimary('primary-a', 'primary-b')
163 fs.AddFloating('floating-a', 'floating-b')
164
165 self.builder.set_online_slaves('primary-a', 'primary-b', 'floating-a',
166 'floating-b')
167 self.builder.set_busy_slaves('primary-a')
168
169 fnsf = fs.NextSlaveFunc(datetime.timedelta(seconds=10))
170 nsb = fnsf(self.builder, self.builder.slavebuilders)
171 self.assertIsNotNone(nsb)
172 self.assertEqual(nsb.slave.slavename, 'primary-b')
173
174 def testNoBuilderIsSelectedWhenPrimariesAreOfflineWithinGrace(self):
175 fs = fb.FloatingSet()
176 fs.AddPrimary('primary-a', 'primary-b')
177 fs.AddFloating('floating-a', 'floating-b')
178
179 self.builder.set_online_slaves('floating-a')
180 self._slaves['primary-b']._set_last_seen(self.now, seconds=-1)
181
182 fnsf = fs.NextSlaveFunc(datetime.timedelta(seconds=10))
183 nsb = fnsf(self.builder, self.builder.slavebuilders)
184 self.assertIsNone(nsb)
185 self.assertEqual(self.poke_delta, datetime.timedelta(seconds=9))
186
187 def testFloatingBuilderIsSelectedWhenPrimariesAreOfflineForAWhile(self):
188 fs = fb.FloatingSet()
189 fs.AddPrimary('primary-a', 'primary-b')
190 fs.AddFloating('floating-a', 'floating-b')
191
192 self.builder.set_online_slaves('floating-a')
193
194 fnsf = fs.NextSlaveFunc(datetime.timedelta(seconds=10))
195 nsb = fnsf(self.builder, self.builder.slavebuilders)
196 self.assertIsNotNone(nsb)
197 self.assertEqual(nsb.slave.slavename, 'floating-a')
198
199
200 if __name__ == '__main__':
201 unittest.main()
OLDNEW
« no previous file with comments | « scripts/master/floating_builder.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698