fix bug in bucket checker; fix enforcer test case
[raven.git] / apps / gacks / gacksenforce_test.py
1 import time
2
3 from gacksaccount import GacksAccount
4 from gacksaccountmanager import GacksAccountManager
5 from gackscalendar_mysql import GacksMySQLCalendar
6 from gacksresource import GacksResourceDirectory
7 from gacksenforce import GacksEnforcer
8 from gackspolicy import GacksPolicyDirectory
9 from gackshandle import GacksHandle, GacksRecord
10 from gacksexcep import *
11 from gacksid import *
12
13 HOUR=60*60
14 DAY=24*60*60
15
16 CORES_PER_NODE=11
17 NODE1=CORES_PER_NODE*0
18 NODE2=CORES_PER_NODE*1
19 NODE3=CORES_PER_NODE*2
20 NODE4=CORES_PER_NODE*3
21 NODE5=CORES_PER_NODE*4
22 NODE6=CORES_PER_NODE*5
23 NODE7=CORES_PER_NODE*6
24 NODE8=CORES_PER_NODE*7
25 NODE9=CORES_PER_NODE*8
26 NODE10=CORES_PER_NODE*9
27 NODE11=CORES_PER_NODE*10
28
29 class test:
30     def __init__(self):
31         self.accounts = GacksAccountManager()
32         self.policies = GacksPolicyDirectory(dir="./policy.d")
33         self.resources = GacksResourceDirectory(dir="./resources.d")
34         self.calendar = GacksMySQLCalendar(tableName = "gacksaccount_test")
35
36         self.calendar.reset()
37
38         self.init_accounts()
39
40         self.enforcer = GacksEnforcer(self.accounts, self.policies, self.calendar, self.resources)
41
42         self.test_goodStanding()
43         self.test_kind()
44         self.test_duration()
45         self.test_endtime()
46         self.test_max_on_node()
47         self.test_max_concurrent()
48         self.test_bucket()
49
50     def handle_to_rec(self, h, allocatorHRNs):
51         r = GacksRecord(id=h.id, unitStart=h.unitStart, unitStop=h.unitStop,
52                         timeStart=h.timeStart, timeStop=h.timeStop, allocatorHRNs=allocatorHRNs)
53         return r
54
55     def init_accounts(self):
56         # initialize some accounts
57         self.accounts.delete_account(hrn_to_gacksid("plc.test.gold"), "user")
58         self.accounts.delete_account(hrn_to_gacksid("plc.test.silver"), "user")
59         self.accounts.delete_account(hrn_to_gacksid("plc.test.best"), "user")
60         self.accounts.delete_account(hrn_to_gacksid("plc.test.test1"), "user")
61         self.accounts.delete_account(hrn_to_gacksid("plc.test.test1b"), "user")
62         self.accounts.delete_account(hrn_to_gacksid("plc.test.test1c"), "user")
63         self.accounts.delete_account(hrn_to_gacksid("plc.test.test1d"), "user")
64         self.accounts.delete_account(hrn_to_gacksid("plc.test.test2"), "user")
65         self.accounts.delete_account(hrn_to_gacksid("plc.test.test2"), "bucket")
66
67         self.gold=self.accounts.new_account(hrn_to_gacksid("plc.test.gold"), "user")
68         self.gold.level="gold"
69         self.gold.goodStanding=True
70         self.gold.commit()
71
72         self.silver=self.accounts.new_account(hrn_to_gacksid("plc.test.silver"), "user")
73         self.silver.level="silver"
74         self.silver.goodStanding=True
75         self.silver.commit()
76
77         self.best=self.accounts.new_account(hrn_to_gacksid("plc.test.best"), "user")
78         self.best.goodStanding=True
79         self.best.commit()
80
81         self.test1=self.accounts.new_account(hrn_to_gacksid("plc.test.test1"), "user")
82         self.test1.level="test_policy_1"
83         self.test1.goodStanding=True
84         self.test1.commit()
85
86         self.test1b=self.accounts.new_account(hrn_to_gacksid("plc.test.test1b"), "user")
87         self.test1b.level="test_policy_1"
88         self.test1b.goodStanding=True
89         self.test1b.commit()
90
91         self.test1c=self.accounts.new_account(hrn_to_gacksid("plc.test.test1c"), "user")
92         self.test1c.level="test_policy_1"
93         self.test1c.multiplier=2
94         self.test1c.goodStanding=True
95         self.test1c.commit()
96
97         self.test1d=self.accounts.new_account(hrn_to_gacksid("plc.test.test1d"), "user")
98         self.test1d.level="test_policy_1"
99         self.test1d.goodStanding=False
100         self.test1d.commit()
101
102         self.test2=self.accounts.new_account(hrn_to_gacksid("plc.test.test2"), "user")
103         self.test2.level="test_policy_2"
104         self.test2.goodStanding=True
105         self.test2.commit()
106
107     def test_kind(self):
108         t = time.time()
109
110         # calendar day, should be okay
111         h = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+1*24*60*60, unitStart=1, unitStop=2)
112         self.enforcer.check("plc.test.test1", [h], "calendar")
113
114         # asap, should fail
115         h = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+1*24*60*60, unitStart=1, unitStop=2)
116         try:
117             self.enforcer.check("plc.test.test1", [h], "asap")
118         except GacksEnforcerNoReservation:
119             pass
120         else:
121             raise "Failed to raise GacksEnforcerNoReservation"
122
123     def test_duration(self):
124         t = time.time()
125
126         # 1 day, should be okay
127         h = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+1*24*60*60, unitStart=1, unitStop=2)
128         self.enforcer.check("plc.test.test1", [h])
129
130         # 5 days, ought to just fit
131         h = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+5*24*60*60, unitStart=1, unitStop=2)
132         self.enforcer.check("plc.test.test1", [h])
133
134         # 5 days + 1 second, too long
135         try:
136             h = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+5*24*60*60+1, unitStart=1, unitStop=2)
137             self.enforcer.check("plc.test.test1", [h])
138         except GacksEnforcerDurationTooLong:
139             pass
140         else:
141             raise "Failed to raise GacksEnforcerDurationTooLong"
142
143     def test_endtime(self):
144         t = time.time()
145
146         # 1 day from now, should be okay
147         h = GacksHandle(id="plc.vicci.cores", timeStart=t+5*DAY, timeStop=t+6*DAY, unitStart=1, unitStop=2)
148         self.enforcer.check("plc.test.test1", [h])
149
150         # 11 days from now, should be bad
151         try:
152             h = GacksHandle(id="plc.vicci.cores", timeStart=t+10*DAY, timeStop=t+11*DAY, unitStart=1, unitStop=2)
153             self.enforcer.check("plc.test.test1", [h])
154         except GacksEnforcerEndDateBeyondLimit:
155             pass
156         else:
157             raise "Failed to raise GacksEnforcerEndDateBeyondLimit"
158
159     def test_max_on_node(self):
160         t = time.time()
161
162         # 3 units is okay
163         h = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=1, unitStop=4)
164         self.enforcer.check("plc.test.test1", [h])
165
166         # 4 units is bad
167         try:
168             h = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=1, unitStop=5)
169             self.enforcer.check("plc.test.test1", [h])
170         except GacksEnforcerTooManyOnNode:
171             pass
172         else:
173             raise "Failed to raise GacksEnforcerTooManyOnNode"
174
175         # 3 units is okay
176         h1 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=1, unitStop=2)
177         h2 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=5, unitStop=7)
178         self.enforcer.check("plc.test.test1", [h1,h2])
179
180         # 4 units is bad
181         try:
182             h1 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=1, unitStop=3)
183             h2 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=5, unitStop=7)
184             self.enforcer.check("plc.test.test1", [h1,h2])
185         except GacksEnforcerTooManyOnNode:
186             pass
187         else:
188             raise "Failed to raise GacksEnforcerTooManyOnNode"
189
190         # 3 units each on 2 different nodes is okay
191         h1 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=1, unitStop=4)
192         h2 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=13, unitStop=16)
193         self.enforcer.check("plc.test.test1", [h1,h2])
194
195         # lets put some stuff in the calendar
196         r1 = GacksRecord(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=1, unitStop=2, allocatorHRNs=["plc.test.test1"])
197         self.calendar.insert_record(r1)
198
199         # 3 units is okay
200         h2 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=5, unitStop=7)
201         self.enforcer.check("plc.test.test1", [h2])
202
203         # 4 units is bad
204         try:
205             h2 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=5, unitStop=8)
206             self.enforcer.check("plc.test.test1", [h2])
207         except GacksEnforcerTooManyOnNode:
208             pass
209         else:
210             raise "Failed to raise GacksEnforcerTooManyOnNode"
211
212         # clean out the changes we made to the calendar
213         self.calendar.reset()
214
215     def test_max_concurrent(self):
216         t = time.time()
217
218         # 3 units per node, 9 units total is okay
219         h1 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=NODE1, unitStop=NODE1+3)
220         h2 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=NODE2, unitStop=NODE2+3)
221         h3 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=NODE3, unitStop=NODE3+3)
222         self.enforcer.check("plc.test.test1", [h1,h2,h3])
223
224         # 10 units total is bad
225         h4 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=NODE4, unitStop=NODE4+1)
226         try:
227             self.enforcer.check("plc.test.test1", [h1,h2,h3,h4])
228         except GacksEnforcerTooManyConcurrent:
229             pass
230         else:
231             raise "Failed to raise GacksEnforcerTooManyConcurrent"
232
233         # put some in the database
234         r1 = self.handle_to_rec(h1, ["plc.test.test1"])
235         r2 = self.handle_to_rec(h2, ["plc.test.test1"])
236         r3 = self.handle_to_rec(h3, ["plc.test.test1"])
237
238         self.calendar.insert_record(r1)
239         self.calendar.insert_record(r2)
240         self.calendar.insert_record(r3)
241
242         # units to a different user should be okay
243         h4 = GacksHandle(id="plc.vicci.cores", timeStart=t+DAY, timeStop=t+2*DAY, unitStart=NODE4, unitStop=NODE4+1)
244         self.enforcer.check("plc.test.test1b", [h4])
245
246         # units at a different time should be okay
247         h4 = GacksHandle(id="plc.vicci.cores", timeStart=t+DAY, timeStop=t+2*DAY, unitStart=NODE4, unitStop=NODE4+1)
248         self.enforcer.check("plc.test.test1", [h4])
249
250         # 10 units at the same time is bad
251         h4 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+1*DAY, unitStart=NODE4, unitStop=NODE4+1)
252         try:
253             self.enforcer.check("plc.test.test1", [h4])
254         except GacksEnforcerTooManyConcurrent:
255             pass
256         else:
257             raise "Failed to raise GacksEnforcerTooManyConcurrent"
258
259         # multiplier = 2, then we can do up to 18
260         h5 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=NODE5, unitStop=NODE5+3)
261         h6 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=NODE6, unitStop=NODE6+3)
262         h7 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=NODE7, unitStop=NODE7+3)
263         self.enforcer.check("plc.test.test1c", [h1,h2,h3,h5,h6,h7])
264
265         # but not 19
266         try:
267            self.enforcer.check("plc.test.test1c", [h1,h2,h3,h5,h6,h7,h4])
268         except GacksEnforcerTooManyConcurrent:
269             pass
270         else:
271             raise "Failed to raise GacksEnforcerTooManyConcurrent"
272
273         self.calendar.reset()
274
275     def test_goodStanding(self):
276         t = time.time()
277
278         # 3 units per node, 9 units total is okay
279         h1 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=NODE1, unitStop=NODE1+3)
280
281         try:
282             self.enforcer.check("plc.test.test1d", [h1])
283         except GacksEnforcerNotGoodStanding:
284             pass
285         else:
286             raise "Failed to raise GacksEnforcerNotGoodStanding"
287
288     def test_bucket(self):
289         t = time.time()
290
291         # lets work on an hour boundary
292         t = ((int(t)/3600) + 1) * 3600
293
294         h1 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+HOUR, unitStart=NODE1, unitStop=NODE1+3)
295
296         # 3 units is okay
297         self.enforcer.check("plc.test.test2", [h1])
298
299         r1 = self.handle_to_rec(h1, ["plc.test.test2"])
300         self.calendar.insert_record(r1)
301
302         h2 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+HOUR, unitStart=NODE2, unitStop=NODE2+3)
303
304         try:
305             # 6 units is too many
306             self.enforcer.check("plc.test.test2", [h2])
307         except GacksEnforcerBucketUnderflow:
308             pass
309         else:
310             raise "Failed to raise GacksEnforcerBuckerUnderflow"
311
312         h3 = GacksHandle(id="plc.vicci.cores", timeStart=t+HOUR, timeStop=t+2*HOUR, unitStart=NODE3, unitStop=NODE3+3)
313
314         # 3 units followed by 3 units is okay
315         self.enforcer.check("plc.test.test2", [h3])
316
317         r3 = self.handle_to_rec(h3, ["plc.test.test2"])
318         self.calendar.insert_record(r3)
319
320         # there should be 5 units available at time t+2hours
321         #    5 starting units
322         #   +6 bucket filled units
323         #   -6 allocated units
324         #   =5 units left
325
326         h4= GacksHandle(id="plc.vicci.cores", timeStart=t+2*HOUR, timeStop=t+3*HOUR, unitStart=NODE4, unitStop=NODE4+5)
327
328         # 5 units is okay
329         self.enforcer.check("plc.test.test2", [h4])
330
331         r4 = self.handle_to_rec(h4, ["plc.test.test2"])
332         self.calendar.insert_record(r4)
333
334         # 1 unit anywhere else should be a problem
335         h5 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+HOUR, unitStart=NODE4, unitStop=NODE4+1)
336         try:
337             self.enforcer.check("plc.test.test2", [h5])
338         except GacksEnforcerBucketUnderflow:
339             pass
340         else:
341             raise "Failed to raise GacksEnforcerBucketUnderflow"
342
343         h5 = GacksHandle(id="plc.vicci.cores", timeStart=t+HOUR, timeStop=t+2*HOUR, unitStart=NODE4, unitStop=NODE4+1)
344         try:
345             self.enforcer.check("plc.test.test2", [h5])
346         except GacksEnforcerBucketUnderflow:
347             pass
348         else:
349             raise "Failed to raise GacksEnforcerBucketUnderflow"
350
351         h5 = GacksHandle(id="plc.vicci.cores", timeStart=t+2*HOUR, timeStop=t+3*HOUR, unitStart=NODE4, unitStop=NODE4+1)
352         try:
353             self.enforcer.check("plc.test.test2", [h5])
354         except GacksEnforcerBucketUnderflow:
355             pass
356         else:
357             raise "Failed to raise GacksEnforcerBucketUnderflow"
358
359         # try some long reservations
360
361         # 2 nodes for 10 days
362         h6 = GacksHandle(id="plc.vicci.cores", timeStart=t+DAY, timeStop=t+11*DAY, unitStart=NODE6, unitStop=NODE6+2)
363         self.enforcer.check("plc.test.test2", [h6])
364         r6 = self.handle_to_rec(h6, ["plc.test.test2"])
365         self.calendar.insert_record(r6)
366
367         # 1 nodes for 2 days each, overlapped with the 3-day reservation
368         h7 = GacksHandle(id="plc.vicci.cores", timeStart=t+2*DAY, timeStop=t+4*DAY, unitStart=NODE7, unitStop=NODE7+1)
369         h8 = GacksHandle(id="plc.vicci.cores", timeStart=t+6*DAY, timeStop=t+8*DAY, unitStart=NODE8, unitStop=NODE8+1)
370         self.enforcer.check("plc.test.test2", [h7])
371         r7 = self.handle_to_rec(h7, ["plc.test.test2"])
372         self.enforcer.check("plc.test.test2", [h8])
373         r8 = self.handle_to_rec(h8, ["plc.test.test2"])
374         self.calendar.insert_record(r7)
375
376         # 2 additional nodes should not cause a problem
377         h9 = GacksHandle(id="plc.vicci.cores", timeStart=t+2*DAY+5*HOUR, timeStop=t+2*DAY+6*HOUR, unitStart=NODE9, unitStop=NODE9+2)
378         self.enforcer.check("plc.test.test2", [h9])
379         r9 = self.handle_to_rec(h9, ["plc.test.test2"])
380         self.calendar.insert_record(r9)
381
382         # 1 additional node (total of 2+1+2+1 == 6) should cause a bucket underflow
383         h10 = GacksHandle(id="plc.vicci.cores", timeStart=t+2*DAY+5*HOUR, timeStop=t+2*DAY+6*HOUR, unitStart=NODE10, unitStop=NODE10+1)
384         try:
385             self.enforcer.check("plc.test.test2", [h10])
386         except GacksEnforcerBucketUnderflow:
387             pass
388         else:
389             raise "Failed to raise GacksEnforcerBuckerUnderflow"
390
391         # insert a big empty period to test handling gaps efficiently
392         h11 = GacksHandle(id="plc.vicci.cores", timeStart=t+5000*DAY, timeStop=t+5001*DAY, unitStart=NODE11, unitStop=NODE11+2)
393         self.enforcer.check("plc.test.test2", [h11])
394
395
396
397 test()