Skip to content

Commit

Permalink
Migrate change reservation test from seantis.reservation
Browse files Browse the repository at this point in the history
  • Loading branch information
href committed Nov 24, 2014
1 parent 02b09cf commit e7c9e74
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 15 deletions.
14 changes: 12 additions & 2 deletions libres/db/models/reservation.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from libres.db.models.types import GUID, UTCDateTime
from libres.db.models.other import OtherModels
from libres.db.models.timestamp import TimestampMixin
from libres.modules import calendar


class Reservation(TimestampMixin, ORMBase, OtherModels):
Expand Down Expand Up @@ -46,12 +47,12 @@ class Reservation(TimestampMixin, ORMBase, OtherModels):
)

start = Column(
UTCDateTime(),
UTCDateTime(timezone=False),
nullable=True
)

end = Column(
UTCDateTime(),
UTCDateTime(timezone=False),
nullable=True
)

Expand Down Expand Up @@ -111,6 +112,15 @@ def _target_allocations(self):

return query

def display_start(self, timezone=None):
"""Does nothing but to form a nice pair to display_end."""
return calendar.to_timezone(self.start, timezone or self.timezone)

def display_end(self, timezone=None):
"""Returns the end plus one microsecond (nicer display)."""
end = self.end + timedelta(microseconds=1)
return calendar.to_timezone(end, timezone or self.timezone)

def timespans(self, start=None, end=None):

if self.target_type == u'allocation':
Expand Down
19 changes: 13 additions & 6 deletions libres/db/models/reserved_slot.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from libres.db.models import ORMBase, Allocation
from libres.db.models.types import GUID, UTCDateTime
from libres.db.models.timestamp import TimestampMixin
from libres.modules import calendar


class ReservedSlot(TimestampMixin, ORMBase):
Expand All @@ -28,14 +29,14 @@ class ReservedSlot(TimestampMixin, ORMBase):
)

start = Column(
UTCDateTime(),
UTCDateTime(timezone=False),
primary_key=True,
nullable=False,
autoincrement=False
)

end = Column(
UTCDateTime(),
UTCDateTime(timezone=False),
nullable=False
)

Expand Down Expand Up @@ -68,11 +69,17 @@ class ReservedSlot(TimestampMixin, ORMBase):
Index('reservation_resource_ix', 'reservation_token', 'resource'),
)

def display_start(self):
return rasterize_start(self.start, self.allocation.raster)
def display_start(self, timezone=None):
start = rasterize_start(self.start, self.allocation.raster)
return calendar.to_timezone(
start, timezone or self.allocation.timezone
)

def display_end(self):
return rasterize_end(self.end, self.allocation.raster)
def display_end(self, timezone=None):
end = rasterize_end(self.end, self.allocation.raster)
return calendar.to_timezone(
end, timezone or self.allocation.timezone
)

def __eq__(self, other):
return self.start == other.start and \
Expand Down
35 changes: 30 additions & 5 deletions libres/db/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,8 @@ def reserve(
if not allocation.find_spot(start, end):
raise errors.AlreadyReservedError

if allocation.quota_left < quota:
free = self.free_allocations_count(allocation, start, end)
if free < quota:
raise errors.AlreadyReservedError

if allocation.quota_limit > 0:
Expand Down Expand Up @@ -774,6 +775,7 @@ def new_reservations_by_dates(dates):
= raster.rasterize_span(
start, end, allocation.raster
)
reservation.timezone = allocation.timezone
reservation.target = allocation.group
reservation.status = u'pending'
reservation.target_type = u'allocation'
Expand Down Expand Up @@ -925,7 +927,7 @@ def change_reservation_time_candidates(self, tokens=None):
""" Returns the reservations that fullfill the restrictions
imposed by change_reservation_time.
Pass a list of reservaiton tokens to further limit the results.
Pass a list of reservation tokens to further limit the results.
"""

Expand Down Expand Up @@ -1005,8 +1007,8 @@ def change_reservation_time(self, token, id, new_start, new_end):
quota=existing_reservation.quota
)

old_start = existing_reservation.display_start
old_end = existing_reservation.display_end
old_start = existing_reservation.display_start()
old_end = existing_reservation.display_end()

self.session.begin_nested()

Expand All @@ -1023,7 +1025,10 @@ def change_reservation_time(self, token, id, new_start, new_end):
events.on_reservation_time_changed(
self.context.name,
old_time=(old_start, old_end),
new_time=(new_start, new_end),
new_time=(
new_reservation.display_start(),
new_reservation.display_end()
),
)
except:
self.session.rollback()
Expand Down Expand Up @@ -1205,6 +1210,26 @@ def search_allocations(

return allocations

def free_allocations_count(self, master_allocation, start, end):
""" Returns the number of free allocations between master_allocation
and it's mirrors.
"""

free_allocations = 0

if master_allocation.is_available(start, end):
free_allocations += 1

if master_allocation.quota == 1:
return free_allocations

for mirror in self.allocation_mirrors_by_master(master_allocation):
if mirror.is_available(start, end):
free_allocations += 1

return free_allocations

def reservation_targets(self, start, end):
""" Returns a list of allocations that are free within start and end.
These allocations may come from the master or any of the mirrors.
Expand Down
95 changes: 93 additions & 2 deletions libres/tests/test_scheduler.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import pytest

from datetime import datetime
from libres.modules import errors, events
from datetime import datetime, timedelta
from libres.modules import calendar, errors, events
from mock import Mock
from sqlalchemy.orm.exc import MultipleResultsFound

Expand Down Expand Up @@ -226,3 +226,94 @@ def test_change_reservation_assertions(scheduler):
token, reservation.id,
datetime(2014, 3, 7, 8, 0), datetime(2014, 3, 7, 17, 1)
)


def test_change_reservation(scheduler):
reservation_changed = Mock()
events.on_reservation_time_changed.append(reservation_changed)

dates = (datetime(2014, 8, 7, 8, 0), datetime(2014, 8, 7, 10, 0))

scheduler.allocate(dates, partly_available=True)

data = {
'foo': 'bar'
}
token = scheduler.reserve(u'original@example.org', (
datetime(2014, 8, 7, 8, 0), datetime(2014, 8, 7, 9)
), data=data)

scheduler.commit()

reservation = scheduler.reservations_by_token(token).one()
original_id = reservation.id

scheduler.approve_reservations(token)
scheduler.commit()

assert scheduler.change_reservation_time_candidates().count() == 1

# make sure that no changes are made in these cases
assert not scheduler.change_reservation_time(
token, reservation.id,
datetime(2014, 8, 7, 8, 0),
datetime(2014, 8, 7, 9)
)

assert not scheduler.change_reservation_time(
token, reservation.id,
datetime(2014, 8, 7, 8, 0),
datetime(2014, 8, 7, 9) - timedelta(microseconds=1)
)

assert not reservation_changed.called

# make sure the change is propagated
scheduler.change_reservation_time(
token, reservation.id,
datetime(2014, 8, 7, 8, 0),
datetime(2014, 8, 7, 10)
)
scheduler.commit()

assert reservation_changed.called
assert reservation_changed.call_args[0][0] == scheduler.context.name
assert reservation_changed.call_args[1]['old_time'][0].hour == 8
assert reservation_changed.call_args[1]['old_time'][1].hour == 9
assert reservation_changed.call_args[1]['new_time'][0].hour == 8
assert reservation_changed.call_args[1]['new_time'][1].hour == 10

reservation = scheduler.reservations_by_token(token).one()

assert reservation.start == calendar.normalize_date(
datetime(2014, 8, 7, 8, 0), scheduler.timezone
)
assert reservation.end == calendar.normalize_date(
datetime(2014, 8, 7, 10, 0) - timedelta(microseconds=1),
scheduler.timezone
)

# the data must stay the same
assert reservation.data == data
assert reservation.email == u'original@example.org'
assert reservation.id == original_id
assert reservation.token == token

scheduler.change_reservation_time(
token, reservation.id,
datetime(2014, 8, 7, 9, 0),
datetime(2014, 8, 7, 10, 0)
)

scheduler.approve_reservations(
scheduler.reserve(u'original@example.org', (
datetime(2014, 8, 7, 8, 0), datetime(2014, 8, 7, 9)
))
)

with pytest.raises(errors.AlreadyReservedError):
scheduler.change_reservation_time(
token, reservation.id,
datetime(2014, 8, 7, 8, 0),
datetime(2014, 8, 7, 10, 0)
)

0 comments on commit e7c9e74

Please sign in to comment.