Exemple #1
0
def locationize_endpoint(location):
    """Select Yik Yak server based on location of request"""
    for endpoint in get_endpoints():
        min_loc = Location(endpoint["min_latitude"], endpoint["min_longitude"])
        max_loc = Location(endpoint["max_latitude"], endpoint["max_longitude"])
        if min_loc.longitude <= location.longitude <= max_loc.longitude:
            if min_loc.latitude <= location.latitude <= max_loc.latitude:
                settings.YIKYAK_ENDPOINT = endpoint["url"]
                return
    settings.YIKYAK_ENDPOINT = get_default_endpoint()
Exemple #2
0
    def test_estimate_route_properties(self, osrm):
        """Test to verify the route estimation works correctly"""

        # Defines an origin and a route that must be fulfilled
        origin = Location(4.678622, -74.055694)
        route = Route(stops=[
            Stop(position=0, location=Location(4.690207, -74.044235)),
            Stop(position=1, location=Location(4.709022, -74.035102))
        ])

        # Obtains the route's distance and time and asserts expected values
        distance, time = OSRMService.estimate_route_properties(
            origin=origin, route=route, vehicle=Vehicle.CAR)
        self.assertEqual(int(distance), 4)
        self.assertEqual(time, 594)
Exemple #3
0
    def test_get_route(self, osrm):
        """Test to verify the route construction works correctly"""

        # Defines an origin and a destination
        origin = Location(4.678622, -74.055694)
        destination = Location(4.690207, -74.044235)

        # Obtains the route and asserts it is equal to the mocked value
        route = OSRMService.get_route(origin, destination)
        self.assertEqual(
            route.stops,
            Route(stops=[
                Stop(position=0, location=origin),
                Stop(position=1, location=destination)
            ]).stops)
Exemple #4
0
 def __init__(self, org_id, API_key, loc_id=None):
     self.API_key = API_key
     self.org_id = org_id
     self.loc_id = loc_id
     self.header = {'Authorization': f'Access-Token {API_key}'}
     self.url = 'https://api.robinpowered.com/v1.0'
     self.organization = Organization(self)
     self.location = Location(self)
     self.spaces = Spaces(self)
Exemple #5
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, {})
Exemple #6
0
    def parse_world(self, file_name: str) -> NoReturn:
        with open(file_name, 'rb') as f:
            rows, cols, drone_count, turns, max_payload = [
                int(x) for x in f.readline().split()
            ]
            self.grid = Location(rows, cols)
            self.turns = turns
            self.max_payload = max_payload

            product_types_count = int(f.readline())
            self.products = [int(x) for x in f.readline().split()]
            assert (len(self.products) == product_types_count)

            warehouse_count = int(f.readline())
            for wi in range(warehouse_count):
                row, col = [int(x) for x in f.readline().split()]
                stocks = [int(x) for x in f.readline().split()]
                self.warehouses.append(Warehouse(Location(row, col), stocks))

            order_count = int(f.readline())
            for ci in range(order_count):
                row, col = [int(x) for x in f.readline().split()]
                order_items_count = int(f.readline())
                items = [int(x) for x in f.readline().split()]
                cart = {}
                for item in items:
                    cart[item] = cart.setdefault(item, 0) + 1
                self.orders.append(Order(Location(row, col), cart))

        self.drones = [
            Drone(Location(0, 0), self.products, self.max_payload)
            for _ in range(drone_count)
        ]

        logger.info("World is of size %d X %d", rows, cols)
        logger.info("There are %d drones", drone_count)
        logger.info("There are %d turns", turns)
        logger.info("Maximum drone lift-off payload is: %d", max_payload)
        logger.info("There are %d drones", drone_count)
        logger.info("There are %d warehouses", warehouse_count)
        logger.info("There are %d orders", order_count)
        logger.debug(self.products)
        logger.debug(self.warehouses)
        logger.debug(self.orders)
Exemple #7
0
    def test_group_by_geohash(self):
        """Test to verify how the target bundle size is calculated"""

        # Create 3 orders to be grouped into 2 geohashes
        order_1 = Order(order_id=1,
                        pick_up_at=Location(lat=4.678417, lng=-74.054725))
        order_2 = Order(order_id=2,
                        pick_up_at=Location(lat=4.678417, lng=-74.054725))
        order_3 = Order(order_id=3,
                        pick_up_at=Location(lat=4.717045, lng=-74.036359))

        groups = MyopicMatchingPolicy._group_by_geohash(
            orders=[order_1, order_2, order_3])

        # Asserts only 2 groups are created from 3 groups
        self.assertEqual(len(groups), 2)
        self.assertIn(order_1, groups.get('d2g6dgd'))
        self.assertIn(order_2, groups.get('d2g6dgd'))
        self.assertIn(order_3, groups.get('d2g6g68'))
Exemple #8
0
 def __init__(self, file_name):
     self.warehouses = []
     self.orders = []
     self.products = []
     self.grid = Location(0, 0)
     self.turns = 0
     self.drones = []
     self.max_payload = 0
     self.time = 0
     self.parse_world(file_name)
Exemple #9
0
    def _new_users_procedure(self, orders_info: List[Dict[str, Any]]):
        """Method to establish how a new user is created in the World"""

        for order_info in orders_info:
            user = User(env=self.env,
                        dispatcher=self.dispatcher,
                        cancellation_policy=USER_CANCELLATION_POLICIES_MAP[
                            settings.USER_CANCELLATION_POLICY],
                        user_id=order_info['order_id'])
            user.submit_order_event(
                order_id=order_info['order_id'],
                pick_up_at=Location(lat=order_info['pick_up_lat'],
                                    lng=order_info['pick_up_lng']),
                drop_off_at=Location(lat=order_info['drop_off_lat'],
                                     lng=order_info['drop_off_lng']),
                placement_time=order_info['placement_time'],
                expected_drop_off_time=order_info['expected_drop_off_time'],
                preparation_time=order_info['preparation_time'],
                ready_time=order_info['ready_time'])
            self.users.append(user)
Exemple #10
0
    def execute(self, current_location: Location) -> Optional[Location]:
        """Execution of the Movement Evaluation Policy"""

        if random.random() <= settings.COURIER_MOVEMENT_PROBABILITY:
            current_geohash = geohash.encode(*current_location.coordinates, precision=6)
            geohash_neighbors = geohash.neighbors(current_geohash)
            destination_geohash = random.choice(geohash_neighbors)
            destination_coordinates = geohash.decode(destination_geohash)

            return Location(lat=destination_coordinates[0], lng=destination_coordinates[1])

        return None
Exemple #11
0
    def test_get_estimations(self, osrm):
        """Test to verify that estimations are correctly calculated"""

        # Constants
        on_time = time(15, 0, 0)
        off_time = time(16, 0, 0)

        # Services
        policy = GreedyMatchingPolicy()

        # Create an order and a courier and have them be prospects
        order = Order(pick_up_at=Location(4.678622, -74.055694),
                      drop_off_at=Location(4.690207, -74.044235))
        courier = Courier(location=Location(4.709022, -74.035102),
                          on_time=on_time,
                          off_time=off_time,
                          vehicle=Vehicle.CAR)
        prospects = np.array([[0, 0]])

        # Obtain estimations and assert they are correctly calculated
        estimations = policy._get_estimations(orders=[order],
                                              couriers=[courier],
                                              prospects=prospects)
        self.assertEqual(
            round(estimations['distance'].tolist()[0], 2),
            round(
                haversine(courier.location.coordinates,
                          order.pick_up_at.coordinates) +
                haversine(order.pick_up_at.coordinates,
                          order.drop_off_at.coordinates), 2))
        average_velocity = courier.vehicle.average_velocity
        self.assertEqual(
            int(estimations['time'][0]),
            int(
                haversine(courier.location.coordinates,
                          order.pick_up_at.coordinates) / average_velocity +
                haversine(order.pick_up_at.coordinates,
                          order.drop_off_at.coordinates) / average_velocity +
                order.pick_up_service_time + order.drop_off_service_time))
Exemple #12
0
 def update(self):
     """Update Yakarma and basecamp information"""
     raw = yikyakapi.get_messages(self, self.location, basecamp=True)
     # Check if too close to school
     self._get_yak_list(raw)
     try:
         self.yakarma = int(raw.json()["yakarma"])
     except (KeyError, ValueError):
         raise ParsingResponseError("Getting Yakarma failed", raw)
     try:
         self.basecamp_set = bool(int(raw.json()["bcEligible"]))
     except (KeyError, ValueError):
         raise ParsingResponseError("Getting bcEligible failed", raw)
     try:
         latitude = float(raw.json()["bcLat"])
         longitude = float(raw.json()["bcLong"])
         self.basecamp_name = raw.json()["bcName"]
         self.basecamp_location = Location(latitude, longitude)
     except (KeyError, ValueError):
         pass
    def addToInventory(self,title="",status="STOCK",authors=[],publisher="",listprice="",ourprice='',isbn="",categories=[],distributor="",location="",owner="",notes="",quantity=1,known_title=False,types='',kind_name="",kind=default_kind, extra_prices={}, tag='', num_copies=0, printlabel=False):
        print "GOT to addToInventory"
        if not(known_title):
            print "unknown title"
            #add a title
            the_kinds=list(Kind.select(Kind.q.kindName==kind))
            kind_id = None
            if the_kinds:
                kind_id = the_kinds[0].id
            print 'kind id is', kind_id

            #print title
            
            title=title
            publisher=publisher
            #print title, publisher
            known_title=Title(isbn=isbn, booktitle=title, publisher=publisher,tag=" ",type=types, kindID=kind_id)
            print known_title
            for rawAuthor in authors:
                author = rawAuthor.encode("utf8", "backslashreplace")
            theAuthors = Author.selectBy(authorName=author)
            theAuthorsList = list(theAuthors)
            if len(theAuthorsList) == 1:
                known_title.addAuthor(theAuthorsList[0])
            elif len(theAuthorsList) == 0:
                a = Author(authorName=author)
                known_title.addAuthor(a)
            else:
                # We should SQLDataCoherenceLost here
                print "mmm... looks like you have multiple author of the sama name in your database..."
            for category in categories:
                Category(categoryName=category.encode("utf8", "backslashreplace"),title=known_title)
        the_locations=list(Location.select(Location.q.locationName==location))
        location_id=1
        if the_locations:
            location_id = the_locations[0].id
        if not ourprice:
            ourprice=listprice
        for i in range(int(quantity)): 
            #print "book loop"
            b=Book(title=known_title,status=status.encode("utf8", "backslashreplace"), distributor=distributor.encode('ascii', "backslashreplace"),listprice=listprice, ourprice=ourprice, location=location_id,owner=owner.encode("utf8", "backslashreplace"),notes=notes.encode("utf8", "backslashreplace"),consignmentStatus="")
Exemple #14
0
    def get_route(cls, origin: Location, destination: Location) -> Route:
        """Method to obtain a movement route using docker-mounted OSRM"""

        lat_0, lng_0 = origin.coordinates
        lat_1, lng_1 = destination.coordinates

        url = cls.URL.format(lng_0=lng_0, lat_0=lat_0, lng_1=lng_1, lat_1=lat_1)

        try:
            response = requests.get(url, timeout=5)

            if response and response.status_code in [requests.codes.ok, requests.codes.no_content]:
                response_data = response.json()
                steps = response_data.get('routes', [])[0].get('legs', [])[0].get('steps', [])

                stops = []
                for ix, step in enumerate(steps):
                    lng, lat = step.get('maneuver', {}).get('location', [])
                    stop = Stop(
                        location=Location(lat=lat, lng=lng),
                        position=ix
                    )
                    stops.append(stop)

                return Route(stops=stops)

        except:
            logging.exception('Exception captured in OSRMService.get_route. Check Docker.')

            return Route(
                stops=[
                    Stop(
                        location=origin,
                        position=0
                    ),
                    Stop(
                        location=destination,
                        position=1
                    )
                ]
            )
Exemple #15
0
    def _new_couriers_procedure(self, couriers_info: List[Dict[str, Any]]):
        """Method to establish how a new courier is created in the World"""

        for courier_info in couriers_info:
            courier = Courier(
                env=self.env,
                dispatcher=self.dispatcher,
                acceptance_policy=COURIER_ACCEPTANCE_POLICIES_MAP[
                    settings.COURIER_ACCEPTANCE_POLICY],
                movement_evaluation_policy=
                COURIER_MOVEMENT_EVALUATION_POLICIES_MAP[
                    settings.COURIER_MOVEMENT_EVALUATION_POLICY],
                movement_policy=COURIER_MOVEMENT_POLICIES_MAP[
                    settings.COURIER_MOVEMENT_POLICY],
                courier_id=courier_info['courier_id'],
                vehicle=Vehicle.from_label(label=courier_info['vehicle']),
                location=Location(lat=courier_info['on_lat'],
                                  lng=courier_info['on_lng']),
                on_time=courier_info['on_time'],
                off_time=courier_info['off_time'])
            self.couriers.append(courier)
Exemple #16
0
    def __init__(self, raw, user):
        """Initialize comment from raw JSON dict and user"""
        super(Yak, self).__init__(raw, user)
        latitude = raw["latitude"]
        longitude = raw["longitude"]
        self.comments = raw["comments"]
        self.hide_pin = bool(raw["hidePin"])
        self.loaded = raw["messageID"][:2] == "R/"
        self.location = Location(latitude, longitude)
        self.message = raw["message"]
        self.type = int(raw["type"])

        # If Yak is not fully loaded
        try:
            self.gmt = raw["gmt"]
            self.read_only = bool(raw["readOnly"])
            self.score = raw["score"]
        except KeyError:
            self.gmt = None
            self.read_only = None
            self.score = None
            
        # If handle is present
        try:
            self.handle = raw["handle"]
        except KeyError:
            self.handle = None

        # If Yak contains a picture
        if self.type == YAK_TYPE_PICTURE:
            self.url = raw["url"]
            self.expand_in_feed = bool(raw["expandInFeed"])
        else:
            self.expand_in_feed = None
            self.thumbnail_url = None
            self.url = None
Exemple #17
0
    def test_myopic_matching_policy_execute_mip_matcher(self, osrm):
        """Test to verify how the optimization model is solved with a MIP approach"""

        # Constants
        env_time = hour_to_sec(12) + min_to_sec(20)
        on_time = time(8, 0, 0)
        off_time = time(16, 0, 0)
        random.seed(45)

        # Orders
        order_1 = Order(order_id=1,
                        pick_up_at=Location(lat=4.678759, lng=-74.055729),
                        drop_off_at=Location(lat=4.681694, lng=-74.044811),
                        ready_time=time(12, 30, 0),
                        expected_drop_off_time=time(12, 40, 0),
                        pick_up_service_time=0,
                        drop_off_service_time=0)
        order_2 = Order(order_id=2,
                        pick_up_at=Location(lat=4.678759, lng=-74.055729),
                        drop_off_at=Location(lat=4.695001, lng=-74.040737),
                        ready_time=time(12, 32, 0),
                        expected_drop_off_time=time(12, 42, 0),
                        pick_up_service_time=0,
                        drop_off_service_time=0)
        order_3 = Order(order_id=3,
                        pick_up_at=Location(lat=4.678759, lng=-74.055729),
                        drop_off_at=Location(lat=4.668742, lng=-74.056684),
                        ready_time=time(12, 33, 0),
                        expected_drop_off_time=time(12, 43, 0),
                        pick_up_service_time=0,
                        drop_off_service_time=0)
        order_4 = Order(order_id=4,
                        pick_up_at=Location(lat=4.678759, lng=-74.055729),
                        drop_off_at=Location(lat=4.661441, lng=-74.056955),
                        ready_time=time(12, 34, 0),
                        expected_drop_off_time=time(12, 44, 0),
                        pick_up_service_time=0,
                        drop_off_service_time=0)

        # Couriers
        courier_1 = Courier(courier_id=1,
                            on_time=on_time,
                            off_time=off_time,
                            condition='idle',
                            location=Location(lat=4.676854, lng=-74.057498))
        courier_2 = Courier(courier_id=2,
                            on_time=on_time,
                            off_time=off_time,
                            condition='idle',
                            location=Location(lat=4.679408, lng=-74.052524))
        courier_3 = Courier(
            courier_id=3,
            on_time=on_time,
            off_time=off_time,
            condition='picking_up',
            location=order_3.pick_up_at,
            active_route=Route(orders={order_3.order_id: order_3},
                               stops=[
                                   Stop(location=order_3.pick_up_at,
                                        orders={order_3.order_id: order_3},
                                        position=0,
                                        type=StopType.PICK_UP),
                                   Stop(location=order_3.drop_off_at,
                                        orders={order_3.order_id: order_3},
                                        position=1,
                                        type=StopType.DROP_OFF)
                               ]),
            active_stop=Stop(location=order_3.pick_up_at,
                             orders={order_3.order_id: order_3},
                             position=0,
                             type=StopType.PICK_UP))

        # Get all the elements from the policy and assert their expected behavior
        policy = MyopicMatchingPolicy(assignment_updates=False,
                                      prospects=False,
                                      notification_filtering=False,
                                      mip_matcher=False)
        routes = policy._generate_routes(
            orders=[order_1, order_2, order_4],
            couriers=[courier_1, courier_2, courier_3],
            env_time=env_time)
        self.assertTrue(routes)
        self.assertEqual(len(routes), 2)
        self.assertEqual(len(routes[0].orders), 2)
        self.assertEqual(len(routes[1].orders), 1)

        prospects = policy._generate_matching_prospects(
            routes=routes,
            couriers=[courier_1, courier_2, courier_3],
            env_time=env_time)
        self.assertTrue(prospects.tolist())
        self.assertEqual(len(prospects), 4),
        self.assertEqual(len(prospects),
                         len(routes) * len([courier_1, courier_2]))

        costs = policy._generate_matching_costs(
            routes=routes,
            couriers=[courier_1, courier_2, courier_3],
            prospects=prospects,
            env_time=env_time)
        self.assertTrue(costs.tolist())
        self.assertEqual(len(prospects), len(costs))
        self.assertEqual(len(costs), 4)
        self.assertNotIn(0., costs)

        problem = MatchingProblemBuilder.build(
            routes=routes,
            couriers=[courier_1, courier_2, courier_3],
            prospects=prospects,
            costs=costs)
        self.assertTrue(problem)
        self.assertEqual(len(prospects), len(problem.prospects))
        self.assertEqual(len(prospects), len(problem.matching_prospects))
        self.assertEqual(len(prospects), len(problem.costs))
        self.assertEqual(routes, problem.routes)
        self.assertEqual(problem.couriers, [courier_1, courier_2, courier_3])
        self.assertNotIn(str(courier_3.courier_id),
                         problem.matching_prospects['i'])

        model_builder = MIPOptimizationModelBuilder(
            sense='max',
            model_constraints=[
                CourierAssignmentConstraint(),
                RouteAssignmentConstraint()
            ],
            optimizer='pulp')
        model = model_builder.build(problem)
        self.assertTrue(model)
        self.assertEqual(len(model.constraints),
                         len(problem.routes) + len([courier_1, courier_2]))
        self.assertEqual(len(model.variable_set),
                         len(problem.matching_prospects) + len(problem.routes))

        solution = model.solve()
        self.assertTrue(solution.tolist())
        self.assertEqual(len(solution),
                         len(problem.matching_prospects) + len(problem.routes))
        self.assertEqual(solution[0:len(problem.prospects)].sum(), 2)
        self.assertEqual(solution.sum(), 2)

        notifications = policy._process_solution(solution, problem, env_time)
        self.assertEqual(len(notifications), len(routes))
        self.assertIsInstance(notifications[0].instruction, Route)
        self.assertIsInstance(notifications[1].instruction, Route)
        self.assertEqual(notifications[0].courier, courier_1)
        self.assertEqual(notifications[1].courier, courier_2)
        self.assertIn(order_1.order_id,
                      notifications[1].instruction.orders.keys())
        self.assertIn(order_4.order_id,
                      notifications[1].instruction.orders.keys())
Exemple #18
0
class TestsUser(unittest.TestCase):
    """Tests for the User actor class"""

    # Order properties to be reused
    order_id = 0
    pick_up_at = Location(lat=4.689697, lng=-74.055495)
    drop_off_at = Location(lat=4.690296, lng=-74.043929)
    placement_time = time(12, 0, 0)
    expected_drop_off_time = time(12, 40, 0)
    preparation_time = time(12, 1, 0)
    ready_time = time(12, 11, 0)

    # Services to be reused
    cancellation_policy = RandomCancellationPolicy()

    @patch('settings.settings.USER_WAIT_TO_CANCEL', min_to_sec(5))
    @patch('settings.settings.USER_CANCELLATION_PROBABILITY', 0.99)
    @patch('settings.settings.DISPATCHER_WAIT_TO_CANCEL', min_to_sec(50))
    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')

    @patch('settings.settings.USER_WAIT_TO_CANCEL', min_to_sec(40))
    @patch('settings.settings.DISPATCHER_WAIT_TO_CANCEL', min_to_sec(50))
    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')

    @patch('settings.settings.USER_CANCELLATION_PROBABILITY', 0)
    @patch('settings.settings.DISPATCHER_WAIT_TO_CANCEL', min_to_sec(120))
    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')
Exemple #19
0
    def test_get_prospects(self):
        """Test to verify how prospects are obtained"""

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

        # Services
        policy = GreedyMatchingPolicy()

        # Case 1: verify an order is prospect to a courier
        order = Order(pick_up_at=Location(4.678622, -74.055694),
                      drop_off_at=Location(4.690207, -74.044235))
        courier = Courier(location=Location(4.709022, -74.035102),
                          on_time=on_time,
                          off_time=off_time)
        prospects = policy._get_prospects(orders=[order], couriers=[courier])
        self.assertEqual(prospects.tolist(), [[0, 0]])

        # Case 2: verify an order is not prospect to a courier
        order = Order(pick_up_at=Location(4.678622, -74.055694),
                      drop_off_at=Location(4.690207, -74.044235))
        courier = Courier(location=Location(4.8090, -74.9351),
                          on_time=on_time,
                          off_time=off_time,
                          active_route=Route(stops=[],
                                             orders={
                                                 2: Order(),
                                                 3: Order(),
                                                 4: Order()
                                             }))
        prospects = policy._get_prospects(orders=[order], couriers=[courier])
        self.assertEqual(prospects.tolist(), [])

        # Case 3: assert some orders being prospect and some not to some couriers
        order_1 = Order(pick_up_at=Location(4.678622, -74.055694),
                        drop_off_at=Location(4.690207, -74.044235),
                        order_id=1)
        order_2 = Order(pick_up_at=Location(1.178, -72.25),
                        drop_off_at=Location(1.690207, -75.044235),
                        order_id=2)
        courier_1 = Courier(location=Location(4.709022, -74.035102),
                            on_time=on_time,
                            off_time=off_time,
                            courier_id=1)
        courier_2 = Courier(location=Location(4.709022, -74.035102),
                            on_time=on_time,
                            off_time=off_time,
                            courier_id=2)
        prospects = policy._get_prospects(orders=[order_1, order_2],
                                          couriers=[courier_1, courier_2])
        self.assertEqual(len(prospects), 2)
Exemple #20
0
    def test_execute(self, osrm):
        """Test the full functionality of the greedy matching policy"""

        # Constants
        on_time = time(7, 0, 0)
        off_time = time(9, 0, 0)

        # Services
        policy = GreedyMatchingPolicy()

        # Test 1: creates an order and two couriers.
        # Since the courier_2 is at the same location as the pick up, asserts it should get chosen for notification
        order = Order(pick_up_at=Location(4.678622, -74.055694),
                      drop_off_at=Location(4.690207, -74.044235))
        courier_1 = Courier(location=Location(4.709022, -74.035102),
                            on_time=on_time,
                            off_time=off_time,
                            vehicle=Vehicle.CAR,
                            condition='idle')
        courier_2 = Courier(location=Location(4.678622, -74.055694),
                            on_time=on_time,
                            off_time=off_time,
                            vehicle=Vehicle.CAR,
                            condition='idle')
        notifications, _ = policy.execute(orders=[order],
                                          couriers=[courier_1, courier_2],
                                          env_time=3)
        self.assertEqual(len(notifications), 1)
        self.assertEqual(notifications[0].courier, courier_2)
        self.assertIn(order, notifications[0].instruction.orders.values())

        # Test 2: creates two orders and two couriers.
        # The courier_1 is at the same location as the pick up of order_1.
        # The courier_2 is at the same location as the pick up of order_2.
        # In this fashion, courier_1 should be selected for order_1 and courier_2 for order_2
        order_1 = Order(pick_up_at=Location(4.678622, -74.055694),
                        drop_off_at=Location(4.690207, -74.044235),
                        order_id=1)
        order_2 = Order(pick_up_at=Location(4.690207, -74.044235),
                        drop_off_at=Location(4.678622, -74.055694),
                        order_id=2)
        courier_1 = Courier(location=Location(4.678622, -74.055694),
                            on_time=on_time,
                            off_time=off_time,
                            vehicle=Vehicle.CAR,
                            condition='idle',
                            courier_id=1)
        courier_2 = Courier(location=Location(4.690207, -74.044235),
                            on_time=on_time,
                            off_time=off_time,
                            vehicle=Vehicle.CAR,
                            condition='idle',
                            courier_id=2)
        notifications, _ = policy.execute(orders=[order_1, order_2],
                                          couriers=[courier_1, courier_2],
                                          env_time=4)
        self.assertEqual(len(notifications), 2)
        self.assertEqual(notifications[0].courier, courier_1)
        self.assertIn(order_1, notifications[0].instruction.orders.values())
        self.assertEqual(notifications[1].courier, courier_2)
        self.assertIn(order_2, notifications[1].instruction.orders.values())

        # Test 3: creates more orders than couriers to check nothing breaks
        order_1 = Order(pick_up_at=Location(4.678622, -74.055694),
                        drop_off_at=Location(4.690207, -74.044235),
                        order_id=1)
        order_2 = Order(pick_up_at=Location(4.690207, -74.044235),
                        drop_off_at=Location(4.678622, -74.055694),
                        order_id=2)
        courier = Courier(location=Location(4.678622, -74.055694),
                          on_time=on_time,
                          off_time=off_time,
                          vehicle=Vehicle.CAR,
                          condition='idle',
                          courier_id=1)
        notifications, _ = policy.execute(orders=[order_1, order_2],
                                          couriers=[courier],
                                          env_time=5)
        self.assertEqual(len(notifications), 1)
        self.assertEqual(notifications[0].courier, courier)
        self.assertIn(order_1, notifications[0].instruction.orders.values())
Exemple #21
0
    def test_update_route(self, osrm):
        """Test to verify a route is updated based on canceled orders"""

        # Constants
        order_1 = Order(order_id=1,
                        pick_up_at=Location(lat=4.567, lng=1.234),
                        drop_off_at=Location(lat=1.234, lng=4.567))
        order_2 = Order(order_id=2,
                        pick_up_at=Location(lat=4.567, lng=1.234),
                        drop_off_at=Location(lat=1.234, lng=4.567))

        # Test 1: define a route and some orders being canceled
        orders_dict = {order_1.order_id: order_1, order_2.order_id: order_2}
        route = Route(orders=orders_dict,
                      stops=[
                          Stop(orders={order_1.order_id: order_1},
                               type=StopType.PICK_UP,
                               position=0,
                               location=order_1.pick_up_at),
                          Stop(orders={order_2.order_id: order_2},
                               type=StopType.PICK_UP,
                               position=1,
                               location=order_2.pick_up_at),
                          Stop(orders={order_1.order_id: order_1},
                               type=StopType.DROP_OFF,
                               position=2,
                               location=order_1.drop_off_at),
                          Stop(orders={order_2.order_id: order_2},
                               type=StopType.DROP_OFF,
                               position=3,
                               location=order_2.drop_off_at)
                      ])
        canceled_order_ids = [1]

        # Update the route and assert canceled orders were removed
        route.update(canceled_order_ids)
        self.assertEqual(len(route.orders), 1)
        self.assertEqual(len(route.stops), 2)
        for stop in route.stops:
            self.assertNotIn(order_1.order_id, stop.orders)
            self.assertEqual(len(stop.orders), 1)

        # Test 2: define a route and all orders being canceled
        orders_dict = {order_1.order_id: order_1, order_2.order_id: order_2}
        route = Route(orders=orders_dict,
                      stops=[
                          Stop(orders=orders_dict,
                               type=StopType.PICK_UP,
                               position=0,
                               location=order_1.pick_up_at),
                          Stop(orders=orders_dict,
                               type=StopType.DROP_OFF,
                               position=2,
                               location=order_1.drop_off_at)
                      ])
        canceled_order_ids = [1, 2]

        # Update the route and assert canceled orders were removed
        route.update(canceled_order_ids)
        self.assertEqual(len(route.orders), 0)
        self.assertEqual(len(route.stops), 0)
Exemple #22
0
class TestsDispatcher(unittest.TestCase):
    """Tests for the Dispatcher actor class"""

    # Order properties to be reused
    order_id = 0
    pick_up_at = Location(lat=4.689697, lng=-74.055495)
    drop_off_at = Location(lat=4.690296, lng=-74.043929)
    placement_time = time(12, 0, 0)
    expected_drop_off_time = time(12, 40, 0)
    preparation_time = time(12, 1, 0)
    ready_time = time(12, 11, 0)

    # Services to be reused
    cancellation_policy = RandomCancellationPolicy()
    dispatcher_cancellation_policy = StaticCancellationPolicy()

    @staticmethod
    def assign_courier(_user: User, _env: Environment, _dispatcher: Dispatcher):
        """Dummy method to assign a courier"""

        yield _env.timeout(delay=min_to_sec(8))
        _user.order.courier_id = 999
        del _dispatcher.unassigned_orders[_user.order.order_id]
        _dispatcher.assigned_orders[_user.order.order_id] = _user.order

    @patch('settings.settings.USER_CANCELLATION_PROBABILITY', 0)
    @patch('settings.settings.USER_WAIT_TO_CANCEL', min_to_sec(10))
    @patch('settings.settings.DISPATCHER_WAIT_TO_CANCEL', min_to_sec(15))
    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')

    @patch('settings.settings.USER_CANCELLATION_PROBABILITY', 0)
    @patch('settings.settings.USER_WAIT_TO_CANCEL', min_to_sec(44))
    @patch('settings.settings.DISPATCHER_WAIT_TO_CANCEL', min_to_sec(55))
    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_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_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))

    @patch('settings.settings.COURIER_MOVEMENT_PROBABILITY', 0.01)
    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_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, {})

    @patch('settings.settings.COURIER_MOVEMENT_PROBABILITY', 0.01)
    def test_notification_rejected_event(self):
        """Test to verify the mechanics of a 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 an instruction with an order, a courier and sends the rejected 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)
        notification = Notification(
            courier=courier,
            instruction=instruction
        )
        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.assertEqual(order.state, 'unassigned')
        self.assertIsNone(order.acceptance_time)
        self.assertIsNone(order.courier_id)
        self.assertIn(order.order_id, dispatcher.unassigned_orders.keys())
        self.assertIsNone(courier.active_route)
        self.assertIn(courier.courier_id, order.rejected_by)
        self.assertIn(order.order_id, courier.rejected_orders)

    @patch('settings.settings.COURIER_MOVEMENT_PROBABILITY', 0.01)
    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, {})

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

    @patch('services.osrm_service.OSRMService.get_route', side_effect=mocked_get_route)
    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, {})

    @patch('settings.settings.DISPATCHER_WAIT_TO_CANCEL', min_to_sec(55))
    @patch('settings.settings.USER_WAIT_TO_CANCEL', min_to_sec(44))
    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)

    @patch('settings.settings.COURIER_MOVEMENT_PROBABILITY', 0.01)
    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_prepositioning_notification_accepted_event(self):
        """Test to verify the mechanics of a prepositioning 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 a prepositioning notification, a courier and sends the accepted event
        instruction = Route(
            stops=[
                Stop(position=0, type=StopType.PREPOSITION),
                Stop(position=1, type=StopType.PREPOSITION)
            ]
        )
        courier = Courier(dispatcher=dispatcher, env=env, courier_id=666, on_time=on_time, off_time=off_time)
        notification = Notification(courier=courier, instruction=instruction, type=NotificationType.PREPOSITIONING)
        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.assertIsNotNone(courier.active_route)
        self.assertEqual(courier.active_route, instruction)

    @patch('settings.settings.COURIER_MOVEMENT_PROBABILITY', 0.01)
    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)
Exemple #23
0
from objects.user import User
from objects.location import Location

u = User()
u.username = "******"
u.password = "******"
u.email = "*****@*****.**"
u.ip = "123.123.123.123"
print u.create()

l = Location()
l.name = "City"
l.id = "[1,2,3]"
l.x = 1
l.y = 2
l.z = 3
l.description = "a small city near a river"
print l.create()
Exemple #24
0
class TestsCourier(unittest.TestCase):
    """Tests for the Courier actor class"""

    # Properties to be reused
    courier_id = 56
    vehicle = Vehicle.MOTORCYCLE
    start_location = Location(lat=4.697893, lng=-74.051565)

    order_id = 0
    pick_up_at = Location(lat=4.689697, lng=-74.055495)
    drop_off_at = Location(lat=4.690296, lng=-74.043929)
    placement_time = time(12, 0, 0)
    expected_drop_off_time = time(12, 40, 0)
    preparation_time = time(12, 2, 0)
    ready_time = time(12, 12, 0)

    # Services to be reused
    acceptance_policy = UniformAcceptancePolicy()
    movement_evaluation_policy = NeighborsMoveEvalPolicy()
    movement_policy = OSRMMovementPolicy()

    @patch('settings.settings.COURIER_MOVEMENT_PROBABILITY', 0.01)
    @patch('services.osrm_service.OSRMService.get_route',
           side_effect=mocked_get_route)
    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())

    @patch('services.osrm_service.OSRMService.get_route',
           side_effect=mocked_get_route)
    @patch('settings.settings.COURIER_MOVEMENT_PROBABILITY', 0.95)
    @patch('settings.settings.COURIER_WAIT_TO_MOVE', min_to_sec(7))
    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())

    @patch('services.osrm_service.OSRMService.get_route',
           side_effect=mocked_get_route)
    @patch('settings.settings.COURIER_MOVEMENT_PROBABILITY', 0.1)
    @patch('settings.settings.COURIER_MIN_ACCEPTANCE_RATE', 0.99)
    def test_notify_event_accept_idle(self, osrm):
        """Test to evaluate how a courier handles a notification while being idle and accepts it"""

        # Constants
        random.seed(126)
        initial_time = hour_to_sec(12)
        time_delta = min_to_sec(40)
        on_time = time(12, 0, 0)
        off_time = time(13, 0, 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 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.99,
            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,
                      user=User(env=env))
        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=initial_time + time_delta)

        # Asserts that the courier fulfilled the route and is at a different start location
        self.assertIsNotNone(order.pick_up_time)
        self.assertIsNotNone(order.drop_off_time)
        self.assertEqual(order.courier_id, courier.courier_id)
        self.assertTrue(order.pick_up_time < order.drop_off_time)
        self.assertIsNone(courier.active_route)
        self.assertIsNone(courier.active_stop)
        self.assertEqual(dispatcher.fulfilled_orders, {order.order_id: order})
        self.assertEqual(order.state, 'dropped_off')
        self.assertNotEqual(courier.location, self.start_location)
        self.assertEqual(courier.condition, 'idle')
        self.assertIn(courier.courier_id, dispatcher.idle_couriers.keys())

    @patch('services.osrm_service.OSRMService.get_route',
           side_effect=mocked_get_route)
    @patch('settings.settings.COURIER_MOVEMENT_PROBABILITY', 0.1)
    @patch('settings.settings.COURIER_MIN_ACCEPTANCE_RATE', 0.99)
    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())

    @patch('services.osrm_service.OSRMService.get_route',
           side_effect=mocked_get_route)
    @patch('settings.settings.COURIER_MOVEMENT_PROBABILITY', 0.99)
    @patch('settings.settings.COURIER_MIN_ACCEPTANCE_RATE', 0.99)
    def test_notify_event_accept_picking_up(self, osrm):
        """Test to evaluate how a courier handles a notification while picking up and accepts it"""

        # Constants
        random.seed(184)
        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 high 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.99,
            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(13) + min_to_sec(12))

        # Asserts that the courier fulfilled the active and new order and is at a different start location
        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.assertIsNotNone(new_order.pick_up_time)
        self.assertIsNotNone(new_order.drop_off_time)
        self.assertEqual(new_order.courier_id, courier.courier_id)
        self.assertTrue(new_order.pick_up_time < new_order.drop_off_time)
        self.assertEqual(new_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,
            new_order.order_id: new_order
        })
        self.assertEqual(courier.condition, 'idle')
        self.assertIn(courier.courier_id, dispatcher.idle_couriers.keys())

    @patch('services.osrm_service.OSRMService.get_route',
           side_effect=mocked_get_route)
    @patch('settings.settings.COURIER_MOVEMENT_PROBABILITY', 0.01)
    @patch('settings.settings.COURIER_MIN_ACCEPTANCE_RATE', 0.99)
    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())

    @patch('settings.settings.COURIER_MOVEMENT_PROBABILITY', 0.01)
    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')

    @patch('settings.settings.COURIER_EARNINGS_PER_ORDER', 3)
    @patch('settings.settings.COURIER_EARNINGS_PER_HOUR', 8)
    @patch('settings.settings.COURIER_MOVEMENT_PROBABILITY', 0.01)
    def test_calculate_earnings(self):
        """Test to verify the mechanics of calculating the shift's earnings"""

        # Constants
        random.seed(523)
        on_time = time(0, 0, 0)
        off_time = time(2, 0, 0)

        # Services
        env = Environment()

        # Creates a two hour - shift courier
        courier = Courier(env=env, on_time=on_time, off_time=off_time)

        # Verifies for two scenarios how the earnings are calculated.
        # In the first test, raw earnings from orders are chosen.
        # In the second test, the hourly earnings rate is chosen.

        # Test 1. Creates courier earnings to select the raw earnings from orders.
        # Asserts that these earnings are selected over the hourly earnings rate
        courier.fulfilled_orders = [Order()] * 7
        courier.earnings = courier._calculate_earnings()
        self.assertEqual(
            courier.earnings,
            len(courier.fulfilled_orders) *
            settings.COURIER_EARNINGS_PER_ORDER)

        # Test 2. Creates courier earnings to select the hourly earnings rate.
        # Asserts that these earnings are selected over the order earnings
        courier.fulfilled_orders = [Order()] * 2
        courier.earnings = courier._calculate_earnings()
        self.assertEqual(
            courier.earnings,
            sec_to_hour(time_diff(courier.off_time, courier.on_time)) *
            settings.COURIER_EARNINGS_PER_HOUR)

    @patch('services.osrm_service.OSRMService.get_route',
           side_effect=mocked_get_route)
    @patch('settings.settings.COURIER_MOVEMENT_PROBABILITY', 0.1)
    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())

    @patch('services.osrm_service.OSRMService.get_route',
           side_effect=mocked_get_route)
    @patch('settings.settings.COURIER_MOVEMENT_PROBABILITY', 0.01)
    def test_notify_prepositioning_event_reject_idle(self, osrm):
        """Test to evaluate how a courier handles a prepositioning notification while being idle and rejects it"""

        # Constants
        random.seed(672)
        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 with low 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.01,
            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=hour_to_sec(7))

        # Asserts that the courier didn't fulfill the route
        self.assertIsNone(courier.active_route)
        self.assertIsNone(courier.active_stop)
        self.assertEqual(courier.location, self.start_location)
        self.assertEqual(courier.condition, 'idle')
        self.assertIn(courier.courier_id, dispatcher.idle_couriers.keys())

    @patch('services.osrm_service.OSRMService.get_route',
           side_effect=mocked_get_route)
    @patch('settings.settings.COURIER_MOVEMENT_PROBABILITY', 0.01)
    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)))
Exemple #25
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())
Exemple #26
0
    def test_generate_matching_prospects_picking_up_couriers(self, osrm):
        """Test to verify how prospects are created"""

        # Constants
        env_time = hour_to_sec(12) + min_to_sec(20)
        on_time = time(8, 0, 0)
        off_time = time(16, 0, 0)

        # Orders
        order_1 = Order(order_id=1,
                        pick_up_at=Location(lat=4.678759, lng=-74.055729),
                        drop_off_at=Location(lat=4.681694, lng=-74.044811),
                        ready_time=time(12, 30, 0),
                        expected_drop_off_time=time(12, 40, 0),
                        pick_up_service_time=0,
                        drop_off_service_time=0)
        order_2 = Order(order_id=2,
                        pick_up_at=Location(lat=4.678759, lng=-74.055729),
                        drop_off_at=Location(lat=4.695001, lng=-74.040737),
                        ready_time=time(12, 32, 0),
                        expected_drop_off_time=time(12, 42, 0),
                        pick_up_service_time=0,
                        drop_off_service_time=0)
        order_3 = Order(order_id=3,
                        pick_up_at=Location(lat=4.678759, lng=-74.055729),
                        drop_off_at=Location(lat=4.668742, lng=-74.056684),
                        ready_time=time(12, 33, 0),
                        expected_drop_off_time=time(12, 43, 0),
                        pick_up_service_time=0,
                        drop_off_service_time=0)

        # Couriers
        courier_3 = Courier(
            courier_id=3,
            on_time=on_time,
            off_time=off_time,
            condition='picking_up',
            location=order_3.pick_up_at,
            active_route=Route(orders={order_3.order_id: order_3},
                               stops=[
                                   Stop(location=order_3.pick_up_at,
                                        orders={order_3.order_id: order_3},
                                        position=0,
                                        type=StopType.PICK_UP),
                                   Stop(location=order_3.drop_off_at,
                                        orders={order_3.order_id: order_3},
                                        position=1,
                                        type=StopType.DROP_OFF)
                               ]),
            active_stop=Stop(location=order_3.pick_up_at,
                             orders={order_3.order_id: order_3},
                             position=0,
                             type=StopType.PICK_UP))

        # Get routes and assert expected behavior
        policy = MyopicMatchingPolicy(assignment_updates=True,
                                      prospects=True,
                                      notification_filtering=False,
                                      mip_matcher=False)
        routes = policy._generate_routes(orders=[order_1, order_2],
                                         couriers=[courier_3],
                                         env_time=env_time)

        # Generate prospects and assert expected behavior
        prospects = policy._generate_matching_prospects(routes=routes,
                                                        couriers=[courier_3],
                                                        env_time=env_time)
        self.assertFalse(prospects.tolist())
Exemple #27
0
    def test_generate_matching_prospects_all(self, osrm):
        """Test to verify how prospects are created"""

        # Constants
        env_time = hour_to_sec(12) + min_to_sec(20)
        on_time = time(8, 0, 0)
        off_time = time(16, 0, 0)

        # Orders
        order_1 = Order(order_id=1,
                        pick_up_at=Location(lat=4.678759, lng=-74.055729),
                        drop_off_at=Location(lat=4.681694, lng=-74.044811),
                        ready_time=time(12, 30, 0),
                        expected_drop_off_time=time(12, 40, 0),
                        pick_up_service_time=0,
                        drop_off_service_time=0)
        order_2 = Order(order_id=2,
                        pick_up_at=Location(lat=4.678759, lng=-74.055729),
                        drop_off_at=Location(lat=4.695001, lng=-74.040737),
                        ready_time=time(12, 32, 0),
                        expected_drop_off_time=time(12, 42, 0),
                        pick_up_service_time=0,
                        drop_off_service_time=0)
        order_3 = Order(order_id=3,
                        pick_up_at=Location(lat=4.678759, lng=-74.055729),
                        drop_off_at=Location(lat=4.668742, lng=-74.056684),
                        ready_time=time(12, 33, 0),
                        expected_drop_off_time=time(12, 43, 0),
                        pick_up_service_time=0,
                        drop_off_service_time=0)
        order_4 = Order(order_id=4,
                        pick_up_at=Location(lat=4.678759, lng=-74.055729),
                        drop_off_at=Location(lat=4.661441, lng=-74.056955),
                        ready_time=time(12, 34, 0),
                        expected_drop_off_time=time(12, 44, 0),
                        pick_up_service_time=0,
                        drop_off_service_time=0)

        # Couriers
        courier_1 = Courier(courier_id=1,
                            on_time=on_time,
                            off_time=off_time,
                            condition='idle',
                            location=Location(lat=4.676854, lng=-74.057498))
        courier_2 = Courier(courier_id=2,
                            on_time=on_time,
                            off_time=off_time,
                            condition='idle',
                            location=Location(lat=4.679408, lng=-74.052524))

        # Routes
        policy = MyopicMatchingPolicy(assignment_updates=True,
                                      prospects=True,
                                      notification_filtering=False,
                                      mip_matcher=False)
        routes = policy._generate_routes(
            orders=[order_1, order_2, order_3, order_4],
            couriers=[courier_1, courier_2],
            env_time=env_time)

        # Generate prospects and assert expected behavior
        prospects = policy._generate_matching_prospects(
            routes=routes, couriers=[courier_1, courier_2], env_time=env_time)
        self.assertTrue(prospects.tolist())
        self.assertEqual(len(prospects), 8)
Exemple #28
0
    def test_add_order(self, osrm):
        """Test to verify how a new order is added to an existing route"""

        # Constants
        old_order = Order(order_id=5,
                          pick_up_at=Location(lat=4.567, lng=1.234),
                          drop_off_at=Location(lat=1.234, lng=4.567))
        new_order = Order(order_id=1,
                          pick_up_at=Location(lat=1.234, lng=4.567),
                          drop_off_at=Location(lat=4.567, lng=1.234))

        # Case 1: the route is empty
        route = Route(num_stops=2)
        route.add_order(new_order)
        self.assertTrue(route.stops)
        self.assertEqual(len(route.stops), 2)
        self.assertEqual(len(route.stops), route.num_stops)
        self.assertIn(new_order.order_id, route.orders.keys())
        self.assertIn(new_order.order_id, route.stops[0].orders.keys())
        self.assertIn(new_order.order_id, route.stops[1].orders.keys())
        self.assertEqual(route.stops[0].type, StopType.PICK_UP)
        self.assertEqual(route.stops[1].type, StopType.DROP_OFF)
        self.assertTrue(route.time)

        # Case 2. the route has an order and is inserted at correct position
        route = Route(orders={old_order.order_id: old_order},
                      stops=[
                          Stop(location=old_order.pick_up_at,
                               orders={old_order.order_id: old_order},
                               position=0,
                               type=StopType.PICK_UP),
                          Stop(location=old_order.drop_off_at,
                               orders={old_order.order_id: old_order},
                               position=1,
                               type=StopType.DROP_OFF)
                      ])
        route.add_order(new_order, route_position=2)
        self.assertTrue(route)
        self.assertEqual(len(route.stops), 3)
        self.assertEqual(len(route.stops), route.num_stops)
        self.assertIn(new_order.order_id, route.orders.keys())
        self.assertIn(old_order.order_id, route.orders.keys())
        self.assertIn(new_order.order_id, route.stops[0].orders.keys())
        self.assertIn(old_order.order_id, route.stops[0].orders.keys())
        self.assertIn(old_order.order_id, route.stops[1].orders.keys())
        self.assertIn(new_order.order_id, route.stops[2].orders.keys())
        self.assertEqual(route.stops[0].type, StopType.PICK_UP)
        self.assertEqual(route.stops[1].type, StopType.DROP_OFF)
        self.assertEqual(route.stops[2].type, StopType.DROP_OFF)
        self.assertTrue(route.time)

        # Case 3. the route has an order and is inserted at wrong position (greater position)
        route = Route(orders={old_order.order_id: old_order},
                      stops=[
                          Stop(location=old_order.pick_up_at,
                               orders={old_order.order_id: old_order},
                               position=0,
                               type=StopType.PICK_UP),
                          Stop(location=old_order.drop_off_at,
                               orders={old_order.order_id: old_order},
                               position=1,
                               type=StopType.DROP_OFF)
                      ])
        route.add_order(new_order, route_position=6)
        self.assertTrue(route)
        self.assertEqual(len(route.stops), 3)
        self.assertEqual(len(route.stops), route.num_stops)
        self.assertIn(new_order.order_id, route.orders.keys())
        self.assertIn(old_order.order_id, route.orders.keys())
        self.assertIn(new_order.order_id, route.stops[0].orders.keys())
        self.assertIn(old_order.order_id, route.stops[0].orders.keys())
        self.assertIn(old_order.order_id, route.stops[1].orders.keys())
        self.assertIn(new_order.order_id, route.stops[2].orders.keys())
        self.assertEqual(route.stops[0].type, StopType.PICK_UP)
        self.assertEqual(route.stops[1].type, StopType.DROP_OFF)
        self.assertEqual(route.stops[2].type, StopType.DROP_OFF)
        self.assertTrue(route.time)

        # Case 4. the route has an order and is inserted at wrong position (equal position)
        route = Route(orders={old_order.order_id: old_order},
                      stops=[
                          Stop(location=old_order.pick_up_at,
                               orders={old_order.order_id: old_order},
                               position=0,
                               type=StopType.PICK_UP),
                          Stop(location=old_order.drop_off_at,
                               orders={old_order.order_id: old_order},
                               position=1,
                               type=StopType.DROP_OFF)
                      ])
        route.add_order(new_order, route_position=1)
        self.assertTrue(route)
        self.assertEqual(len(route.stops), 3)
        self.assertEqual(len(route.stops), route.num_stops)
        self.assertIn(new_order.order_id, route.orders.keys())
        self.assertIn(old_order.order_id, route.orders.keys())
        self.assertIn(new_order.order_id, route.stops[0].orders.keys())
        self.assertIn(old_order.order_id, route.stops[0].orders.keys())
        self.assertIn(old_order.order_id, route.stops[1].orders.keys())
        self.assertIn(new_order.order_id, route.stops[2].orders.keys())
        self.assertEqual(route.stops[0].type, StopType.PICK_UP)
        self.assertEqual(route.stops[1].type, StopType.DROP_OFF)
        self.assertEqual(route.stops[2].type, StopType.DROP_OFF)
        self.assertTrue(route.time)

        # Case 5. the route has an order and is inserted at wrong position (smaller position)
        route = Route(orders={old_order.order_id: old_order},
                      stops=[
                          Stop(location=old_order.pick_up_at,
                               orders={old_order.order_id: old_order},
                               position=0,
                               type=StopType.PICK_UP),
                          Stop(location=old_order.drop_off_at,
                               orders={old_order.order_id: old_order},
                               position=1,
                               type=StopType.DROP_OFF)
                      ])
        route.add_order(new_order, route_position=1)
        self.assertTrue(route)
        self.assertEqual(len(route.stops), 3)
        self.assertEqual(len(route.stops), route.num_stops)
        self.assertIn(new_order.order_id, route.orders.keys())
        self.assertIn(old_order.order_id, route.orders.keys())
        self.assertIn(new_order.order_id, route.stops[0].orders.keys())
        self.assertIn(old_order.order_id, route.stops[0].orders.keys())
        self.assertIn(old_order.order_id, route.stops[1].orders.keys())
        self.assertIn(new_order.order_id, route.stops[2].orders.keys())
        self.assertEqual(route.stops[0].type, StopType.PICK_UP)
        self.assertEqual(route.stops[1].type, StopType.DROP_OFF)
        self.assertEqual(route.stops[2].type, StopType.DROP_OFF)
        self.assertTrue(route.time)
Exemple #29
0
    def test_generate_group_routes(self, osrm):
        """Test to verify how the heuristic to generate routes work"""

        # Constants
        order_1 = Order(order_id=1,
                        pick_up_at=Location(lat=4.678417, lng=-74.054725),
                        drop_off_at=Location(lat=4.717045, lng=-74.036359),
                        ready_time=time(12, 13, 0))
        order_2 = Order(order_id=2,
                        pick_up_at=Location(lat=4.678417, lng=-74.054725),
                        drop_off_at=Location(lat=4.723418, lng=-74.037067),
                        ready_time=time(12, 10, 0))
        order_3 = Order(order_id=3,
                        pick_up_at=Location(lat=4.678417, lng=-74.054725),
                        drop_off_at=Location(lat=4.723418, lng=-74.037067),
                        ready_time=time(12, 30, 0))
        old_order = Order(order_id=9898,
                          pick_up_at=Location(lat=4.678417, lng=-74.054725),
                          drop_off_at=Location(lat=4.727278, lng=-74.039299),
                          ready_time=time(11, 50, 0))
        target_size = 2

        # Case 1: orders routed without initial routes and courier slack
        num_idle_couriers = 4
        routes = MyopicMatchingPolicy._generate_group_routes(
            orders=[order_1, order_2],
            target_size=target_size,
            courier_routes=[],
            num_idle_couriers=num_idle_couriers)
        self.assertTrue(routes)
        self.assertEqual(len(routes), 2)

        routed_orders = [o for route in routes for o in route.orders.keys()]
        for order in [order_1, order_2]:
            self.assertIn(order.order_id, routed_orders)

        # Case 2: orders routed without initial routes and no courier slack
        num_idle_couriers = 0
        routes = MyopicMatchingPolicy._generate_group_routes(
            orders=[order_1, order_2],
            target_size=target_size,
            courier_routes=[],
            num_idle_couriers=num_idle_couriers)
        self.assertTrue(routes)
        self.assertEqual(len(routes), 1)

        routed_orders = [o for route in routes for o in route.orders.keys()]
        for order in [order_1, order_2]:
            self.assertIn(order.order_id, routed_orders)

        # Case 3: orders routed with initial routes and courier slack
        num_idle_couriers = 1
        initial_route = Route(orders={old_order.order_id: old_order},
                              stops=[
                                  Stop(orders={old_order.order_id: old_order},
                                       location=old_order.pick_up_at,
                                       position=0,
                                       type=StopType.PICK_UP),
                                  Stop(orders={old_order.order_id: old_order},
                                       location=old_order.drop_off_at,
                                       position=1,
                                       type=StopType.DROP_OFF)
                              ])
        routes = MyopicMatchingPolicy._generate_group_routes(
            orders=[order_1, order_2],
            target_size=2,
            courier_routes=[initial_route],
            num_idle_couriers=num_idle_couriers,
            max_orders=3,
            courier_ids=[3])
        self.assertTrue(routes)
        self.assertEqual(len(routes), 1)

        routed_orders = [o for route in routes for o in route.orders.keys()]
        for order in [order_1, order_2]:
            self.assertIn(order.order_id, routed_orders)

        self.assertIsNone(routes[0].initial_prospect)

        # Case 4: orders routed without initial routes and insufficient couriers
        num_idle_couriers = 0
        target_size = 5
        routes = MyopicMatchingPolicy._generate_group_routes(
            orders=[order_1, order_2, order_3],
            target_size=target_size,
            courier_routes=[],
            num_idle_couriers=num_idle_couriers)
        self.assertTrue(routes)
        self.assertEqual(len(routes), 1)

        routed_orders = [o for route in routes for o in route.orders.keys()]
        for order in [order_1, order_2, order_3]:
            self.assertIn(order.order_id, routed_orders)
Exemple #30
0
def randomize_endpoint():
    """Select random Yik Yak server to make requests from"""
    # Choose random location and locationize
    locationize_endpoint(Location(randint(-90, 90), randint(-180, 180)))
from objects.user import User
from objects.location import Location

u = User()
u.username = "******"
print u.fetch()

l = Location()
l.id = "[1,2,3]"
print l.fetch()