def test_water_level(self):
        '''Tests if water level increases after watering.'''
        database = MemcachedDatabase()
        world = World()

        robot = Robot("198.1287.fkdfjei", "123")
        robot.set_location((5, 0))
        robot.set_has_water(True)

        plant = Plant()
        plant.set_water_level(30)

        world.plant(plant, (5, 0))

        database.commit()

        action = WaterAction()
        action.do_action(robot, ["198.1287.fkdfjei"])

        database.commit()

        updated_square = world.get_square((5, 0))
        plant = updated_square.get_plant()

        # Checking if honor increased.
        self.assertEqual(robot.get_honor(), 1)

        self.assertEqual(plant.get_water_level(), 100)
        self.assertFalse(robot.get_has_water())
Exemplo n.º 2
0
    def test_bad_name(self):
        '''Tries to born a robot with an invalid name. Should be fail.'''
        population_control = PopulationControl()
        database = MemcachedDatabase()

        database.add_password("OIkdj981HJDJHcnm_1")
        database.add_password("OIkdj981HJDJHcnm_2")
        database.add_password("OIkdj981HJDJHcnm_3")
        database.add_password("OIkdj981HJDJHcnm_4")
        database.commit()

        long_name = "n" * (MAX_ROBOT_NAME + 1)
        with self.assertRaises(LongRobotNameError):
            population_control.execute_command("OIkdj981HJDJHcnm_1", "born", [None, long_name])
        database.rollback()

        with self.assertRaises(LongRobotNameError):
            population_control.execute_command("OIkdj981HJDJHcnm_2", "born", [None, None])
        database.rollback()

        with self.assertRaises(LongRobotNameError):
            population_control.execute_command("OIkdj981HJDJHcnm_3", "born", [None, b"some bytes"])
        database.rollback()

        with self.assertRaises(LongRobotNameError):
            population_control.execute_command("OIkdj981HJDJHcnm_4", "born", [None, database])
        database.rollback()
    def test_specific_point(self):
        '''Gets information of a specific point, and check its result.'''
        database = MemcachedDatabase()
        new_robot = Robot("oie982736hhjf", "lo098173635")
        new_robot.set_location((9, 4))

        database.add_robot(new_robot, (9, 4))
        database.commit()

        action_manager = ActionManager()
        info = action_manager.do_action(new_robot.get_password(), "sense", [new_robot.get_id()])

        self.assertEqual(len(info), 9)
        self.assertEqual(info["9,4"], {"surface_type": MapSquareTypes.SOIL,
                                       "robot": True,
                                       "plant": None})
        self.assertEqual(info["9,3"], {"surface_type": MapSquareTypes.WATER,
                                       "robot": False,
                                       "plant": None})
        self.assertEqual(info["10,5"], {"surface_type": MapSquareTypes.SOIL,
                                        "robot": False,
                                        "plant": None})
        self.assertEqual(info["8,4"], {"surface_type": MapSquareTypes.SOIL,
                                       "robot": False,
                                       "plant": None})
 def setUpClass(cls):
     # Creating a robot that all the tests will use.
     database = MemcachedDatabase()
     world = World()
     robot = Robot(TestGiveBirth.ROBOT_ID, "123")
     world.add_robot(robot, (0, 14))
     database.commit()
    def test_for_update(self):
        '''Tests of for_update flag works correctly.'''
        database = MemcachedDatabase()

        robot_id = "test_for_update_18762"
        robot = Robot(robot_id, "123")
        database.add_robot(robot, (10, 0))
        database.commit()

        new_robot = database.get_robot(robot_id, for_update=True)

        # Testing lock
        with self.assertRaises(LockAlreadyAquiredError):
            database.get_robot(robot_id, for_update=True)

        # Testing commit.
        new_robot.set_alive(False)

        # It shouldn't be changed yet.
        new_robot_2 = database.get_robot(robot_id)
        self.assertNotEqual(new_robot.get_alive(), new_robot_2.get_alive())

        # Actually committing changes.
        database.commit()
        new_robot_2 = database.get_robot(robot_id)
        self.assertEqual(new_robot.get_alive(), new_robot_2.get_alive())

        # Lock should be freed.
        database.get_robot(robot_id, for_update=True)
        database.rollback()
Exemplo n.º 6
0
class Communicator(Singleton):
    '''Interface between listeners and the application.'''

    def _initialize(self):
        self._database = MemcachedDatabase()
        self._action_manager = ActionManager()
        self._population_control = PopulationControl()
        self._admin_handler = AdminHandler()

    def execute_command(self, password, command, args):
        '''Execute client's command.'''

        try:
            if command in ["born", "give_birth"]:
                result = self._population_control.execute_command(password, command, args)
            elif command == "map_data":
                result = self._admin_handler.execute_command(password, command, args)
            else:
                result = self._action_manager.do_action(password, command, args)

            # Committing or rollbacking all changes after the completion of execution.
            self._database.commit()
            return result

        except Exception:
            self._database.rollback()
            raise
    def test_bad_direction(self):
        '''Sends an invalid direction as arguments.'''
        robot_id = "test_bad_direction_18445"
        robot = Robot(robot_id, "123")
        world = World()
        action_manager = ActionManager()
        database = MemcachedDatabase()

        world.add_robot(robot, (12, 6))
        database.commit()

        with self.assertRaises(InvalidArgumentsError):
            action_manager.do_action("123", "move", [robot_id, "U"])

        database.rollback()

        with self.assertRaises(InvalidArgumentsError):
            action_manager.do_action("123", "move", [robot_id, 988])

        database.rollback()

        with self.assertRaises(InvalidArgumentsError):
            action_manager.do_action("123", "move", [robot_id, None])

        database.rollback()

        with self.assertRaises(InvalidArgumentsError):
            action_manager.do_action("123", "move", [robot_id])

        database.rollback()
    def test_invalid_location(self):
        '''Tests adding a robot to an invalid location.'''
        database = MemcachedDatabase()
        robot = Robot("invalid_location_robot_1863", "123")

        with self.assertRaises(InvalidLocationError):
            self._world.add_robot(robot, (19872, 1190))
            database.commit()
    def setUpClass(cls):
        # Addin a robot to the world. All the tests would use this robot.
        robot = Robot(cls.ROBOT_ID, "123")
        world = World()

        world.add_robot(robot, cls.LOCATION)

        database = MemcachedDatabase()
        database.commit()
Exemplo n.º 10
0
    def test_invalid_location(self):
        '''Tests if database checks for invalid locations.'''
        database = MemcachedDatabase()

        new_robot = Robot("test_invalid_location_19887", "123")

        with self.assertRaises(InvalidLocationError):
            database.add_robot(new_robot, (91872, 16652))
            database.commit()
Exemplo n.º 11
0
    def test_duplicate_add(self):
        '''Adding two robots with same ID. Should be failed.'''
        database = MemcachedDatabase()

        new_robot = Robot("test_duplicate_add_", "123")
        database.add_robot(new_robot, (1, 1))
        database.commit()

        robot2 = Robot("test_duplicate_add_", "123")
        with self.assertRaises(CannotAddObjectError):
            database.add_robot(robot2, (1, 2))
            database.commit()
Exemplo n.º 12
0
    def test_blocked_location(self):
        '''Tests adding the robot to a blocked square.'''
        database = MemcachedDatabase()
        robot = Robot("test_blocked_location_91882", "123")

        # There's a rock here.
        self._world.add_robot(robot, (6, 1))
        database.commit()

        received_robot = database.get_robot(robot.get_id())

        self.assertNotEqual(received_robot.get_location(), (6, 1))
Exemplo n.º 13
0
    def test_rollback(self):
        '''Tests if calling rollback works correctly.'''
        database = MemcachedDatabase()

        new_robot = Robot("test_rollback_87162", "123")
        database.add_robot(new_robot, (1, 1))

        database.rollback()
        database.commit()

        with self.assertRaises(RobotNotFoundError):
            database.get_robot("test_rollback_87162")
Exemplo n.º 14
0
    def test_getting_data(self):
        robot = Robot("13329.12900.12213", "123", name="HappyBot")
        robot.set_energy(124)
        robot.set_honor(7)
        robot.set_life(3)
        robot.set_has_water(True)

        plant = Plant()
        plant.set_age(64)
        plant.set_water_level(98)

        database = MemcachedDatabase()
        database.add_robot(robot, (6, 11))
        square = database.get_square((5, 11), for_update=True)
        square.set_plant(plant)
        database.commit()

        expected_result = {
            "5,11": {
                "surface_type": MapSquareTypes.SOIL,
                "plant": {
                    "water_level": 98,
                    "matured": True,
                    "age": 64
                },
                "robot": None
            },
            "6,11": {
                "surface_type": MapSquareTypes.SOIL,
                "plant": None,
                "robot": {
                    "name": "HappyBot",
                    "has_water": True,
                    "energy": 124,
                    "life": 3,
                    "honor": 7
                }
            },
            "6,2": {
                "surface_type": MapSquareTypes.ROCK,
                "robot": None,
                "plant": None
            }
        }

        communicator = Communicator()
        result = communicator.execute_command("NhdEr32Qcmp0Iue3", "map_data",
                                              expected_result.keys())

        self.assertCountEqual(result, expected_result)
        for expected_key, expected_value in expected_result.items():
            self.assertDictEqual(result[expected_key], expected_value)
    def test_blocking_object(self):
        '''Tests moving toward a blocking object.'''
        robot_id = "test_invalid_location_8765112"
        robot = Robot(robot_id, "123")
        world = World()
        action_manager = ActionManager()
        database = MemcachedDatabase()

        world.add_robot(robot, (11, 6))
        database.commit()

        with self.assertRaises(LocationIsBlockedError):
            action_manager.do_action("123", "move", [robot_id, "W"])
Exemplo n.º 16
0
    def test_ok(self):
        '''Tests a good scenario.'''
        population_control = PopulationControl()
        database = MemcachedDatabase()

        database.add_password("iujeh87UYh6512ewQ")

        robot_info = population_control.execute_command("iujeh87UYh6512ewQ", "born", [None, "RDaniel"])
        database.commit()

        gotted_robot = database.get_robot(robot_info['robot_id'])

        self.assertEqual(gotted_robot.get_name(), "RDaniel")
Exemplo n.º 17
0
    def test_duplicate(self):
        '''Tests adding duplicate robot.'''
        database = MemcachedDatabase()
        robot = Robot("world_duplicate_robot_8722", "123")

        self._world.add_robot(robot, (5, 1))

        database.commit()

        robot_2 = Robot("world_duplicate_robot_8722", "1236")
        with self.assertRaises(CannotAddObjectError):
            self._world.add_robot(robot_2, (5, 2))
            database.commit()
Exemplo n.º 18
0
    def test_with_parent(self):
        '''Tests borning a robot with a parent.'''
        population_control = PopulationControl()
        database = MemcachedDatabase()

        database.add_password("oijdnnh76153WEd")
        robot = Robot("test_with_parent_18873", "123")
        database.add_robot(robot, (14, 1))
        database.commit()

        population_control.execute_command("oijdnnh76153WEd", "born", ["test_with_parent_18873", "My Child"])

        database.rollback()
    def test_blind_point(self):
        '''Gets information of a point, but don't care about the result.'''
        database = MemcachedDatabase()
        new_robot = Robot("1873yudhNCbueio", "ueijdnchiop")
        new_robot.set_location((9, 7))

        database.add_robot(new_robot, (9, 7))
        database.commit()

        action_manager = ActionManager()
        info = action_manager.do_action(new_robot.get_password(), "sense", [new_robot.get_id()])

        self.assertEqual(len(info), 9)
    def test_corner(self):
        '''Tests getting a corner of the map.'''
        database = MemcachedDatabase()
        new_robot = Robot("0981kdjieu871", "oie987163")
        new_robot.set_location((0, 1))

        database.add_robot(new_robot, (0, 1))
        database.commit()

        action_manager = ActionManager()
        info = action_manager.do_action(new_robot.get_password(), "sense", [new_robot.get_id()])

        self.assertEqual(len(info), 6)
Exemplo n.º 21
0
    def test_blind_point(self):
        '''Gets information of a point, but don't care about the result.'''
        database = MemcachedDatabase()
        new_robot = Robot("1873yudhNCbueio", "ueijdnchiop")
        new_robot.set_location((9, 7))

        database.add_robot(new_robot, (9, 7))
        database.commit()

        action_manager = ActionManager()
        info = action_manager.do_action(new_robot.get_password(), "sense",
                                        [new_robot.get_id()])

        self.assertEqual(len(info), 9)
Exemplo n.º 22
0
    def test_corner(self):
        '''Tests getting a corner of the map.'''
        database = MemcachedDatabase()
        new_robot = Robot("0981kdjieu871", "oie987163")
        new_robot.set_location((0, 1))

        database.add_robot(new_robot, (0, 1))
        database.commit()

        action_manager = ActionManager()
        info = action_manager.do_action(new_robot.get_password(), "sense",
                                        [new_robot.get_id()])

        self.assertEqual(len(info), 6)
Exemplo n.º 23
0
    def test_ok(self):
        '''Tests a good scenario.'''
        population_control = PopulationControl()
        database = MemcachedDatabase()

        database.add_password("iujeh87UYh6512ewQ")

        robot_info = population_control.execute_command(
            "iujeh87UYh6512ewQ", "born", [None, "RDaniel"])
        database.commit()

        gotted_robot = database.get_robot(robot_info['robot_id'])

        self.assertEqual(gotted_robot.get_name(), "RDaniel")
Exemplo n.º 24
0
    def test_ok(self):
        '''Adds a good robot object to the world.'''
        database = MemcachedDatabase()
        robot = Robot("world_ok_robot_38364", "123")

        self._world.add_robot(robot, (5, 0))
        database.commit()

        gotted_robot = database.get_robot(robot.get_id())

        self.assertEqual(gotted_robot.get_alive(), robot.get_alive())

        all_robots = database.get_all_robot_ids()
        self.assertIn(robot.get_id(), all_robots)
Exemplo n.º 25
0
    def test_with_parent(self):
        '''Tests borning a robot with a parent.'''
        population_control = PopulationControl()
        database = MemcachedDatabase()

        database.add_password("oijdnnh76153WEd")
        robot = Robot("test_with_parent_18873", "123")
        database.add_robot(robot, (14, 1))
        database.commit()

        population_control.execute_command(
            "oijdnnh76153WEd", "born", ["test_with_parent_18873", "My Child"])

        database.rollback()
Exemplo n.º 26
0
    def test_not_enough_honor(self):
        '''Tests a robot with few honors, trying to give birth.'''
        population_control = PopulationControl()
        database = MemcachedDatabase()
        configs = Configs()

        robot = database.get_robot(TestGiveBirth.ROBOT_ID, for_update=True)
        robot.set_honor(configs.get_robots_birth_required_honor() - 1)
        database.commit()

        with self.assertRaises(NotEnoughHonorError):
            population_control.execute_command("123", "give_birth", [TestGiveBirth.ROBOT_ID])

        database.rollback()
Exemplo n.º 27
0
    def test_locked_location(self):
        '''Tests adding a robot to a locked location.'''
        database = MemcachedDatabase()
        robot = Robot("test_locked_location_0023", "123")

        # Locking 8,1
        database.get_square((8, 1), for_update=True)

        self._world.add_robot(robot, (8, 1))
        database.commit()

        received_robot = database.get_robot(robot.get_id())

        self.assertNotEqual(received_robot.get_location(), (8, 1))
Exemplo n.º 28
0
    def test_out_of_water(self):
        '''Tests if plant die after running out of water.'''
        plant = Plant()
        world = World()
        database = MemcachedDatabase()

        world.plant(plant, (4, 8))
        database.commit()

        # Waiting for 11 cycles.
        time.sleep(11 * 0.03)

        square = world.get_square((4, 8), for_update=False)

        self.assertIsNone(square.get_plant())
    def test_moving_outside(self):
        '''Tests moving a robot to outside of the world.'''
        robot_id = "test_moving_outside_981165"
        robot = Robot(robot_id, "123")
        world = World()
        action_manager = ActionManager()
        database = MemcachedDatabase()

        world.add_robot(robot, (14, 2))
        database.commit()

        with self.assertRaises(InvalidLocationError):
            action_manager.do_action("123", "move", [robot_id, "E"])

        database.rollback()
    def test_out_of_water(self):
        '''Tests if plant die after running out of water.'''
        plant = Plant()
        world = World()
        database = MemcachedDatabase()

        world.plant(plant, (4, 8))
        database.commit()

        # Waiting for 11 cycles.
        time.sleep(11 * 0.03)

        square = world.get_square((4, 8), for_update=False)

        self.assertIsNone(square.get_plant())
Exemplo n.º 31
0
    def test_simple_add(self):
        '''Test adding a single robot to database.'''
        database = MemcachedDatabase()

        new_robot = Robot("test_simple_add_", "123")

        # No exception should be raise.
        database.add_robot(new_robot, (0, 0))
        database.commit()

        gotted_robot = database.get_robot("test_simple_add_")

        self.assertEqual(gotted_robot.get_id(), new_robot.get_id())
        self.assertEqual(gotted_robot.get_alive(), new_robot.get_alive())
        self.assertEqual(gotted_robot.get_password(), new_robot.get_password())
Exemplo n.º 32
0
    def test_not_enough_honor(self):
        '''Tests a robot with few honors, trying to give birth.'''
        population_control = PopulationControl()
        database = MemcachedDatabase()
        configs = Configs()

        robot = database.get_robot(TestGiveBirth.ROBOT_ID, for_update=True)
        robot.set_honor(configs.get_robots_birth_required_honor() - 1)
        database.commit()

        with self.assertRaises(NotEnoughHonorError):
            population_control.execute_command("123", "give_birth",
                                               [TestGiveBirth.ROBOT_ID])

        database.rollback()
Exemplo n.º 33
0
    def test_locked(self):
        '''Tests with a locked square.'''
        database = MemcachedDatabase()
        world = World()

        robot = Robot("test_locked_robot_190083", "123")
        # Setting the energy to zero, so the updater tries to update the square too.
        robot.set_energy(0)

        world.add_robot(robot, (5, 9))
        database.commit()

        world.get_square((5, 9), for_update=True)

        with self.assertRaises(LockAlreadyAquiredError):
            database.get_robot(robot.get_id(), for_update=True)
    def test_locked(self):
        '''Tests with a locked square.'''
        database = MemcachedDatabase()
        world = World()

        robot = Robot("test_locked_robot_190083", "123")
        # Setting the energy to zero, so the updater tries to update the square too.
        robot.set_energy(0)

        world.add_robot(robot, (5, 9))
        database.commit()

        world.get_square((5, 9), for_update=True)

        with self.assertRaises(LockAlreadyAquiredError):
            database.get_robot(robot.get_id(), for_update=True)
    def test_out_of_energy_robot(self):
        '''Tests when a robot ran out of energy.'''
        database = MemcachedDatabase()
        world = World()

        robot = Robot("test_out_of_energy_robot_18773", "123")
        robot.set_energy(0)

        world.add_robot(robot, (1, 9))
        database.commit()

        got_robot = database.get_robot("test_out_of_energy_robot_18773", for_update=False)
        self.assertFalse(got_robot.get_alive())

        square = world.get_square((1, 9))
        self.assertIsNone(square.get_robot_id())
    def test_out_of_life_robot(self):
        '''Tests when a robot ran out of life.'''
        database = MemcachedDatabase()
        world = World()

        robot = Robot("test_out_of_life_robot_9022", "123")
        robot.set_life(0)

        world.add_robot(robot, (0, 9))
        database.commit()

        received_robot = database.get_robot("test_out_of_life_robot_9022", for_update=False)
        self.assertFalse(received_robot.get_alive())

        square = world.get_square((0, 9))
        self.assertIsNone(square.get_robot_id())
Exemplo n.º 37
0
    def test_out_of_life_robot(self):
        '''Tests when a robot ran out of life.'''
        database = MemcachedDatabase()
        world = World()

        robot = Robot("test_out_of_life_robot_9022", "123")
        robot.set_life(0)

        world.add_robot(robot, (0, 9))
        database.commit()

        received_robot = database.get_robot("test_out_of_life_robot_9022",
                                            for_update=False)
        self.assertFalse(received_robot.get_alive())

        square = world.get_square((0, 9))
        self.assertIsNone(square.get_robot_id())
    def test_lock(self):
        '''Tests if location is locked.'''
        robot_id = "test_move_lock_76120"
        robot = Robot(robot_id, "123")
        world = World()
        action_manager = ActionManager()
        database = MemcachedDatabase()

        world.add_robot(robot, (13, 6))
        database.commit()

        database.get_square((13, 7), for_update=True)

        with self.assertRaises(LockAlreadyAquiredError):
            action_manager.do_action("123", "move", [robot_id, "S"])

        database.rollback()
    def test_locked_square(self):
        '''Tests updating a locked square.'''
        plant = Plant()
        world = World()
        database = MemcachedDatabase()

        world.plant(plant, (7, 8))
        database.commit()

        # Locking the square.
        world.get_square((7, 8), for_update=True)

        # Sleeping one cycle.
        time.sleep(0.031)

        with self.assertRaises(LockAlreadyAquiredError):
            world.get_square((7, 8), for_update=False)
Exemplo n.º 40
0
    def test_rollback(self):
        '''Tests if changes rolls back correctly.'''
        database = MemcachedDatabase()

        robot_id = "test_rollback_18098"
        robot = Robot(robot_id, "123")
        database.add_robot(robot, (11, 0))
        database.commit()

        new_robot = database.get_robot(robot_id, for_update=True)
        new_robot.set_alive(False)

        database.rollback()
        database.commit()

        new_robot_2 = database.get_robot(robot_id)
        self.assertNotEqual(new_robot.get_alive(), new_robot_2.get_alive())
Exemplo n.º 41
0
    def test_rollback(self):
        '''Tests if changes rolls back correctly.'''
        database = MemcachedDatabase()

        robot_id = "test_rollback_18098"
        robot = Robot(robot_id, "123")
        database.add_robot(robot, (11, 0))
        database.commit()

        new_robot = database.get_robot(robot_id, for_update=True)
        new_robot.set_alive(False)

        database.rollback()
        database.commit()

        new_robot_2 = database.get_robot(robot_id)
        self.assertNotEqual(new_robot.get_alive(), new_robot_2.get_alive())
Exemplo n.º 42
0
    def test_out_of_energy_robot(self):
        '''Tests when a robot ran out of energy.'''
        database = MemcachedDatabase()
        world = World()

        robot = Robot("test_out_of_energy_robot_18773", "123")
        robot.set_energy(0)

        world.add_robot(robot, (1, 9))
        database.commit()

        got_robot = database.get_robot("test_out_of_energy_robot_18773",
                                       for_update=False)
        self.assertFalse(got_robot.get_alive())

        square = world.get_square((1, 9))
        self.assertIsNone(square.get_robot_id())
Exemplo n.º 43
0
    def test_locked_square(self):
        '''Tests updating a locked square.'''
        plant = Plant()
        world = World()
        database = MemcachedDatabase()

        world.plant(plant, (7, 8))
        database.commit()

        # Locking the square.
        world.get_square((7, 8), for_update=True)

        # Sleeping one cycle.
        time.sleep(0.031)

        with self.assertRaises(LockAlreadyAquiredError):
            world.get_square((7, 8), for_update=False)
Exemplo n.º 44
0
    def test_one_cycle(self):
        '''Tests if plant updates correctly after one cycle.'''
        plant = Plant()
        world = World()
        database = MemcachedDatabase()

        world.plant(plant, (3, 8))
        database.commit()

        # Sleeping one cycle.
        time.sleep(0.031)

        square = world.get_square((3, 8), for_update=False)

        plant = square.get_plant()

        self.assertEqual(plant.get_age(), 1)
        self.assertEqual(plant.get_water_level(), 90)
Exemplo n.º 45
0
    def test_maximum_age(self):
        '''Tests if plant die after maximum age.'''
        plant = Plant()
        world = World()
        database = MemcachedDatabase()

        world.plant(plant, (11, 8))
        database.commit()

        square = world.get_square((11, 8), for_update=True)
        plant = square.get_plant()
        plant.set_age(40)
        database.commit()

        # Sleeping one cycle.
        time.sleep(0.031)

        square = world.get_square((11, 8), for_update=False)
        self.assertIsNone(square.get_plant())
Exemplo n.º 46
0
    def test_ok(self):
        '''Tests a valid situation.'''
        population_control = PopulationControl()
        database = MemcachedDatabase()
        configs = Configs()

        robot = database.get_robot(TestGiveBirth.ROBOT_ID, for_update=True)
        robot.set_honor(configs.get_robots_birth_required_honor() + 1)
        database.commit()

        new_password = population_control.execute_command(
            "123", "give_birth", [TestGiveBirth.ROBOT_ID])
        database.commit()

        updated_robot = database.get_robot(TestGiveBirth.ROBOT_ID,
                                           for_update=False)

        self.assertEqual(updated_robot.get_honor(), 1)
        self.assertTrue(isinstance(new_password, str))
        self.assertEqual(len(new_password), 16)
Exemplo n.º 47
0
    def test_no_cycle_passed(self):
        '''Tests if plant not changed if no cycle passed.'''
        world = World()
        database = MemcachedDatabase()
        plant = Plant()
        plant.set_age(2)
        plant.set_water_level(70)

        world.plant(plant, (6, 8))
        database.commit()

        # Waiting just a little.
        time.sleep(0.01)

        square = world.get_square((6, 8), for_update=False)
        received_plant = square.get_plant()

        self.assertEqual(received_plant.get_age(), plant.get_age())
        self.assertEqual(received_plant.get_water_level(),
                         plant.get_water_level())
        self.assertEqual(received_plant.get_last_update(),
                         plant.get_last_update())
Exemplo n.º 48
0
    def test_concurrent_add_failure(self):
        '''Tests the behavior of Database class, when concurrent add fails.'''

        # Mocking `cas' method, making it always return False.
        def mocked_cas(*args):
            return False
        mc_connection = MemcachedConnection().get_connection()
        original_cas = mc_connection.cas
        mc_connection.cas = unittest.mock.Mock(side_effect=mocked_cas)

        try:
            new_robot = Robot("test_concurrent_add_failure_9865", "123")
            database = MemcachedDatabase()

            with self.assertRaises(CouldNotSetValueBecauseOfConcurrencyError):
                database.add_robot(new_robot, (1, 1))
                database.commit()

        finally:
            # Setting back the original cas method.
            mc_connection.cas = original_cas

        # Checking to see added robot is clearly rolled back.
        self.assertFalse(mc_connection.get(new_robot.get_id()))
Exemplo n.º 49
0
    def test_eating_not_matured(self):
        '''Tests when robot eat a non matured plant.'''
        world = World()
        database = MemcachedDatabase()
        action_manager = ActionManager()
        plant = Plant()
        plant.set_age(1)

        world.plant(plant, TestEatAction.LOCATION)
        database.commit()

        robot = database.get_robot(TestEatAction.ROBOT_ID, for_update=True)
        robot.set_energy(10)
        database.commit()

        action_manager.do_action("123", "eat", [TestEatAction.ROBOT_ID])
        database.commit()

        updated_robot = database.get_robot(TestEatAction.ROBOT_ID)
        self.assertEqual(updated_robot.get_energy(), robot.get_energy() - 1)
Exemplo n.º 50
0
class ActionManager:

    def __init__(self):
        self._authenticator = Authenticator()
        self._database = MemcachedDatabase()

        configs = Configs()
        self._robots_action_delay = configs.get_robots_actions_delay() / 1000

        self._actions = {'status': StatusAction(),
                         'sense': SenseAction(),
                         'move': MoveAction(),
                         'plant': PlantAction(),
                         'pick_water': PickWaterAction(),
                         'info': InfoAction(),
                         'eat': EatAction(),
                         'water': WaterAction()}

    def do_action(self, password, action_type, args):
        '''Will do the requested action.'''
        if len(args) == 0:
            raise exceptions.InvalidArgumentsError("`robot_id' should be passes as the first argument.")

        robot_id = args[0]
        if not isinstance(robot_id, str):
            raise exceptions.InvalidArgumentsError(
                "First argument (robot_id) should be a string, not {0}".format(type(robot_id)))

        robot = None
        try:
            robot = self._database.get_robot(robot_id, for_update=True)

            self._authenticator.authenticate_robot(robot, password)

            actions_delay = time.time() - robot.get_last_executed_action_time()
            if actions_delay < self._robots_action_delay:
                # Robot is sending actions too fast. Putting a delay between its actions.
                time.sleep(self._robots_action_delay - actions_delay)

            handler = self._get_action_handler(action_type)

            result = handler.do_action(robot, args)

            # Reducing age and energy.
            robot.set_energy(robot.get_energy() - 1)
            robot.set_life(robot.get_life() - 1)

            # Updating last executed action time.
            robot.set_last_executed_action_time(time.time())

            return result

        except LockAlreadyAquiredError as error:
            # Logging all concurrency errors, so we can investigate them later.
            Logger().info("LockAlreadyAquiredError: {0}".format(error))
            raise
        except AuthenticationFailedError:
            raise
        except BinarySkyException:
            # Concurrency exception is a fault of the server. Also, we ignored
            # authentication errors. Otherwise, robot should lose energy and age.

            # Note that we didn't handled unexpected errors (e.g. Exception class).
            # XXX: Dirty code. It shouldn't rollback and/or commit database changes.
            #      But right now, there's no better way.
            self._database.rollback()
            if robot is None:
                # Seems we couldn't even get the robot. So, robot didn't do any actions
                # and shouldn't lose energy and age.
                raise

            robot = self._database.get_robot(robot_id, for_update=True)
            robot.set_energy(robot.get_energy() - 1)
            robot.set_life(robot.get_life() - 1)
            robot.set_last_executed_action_time(time.time())

            self._database.commit()

            raise


    def _get_action_handler(self, action_type):
        '''Returns instance that should handle this action.'''
        if not isinstance(action_type, str):
            raise exceptions.InvalidActionError("Action type must be str, not {0}".format(type(action_type)))

        handler = self._actions.get(action_type)

        if handler is None:
            raise exceptions.InvalidActionError("Action {0} does not exists.".format(action_type))

        return handler
Exemplo n.º 51
0
class ObjectUpdater(DatabaseHook):
    '''This class checks objects in the world, and updates them
    if required.

    Responsibilities of this class:
        * Killing and removing a robot from the world, if its
          energy reached zero or it ran out of life.
        * Removing a plant from the world if its water level
          reached zero or it became too old.
        * Maturing a plant if it reached a certain age.
        * Updating a plant's water level during time.
    '''
    def __init__(self):
        self._database = MemcachedDatabase()
        self._configs = Configs()

    def robot_got(self, robot_object, locked_for_update):
        '''Checks and updates the specified robot's object.'''
        if robot_object.get_energy() <= 0 or robot_object.get_life() <= 0:

            if not locked_for_update:
                # This would call this method again, and robot will be updated.
                return self._database.get_robot(robot_object.get_id(),
                                                for_update=True)

            robot_object.set_alive(False)

            # Removing the robot from its location.
            try:
                square = self._database.get_square(robot_object.get_location(),
                                                   for_update=True)
            except LockAlreadyAquiredError:
                # Trying one more time.
                time.sleep(0.02)
                square = self._database.get_square(robot_object.get_location(),
                                                   for_update=True)

            square.set_robot_id(None)

            # XXX: Though it's a very dirty thing to do, we have to commit these changes, because
            #      later this robot will face an Authentication Exception, and our changes will be
            #      lost.
            self._database.commit()

            # Immediately, locking the robot object. It's not atomic, so there's a little chance
            # that concurrency happens. But, it shouldn't be a problem, since the robot is already
            # dead, and can't do anything anyway.
            self._database.get_lock(robot_object.get_id())

        return robot_object

    def square_got(self, location, square_object, locked_for_update):
        '''Checks and updates specified square object.'''
        plant = square_object.get_plant()

        if plant is None:
            return square_object

        # Time passed from the last time this plant updated.
        last_update = time.time() - plant.get_last_update()
        passed_cycles = math.floor(last_update /
                                   (self._configs.get_plant_cylce() / 1000))

        if passed_cycles <= 0:
            # No cycle passed, no need to be updated.
            return square_object

        if not locked_for_update:
            # This will call this method again.
            try:
                return self._database.get_square(location, for_update=True)
            except LockAlreadyAquiredError:
                # Trying one more time.
                time.sleep(0.02)
                return self._database.get_square(location, for_update=True)

        plant.set_age(plant.get_age() + passed_cycles)
        plant.set_water_level(plant.get_water_level() -
                              (passed_cycles *
                               self._configs.get_plant_lose_water_in_cycle()))

        if plant.get_age() > self._configs.get_plant_max_age(
        ) or plant.get_water_level() <= 0:
            # Plant is dead! Removing it from the world.
            square_object.set_plant(None)

        plant.set_last_update(time.time())

        return square_object
    def test_directions(self):
        '''Tests if moving in different directions works correctly.'''
        robot_id = "test_directions_154332"
        robot = Robot(robot_id, "123")
        world = World()
        database = MemcachedDatabase()

        world.add_robot(robot, (10, 2))
        database.commit()

        action_manager = ActionManager()

        action_manager.do_action("123", "move", [robot_id, "N"])
        database.commit()
        robot = database.get_robot(robot_id)
        self.assertEqual(robot.get_location(), (10, 1))

        action_manager.do_action("123", "move", [robot_id, "NE"])
        database.commit()
        robot = database.get_robot(robot_id)
        self.assertEqual(robot.get_location(), (11, 0))

        action_manager.do_action("123", "move", [robot_id, "E"])
        database.commit()
        robot = database.get_robot(robot_id)
        self.assertEqual(robot.get_location(), (12, 0))

        action_manager.do_action("123", "move", [robot_id, "SE"])
        database.commit()
        robot = database.get_robot(robot_id)
        self.assertEqual(robot.get_location(), (13, 1))

        action_manager.do_action("123", "move", [robot_id, "S"])
        database.commit()
        robot = database.get_robot(robot_id)
        self.assertEqual(robot.get_location(), (13, 2))

        action_manager.do_action("123", "move", [robot_id, "SW"])
        database.commit()
        robot = database.get_robot(robot_id)
        self.assertEqual(robot.get_location(), (12, 3))

        action_manager.do_action("123", "move", [robot_id, "W"])
        database.commit()
        robot = database.get_robot(robot_id)
        self.assertEqual(robot.get_location(), (11, 3))

        action_manager.do_action("123", "move", [robot_id, "NW"])
        database.commit()
        robot = database.get_robot(robot_id)
        self.assertEqual(robot.get_location(), (10, 2))
class TestActionManager(unittest.TestCase):
    def __init__(self, *args, **kwargs):
        super(TestActionManager, self).__init__(*args, **kwargs)

        self._action_manager = ActionManager()
        self._database = MemcachedDatabase()

    def tearDown(self):
        # Rolling back any remaining thing.
        self._database.rollback()

    def test_not_exist_robot(self):
        '''Test if ActionManager handles not-existed robot.'''
        with self.assertRaises(RobotNotFoundError):
            self._action_manager.do_action("123", "move",
                                           ["not_existed_robot_id"])

    def test_bad_robot_id(self):
        '''Test invalid robot IDs.'''
        # Note that listeners checks if `args' is a list, so action manager won't receive another type.

        with self.assertRaises(actions.exceptions.InvalidArgumentsError):
            self._action_manager.do_action("123", "move", [])

        with self.assertRaises(actions.exceptions.InvalidArgumentsError):
            self._action_manager.do_action("123", "move", [None])

    def test_invalid_password(self):
        '''Test if ActionManager authenticate passwords correctly.'''
        robot = Robot("test_invalid_password_95312", "andhue-ifue876-fkdnpw-1")
        self._database.add_robot(robot, (3, 1))
        self._database.commit()

        with self.assertRaises(AuthenticationFailedError):
            self._action_manager.do_action("ieukjdf-ioquiwe-751io", "status",
                                           ["test_invalid_password_95312"])

    def test_dead_robot(self):
        '''Test if ActionManager checks a dead robot.'''
        robot = Robot("test_dead_robot_98176", "1234")
        robot.set_alive(False)
        self._database.add_robot(robot, (3, 2))
        self._database.commit()

        with self.assertRaises(AuthenticationFailedError):
            self._action_manager.do_action("1234", "status",
                                           ["test_dead_robot_98176"])

    def test_bad_actions(self):
        '''Test wrong action IDs.'''
        robot = Robot("test_bad_actions_2376", "123")
        self._database.add_robot(robot, (4, 1))
        self._database.commit()

        with self.assertRaises(actions.exceptions.InvalidActionError):
            self._action_manager.do_action("123", "not-exist-action",
                                           ["test_bad_actions_2376"])

        self._database.rollback()
        with self.assertRaises(actions.exceptions.InvalidActionError):
            self._action_manager.do_action("123", 5432,
                                           ["test_bad_actions_2376"])

        self._database.rollback()
        with self.assertRaises(actions.exceptions.InvalidActionError):
            self._action_manager.do_action("123", None,
                                           ["test_bad_actions_2376"])

        self._database.rollback()
        with self.assertRaises(actions.exceptions.InvalidActionError):
            self._action_manager.do_action("123", "",
                                           ["test_bad_actions_2376"])

    def test_ok(self):
        '''Execute a fine action.'''
        robot = Robot("test_ok_action_3278", "4467yrt-ddfjh-1u872-oiie")
        self._database.add_robot(robot, (3, 3))
        self._database.commit()

        initial_energy = robot.get_energy()
        initial_age = robot.get_life()

        result = self._action_manager.do_action("4467yrt-ddfjh-1u872-oiie",
                                                "status",
                                                ["test_ok_action_3278"])

        self.assertEqual(result['alive'], True)

        # Robot should lost energy and age.
        self._database.commit()
        robot = self._database.get_robot("test_ok_action_3278")
        self.assertEqual(robot.get_energy(), initial_energy - 1)
        self.assertEqual(robot.get_life(), initial_age - 1)

    def test_losing_energy_on_error(self):
        '''Tests if ActionManager reduces energy and age after an exception.'''
        robot = Robot("test_losing_energy_on_error_981", "091oikjdmncj")
        self._database.add_robot(robot, (5, 3))
        self._database.commit()

        initial_energy = robot.get_energy()
        initial_age = robot.get_life()

        with self.assertRaises(actions.exceptions.InvalidActionError):
            self._action_manager.do_action("091oikjdmncj", "invalid_action",
                                           ["test_losing_energy_on_error_981"])

        self._database.commit()
        robot = self._database.get_robot("test_losing_energy_on_error_981")
        self.assertEqual(robot.get_energy(), initial_energy - 1)
        self.assertEqual(robot.get_life(), initial_age - 1)

        # Robot shouldn't lose energy on authentication error.
        with self.assertRaises(AuthenticationFailedError):
            self._action_manager.do_action("wrong pass", "invalid_action",
                                           ["test_losing_energy_on_error_981"])

        self._database.rollback()
        robot = self._database.get_robot("test_losing_energy_on_error_981")
        self.assertEqual(robot.get_energy(), initial_energy - 1)
        self.assertEqual(robot.get_life(), initial_age - 1)

    def test_delay(self):
        '''Tests delay between robot actions.'''
        robot = Robot("test_delay_1223", "09112345")
        self._database.add_robot(robot, (6, 3))
        self._database.commit()

        self._action_manager.do_action("09112345", "sense", [robot.get_id()])
        self._database.commit()

        start_time = time.time()
        self._action_manager.do_action("09112345", "sense", [robot.get_id()])
        elapsed_time = time.time() - start_time
        self._database.commit()

        # one millisecond reduced from delay to cover error.
        self.assertGreater(elapsed_time, 0.029)
    def test_robot_simulation(self):
        '''This test simulates a full game scenario.'''
        database = MemcachedDatabase()
        world = World()
        configs = Configs()

        print()
        print("Simulating a robot playing the game. This may take a while.")

        # Creating a world for the robot to live in.
        # The world map is:
        #
        #    000000
        #    000222
        #    000144
        #    000144

        row01 = [
            MapSquare(MapSquareTypes.SOIL, (0, 30)),
            MapSquare(MapSquareTypes.SOIL, (1, 30)),
            MapSquare(MapSquareTypes.SOIL, (2, 30)),
            MapSquare(MapSquareTypes.SOIL, (3, 30)),
            MapSquare(MapSquareTypes.SOIL, (4, 30)),
            MapSquare(MapSquareTypes.SOIL, (5, 30))
        ]
        row02 = [
            MapSquare(MapSquareTypes.SOIL, (0, 31)),
            MapSquare(MapSquareTypes.SOIL, (1, 31)),
            MapSquare(MapSquareTypes.SOIL, (2, 31)),
            MapSquare(MapSquareTypes.ROCK, (3, 31)),
            MapSquare(MapSquareTypes.ROCK, (4, 31)),
            MapSquare(MapSquareTypes.ROCK, (5, 31))
        ]
        row03 = [
            MapSquare(MapSquareTypes.SOIL, (0, 32)),
            MapSquare(MapSquareTypes.SOIL, (1, 32)),
            MapSquare(MapSquareTypes.SOIL, (2, 32)),
            MapSquare(MapSquareTypes.SAND, (3, 32)),
            MapSquare(MapSquareTypes.WATER, (4, 32)),
            MapSquare(MapSquareTypes.WATER, (5, 32))
        ]
        row04 = [
            MapSquare(MapSquareTypes.SOIL, (0, 33)),
            MapSquare(MapSquareTypes.SOIL, (1, 33)),
            MapSquare(MapSquareTypes.SOIL, (2, 33)),
            MapSquare(MapSquareTypes.SAND, (3, 33)),
            MapSquare(MapSquareTypes.WATER, (4, 33)),
            MapSquare(MapSquareTypes.WATER, (5, 33))
        ]

        database.add_square_row(row01)
        database.add_square_row(row02)
        database.add_square_row(row03)
        database.add_square_row(row04)

        # Creating parent of our robot.
        parent_robot = Robot("parent_robot_1982.345", "123", name="Parent")
        parent_robot.set_honor(configs.get_robots_birth_required_honor() + 1)
        world.add_robot(parent_robot, (2, 31))
        database.commit()

        # Giving birth to our hero.
        result = self.post_request({
            'command': 'give_birth',
            'password': '******',
            'args': ["parent_robot_1982.345"]
        })
        self.assertEqual(result['status'], 200, result)
        born_password = result['result']

        # Robot requests a born.
        result = self.post_request({
            'command': 'born',
            'password': born_password,
            'args': [parent_robot.get_id()]
        })
        self.assertEqual(result['status'], 200)
        robot_id = result['result']['robot_id']
        password = result['result']['password']

        # Getting status.
        result = self.post_request({
            'command': 'status',
            'password': password,
            'args': [robot_id]
        })
        self.assertEqual(result['status'], 200, result)
        self.assertTrue(result['result']['alive'])
        self.assertFalse(result['result']['has_water'])
        self.assertEqual(result['result']['location'], "2,30")

        # Moving somewhere to plan a corp.
        # Note that parent robot is on the south. So, we have to turn around it.
        result = self.post_request({
            'command': 'move',
            'password': password,
            'args': [robot_id, 'W']
        })
        self.assertEqual(result['status'], 200, result)
        result = self.post_request({
            'command': 'move',
            'password': password,
            'args': [robot_id, 'S']
        })
        self.assertEqual(result['status'], 200, result)
        result = self.post_request({
            'command': 'move',
            'password': password,
            'args': [robot_id, 'S']
        })
        self.assertEqual(result['status'], 200, result)
        result = self.post_request({
            'command': 'move',
            'password': password,
            'args': [robot_id, 'E']
        })
        self.assertEqual(result['status'], 200, result)

        # We are at the location. Checking if its correct.
        result = self.post_request({
            'command': 'status',
            'password': password,
            'args': [robot_id]
        })
        self.assertEqual(result['status'], 200, result)
        self.assertEqual(result['result']['location'], "2,32")

        # Planting a corp here.
        result = self.post_request({
            'command': 'plant',
            'password': password,
            'args': [robot_id]
        })
        self.assertEqual(result['status'], 200, result)

        # Checking if it is planted.
        result = self.post_request({
            'command': 'sense',
            'password': password,
            'args': [robot_id]
        })
        self.assertEqual(result['status'], 200, result)
        self.assertEqual(result['result']['2,32']['surface_type'],
                         MapSquareTypes.SOIL)
        self.assertIsNotNone(result['result']['2,32']['plant'])

        # Going to pick water.
        result = self.post_request({
            'command': 'move',
            'password': password,
            'args': [robot_id, 'E']
        })
        self.assertEqual(result['status'], 200, result)
        result = self.post_request({
            'command': 'move',
            'password': password,
            'args': [robot_id, 'E']
        })
        self.assertEqual(result['status'], 200, result)

        result = self.post_request({
            'command': 'pick_water',
            'password': password,
            'args': [robot_id]
        })
        self.assertEqual(result['status'], 200, result)

        result = self.post_request({
            'command': 'status',
            'password': password,
            'args': [robot_id]
        })
        self.assertEqual(result['status'], 200, result)
        self.assertTrue(result['result']['has_water'])

        # Getting back to the plant location.
        result = self.post_request({
            'command': 'move',
            'password': password,
            'args': [robot_id, 'W']
        })
        self.assertEqual(result['status'], 200, result)
        result = self.post_request({
            'command': 'move',
            'password': password,
            'args': [robot_id, 'W']
        })
        self.assertEqual(result['status'], 200, result)

        # Watering
        result = self.post_request({
            'command': 'water',
            'password': password,
            'args': [robot_id]
        })
        self.assertEqual(result['status'], 200, result)

        # Checking
        result = self.post_request({
            'command': 'sense',
            'password': password,
            'args': [robot_id]
        })
        self.assertEqual(result['status'], 200, result)
        # It lost some water already.
        self.assertGreater(result['result']['2,32']['plant']['water_level'],
                           70)

        # Plant should be matured by now. Eating!
        result = self.post_request({
            'command': 'status',
            'password': password,
            'args': [robot_id]
        })
        self.assertEqual(result['status'], 200, result)
        previous_energy = result['result']['energy']

        result = self.post_request({
            'command': 'eat',
            'password': password,
            'args': [robot_id]
        })
        self.assertEqual(result['status'], 200, result)

        result = self.post_request({
            'command': 'status',
            'password': password,
            'args': [robot_id]
        })
        self.assertEqual(result['status'], 200, result)
        self.assertGreater(result['result']['energy'], previous_energy)

        # Now, trying some bad moves!

        # Trying to plant on a sand.
        result = self.post_request({
            'command': 'move',
            'password': password,
            'args': [robot_id, 'E']
        })
        self.assertEqual(result['status'], 200, result)

        result = self.post_request({
            'command': 'plant',
            'password': password,
            'args': [robot_id]
        })
        self.assertEqual(result['status'], 500, result)
        self.assertEqual(result['error_code'], 'CannotPlantHereError')

        # Trying to move to a rock.
        result = self.post_request({
            'command': 'move',
            'password': password,
            'args': [robot_id, 'N']
        })
        self.assertEqual(result['status'], 500, result)
        self.assertEqual(result['error_code'], 'LocationIsBlockedError')