|
1 #!/usr/bin/python2.5 |
|
2 # |
|
3 # Copyright 2008 the Melange authors. |
|
4 # |
|
5 # Licensed under the Apache License, Version 2.0 (the "License"); |
|
6 # you may not use this file except in compliance with the License. |
|
7 # You may obtain a copy of the License at |
|
8 # |
|
9 # http://www.apache.org/licenses/LICENSE-2.0 |
|
10 # |
|
11 # Unless required by applicable law or agreed to in writing, software |
|
12 # distributed under the License is distributed on an "AS IS" BASIS, |
|
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
14 # See the License for the specific language governing permissions and |
|
15 # limitations under the License. |
|
16 |
|
17 |
|
18 __authors__ = [ |
|
19 '"Sverre Rabbelier" <sverre@rabbelier.nl>', |
|
20 ] |
|
21 |
|
22 |
|
23 import unittest |
|
24 |
|
25 from soc.logic import allocations |
|
26 |
|
27 |
|
28 class Student(object): |
|
29 """Mocker for Student object. |
|
30 """ |
|
31 |
|
32 def __init__(self, id): |
|
33 """Simple init that stores id for later use. |
|
34 """ |
|
35 |
|
36 self.id = id |
|
37 |
|
38 def __eq__(self, other): |
|
39 """Simple eq that compares ids. |
|
40 """ |
|
41 |
|
42 return self.id == other.id |
|
43 |
|
44 def __str__(self): |
|
45 """Simple str that returns str(id). |
|
46 """ |
|
47 |
|
48 return str(self.id) |
|
49 |
|
50 def __repr__(self): |
|
51 """Simple repr that returns repr(id). |
|
52 """ |
|
53 |
|
54 return repr(self.id) |
|
55 |
|
56 |
|
57 class AllocationsTest(unittest.TestCase): |
|
58 """Tests related to the slot allocation algorithm. |
|
59 """ |
|
60 |
|
61 def setUp(self): |
|
62 """Set up required for the slot allocation tests. |
|
63 """ |
|
64 |
|
65 self.slots = 60 |
|
66 self.max_slots_per_org = 40 |
|
67 self.allocated = 0 |
|
68 |
|
69 self.applications = { |
|
70 'asf': self.allocate(20), |
|
71 'gcc': self.allocate(15), |
|
72 'git': self.allocate(6), |
|
73 'google': self.allocate(3), |
|
74 'melange': self.allocate(100), |
|
75 } |
|
76 |
|
77 self.orgs = self.applications.keys() |
|
78 |
|
79 self.allocater = allocations.Allocator(self.orgs, self.applications, |
|
80 self.slots, self.max_slots_per_org) |
|
81 |
|
82 def allocate(self, count): |
|
83 """Returns a list with count new student objects. |
|
84 """ |
|
85 |
|
86 i = self.allocated |
|
87 j = i + count |
|
88 self.allocated += count |
|
89 |
|
90 return [Student(i) for i in range(i,j)] |
|
91 |
|
92 def testAllocate(self): |
|
93 """Test that the allocate helper works properly. |
|
94 |
|
95 A meta-test, it never hurts to be certain. |
|
96 """ |
|
97 |
|
98 stash = self.allocated |
|
99 self.allocated = 0 |
|
100 |
|
101 expected = [Student(0), Student(1), Student(2)] |
|
102 actual = self.allocate(3) |
|
103 self.failUnlessEqual(expected, actual) |
|
104 |
|
105 expected = [] |
|
106 actual = self.allocate(0) |
|
107 self.failUnlessEqual(expected, actual) |
|
108 |
|
109 expected = [Student(3)] |
|
110 actual = self.allocate(1) |
|
111 self.failUnlessEqual(expected, actual) |
|
112 |
|
113 self.allocated = stash |
|
114 |
|
115 def testInitialAllocation(self): |
|
116 """Test that an allocation with no arguments does not crash. |
|
117 """ |
|
118 |
|
119 locked_slots = {} |
|
120 adjusted_slots = {} |
|
121 self.allocater.allocate(locked_slots, adjusted_slots) |
|
122 |
|
123 def testLockedSlotsAllocation(self): |
|
124 """Test that an allocation with an org locked does not crash. |
|
125 """ |
|
126 |
|
127 locked_slots = {'melange': 3} |
|
128 adjusted_slots = {} |
|
129 self.allocater.allocate(locked_slots, adjusted_slots) |
|
130 |
|
131 def testAdjustedSlotsAllocation(self): |
|
132 """Test that an allocation with an org adjusted does not crash. |
|
133 """ |
|
134 |
|
135 locked_slots = {} |
|
136 adjusted_slots = {'google': -1} |
|
137 self.allocater.allocate(locked_slots, adjusted_slots) |
|
138 |
|
139 def testInvalidSlotsAllocation(self): |
|
140 """Test that an allocation with an org locked and adjusted errors out. |
|
141 """ |
|
142 |
|
143 locked_slots = {'git': 1} |
|
144 adjusted_slots = {'git': 1} |
|
145 self.failUnlessRaises(allocations.Error, self.allocater.allocate, |
|
146 locked_slots, adjusted_slots) |
|
147 |
|
148 def testNonExistantOrgAllocation1(self): |
|
149 """Test that locking a non-existing org errors out. |
|
150 """ |
|
151 |
|
152 locked_slots = {'gnome': 1} |
|
153 adjusted_slots = {} |
|
154 self.failUnlessRaises(allocations.Error, self.allocater.allocate, |
|
155 locked_slots, adjusted_slots) |
|
156 |
|
157 def testNonExistantOrgAllocation2(self): |
|
158 """Test that adjusting a non-existing org errors out. |
|
159 """ |
|
160 |
|
161 locked_slots = {} |
|
162 adjusted_slots = {'gnome': 1} |
|
163 self.failUnlessRaises(allocations.Error, self.allocater.allocate, |
|
164 locked_slots, adjusted_slots) |
|
165 |
|
166 def testInitialAllocationBelowMaxSlots(self): |
|
167 """Test that the initial allocation is below the max slot count. |
|
168 """ |
|
169 |
|
170 locked_slots = {} |
|
171 adjusted_slots = {} |
|
172 |
|
173 result = self.allocater.allocate(locked_slots, adjusted_slots) |
|
174 self.failIf(sum(result.values()) > self.slots) |
|
175 |
|
176 def testLockedAllocationCorrect(self): |
|
177 """Test that locking an allocation assigns the org the allocation. |
|
178 """ |
|
179 |
|
180 locked_slots = {'git': 6} |
|
181 adjusted_slots = {} |
|
182 |
|
183 result = self.allocater.allocate(locked_slots, adjusted_slots) |
|
184 |
|
185 expected = 6 |
|
186 actual = result['git'] |
|
187 |
|
188 self.failUnlessEqual(expected, actual) |
|
189 |
|
190 def testOverassignedAllocationCorrect(self): |
|
191 """Test that over-assigned allocation are cut down. |
|
192 """ |
|
193 |
|
194 locked_slots = {'git': 20} |
|
195 adjusted_slots = {} |
|
196 |
|
197 result = self.allocater.allocate(locked_slots, adjusted_slots) |
|
198 |
|
199 expected = 6 |
|
200 actual = result['git'] |
|
201 |
|
202 self.failUnlessEqual(expected, actual) |
|
203 |
|
204 def testAdjustedAllocationCorrect(self): |
|
205 """Test that locking an allocation assigns the org the allocation. |
|
206 """ |
|
207 |
|
208 locked_slots = {} |
|
209 adjusted_slots = {'google': 1} |
|
210 |
|
211 with_adjusting = self.allocater.allocate(locked_slots, adjusted_slots) |
|
212 without_adjusting = self.allocater.allocate(locked_slots, {}) |
|
213 |
|
214 expected = without_adjusting['google'] + 1 |
|
215 actual = with_adjusting['google'] |
|
216 |
|
217 self.failUnlessEqual(expected, actual) |