Revision 3adbfafa
b/snf-astakos-app/astakos/quotaholder/callpoint.py | ||
---|---|---|
35 | 35 |
QuotaholderError, |
36 | 36 |
CorruptedError, InvalidDataError, |
37 | 37 |
NoQuantityError, NoCapacityError, |
38 |
ExportLimitError, ImportLimitError, |
|
39 | 38 |
DuplicateError) |
40 | 39 |
|
41 | 40 |
from astakos.quotaholder.utils.newname import newname |
... | ... | |
62 | 61 |
except Policy.DoesNotExist: |
63 | 62 |
continue |
64 | 63 |
|
65 |
append((policy, p.quantity, p.capacity, |
|
66 |
p.import_limit, p.export_limit)) |
|
64 |
append((policy, p.quantity, p.capacity)) |
|
67 | 65 |
|
68 | 66 |
return limits |
69 | 67 |
|
70 | 68 |
def set_limits(self, context=None, set_limits=()): |
71 | 69 |
|
72 |
for (policy, quantity, capacity, |
|
73 |
import_limit, export_limit) in set_limits: |
|
70 |
for (policy, quantity, capacity) in set_limits: |
|
74 | 71 |
|
75 | 72 |
try: |
76 | 73 |
policy = db_get_policy(policy=policy, for_update=True) |
... | ... | |
78 | 75 |
Policy.objects.create(policy=policy, |
79 | 76 |
quantity=quantity, |
80 | 77 |
capacity=capacity, |
81 |
import_limit=import_limit, |
|
82 |
export_limit=export_limit) |
|
78 |
) |
|
83 | 79 |
else: |
84 | 80 |
policy.quantity = quantity |
85 | 81 |
policy.capacity = capacity |
86 |
policy.export_limit = export_limit |
|
87 |
policy.import_limit = import_limit |
|
88 | 82 |
policy.save() |
89 | 83 |
|
90 | 84 |
return () |
... | ... | |
287 | 281 |
p = h.policy |
288 | 282 |
|
289 | 283 |
append((h.holder, h.resource, p.quantity, p.capacity, |
290 |
p.import_limit, p.export_limit, |
|
291 | 284 |
h.imported, h.exported, |
292 | 285 |
h.returned, h.released, |
293 | 286 |
h.flags)) |
... | ... | |
300 | 293 |
|
301 | 294 |
q_holdings = Q() |
302 | 295 |
holders = [] |
303 |
for (holder, resource, _, _, _, _, _) in set_quota:
|
|
296 |
for (holder, resource, _, _, _) in set_quota: |
|
304 | 297 |
holders.append(holder) |
305 | 298 |
|
306 | 299 |
hs = Holding.objects.filter(holder__in=holders).select_for_update() |
... | ... | |
312 | 305 |
|
313 | 306 |
for (holder, resource, |
314 | 307 |
quantity, capacity, |
315 |
import_limit, export_limit, flags) in set_quota:
|
|
308 |
flags) in set_quota: |
|
316 | 309 |
|
317 | 310 |
policy = newname('policy_') |
318 | 311 |
newp = Policy(policy=policy, |
319 | 312 |
quantity=quantity, |
320 | 313 |
capacity=capacity, |
321 |
import_limit=import_limit, |
|
322 |
export_limit=export_limit) |
|
314 |
) |
|
323 | 315 |
|
324 | 316 |
try: |
325 | 317 |
h = holdings[(holder, resource)] |
... | ... | |
353 | 345 |
sources = sub_quota + add_quota |
354 | 346 |
q_holdings = Q() |
355 | 347 |
holders = [] |
356 |
for (holder, resource, _, _, _, _) in sources:
|
|
348 |
for (holder, resource, _, _) in sources: |
|
357 | 349 |
holders.append(holder) |
358 | 350 |
|
359 | 351 |
hs = Holding.objects.filter(holder__in=holders).select_for_update() |
... | ... | |
369 | 361 |
for removing, source in [(True, sub_quota), (False, add_quota)]: |
370 | 362 |
for (holder, resource, |
371 | 363 |
quantity, capacity, |
372 |
import_limit, export_limit) in source:
|
|
364 |
) in source: |
|
373 | 365 |
|
374 | 366 |
try: |
375 | 367 |
h = holdings[(holder, resource)] |
... | ... | |
393 | 385 |
invert=removing) |
394 | 386 |
newp.capacity = _add(p.capacity if p else 0, capacity, |
395 | 387 |
invert=removing) |
396 |
newp.import_limit = _add(p.import_limit if p else 0, |
|
397 |
import_limit, invert=removing) |
|
398 |
newp.export_limit = _add(p.export_limit if p else 0, |
|
399 |
export_limit, invert=removing) |
|
400 |
|
|
401 |
new_values = [newp.capacity, |
|
402 |
newp.import_limit, newp.export_limit] |
|
403 |
if any(map(_isneg, new_values)): |
|
388 |
|
|
389 |
if _isneg(newp.capacity): |
|
404 | 390 |
append((holder, resource)) |
405 | 391 |
continue |
406 | 392 |
|
... | ... | |
466 | 452 |
hp = h.policy |
467 | 453 |
|
468 | 454 |
if not release: |
469 |
current = h.exporting |
|
470 |
limit = hp.export_limit |
|
471 |
if current + quantity > limit: |
|
472 |
m = ("Export limit reached for %s.%s" % (holder, resource)) |
|
473 |
raise ExportLimitError(m, |
|
474 |
source=holder, |
|
475 |
target=target, |
|
476 |
resource=resource, |
|
477 |
requested=quantity, |
|
478 |
current=current, |
|
479 |
limit=limit) |
|
480 |
|
|
481 | 455 |
limit = hp.quantity + h.imported - h.releasing |
482 | 456 |
unavailable = h.exporting - h.returned |
483 | 457 |
available = limit - unavailable |
... | ... | |
525 | 499 |
tp = th.policy |
526 | 500 |
|
527 | 501 |
if not release: |
528 |
limit = tp.import_limit |
|
529 |
current = th.importing |
|
530 |
if current + quantity > limit: |
|
531 |
m = ("Import limit reached for %s.%s" % (target, resource)) |
|
532 |
raise ImportLimitError(m, |
|
533 |
source=holder, |
|
534 |
target=target, |
|
535 |
resource=resource, |
|
536 |
requested=quantity, |
|
537 |
current=current, |
|
538 |
limit=limit) |
|
539 |
|
|
540 | 502 |
limit = tp.quantity + tp.capacity |
541 | 503 |
current = (+ th.importing + th.returning + tp.quantity |
542 | 504 |
- th.exported - th.released) |
... | ... | |
600 | 562 |
'resource': provision.resource, |
601 | 563 |
'source_quantity': s_policy.quantity, |
602 | 564 |
'source_capacity': s_policy.capacity, |
603 |
'source_import_limit': s_policy.import_limit, |
|
604 |
'source_export_limit': s_policy.export_limit, |
|
605 | 565 |
'source_imported': s_holding.imported, |
606 | 566 |
'source_exported': s_holding.exported, |
607 | 567 |
'source_returned': s_holding.returned, |
608 | 568 |
'source_released': s_holding.released, |
609 | 569 |
'target_quantity': t_policy.quantity, |
610 | 570 |
'target_capacity': t_policy.capacity, |
611 |
'target_import_limit': t_policy.import_limit, |
|
612 |
'target_export_limit': t_policy.export_limit, |
|
613 | 571 |
'target_imported': t_holding.imported, |
614 | 572 |
'target_exported': t_holding.exported, |
615 | 573 |
'target_returned': t_holding.returned, |
b/snf-astakos-app/astakos/quotaholder/exception.py | ||
---|---|---|
67 | 67 |
pass |
68 | 68 |
|
69 | 69 |
|
70 |
class ExportLimitError(CommissionValueException): |
|
71 |
pass |
|
72 |
|
|
73 |
|
|
74 |
class ImportLimitError(CommissionValueException): |
|
75 |
pass |
|
76 |
|
|
77 |
|
|
78 | 70 |
class DuplicateError(CommissionException): |
79 | 71 |
pass |
b/snf-astakos-app/astakos/quotaholder/models.py | ||
---|---|---|
44 | 44 |
policy = CharField(max_length=4096, primary_key=True) |
45 | 45 |
quantity = intDecimalField() |
46 | 46 |
capacity = intDecimalField() |
47 |
import_limit = intDecimalField() |
|
48 |
export_limit = intDecimalField() |
|
49 | 47 |
|
50 | 48 |
objects = ForUpdateManager() |
51 | 49 |
|
... | ... | |
111 | 109 |
resource = CharField(max_length=4096) |
112 | 110 |
source_quantity = intDecimalField() |
113 | 111 |
source_capacity = intDecimalField() |
114 |
source_import_limit = intDecimalField() |
|
115 |
source_export_limit = intDecimalField() |
|
116 | 112 |
source_imported = intDecimalField() |
117 | 113 |
source_exported = intDecimalField() |
118 | 114 |
source_returned = intDecimalField() |
119 | 115 |
source_released = intDecimalField() |
120 | 116 |
target_quantity = intDecimalField() |
121 | 117 |
target_capacity = intDecimalField() |
122 |
target_import_limit = intDecimalField() |
|
123 |
target_export_limit = intDecimalField() |
|
124 | 118 |
target_imported = intDecimalField() |
125 | 119 |
target_exported = intDecimalField() |
126 | 120 |
target_returned = intDecimalField() |
b/snf-astakos-app/astakos/quotaholder/test/simpletests.py | ||
---|---|---|
39 | 39 |
QuotaholderError, |
40 | 40 |
InvalidDataError, |
41 | 41 |
NoQuantityError, NoCapacityError, |
42 |
ExportLimitError, ImportLimitError, |
|
43 | 42 |
CommissionValueException, |
44 | 43 |
DuplicateError) |
45 | 44 |
|
... | ... | |
87 | 86 |
def rand_limits(self): |
88 | 87 |
q = random_nat() |
89 | 88 |
c = random_nat() |
90 |
il = random_nat() |
|
91 |
el = random_nat() |
|
92 |
return q, c, il, el |
|
89 |
return q, c, |
|
93 | 90 |
|
94 | 91 |
def rand_policy_limits(self): |
95 | 92 |
p = self.rand_policy() |
... | ... | |
183 | 180 |
resource1 = self.rand_resource() |
184 | 181 |
|
185 | 182 |
self.qh.set_quota( |
186 |
set_quota=[(e0, resource0) + (5, QH_PRACTICALLY_INFINITE, 5, 6) + (0,),
|
|
187 |
(e1, resource0) + (5, 5, 5, 5) + (0,)])
|
|
183 |
set_quota=[(e0, resource0) + (5, QH_PRACTICALLY_INFINITE) + (0,), |
|
184 |
(e1, resource0) + (5, 5) + (0,)]) |
|
188 | 185 |
|
189 | 186 |
self.qh.add_quota(sub_quota=[(e0, resource0, |
190 |
0, QH_PRACTICALLY_INFINITE, 1, 1)],
|
|
187 |
0, QH_PRACTICALLY_INFINITE)], |
|
191 | 188 |
add_quota=[(e0, resource0, |
192 |
0, 3, QH_PRACTICALLY_INFINITE, 0),
|
|
189 |
0, 3), |
|
193 | 190 |
# new holding |
194 | 191 |
(e0, resource1, |
195 |
0, QH_PRACTICALLY_INFINITE, 5, 5)])
|
|
192 |
0, QH_PRACTICALLY_INFINITE)]) |
|
196 | 193 |
|
197 | 194 |
r = self.qh.get_quota(get_quota=[(e0, resource0), |
198 | 195 |
(e0, resource1)]) |
199 |
self.assertEqual(r, [(e0, resource0, 5, 3, QH_PRACTICALLY_INFINITE+4, 5)
|
|
196 |
self.assertEqual(r, [(e0, resource0, 5, 3) |
|
200 | 197 |
+ DEFAULT_HOLDING + (0,), |
201 |
(e0, resource1, 0, QH_PRACTICALLY_INFINITE, 5, 5)
|
|
198 |
(e0, resource1, 0, QH_PRACTICALLY_INFINITE) |
|
202 | 199 |
+ DEFAULT_HOLDING + (0,)]) |
203 | 200 |
|
204 | 201 |
with self.assertRaises(QuotaholderError) as cm: |
205 | 202 |
self.qh.add_quota(add_quota=[(e1, resource0, |
206 |
0, (-10), QH_PRACTICALLY_INFINITE, 0),
|
|
207 |
(e0, resource1, 1, 0, 0, 0)])
|
|
203 |
0, (-10)), |
|
204 |
(e0, resource1, 1, 0)]) |
|
208 | 205 |
|
209 | 206 |
err = cm.exception |
210 | 207 |
self.assertEqual(err.message, [(e1, resource0)]) |
211 | 208 |
|
212 | 209 |
# r = self.qh.get_quota(get_quota=[(e1, resource0), |
213 | 210 |
# (e0, resource1)]) |
214 |
# self.assertEqual(r, [(e1, resource0, 5, 5 , 5, 5)
|
|
211 |
# self.assertEqual(r, [(e1, resource0, 5, 5) |
|
215 | 212 |
# + DEFAULT_HOLDING + (0,), |
216 |
# (e0, resource1, 0, QH_PRACTICALLY_INFINITE, 5, 5)
|
|
213 |
# (e0, resource1, 0, QH_PRACTICALLY_INFINITE) |
|
217 | 214 |
# + DEFAULT_HOLDING + (0,)]) |
218 | 215 |
|
219 | 216 |
@transaction.commit_on_success |
... | ... | |
225 | 222 |
|
226 | 223 |
self.qh.set_quota( |
227 | 224 |
set_quota=[(e0, resource0) + |
228 |
(5, QH_PRACTICALLY_INFINITE, 5, 6) + (0,)])
|
|
225 |
(5, QH_PRACTICALLY_INFINITE) + (0,)]) |
|
229 | 226 |
|
230 | 227 |
self.qh.add_quota(add_quota=[(e0, resource0, |
231 |
0, QH_PRACTICALLY_INFINITE, 0, 0)])
|
|
228 |
0, QH_PRACTICALLY_INFINITE)]) |
|
232 | 229 |
|
233 | 230 |
r = self.qh.get_quota(get_quota=[(e0, resource0)]) |
234 |
self.assertEqual(r, [(e0, resource0, 5, 2*QH_PRACTICALLY_INFINITE, 5, 6)
|
|
231 |
self.assertEqual(r, [(e0, resource0, 5, 2*QH_PRACTICALLY_INFINITE) |
|
235 | 232 |
+ DEFAULT_HOLDING + (0,)]) |
236 | 233 |
|
237 | 234 |
@transaction.commit_on_success |
... | ... | |
239 | 236 |
e0 = self.rand_holder() |
240 | 237 |
e1 = self.rand_holder() |
241 | 238 |
resource = self.rand_resource() |
242 |
q0, c0, il0, el0 = self.new_quota(e0, resource)
|
|
243 |
q1, c1, il1, el1 = self.new_quota(e1, resource)
|
|
239 |
q0, c0 = self.new_quota(e0, resource) |
|
240 |
q1, c1 = self.new_quota(e1, resource) |
|
244 | 241 |
|
245 |
most = min(c0, il0, q1, el1)
|
|
242 |
most = min(c0, q1)
|
|
246 | 243 |
if most < 0: |
247 | 244 |
raise AssertionError("%s <= 0" % most) |
248 | 245 |
|
... | ... | |
278 | 275 |
et1 = self.rand_holder() |
279 | 276 |
et2 = self.rand_holder() |
280 | 277 |
resource = self.rand_resource() |
281 |
self.new_quota(es1, resource, (10, 5, 5, 15))
|
|
282 |
self.new_quota(es2, resource, (10, 5, 5, 10))
|
|
283 |
self.new_quota(et1, resource, (0, 15, 3, 20))
|
|
284 |
self.new_quota(et2, resource, (0, 15, 20, 20))
|
|
278 |
self.new_quota(es1, resource, (10, 5)) |
|
279 |
self.new_quota(es2, resource, (10, 5)) |
|
280 |
self.new_quota(et1, resource, (0, 15)) |
|
281 |
self.new_quota(et2, resource, (0, 15)) |
|
285 | 282 |
|
286 | 283 |
with self.assertRaises(NoQuantityError) as cm: |
287 | 284 |
self.qh.issue_commission(clientkey=self.client, target=et1, |
... | ... | |
300 | 297 |
provisions=[(es1, resource, 2)]) |
301 | 298 |
self.assertGreater(r, 0) |
302 | 299 |
|
303 |
with self.assertRaises(ImportLimitError) as cm: |
|
304 |
self.qh.issue_commission(clientkey=self.client, target=et1, |
|
305 |
name='something', |
|
306 |
provisions=[(es1, resource, 2)]) |
|
307 |
e = cm.exception |
|
308 |
self.assertEqual(e.source, es1) |
|
309 |
self.assertEqual(e.target, et1) |
|
310 |
self.assertEqual(e.resource, resource) |
|
311 |
self.assertEqual(int(e.limit), 3) |
|
312 |
self.assertEqual(int(e.requested), 2) |
|
313 |
self.assertEqual(int(e.current), 2) |
|
300 |
# with self.assertRaises(ImportLimitError) as cm:
|
|
301 |
# self.qh.issue_commission(clientkey=self.client, target=et1,
|
|
302 |
# name='something',
|
|
303 |
# provisions=[(es1, resource, 2)])
|
|
304 |
# e = cm.exception
|
|
305 |
# self.assertEqual(e.source, es1)
|
|
306 |
# self.assertEqual(e.target, et1)
|
|
307 |
# self.assertEqual(e.resource, resource)
|
|
308 |
# self.assertEqual(int(e.limit), 3)
|
|
309 |
# self.assertEqual(int(e.requested), 2)
|
|
310 |
# self.assertEqual(int(e.current), 2)
|
|
314 | 311 |
|
315 | 312 |
r = self.qh.issue_commission(clientkey=self.client, target=et2, |
316 | 313 |
name='something', |
... | ... | |
338 | 335 |
resource = 'list_holdings_resource' |
339 | 336 |
sys = 'system' |
340 | 337 |
|
341 |
self.qh.set_quota(set_quota=[(sys, resource, 10, 0, |
|
342 |
QH_PRACTICALLY_INFINITE, |
|
343 |
QH_PRACTICALLY_INFINITE, 0), |
|
344 |
(e0, resource, 0, 10, |
|
345 |
QH_PRACTICALLY_INFINITE, |
|
346 |
QH_PRACTICALLY_INFINITE, 0), |
|
347 |
(e1, resource, 0, 10, |
|
348 |
QH_PRACTICALLY_INFINITE, |
|
349 |
QH_PRACTICALLY_INFINITE, 0)]) |
|
338 |
self.qh.set_quota(set_quota=[(sys, resource, 10, 0, 0), |
|
339 |
(e0, resource, 0, 10, 0), |
|
340 |
(e1, resource, 0, 10, 0)]) |
|
350 | 341 |
|
351 | 342 |
s0 = self.qh.issue_commission(clientkey=self.client, target=e0, |
352 | 343 |
name='a commission', |
... | ... | |
370 | 361 |
def test_0130_release_holding(self): |
371 | 362 |
e = self.rand_holder() |
372 | 363 |
resource = self.rand_resource() |
373 |
limits = self.new_quota(e, resource, (1, 2, 3, 4))
|
|
364 |
limits = self.new_quota(e, resource, (1, 2)) |
|
374 | 365 |
|
375 | 366 |
with self.assertRaises(QuotaholderError) as cm: |
376 | 367 |
self.qh.release_holding(release_holding=[(e, resource)]) |
... | ... | |
382 | 373 |
def test_0131_release_holding(self): |
383 | 374 |
e = self.rand_holder() |
384 | 375 |
resource = self.rand_resource() |
385 |
limits = self.new_quota(e, resource, (0, 2, 3, 4))
|
|
376 |
limits = self.new_quota(e, resource, (0, 2)) |
|
386 | 377 |
|
387 | 378 |
self.qh.release_holding(release_holding=[(e, resource)]) |
388 | 379 |
|
... | ... | |
391 | 382 |
resource = self.rand_resource() |
392 | 383 |
|
393 | 384 |
es = self.rand_holder() |
394 |
limits_s = self.new_quota(es, resource, (3, 3, 3, 3))
|
|
385 |
limits_s = self.new_quota(es, resource, (3, 3)) |
|
395 | 386 |
e = self.rand_holder() |
396 |
limits = self.new_quota(e, resource, (0, 2, 3, 4))
|
|
387 |
limits = self.new_quota(e, resource, (0, 2)) |
|
397 | 388 |
|
398 | 389 |
r = self.qh.issue_commission(clientkey=self.client, target=e, |
399 | 390 |
name='something', |
... | ... | |
436 | 427 |
resource = "resource" |
437 | 428 |
target = "test_015_release_nocapacity_target" |
438 | 429 |
flags = 0 |
439 |
source_limits = [source, 6, 0, 1000, 1000]
|
|
430 |
source_limits = [source, 6, 0] |
|
440 | 431 |
source_holding = [source, resource, source, flags] |
441 |
target_limits = [target, 0, 5, 1000, 1000]
|
|
432 |
target_limits = [target, 0, 5] |
|
442 | 433 |
target_holding = [target, resource, target, flags] |
443 | 434 |
|
444 | 435 |
failed = AssertionError("Quotaholder call failed") |
... | ... | |
472 | 463 |
name="something", |
473 | 464 |
provisions=[(source, resource, -7)]) |
474 | 465 |
|
475 |
source_limits = [source, 6, 10, 1000, 1000]
|
|
466 |
source_limits = [source, 6, 10] |
|
476 | 467 |
if qh.set_limits(set_limits=[source_limits]): |
477 | 468 |
raise failed |
478 | 469 |
|
Also available in: Unified diff