def test_simple_add(self):

        # Add one slot together with a timespan
        allocation = Allocation(raster=15, resource=uuid())
        allocation.start = datetime(2011, 1, 1, 15)
        allocation.end = datetime(2011, 1, 1, 15, 59)
        allocation.group = uuid()

        reservation = uuid()

        slot = ReservedSlot(resource=allocation.resource)
        slot.start = allocation.start
        slot.end = allocation.end
        slot.allocation = allocation
        slot.reservation = reservation
        allocation.reserved_slots.append(slot)

        # Ensure that the same slot cannot be doubly used
        anotherslot = ReservedSlot(resource=allocation.resource)
        anotherslot.start = allocation.start
        anotherslot.end = allocation.end
        anotherslot.allocation = allocation
        anotherslot.reservation = reservation

        Session.add(anotherslot)
        self.assertRaises(IntegrityError, Session.flush)
Esempio n. 2
0
    def test_simple_add(self):

        # Add one slot together with a timespan
        allocation = Allocation(raster=15, resource=uuid())
        allocation.start = datetime(2011, 1, 1, 15)
        allocation.end = datetime(2011, 1, 1, 15, 59)
        allocation.group = uuid()

        reservation = uuid()

        slot = ReservedSlot(resource=allocation.resource)
        slot.start = allocation.start
        slot.end = allocation.end
        slot.allocation = allocation
        slot.reservation = reservation
        allocation.reserved_slots.append(slot)

        # Ensure that the same slot cannot be doubly used
        anotherslot = ReservedSlot(resource=allocation.resource)
        anotherslot.start = allocation.start
        anotherslot.end = allocation.end
        anotherslot.allocation = allocation
        anotherslot.reservation = reservation

        Session.add(anotherslot)
        self.assertRaises(IntegrityError, Session.flush)
def add_something(resource=None):
    resource = resource or uuid()
    allocation = Allocation(raster=15, resource=resource, mirror_of=resource)
    allocation.start = datetime(2011, 1, 1, 15)
    allocation.end = datetime(2011, 1, 1, 15, 59)
    allocation.group = uuid()

    Session.add(allocation)
 def _create_allocation(self):
     allocation = Allocation(raster=15, resource=uuid())
     allocation.start = datetime(2011, 1, 1, 15, 00)
     allocation.end = datetime(2011, 1, 1, 16, 00)
     allocation.group = str(uuid())
     allocation.mirror_of = allocation.resource
     Session.add(allocation)
     return allocation
Esempio n. 5
0
def add_something(resource=None):
    resource = resource or uuid()
    allocation = Allocation(raster=15, resource=resource, mirror_of=resource)
    allocation.start = datetime(2011, 1, 1, 15)
    allocation.end = datetime(2011, 1, 1, 15, 59)
    allocation.group = uuid()

    Session.add(allocation)
 def _create_allocation(self):
     allocation = Allocation(raster=15, resource=uuid())
     allocation.start = datetime(2011, 1, 1, 15, 00)
     allocation.end = datetime(2011, 1, 1, 16, 00)
     allocation.group = str(uuid())
     allocation.mirror_of = allocation.resource
     Session.add(allocation)
     return allocation
    def test_simple_add(self):
        # Test a simple add
        allocation = Allocation(raster=15, resource=uuid())
        allocation.start = datetime(2011, 1, 1, 15)
        allocation.end = datetime(2011, 1, 1, 15, 59)
        allocation.group = str(uuid())
        allocation.mirror_of = allocation.resource

        Session.add(allocation)

        self.assertEqual(Session.query(Allocation).count(), 1)

        # Test failing add
        allocation = Allocation(raster=15)

        Session.add(allocation)
        self.assertRaises(IntegrityError, Session.flush)
    def test_date_functions(self):
        allocation = Allocation(raster=60, resource=uuid())
        allocation.start = datetime(2011, 1, 1, 12, 30)
        allocation.end = datetime(2011, 1, 1, 14, 00)

        self.assertEqual(allocation.start.hour, 12)
        self.assertEqual(allocation.start.minute, 0)

        self.assertEqual(allocation.end.hour, 13)
        self.assertEqual(allocation.end.minute, 59)

        start = datetime(2011, 1, 1, 11, 00)
        end = datetime(2011, 1, 1, 12, 05)

        self.assertTrue(allocation.overlaps(start, end))
        self.assertFalse(allocation.contains(start, end))

        start = datetime(2011, 1, 1, 13, 00)
        end = datetime(2011, 1, 1, 15, 00)

        self.assertTrue(allocation.overlaps(start, end))
        self.assertFalse(allocation.contains(start, end))
    def test_simple_add(self):
        # Test a simple add
        allocation = Allocation(raster=15, resource=uuid())
        allocation.start = datetime(2011, 1, 1, 15)
        allocation.end = datetime(2011, 1, 1, 15, 59)
        allocation.group = str(uuid())
        allocation.mirror_of = allocation.resource

        Session.add(allocation)

        self.assertEqual(Session.query(Allocation).count(), 1)

        # Test failing add
        allocation = Allocation(raster=15)

        Session.add(allocation)
        self.assertRaises(IntegrityError, Session.flush)
    def test_date_functions(self):
        allocation = Allocation(raster=60, resource=uuid())
        allocation.start = datetime(2011, 1, 1, 12, 30)
        allocation.end = datetime(2011, 1, 1, 14, 00)

        self.assertEqual(allocation.start.hour, 12)
        self.assertEqual(allocation.start.minute, 0)

        self.assertEqual(allocation.end.hour, 13)
        self.assertEqual(allocation.end.minute, 59)

        start = datetime(2011, 1, 1, 11, 00)
        end = datetime(2011, 1, 1, 12, 05)

        self.assertTrue(allocation.overlaps(start, end))
        self.assertFalse(allocation.contains(start, end))

        start = datetime(2011, 1, 1, 13, 00)
        end = datetime(2011, 1, 1, 15, 00)

        self.assertTrue(allocation.overlaps(start, end))
        self.assertFalse(allocation.contains(start, end))
    def test_whole_day(self):
        allocation = Allocation(raster=15, resource=uuid())

        allocation.start = datetime(2013, 1, 1, 0, 0)
        allocation.end = datetime(2013, 1, 2, 0, 0)

        self.assertTrue(allocation.whole_day)

        allocation.start = datetime(2013, 1, 1, 0, 0)
        allocation.end = datetime(2013, 1, 1, 23, 59, 59, 999999)

        self.assertTrue(allocation.whole_day)

        allocation.start = datetime(2013, 1, 1, 0, 0)
        allocation.end = datetime(2013, 1, 2, 23, 59, 59, 999999)

        self.assertTrue(allocation.whole_day)

        allocation.start = datetime(2013, 1, 1, 0, 0)
        allocation.end = datetime(2013, 1, 2, 0, 0)

        self.assertTrue(allocation.whole_day)

        allocation.start = datetime(2013, 1, 1, 15, 0)
        allocation.end = datetime(2013, 1, 1, 0, 0)

        self.assertRaises(AssertionError, lambda: allocation.whole_day)
Esempio n. 12
0
    def move_allocation(
            self, master_id, new_start=None, new_end=None,
            group=None, new_quota=None, approve_manually=None,
            reservation_quota_limit=0, whole_day=None):

        assert master_id
        assert any([new_start and new_end, group, new_quota])

        # Find allocation
        master = self.allocation_by_id(master_id)
        mirrors = self.allocation_mirrors_by_master(master)
        changing = [master] + mirrors
        ids = [c.id for c in changing]

        assert(group or master.group)

        # Simulate the new allocation
        new_start = new_start or master.start
        new_end = new_end or master.end

        if whole_day:
            new_start, new_end = utils.align_range_to_day(new_start, new_end)

        new = Allocation(start=new_start, end=new_end, raster=master.raster)

        # Ensure that the new span does not overlap an existing one
        existing_allocations = self.allocations_in_range(new.start, new.end)

        for existing in existing_allocations:
            if existing.id not in ids:
                raise OverlappingAllocationError(new.start, new.end, existing)

        for change in changing:

            if change.partly_available:
                # confirmed reservations
                for reservation in change.reserved_slots:
                    if not new.contains(reservation.start, reservation.end):
                        raise AffectedReservationError(reservation)

                # pending reservations
                if change.is_master:  # (mirrors return the same values)
                    for pending in change.pending_reservations.with_entities(
                            Reservation.start, Reservation.end):
                        if not new.contains(*pending):
                            raise AffectedPendingReservationError(pending)

            else:
                # confirmed reservations
                if change.start != new.start or change.end != new.end:
                    if len(change.reserved_slots):
                        raise AffectedReservationError(
                            change.reserved_slots[0]
                        )

                    if change.is_master and \
                            change.pending_reservations.count():
                        raise AffectedPendingReservationError(
                            change.pending_reservations[0]
                        )

        # the following attributes must be equal over all group members
        # (this still allows to use move_allocation to remove an allocation
        #  from an existing group by specifiying the new group)
        for allocation in self.allocations_by_group(group or master.group):

            if approve_manually is not None:
                allocation.approve_manually = approve_manually

            if reservation_quota_limit is not None:
                allocation.reservation_quota_limit = reservation_quota_limit

            if new_quota is not None and allocation.is_master:
                self.change_quota(allocation, new_quota)

        for change in changing:
            change.start = new.start
            change.end = new.end
            change.group = group or master.group
Esempio n. 13
0
    def allocate(self, dates, raster=15, quota=None, partly_available=False,
                 grouped=False, approve_manually=True,
                 reservation_quota_limit=0, whole_day=False
                 ):
        """Allocates a spot in the calendar.

        An allocation defines a timerange which can be reserved. No
        reservations can exist outside of existing allocations. In fact any
        reserved slot will link to an allocation.

        An allocation may be available as a whole (to reserve all or nothing).
        It may also be partly available which means reservations can be made
        for parts of the allocation.

        If an allocation is partly available a raster defines the granularity
        with which a reservation can be made (e.g. a raster of 15min will
        ensure that reservations are at least 15 minutes long and start either
        at :00, :15, :30 or :45)

        The reason for the raster is mainly to ensure that different
        reservations trying to reserve overlapping times need the same keys in
        the reserved_slots table, ensuring integrity at the database level.

        Allocations may have a quota, which determines how many times an
        allocation may be reserved. Quotas are enabled using a master-mirrors
        relationship.

        The master is the first allocation to be created. The mirrors copies of
        that allocation. See Scheduler.__doc__

        """
        dates = utils.pairs(dates)

        group = new_uuid()
        quota = quota or 1

        # if the allocation is not partly available the raster is set to lowest
        # possible raster value
        raster = partly_available and raster or MIN_RASTER_VALUE

        # the whole day option results in the dates being aligned to
        # the beginning of the day / end of it -> not timezone aware!
        if whole_day:
            for ix, (start, end) in enumerate(dates):
                dates[ix] = utils.align_range_to_day(start, end)

        # Ensure that the list of dates contains no overlaps inside
        for start, end in dates:
            if utils.count_overlaps(dates, start, end) > 1:
                raise InvalidAllocationError

        # Make sure that this span does not overlap another master
        for start, end in dates:
            start, end = rasterize_span(start, end, raster)

            existing = self.allocations_in_range(start, end).first()
            if existing:
                raise OverlappingAllocationError(start, end, existing)

        # Write the master allocations
        allocations = []
        for start, end in dates:
            allocation = Allocation(raster=raster)
            allocation.start = start
            allocation.end = end
            allocation.resource = self.uuid
            allocation.quota = quota
            allocation.mirror_of = self.uuid
            allocation.partly_available = partly_available
            allocation.approve_manually = approve_manually
            allocation.reservation_quota_limit = reservation_quota_limit

            if grouped:
                allocation.group = group
            else:
                allocation.group = new_uuid()

            allocations.append(allocation)

        Session.add_all(allocations)

        return allocations
    def test_whole_day(self):
        allocation = Allocation(raster=15, resource=uuid())

        allocation.start = datetime(2013, 1, 1, 0, 0)
        allocation.end = datetime(2013, 1, 2, 0, 0)

        self.assertTrue(allocation.whole_day)

        allocation.start = datetime(2013, 1, 1, 0, 0)
        allocation.end = datetime(2013, 1, 1, 23, 59, 59, 999999)

        self.assertTrue(allocation.whole_day)

        allocation.start = datetime(2013, 1, 1, 0, 0)
        allocation.end = datetime(2013, 1, 2, 23, 59, 59, 999999)

        self.assertTrue(allocation.whole_day)

        allocation.start = datetime(2013, 1, 1, 0, 0)
        allocation.end = datetime(2013, 1, 2, 0, 0)

        self.assertTrue(allocation.whole_day)

        allocation.start = datetime(2013, 1, 1, 15, 0)
        allocation.end = datetime(2013, 1, 1, 0, 0)

        self.assertRaises(AssertionError, lambda: allocation.whole_day)