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)
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, {})
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)
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)))
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())
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())
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())
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')
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')
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))
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, {})
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')
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())
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, {})
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())
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')
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')
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')
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())
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})
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)
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())
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, {})