示例#1
0
    def test_orders_dropped_off_event(self):
        """Test to verify the mechanics of orders being dropped off"""

        # Constants
        initial_time = hour_to_sec(14)
        on_time = time(14, 0, 0)
        off_time = time(16, 0, 0)

        # Services
        env = Environment(initial_time=initial_time)
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())

        # Creates an order and sends the picked up event
        order = Order(order_id=45, user=User(env=env))
        dispatcher.assigned_orders[order.order_id] = order
        courier = Courier(on_time=on_time, off_time=off_time)
        dispatcher.orders_dropped_off_event(orders={order.order_id: order}, courier=courier)
        env.run(until=initial_time + hour_to_sec(1))

        # Verify order properties are modified and it is allocated correctly
        self.assertEqual(order.state, 'dropped_off')
        self.assertEqual(order.drop_off_time, sec_to_time(initial_time))
        self.assertIn(order.order_id, dispatcher.fulfilled_orders.keys())
        self.assertEqual(dispatcher.assigned_orders, {})
        self.assertIn(order.order_id, courier.fulfilled_orders)
示例#2
0
    def test_courier_available_event(self):
        """Test to verify the mechanics of how the dispatcher sets a courier to available"""

        # Constants
        initial_time = hour_to_sec(14)
        on_time = time(14, 0, 0)
        off_time = time(15, 0, 0)
        service_time = min_to_sec(6)

        # Services
        env = Environment(initial_time=initial_time)
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())

        # Creates a courier and sets it to the picking state
        courier = Courier(dispatcher=dispatcher, env=env, courier_id=32, on_time=on_time, off_time=off_time)
        dispatcher.idle_couriers = {courier.courier_id: courier}
        env.process(courier._picking_up_state(
            orders={
                21: Order(drop_off_service_time=service_time, ready_time=time(14, 20, 0))
            }
        ))
        env.run(until=initial_time + min_to_sec(10))

        # Verify courier properties are modified and it is allocated correctly
        self.assertEqual(courier.condition, 'picking_up')
        self.assertIn(courier.courier_id, dispatcher.picking_up_couriers.keys())
        self.assertEqual(dispatcher.idle_couriers, {})
示例#3
0
    def test_prepositioning_notification_rejected_event(self):
        """Test to verify the mechanics of a prepositioning notification being rejected by a courier"""

        # Constants
        initial_time = hour_to_sec(14)
        on_time = time(14, 0, 0)
        off_time = time(15, 0, 0)

        # Services
        env = Environment(initial_time=initial_time)
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())

        # Creates a prepositioning notification, a courier and sends the rejected event
        instruction = Route(
            stops=[
                Stop(position=0, type=StopType.PREPOSITION),
                Stop(position=1, type=StopType.PREPOSITION)
            ]
        )
        courier = Courier(dispatcher=dispatcher, env=env, courier_id=981, on_time=on_time, off_time=off_time)
        notification = Notification(courier=courier, instruction=instruction, type=NotificationType.PREPOSITIONING)
        dispatcher.notification_rejected_event(notification=notification, courier=courier)
        env.run(until=initial_time + min_to_sec(30))

        # Verify order and courier properties are modified and it is allocated correctly
        self.assertIsNone(courier.active_route)
示例#4
0
    def test_pick_up_waiting_time(self, osrm):
        """Test to verify the mechanics of the waiting time are correctly designed"""

        # Constants
        random.seed(290)
        on_time = time(6, 0, 0)
        off_time = time(8, 0, 0)

        # Services
        env = Environment(initial_time=hour_to_sec(6))
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())

        # Creates a courier and sets it to pick up stuff
        courier = Courier(
            acceptance_policy=self.acceptance_policy,
            dispatcher=dispatcher,
            env=env,
            movement_evaluation_policy=self.movement_evaluation_policy,
            movement_policy=self.movement_policy,
            courier_id=self.courier_id,
            vehicle=self.vehicle,
            location=self.start_location,
            acceptance_rate=0.01,
            on_time=on_time,
            off_time=off_time)
        order = Order(ready_time=time(6, 15, 0), order_id=23)
        stop = Stop(orders={order.order_id: order}, type=StopType.PICK_UP)
        env.process(courier._execute_stop(stop))
        dispatcher.state.interrupt()

        # Run until there are no more events and assert the courier experienced waiting time.
        env.run(until=hour_to_sec(7))
        self.assertTrue(order.pick_up_time >= time(
            6, int(order.ready_time.minute + order.pick_up_service_time / 60)))

        # For another test, if the order's ready time has expired, the courier doesn't experience waiting time
        env = Environment(initial_time=hour_to_sec(6))
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())
        courier = Courier(
            acceptance_policy=self.acceptance_policy,
            dispatcher=dispatcher,
            env=env,
            movement_evaluation_policy=self.movement_evaluation_policy,
            movement_policy=self.movement_policy,
            courier_id=self.courier_id,
            vehicle=self.vehicle,
            location=self.start_location,
            acceptance_rate=0.01,
            on_time=on_time,
            off_time=off_time)
        order = Order(ready_time=time(4, 0, 0), order_id=23)
        stop = Stop(orders={order.order_id: order}, type=StopType.PICK_UP)
        env.process(courier._execute_stop(stop))
        dispatcher.state.interrupt()
        env.run(until=hour_to_sec(7))
        self.assertTrue(
            time(order.pick_up_time.hour, order.pick_up_time.minute) <= time(
                6, int(order.pick_up_service_time / 60)))
示例#5
0
    def __post_init__(self):
        """
        The world is instantiated along with the single dispatcher and the DDBB connection.
        The World begins simulating immediately after it is created.
        """

        logging.info(
            f'Instance {self.instance} | Simulation started at sim time = {sec_to_time(self.env.now)}.'
        )

        self.connection = create_engine(get_db_url(),
                                        pool_size=20,
                                        max_overflow=0,
                                        pool_pre_ping=True)
        self.dispatcher = Dispatcher(
            env=self.env,
            cancellation_policy=DISPATCHER_CANCELLATION_POLICIES_MAP[
                settings.DISPATCHER_CANCELLATION_POLICY],
            buffering_policy=DISPATCHER_BUFFERING_POLICIES_MAP[
                settings.DISPATCHER_BUFFERING_POLICY],
            matching_policy=DISPATCHER_MATCHING_POLICIES_MAP[
                settings.DISPATCHER_MATCHING_POLICY],
            prepositioning_policy=DISPATCHER_PREPOSITIONING_POLICIES_MAP[
                settings.DISPATCHER_PREPOSITIONING_POLICY],
            prepositioning_evaluation_policy=
            DISPATCHER_PREPOSITIONING_EVALUATION_POLICIES_MAP[
                settings.DISPATCHER_PREPOSITIONING_EVALUATION_POLICY])
        self.process = self.env.process(self._simulate())
示例#6
0
    def test_movement_state(self, osrm):
        """Test to evaluate how a courier moves with dummy movement"""

        # Constants
        random.seed(365)
        on_time = time(0, 0, 0)
        off_time = time(5, 0, 0)

        env = Environment()
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())

        # Creates a courier and runs a simulation
        courier = Courier(
            acceptance_policy=self.acceptance_policy,
            dispatcher=dispatcher,
            env=env,
            movement_evaluation_policy=self.movement_evaluation_policy,
            movement_policy=self.movement_policy,
            courier_id=self.courier_id,
            vehicle=self.vehicle,
            location=self.start_location,
            on_time=on_time,
            off_time=off_time)
        env.run(until=hour_to_sec(4) + min_to_sec(5))

        # Asserts that the courier moved and is is in a different location
        self.assertEqual(courier.condition, 'moving')
        self.assertNotEqual(courier.location, self.start_location)
        self.assertIn(courier.courier_id, dispatcher.moving_couriers.keys())
示例#7
0
    def test_always_idle(self, osrm):
        """Test to evaluate a courier never moving"""

        # Constants
        random.seed(187)
        on_time = time(0, 0, 0)
        off_time = time(5, 0, 0)

        # Services
        env = Environment()
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())

        # Creates a courier and runs a simulation
        courier = Courier(
            acceptance_policy=self.acceptance_policy,
            dispatcher=dispatcher,
            env=env,
            movement_evaluation_policy=self.movement_evaluation_policy,
            movement_policy=self.movement_policy,
            courier_id=self.courier_id,
            vehicle=self.vehicle,
            location=self.start_location,
            on_time=on_time,
            off_time=off_time)
        env.run(until=hour_to_sec(4))

        # Asserts that the courier is idle and never moved
        self.assertEqual(courier.condition, 'idle')
        self.assertEqual(courier.location, self.start_location)
        self.assertIn(courier.courier_id, dispatcher.idle_couriers.keys())
示例#8
0
    def test_submit_courier_assigned(self):
        """Test to verify how a user submits and order and doesn't cancel since a courier is assigned"""

        # Constants
        random.seed(666)

        # Services
        env = Environment(initial_time=hour_to_sec(12))
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())

        # Create a user, have it submit an order immediately and after some minutes, assign a courier
        user = User(cancellation_policy=self.cancellation_policy,
                    dispatcher=dispatcher,
                    env=env)
        user.submit_order_event(
            order_id=self.order_id,
            pick_up_at=self.pick_up_at,
            drop_off_at=self.drop_off_at,
            placement_time=self.placement_time,
            expected_drop_off_time=self.expected_drop_off_time,
            preparation_time=self.preparation_time,
            ready_time=self.ready_time)
        env.process(TestsDispatcher.assign_courier(user, env, dispatcher))
        env.run(until=hour_to_sec(13))

        # Verify order is created but not canceled because a courier was assigned
        self.assertTrue(user.order)
        self.assertIsNotNone(user.order.courier_id)
        self.assertIsNone(user.order.cancellation_time)
        self.assertEqual(dispatcher.assigned_orders,
                         {self.order_id: user.order})
        self.assertEqual(dispatcher.unassigned_orders, {})
        self.assertEqual(user.condition, 'waiting')
示例#9
0
    def test_submit_wait_for_order(self, *args):
        """Test to verify how a user submits an order but doesn't cancel even without courier, deciding to wait"""

        # Constants
        random.seed(157)

        # Services
        env = Environment(initial_time=hour_to_sec(12))
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())

        # Create a user and have it submit an order immediately
        user = User(cancellation_policy=self.cancellation_policy,
                    dispatcher=dispatcher,
                    env=env)
        user.submit_order_event(
            order_id=self.order_id,
            pick_up_at=self.pick_up_at,
            drop_off_at=self.drop_off_at,
            placement_time=self.placement_time,
            expected_drop_off_time=self.expected_drop_off_time,
            preparation_time=self.preparation_time,
            ready_time=self.ready_time)
        env.run(until=hour_to_sec(13))

        # Verify order is created but not canceled, disregarding the lack of a courier
        self.assertTrue(user.order)
        self.assertIsNone(user.order.courier_id)
        self.assertIsNone(user.order.cancellation_time)
        self.assertEqual(dispatcher.unassigned_orders,
                         {self.order_id: user.order})
        self.assertEqual(user.condition, 'waiting')
示例#10
0
    def test_orders_picked_up_event(self):
        """Test to verify the mechanics of orders being picked up"""

        # Constants
        initial_time = hour_to_sec(14)

        # Services
        env = Environment(initial_time=initial_time)
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())

        # Creates an order and sends the picked up event
        order = Order(order_id=45)
        dispatcher.orders_picked_up_event(orders={order.order_id: order})
        env.run(until=initial_time + hour_to_sec(1))

        # Verify order properties are modified
        self.assertEqual(order.state, 'picked_up')
        self.assertEqual(order.pick_up_time, sec_to_time(initial_time))
示例#11
0
    def test_courier_busy_event(self, *args):
        """Test to verify the mechanics of how the dispatcher sets a courier to busy"""

        # Constants
        initial_time = hour_to_sec(14)
        courier_id = 14
        time_delta = min_to_sec(10)
        on_time = time(14, 0, 0)
        off_time = time(15, 0, 0)
        service_time = min_to_sec(7)

        # Verifies 2 test cases for how the courier transitions to being busy
        # For each test case, assert the courier starts in a set and ends up in the busy set

        # Test 1: courier starts dropping off state
        env = Environment(initial_time=initial_time)
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())
        courier = Courier(dispatcher=dispatcher, env=env, courier_id=courier_id, on_time=on_time, off_time=off_time)
        env.process(courier._dropping_off_state(
            orders={
                21: Order(drop_off_service_time=service_time, ready_time=time(12, 20, 0))
            }
        ))
        env.run(until=initial_time + time_delta)
        self.assertEqual(courier.condition, 'dropping_off')
        self.assertEqual(dispatcher.dropping_off_couriers, {courier.courier_id: courier})
        self.assertEqual(dispatcher.idle_couriers, {})

        # Test 2: courier start moving state
        env = Environment(initial_time=initial_time)
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())
        courier = Courier(
            dispatcher=dispatcher,
            env=env,
            courier_id=courier_id,
            location=Location(lat=4.690296, lng=-74.043929),
            on_time=on_time,
            off_time=off_time
        )
        env.process(courier._moving_state(destination=Location(lat=4.689697, lng=-74.055495)))
        env.run(until=initial_time + time_delta)
        self.assertEqual(courier.condition, 'moving')
        self.assertEqual(dispatcher.moving_couriers, {courier.courier_id: courier})
        self.assertEqual(dispatcher.idle_couriers, {})
示例#12
0
    def test_log_off(self):
        """Test to evaluate the scheduling of the courier logging off works correctly"""

        # Constants
        random.seed(888)
        on_time = time(8, 0, 0)
        off_time = time(14, 0, 0)
        initial_time = hour_to_sec(8)

        # Verifies for two test cases the scheduling of the courier logging off works correctly.
        # In one case, the courier log off event doesn't yet happen. In the other test, it does

        # Test 1: the courier achieves the log off after a given time
        env = Environment(initial_time=initial_time)
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())
        courier = Courier(env=env,
                          dispatcher=dispatcher,
                          courier_id=84,
                          on_time=on_time,
                          off_time=off_time)
        env.run(until=initial_time + hour_to_sec(10))
        self.assertEqual(dispatcher.logged_off_couriers,
                         {courier.courier_id: courier})
        self.assertEqual(dispatcher.idle_couriers, {})
        self.assertEqual(courier.condition, 'logged_off')

        # Test 2: the courier doesn't achieve the log off because the simulation ends before
        env = Environment(initial_time=initial_time)
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())
        courier = Courier(env=env,
                          dispatcher=dispatcher,
                          courier_id=84,
                          on_time=on_time,
                          off_time=off_time)
        env.run(until=initial_time + hour_to_sec(2))
        self.assertEqual(dispatcher.idle_couriers,
                         {courier.courier_id: courier})
        self.assertEqual(dispatcher.logged_off_couriers, {})
        self.assertEqual(courier.condition, 'idle')
示例#13
0
    def test_order_submitted_event(self):
        """Test to verify the mechanics of the order submitted event"""

        # Constants
        initial_time = hour_to_sec(15)
        placement_time = time(15, 0, 0)
        preparation_time = time(15, 1, 0)
        ready_time = time(15, 15, 0)

        # Services
        env = Environment(initial_time=initial_time)
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())

        # Creates an order and submits it to the dispatcher
        order = Order(order_id=32, placement_time=placement_time)
        dispatcher.order_submitted_event(order, preparation_time, ready_time)
        env.run(until=initial_time + 121)

        # Verify order properties are set and it is correctly allocated
        self.assertEqual(order.preparation_time, preparation_time)
        self.assertEqual(order.ready_time, ready_time)
        self.assertIn(order.order_id, dispatcher.unassigned_orders.keys())
示例#14
0
    def test_notification_accepted_event(self):
        """Test to verify the mechanics of a notification being accepted by a courier"""

        # Constants
        initial_time = hour_to_sec(14)
        on_time = time(14, 0, 0)
        off_time = time(15, 0, 0)

        # Services
        env = Environment(initial_time=initial_time)
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())

        # Creates an instruction with an order, a courier and sends the accepted event
        order = Order(order_id=45)
        instruction = Route(
            stops=[
                Stop(orders={order.order_id: order}, position=0),
                Stop(orders={order.order_id: order}, position=1)
            ],
            orders={order.order_id: order}
        )
        dispatcher.unassigned_orders[order.order_id] = order
        courier = Courier(dispatcher=dispatcher, env=env, courier_id=89, on_time=on_time, off_time=off_time)
        courier.condition = 'idle'
        notification = Notification(
            courier=courier,
            instruction=instruction
        )
        dispatcher.notification_accepted_event(notification=notification, courier=courier)
        env.run(until=initial_time + min_to_sec(10))

        # Verify order and courier properties are modified and it is allocated correctly
        self.assertEqual(order.state, 'in_progress')
        self.assertEqual(order.acceptance_time, sec_to_time(initial_time))
        self.assertEqual(order.courier_id, courier.courier_id)
        self.assertIn(order.order_id, dispatcher.assigned_orders.keys())
        self.assertIsNotNone(courier.active_route)
        self.assertEqual(courier.active_route, instruction)
        self.assertEqual(dispatcher.unassigned_orders, {})
示例#15
0
    def test_notify_prepositioning_event_accept_idle(self, osrm):
        """Test to evaluate how a courier handles a prepositioning notification while being idle and accepts it"""

        # Constants
        random.seed(348)
        initial_time = hour_to_sec(17)
        time_delta = min_to_sec(10)
        on_time = time(17, 0, 0)
        off_time = time(17, 30, 0)

        # Services
        env = Environment(initial_time=initial_time)
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())

        # Creates a courier with high acceptance rate and immediately send a prepositioning notification
        courier = Courier(
            acceptance_policy=self.acceptance_policy,
            dispatcher=dispatcher,
            env=env,
            movement_evaluation_policy=self.movement_evaluation_policy,
            movement_policy=self.movement_policy,
            courier_id=self.courier_id,
            vehicle=self.vehicle,
            location=self.start_location,
            acceptance_rate=0.99,
            on_time=on_time,
            off_time=off_time)

        instruction = Route(orders=None,
                            stops=[
                                Stop(location=self.pick_up_at,
                                     position=0,
                                     orders=None,
                                     type=StopType.PREPOSITION,
                                     visited=False)
                            ])
        notification = Notification(courier=courier,
                                    instruction=instruction,
                                    type=NotificationType.PREPOSITIONING)
        env.process(courier.notification_event(notification))
        env.run(until=initial_time + time_delta)

        # Asserts that the courier fulfilled the route and is at a different start location
        self.assertIsNone(courier.active_route)
        self.assertIsNone(courier.active_stop)
        self.assertEqual(dispatcher.fulfilled_orders, {})
        self.assertNotEqual(courier.location, self.start_location)
        self.assertEqual(courier.condition, 'idle')
        self.assertIn(courier.courier_id, dispatcher.idle_couriers.keys())
示例#16
0
    def test_cancel_order_event(self):
        """Test to verify how the dispatcher cancels an order after certain time"""

        random.seed(741)

        # Services
        env = Environment(initial_time=hour_to_sec(12))
        dispatcher = Dispatcher(
            env=env,
            cancellation_policy=self.dispatcher_cancellation_policy,
            matching_policy=DummyMatchingPolicy()
        )

        # Create a user and have it submit an order immediately, avoiding user cancellation
        user = User(cancellation_policy=self.cancellation_policy, dispatcher=dispatcher, env=env)
        user.submit_order_event(
            order_id=self.order_id,
            pick_up_at=self.pick_up_at,
            drop_off_at=self.drop_off_at,
            placement_time=self.placement_time,
            expected_drop_off_time=self.expected_drop_off_time,
            preparation_time=self.preparation_time,
            ready_time=self.ready_time
        )
        env.run(until=hour_to_sec(14))

        # Verify order is canceled by the dispatcher
        self.assertTrue(user.order)
        self.assertIsNone(user.order.courier_id)
        self.assertIsNotNone(user.order.cancellation_time)
        self.assertEqual(dispatcher.unassigned_orders, {})
        self.assertIn(self.order_id, dispatcher.canceled_orders.keys())
        self.assertEqual(
            user.order.cancellation_time,
            (
                    datetime.combine(date.today(), self.preparation_time) +
                    timedelta(seconds=settings.DISPATCHER_WAIT_TO_CANCEL)
            ).time()
        )
        self.assertEqual(user.condition, 'canceled')
示例#17
0
    def test_order_not_canceled(self):
        """
        Test to verify that the dispatcher doesn't cancel an order if it has a courier assigned.
        The user doesn't see a courier but decides not to cancel.
        """

        random.seed(192)

        # Services
        env = Environment(initial_time=hour_to_sec(12))
        dispatcher = Dispatcher(
            env=env,
            cancellation_policy=self.dispatcher_cancellation_policy,
            matching_policy=DummyMatchingPolicy()
        )

        # Create a user, have it submit an order immediately and after some minutes, assign a courier.
        # Courier is assigned after user cancellation time has expired
        user = User(cancellation_policy=self.cancellation_policy, dispatcher=dispatcher, env=env)
        user.submit_order_event(
            order_id=self.order_id,
            pick_up_at=self.pick_up_at,
            drop_off_at=self.drop_off_at,
            placement_time=self.placement_time,
            expected_drop_off_time=self.expected_drop_off_time,
            preparation_time=self.preparation_time,
            ready_time=self.ready_time
        )
        env.process(self.assign_courier(user, env, dispatcher))
        env.run(until=hour_to_sec(13))

        # Verify order is created but not canceled because a courier was assigned
        self.assertTrue(user.order)
        self.assertIsNotNone(user.order.courier_id)
        self.assertIsNone(user.order.cancellation_time)
        self.assertEqual(dispatcher.assigned_orders, {self.order_id: user.order})
        self.assertEqual(dispatcher.unassigned_orders, {})
        self.assertEqual(user.condition, 'waiting')
示例#18
0
    def test_submit_cancel_order(self):
        """Test to verify how a user submits and decides to cancel an order"""

        # Constants
        random.seed(666)
        initial_time = hour_to_sec(12)
        time_delta = min_to_sec(10)

        # Services
        env = Environment(initial_time=initial_time)
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())

        # Create a user and have it submit an order immediately
        user = User(cancellation_policy=self.cancellation_policy,
                    dispatcher=dispatcher,
                    env=env)
        user.submit_order_event(
            order_id=self.order_id,
            pick_up_at=self.pick_up_at,
            drop_off_at=self.drop_off_at,
            placement_time=self.placement_time,
            expected_drop_off_time=self.expected_drop_off_time,
            preparation_time=self.preparation_time,
            ready_time=self.ready_time)
        env.run(until=initial_time + time_delta)

        # Verify order is created and canceled due to a courier not being assigned
        self.assertTrue(user.order)
        self.assertIsNone(user.order.courier_id)
        self.assertIsNotNone(user.order.cancellation_time)
        self.assertEqual(dispatcher.unassigned_orders, {})
        self.assertIn(self.order_id, dispatcher.canceled_orders.keys())
        self.assertEqual(
            user.order.cancellation_time,
            (datetime.combine(date.today(), self.placement_time) +
             timedelta(seconds=settings.USER_WAIT_TO_CANCEL)).time())
        self.assertEqual(user.condition, 'canceled')
示例#19
0
    def test_notify_event_reject_idle(self, osrm):
        """Test to evaluate how a courier handles a notification while being idle and rejects it"""

        # Constants
        random.seed(122)
        on_time = time(12, 0, 0)
        off_time = time(15, 0, 0)

        # Services
        env = Environment(initial_time=hour_to_sec(12))
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())

        # Creates a courier with low acceptance rate and immediately send a new instruction, composed of a single order
        courier = Courier(
            acceptance_policy=self.acceptance_policy,
            dispatcher=dispatcher,
            env=env,
            movement_evaluation_policy=self.movement_evaluation_policy,
            movement_policy=self.movement_policy,
            courier_id=self.courier_id,
            vehicle=self.vehicle,
            location=self.start_location,
            acceptance_rate=0.01,
            on_time=on_time,
            off_time=off_time)

        order = Order(order_id=self.order_id,
                      drop_off_at=self.drop_off_at,
                      pick_up_at=self.pick_up_at,
                      placement_time=self.placement_time,
                      expected_drop_off_time=self.expected_drop_off_time,
                      preparation_time=self.preparation_time,
                      ready_time=self.ready_time)
        dispatcher.unassigned_orders[order.order_id] = order
        instruction = Route(orders={self.order_id: order},
                            stops=[
                                Stop(location=self.pick_up_at,
                                     position=0,
                                     orders={self.order_id: order},
                                     type=StopType.PICK_UP,
                                     visited=False),
                                Stop(location=self.drop_off_at,
                                     position=1,
                                     orders={self.order_id: order},
                                     type=StopType.DROP_OFF,
                                     visited=False)
                            ])
        notification = Notification(courier=courier, instruction=instruction)
        env.process(courier.notification_event(notification))
        env.run(until=hour_to_sec(14))

        # Asserts that the courier didn't fulfill the route
        self.assertIsNone(order.pick_up_time)
        self.assertIsNone(order.drop_off_time)
        self.assertIsNone(order.courier_id)
        self.assertIsNone(courier.active_route)
        self.assertIsNone(courier.active_stop)
        self.assertIn(courier.courier_id, order.rejected_by)
        self.assertIn(order.order_id, courier.rejected_orders)
        self.assertEqual(dispatcher.unassigned_orders, {order.order_id: order})
        self.assertEqual(order.state, 'unassigned')
        self.assertEqual(courier.location, self.start_location)
        self.assertEqual(courier.condition, 'idle')
        self.assertIn(courier.courier_id, dispatcher.idle_couriers.keys())
示例#20
0
    def test_courier_log_off(self):
        """Test to verify how the dispatcher handles a courier logging off"""

        # Constants
        random.seed(12)
        initial_time = hour_to_sec(12)
        time_delta = hour_to_sec(2)
        service_time = min_to_sec(4)

        # Tests 3 cases: when the courier is idle, busy or available.
        # For each test, assert that the courier ends up being logged off

        # Test 1: the courier is idle
        env = Environment(initial_time=initial_time)
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())
        courier = Courier(
            env=env,
            dispatcher=dispatcher,
            courier_id=69,
            on_time=time(12, 0, 0),
            off_time=time(13, 0, 0)
        )
        env.run(until=initial_time + time_delta)
        self.assertEqual(dispatcher.idle_couriers, {})
        self.assertEqual(dispatcher.moving_couriers, {})
        self.assertEqual(dispatcher.dropping_off_couriers, {})
        self.assertEqual(dispatcher.picking_up_couriers, {})
        self.assertEqual(dispatcher.logged_off_couriers, {courier.courier_id: courier})

        # Test 2: the courier is busy
        env = Environment(initial_time=initial_time)
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())
        courier = Courier(
            env=env,
            dispatcher=dispatcher,
            courier_id=69,
            on_time=time(12, 0, 0),
            off_time=time(13, 0, 0)
        )
        courier.state.interrupt()
        env.process(courier._dropping_off_state(
            orders={21: Order(drop_off_service_time=service_time)}
        ))
        env.run(until=initial_time + time_delta)
        self.assertEqual(dispatcher.idle_couriers, {})
        self.assertEqual(dispatcher.moving_couriers, {})
        self.assertEqual(dispatcher.dropping_off_couriers, {})
        self.assertEqual(dispatcher.picking_up_couriers, {})
        self.assertEqual(dispatcher.logged_off_couriers, {courier.courier_id: courier})

        # Test 3: the courier is available
        env = Environment(initial_time=initial_time)
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())
        courier = Courier(
            env=env,
            dispatcher=dispatcher,
            courier_id=69,
            on_time=time(12, 0, 0),
            off_time=time(13, 0, 0)
        )
        courier.state.interrupt()
        env.process(courier._picking_up_state(
            orders={
                21: Order(drop_off_service_time=service_time, ready_time=time(12, 20, 0))
            }
        ))
        env.run(until=initial_time + time_delta)
        self.assertEqual(dispatcher.idle_couriers, {})
        self.assertEqual(dispatcher.moving_couriers, {})
        self.assertEqual(dispatcher.dropping_off_couriers, {})
        self.assertEqual(dispatcher.picking_up_couriers, {})
        self.assertEqual(dispatcher.logged_off_couriers, {courier.courier_id: courier})
示例#21
0
    def test_buffer_event(self):
        """Test to verify how the mechanics of the dispatcher buffering orders work"""

        # Constants
        initial_time = hour_to_sec(16)
        placement_time = time(16, 0, 0)
        time_delta = min_to_sec(10)

        # Verifies two test cases for how the dispatcher buffers orders
        # For each test, assert the correct number of orders are buffered

        # Test 1: schedules the submission of three orders and assert that only two are buffered
        env = Environment(initial_time=initial_time)
        dispatcher = Dispatcher(
            env=env,
            buffering_policy=RollingBufferingPolicy(),
            matching_policy=DummyMatchingPolicy()
        )
        order_1 = Order(order_id=1, placement_time=placement_time)
        order_2 = Order(order_id=2, placement_time=placement_time)
        order_3 = Order(order_id=3, placement_time=placement_time)
        dispatcher.order_submitted_event(order_1, preparation_time=time(16, 0, 27), ready_time=time(16, 10, 0))
        dispatcher.order_submitted_event(order_2, preparation_time=time(16, 0, 43), ready_time=time(16, 10, 0))
        dispatcher.order_submitted_event(order_3, preparation_time=time(18, 0, 0), ready_time=time(18, 10, 0))

        env.run(until=initial_time + time_delta)
        self.assertEqual(len(dispatcher.unassigned_orders), 2)

        # Test 2: schedules the submission of three orders and assert that all three orders are buffered
        env = Environment(initial_time=initial_time)
        dispatcher = Dispatcher(
            env=env,
            buffering_policy=RollingBufferingPolicy(),
            matching_policy=DummyMatchingPolicy()
        )
        order_1 = Order(order_id=1, placement_time=placement_time)
        order_2 = Order(order_id=2, placement_time=placement_time)
        order_3 = Order(order_id=3, placement_time=placement_time)
        dispatcher.order_submitted_event(order_1, preparation_time=time(16, 0, 27), ready_time=time(16, 10, 0))
        dispatcher.order_submitted_event(order_2, preparation_time=time(16, 0, 43), ready_time=time(16, 10, 0))
        dispatcher.order_submitted_event(order_3, preparation_time=time(16, 4, 1), ready_time=time(16, 14, 0))
        env.run(until=initial_time + time_delta)
        self.assertEqual(len(dispatcher.unassigned_orders), 3)
示例#22
0
    def test_notify_event_reject_picking_up(self, osrm):
        """Test to evaluate how a courier handles a notification while picking up and rejects it"""

        # Constants
        random.seed(4747474)
        on_time = time(12, 0, 0)
        off_time = time(15, 0, 0)

        # Services
        env = Environment(initial_time=hour_to_sec(12) + min_to_sec(12))
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())

        # Creates a courier with low acceptance rate, an active route and in state of picking up.
        # Sends a new instruction, composed of a single new order
        active_order = Order(
            order_id=self.order_id,
            drop_off_at=self.drop_off_at,
            pick_up_at=self.pick_up_at,
            placement_time=self.placement_time,
            expected_drop_off_time=self.expected_drop_off_time,
            preparation_time=self.preparation_time,
            ready_time=self.ready_time,
            courier_id=self.courier_id,
            user=User(env=env))
        dispatcher.assigned_orders[active_order.order_id] = active_order
        new_order = Order(order_id=17,
                          drop_off_at=Location(lat=4.694627, lng=-74.038886),
                          pick_up_at=self.pick_up_at,
                          placement_time=self.placement_time,
                          expected_drop_off_time=self.expected_drop_off_time,
                          preparation_time=self.preparation_time,
                          ready_time=self.ready_time,
                          user=User(env=env))
        dispatcher.unassigned_orders[new_order.order_id] = new_order
        courier = Courier(
            acceptance_policy=self.acceptance_policy,
            dispatcher=dispatcher,
            env=env,
            movement_evaluation_policy=self.movement_evaluation_policy,
            movement_policy=self.movement_policy,
            courier_id=self.courier_id,
            vehicle=self.vehicle,
            location=active_order.pick_up_at,
            acceptance_rate=0.01,
            active_route=Route(orders={self.order_id: active_order},
                               stops=[
                                   Stop(location=self.pick_up_at,
                                        position=0,
                                        orders={self.order_id: active_order},
                                        type=StopType.PICK_UP,
                                        visited=False),
                                   Stop(location=self.drop_off_at,
                                        position=1,
                                        orders={self.order_id: active_order},
                                        type=StopType.DROP_OFF,
                                        visited=False)
                               ]),
            on_time=on_time,
            off_time=off_time)

        instruction = Stop(location=new_order.drop_off_at,
                           position=1,
                           orders={new_order.order_id: new_order},
                           type=StopType.DROP_OFF,
                           visited=False)
        notification = Notification(courier=courier, instruction=instruction)
        courier.state.interrupt()
        courier.active_stop = courier.active_route.stops[0]
        courier.state = env.process(
            courier._picking_up_state(
                orders={active_order.order_id: active_order}))
        env.process(courier.notification_event(notification))
        env.run(until=hour_to_sec(14))

        # Asserts:
        # - the courier didn't fulfill the new order,
        # - fulfilled the active order and
        # - is at a different start location.
        self.assertIsNone(new_order.pick_up_time)
        self.assertIsNone(new_order.drop_off_time)
        self.assertIsNone(new_order.courier_id)
        self.assertIn(courier.courier_id, new_order.rejected_by)
        self.assertIn(new_order.order_id, courier.rejected_orders)
        self.assertEqual(new_order.state, 'unassigned')

        self.assertIsNotNone(active_order.pick_up_time)
        self.assertIsNotNone(active_order.drop_off_time)
        self.assertEqual(active_order.courier_id, courier.courier_id)
        self.assertTrue(active_order.pick_up_time < active_order.drop_off_time)
        self.assertEqual(active_order.state, 'dropped_off')

        self.assertIsNone(courier.active_route)
        self.assertIsNone(courier.active_stop)
        self.assertNotEqual(courier.location, self.start_location)
        self.assertEqual(dispatcher.fulfilled_orders,
                         {active_order.order_id: active_order})
        self.assertEqual(dispatcher.unassigned_orders,
                         {new_order.order_id: new_order})
        self.assertEqual(courier.condition, 'idle')
        self.assertIn(courier.courier_id, dispatcher.idle_couriers.keys())
示例#23
0
    def test_courier_idle_event(self, *args):
        """Test to verifiy the mechanics of how a courier is set to idle by the dispatcher"""

        # Constants
        initial_time = hour_to_sec(14)
        courier_id = 85
        time_delta = min_to_sec(10)
        random.seed(26)
        on_time = time(14, 0, 0)
        off_time = time(15, 0, 0)

        # Verifies 3 test cases: when the courier is busy, available or idle.
        # For each test case, assert the courier starts in a set and ends up in the idle set

        # Test 1: courier is busy
        env = Environment(initial_time=initial_time)
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())
        courier = Courier(dispatcher=dispatcher, env=env, courier_id=courier_id, on_time=on_time, off_time=off_time)
        dispatcher.moving_couriers = {courier.courier_id: courier}
        dispatcher.courier_idle_event(courier)
        env.run(until=initial_time + time_delta)
        self.assertIn(courier.courier_id, dispatcher.idle_couriers.keys())
        self.assertEqual(dispatcher.moving_couriers, {})
        self.assertEqual(dispatcher.picking_up_couriers, {})

        # Test 2: courier is available
        env = Environment(initial_time=initial_time)
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())
        courier = Courier(dispatcher=dispatcher, env=env, courier_id=courier_id, on_time=on_time, off_time=off_time)
        dispatcher.picking_up_couriers = {courier.courier_id: courier}
        dispatcher.courier_idle_event(courier)
        env.run(until=initial_time + time_delta)
        self.assertIn(courier.courier_id, dispatcher.idle_couriers.keys())
        self.assertEqual(dispatcher.moving_couriers, {})
        self.assertEqual(dispatcher.picking_up_couriers, {})

        # Test 3: courier is idle
        env = Environment(initial_time=initial_time)
        dispatcher = Dispatcher(env=env, matching_policy=DummyMatchingPolicy())
        courier = Courier(dispatcher=dispatcher, env=env, courier_id=courier_id, on_time=on_time, off_time=off_time)
        dispatcher.idle_couriers = {courier.courier_id: courier}
        dispatcher.courier_idle_event(courier)
        env.run(until=initial_time + time_delta)
        self.assertIn(courier.courier_id, dispatcher.idle_couriers.keys())
        self.assertEqual(dispatcher.moving_couriers, {})
        self.assertEqual(dispatcher.picking_up_couriers, {})