예제 #1
0
void run_operation_checks(TestServerAccount * ac, Entity * chr, WorldRouter & world)
{
    // Entity injection test
    {
        Anonymous ent;

        // Add the test attributes
        ent->setAttr("objtype", "obj");
        ent->setAttr("name", "test_entity");
        ent->setParents(std::list<std::string>(1,"thing"));
        
        Create op;
        OpVector res;
        op->setArgs1(ent);
        ac->operation(op, res);
        
        Entity *reply = world.findByName("test_entity");
        assert(reply != 0);
    }
    
    // Regular create op tests
    {
        // This is the only op we've overridden
        Create op;
        OpVector res;
        ac->operation(op, res);
        op->setArgs1(Root());
        ac->operation(op, res);
        Anonymous op_arg;
        op->setArgs1(op_arg);
        ac->operation(op, res);
        op_arg->setParents(std::list<std::string>());
        ac->operation(op, res);
        op_arg->setParents(std::list<std::string>(1, "game_entity"));
        ac->operation(op, res);
        op_arg->setObjtype("obj");
        ac->operation(op, res);
        op_arg->setName("Bob");
        ac->operation(op, res);
        op_arg->setObjtype("class");
        ac->operation(op, res);
        op_arg->setId("game_entity");
        ac->operation(op, res);
        op_arg->setId("new_class");
        ac->operation(op, res);
        op_arg->setParents(std::list<std::string>(1, ""));
        ac->operation(op, res);
        op_arg->setParents(std::list<std::string>(1, "non_exist"));
        ac->operation(op, res);
    }
}
예제 #2
0
void Juncture::LoginOperation(const Operation & op, OpVector & res)
{
    log(INFO, "Juncture got login");

    const std::vector<Root> & args = op->getArgs();
    if (args.empty()) {
        error(op, "No argument to connect op", res, getId());
        return;
    }
    const Root & arg = args.front();

    Element username_attr;
    if (arg->copyAttr("username", username_attr) != 0 || !username_attr.isString()) {
        error(op, "Argument to connect op has no username", res, getId());
        return;
    }
    const std::string & username = username_attr.String();

    Element password_attr;
    if (arg->copyAttr("password", password_attr) != 0 || !password_attr.isString()) {
        error(op, "Argument to connect op has no password", res, getId());
        return;
    }
    const std::string & password = password_attr.String();

    if (m_peer == 0) {
        error(op, "Juncture not connected", res, getId());
        return;
    }
    assert(m_socket == 0);

    if (m_peer->getAuthState() != PEER_INIT) {
        error(op, "Juncture not ready", res, getId());
        return;
    }

    Anonymous account;
    account->setAttr("username", username);
    account->setAttr("password", password);

    Login l;
    l->setArgs1(account);
    if (!op->isDefaultSerialno()) {
        l->setSerialno(op->getSerialno());
    }
    // Send the login op
    m_peer->send(l);
    m_peer->setAuthState(PEER_AUTHENTICATING);
}
예제 #3
0
void EntityBuildertest::test_sequence2()
{
    Anonymous attributes;

    assert(EntityBuilder::instance() != 0);

    // Create a normal Entity
    LocatedEntity * test_ent = EntityBuilder::instance()->newEntity("1", 1, "thing", attributes, BaseWorld::instance());
    assert(test_ent != 0);

    // Create an entity specifying an attrbute
    attributes->setAttr("funky", "true");

    test_ent = EntityBuilder::instance()->newEntity("1", 1, "thing", attributes, BaseWorld::instance());
    assert(test_ent != 0);

    // Create an entity causing VELOCITY to be set
    attributes = Anonymous();

    attributes->setVelocity(std::vector<double>(3, 1.5));

    LocatedEntity_merge_action = SET_VELOCITY;

    test_ent = EntityBuilder::instance()->newEntity("1", 1, "thing", attributes, BaseWorld::instance());
    assert(test_ent != 0);

    LocatedEntity_merge_action = DO_NOTHING;

    // Create an entity causing VELOCITY to be set for no obvious reason
    attributes = Anonymous();

    LocatedEntity_merge_action = SET_VELOCITY;

    test_ent = EntityBuilder::instance()->newEntity("1", 1, "thing", attributes, BaseWorld::instance());
    assert(test_ent != 0);

    LocatedEntity_merge_action = DO_NOTHING;

    // Create an entity specifying a LOC
    attributes = Anonymous();

    attributes->setLoc("1");

    test_ent = EntityBuilder::instance()->newEntity("1", 1, "thing", attributes, BaseWorld::instance());
    assert(test_ent != 0);
}
예제 #4
0
int AtlasStreamClient::login(const std::string & username,
                             const std::string & password)
{
    m_username = username;

    Login l;
    Anonymous account;
 
    account->setAttr("username", username);
    account->setAttr("password", password);
 
    l->setArgs1(account);
    l->setSerialno(newSerialNo());
 
    send(l);

    return waitForLoginResponse();
}
예제 #5
0
int AtlasStreamClient::create(const std::string & type,
                              const std::string & username,
                              const std::string & password)
{
    m_username = username;

    Create c;
    Anonymous account;

    account->setAttr("username", username);
    account->setAttr("password", password);
    account->setParents(std::list<std::string>(1, type));

    c->setArgs1(account);
    c->setSerialno(newSerialNo());

    send(c);

    return waitForLoginResponse();
}
예제 #6
0
void Interactive::exec(const std::string & cmd, const std::string & arg)
{
    bool reply_expected = true;
    reply_flag = false;
    error_flag = false;

    boost::shared_ptr<ObjectContext> command_context = m_currentContext.lock();
    if (!command_context) {
        std::cout << "ERROR: Context free" << std::endl << std::flush;
        return;
    }

    if (cmd == "stat") {
        Get g;
        send(g);
    } else if (cmd == "install") {
        size_t space = arg.find(' ');
        if (space == std::string::npos || space >= (arg.size() - 1)) {
            std::cout << "usage: install <type id> <parent id>"
                      << std::endl << std::flush;
        } else {
            Create c;
            c->setFrom(m_accountId);
            Anonymous ent;
            ent->setId(std::string(arg, 0, space));
            ent->setObjtype("class");
            ent->setParents(std::list<std::string>(1, std::string(arg, space + 1)));
            c->setArgs1(ent);
            send(c);
        }
        reply_expected = false;
    } else if (cmd == "look") {
        Look l;
        if (!arg.empty()) {
            Anonymous cmap;
            cmap->setId(arg);
            l->setArgs1(cmap);
        }
        l->setSerialno(newSerialNo());
        command_context->setFromContext(l);
        send(l);
        reply_expected = false;
    } else if (cmd == "logout") {
        Logout l;
        l->setFrom(m_accountId);
        if (!arg.empty()) {
            Anonymous lmap;
            lmap->setId(arg);
            l->setArgs1(lmap);
            reply_expected = false;
        }
        send(l);
    } else if (cmd == "say") {
        Talk t;
        Anonymous ent;
        ent->setAttr("say", arg);
        t->setArgs1(ent);
        t->setFrom(m_accountId);
        send(t);
    } else if (cmd == "help" || cmd == "?") {
        reply_expected = false;
        help();
    } else if (cmd == "query") {
        Get g;

        if (!arg.empty()) {
            Anonymous cmap;
            if (::isdigit(arg[0])) {
                cmap->setObjtype("obj");
            } else {
                cmap->setObjtype("meta");
            }
            cmap->setId(arg);
            g->setArgs1(cmap);
        }
        g->setFrom(m_accountId);

        send(g);
    } else if (cmd == "reload") {
        if (arg.empty()) {
            reply_expected = false;
            std::cout << "reload: Argument required" << std::endl << std::flush;
        } else {
            Set s;

            Anonymous tmap;
            tmap->setObjtype("class");
            tmap->setId(arg);
            s->setArgs1(tmap);
            s->setFrom(m_accountId);

            send(s);
        }
    } else if (cmd == "get") {
        Get g;

        if (!arg.empty()) {
            Anonymous cmap;
            if (::isdigit(arg[0])) {
                cmap->setObjtype("obj");
            } else {
                cmap->setObjtype("meta");
            }
            cmap->setId(arg);
            g->setArgs1(cmap);
        }
        g->setFrom(m_accountId);

        send(g);
    } else if (cmd == "monitor") {
        ClientTask * task = new OperationMonitor;
        if (runTask(task, arg) == 0) {
            Monitor m;

            m->setArgs1(Anonymous());
            m->setFrom(m_accountId);

            send(m);
        }

        reply_expected = false;
    } else if (cmd == "unmonitor") {
        OperationMonitor * om = dynamic_cast<OperationMonitor *>(m_currentTask);

        if (om != 0) {
            Monitor m;

            m->setFrom(m_accountId);

            send(m);

            reply_expected = false;

            SystemTime now;
            now.update();

            time_t monitor_time = now.seconds() - om->startTime();

            std::cout << om->count() << " operations monitored in "
                      << monitor_time << " seconds = "
                      << om->count() / monitor_time
                      << " operations per second"
                      << std::endl << std::flush;

            endTask();
        }
    } else if (cmd == "connect") {
        std::vector<std::string> args;
        tokenize(arg, args);

        if (args.size() != 2) {
            std::cout << "usage: connect <hostname> <port>"
                      << std::endl << std::flush;

            reply_expected = false;
        } else {
            Anonymous cmap;
            cmap->setAttr("hostname", args[0]);
            cmap->setAttr("port", strtol(args[1].c_str(), 0, 10));

            Connect m;
            m->setArgs1(cmap);
            // No serialno yet
            // FIXME add serialno once Juncture context can handle this

            command_context->setFromContext(m);

            send(m);
        }
    } else if (cmd == "add_agent") {
        std::string agent_type("creator");

        if (!arg.empty()) {
            agent_type = arg;
        }
        
        Create c;

        Anonymous cmap;
        cmap->setParents(std::list<std::string>(1, agent_type));
        cmap->setName("cycmd agent");
        cmap->setObjtype("obj");
        c->setArgs1(cmap);
        c->setSerialno(newSerialNo());

        command_context->setFromContext(c);

        send(c);
    } else if (cmd == "delete") {
        if (arg.empty()) {
            std::cout << "Please specify the entity to delete" << std::endl << std::flush;
            reply_expected = false;
        } else {
            Delete del;

            Anonymous del_arg;
            del_arg->setId(arg);
            del->setArgs1(del_arg);

            command_context->setFromContext(del);

            send(del);

            reply_expected = false;
        }
    } else if (cmd == "find_by_name") {
        if (arg.empty()) {
            std::cout << "Please specify the name to search for" << std::endl << std::flush;
            reply_expected = false;
        } else {
            Look l;

            Anonymous lmap;
            lmap->setName(arg);
            l->setArgs1(lmap);
            l->setSerialno(newSerialNo());

            command_context->setFromContext(l);

            send(l);

            reply_expected = false;
        }
    } else if (cmd == "find_by_type") {
        if (arg.empty()) {
            std::cout << "Please specify the type to search for" << std::endl << std::flush;
            reply_expected = false;
        } else {
            Look l;

            Anonymous lmap;
            lmap->setParents(std::list<std::string>(1, arg));
            l->setArgs1(lmap);
            l->setSerialno(newSerialNo());

            command_context->setFromContext(l);

            send(l);

            reply_expected = false;
        }
    } else if (cmd == "flush") {
        if (arg.empty()) {
            // FIXME usage
            std::cout << "Please specify the type to flush" << std::endl << std::flush;
            reply_expected = false;
        } else {
            ClientTask * task = new Flusher(command_context);
            runTask(task, arg);
            reply_expected = false;
        }
    } else if (cmd == "cancel") {
        if (endTask() != 0) {
            std::cout << "No task currently running" << std::endl << std::flush;
        }
    } else if (cmd == "dump") {
        if (command_context->repr() != "avatar") {
            std::cout << "You must have an agent in the world in order to dump the world." << std::endl << std::flush;
        } else {
            //Extract the avatar id by "misusing" the setFromContext method
            Operation op;
            command_context->setFromContext(op);
            ClientTask * task = new EntityExporter(m_accountId, op->getFrom());
            runTask(task, "world.xml");
            reply_expected = false;
        }
    } else if (cmd == "restore") {
        if (command_context->repr() != "avatar") {
            std::cout << "You must have an agent in the world in order to dump the world." << std::endl << std::flush;
        } else {
            //Extract the avatar id by "misusing" the setFromContext method
            Operation op;
            command_context->setFromContext(op);
            ClientTask * task = new EntityImporter(m_accountId, op->getFrom());
            runTask(task, "world.xml");
            reply_expected = false;
        }
    } else if (cmd == "create") {
        std::vector<std::string> args;
        tokenize(arg, args);

        if (args.size() < 1) {
            std::cout << "usage: create <type> <params> ... "
                      << std::endl << std::flush;
        } else {
            Anonymous cmap;
            cmap->setParents(std::list<std::string>(1, args[0]));
            cmap->setObjtype("obj");

            Create c;
            c->setArgs1(cmap);
            c->setSerialno(newSerialNo());
            command_context->setFromContext(c);

            send(c);
        }
        reply_expected = false;
    } else if (cmd == "login") {
        std::vector<std::string> args;
        tokenize(arg, args);

        if (args.size() != 2) {
            std::cout << "usage: login <username> <password>"
                      << std::endl << std::flush;
            reply_expected = false;
        } else {
            Anonymous cmap;
            cmap->setAttr("username", args[0]);
            cmap->setAttr("password", args[1]);

            Login m;
            m->setArgs1(cmap);
            m->setSerialno(newSerialNo());

            command_context->setFromContext(m);

            send(m);
        }
    } else {
        reply_expected = false;
        std::cout << cmd << ": Command not known" << std::endl << std::flush;
    }

    if (!reply_expected) {
        updatePrompt();
        return;
    }
    // Wait for reply
    time_t wait_start_time = time(NULL);
    while (!reply_flag) {
       if (time(NULL) - wait_start_time > 5) {
           std::cout << cmd << ": No reply from server" << std::endl << std::flush;
           return;
       }
       if (select(false) != 0) {
           return;
       }
    }
}
예제 #7
0
int main(int argc, char ** argv)
{
    loadConfig(argc, argv);

    database_flag = false;

    init_python_api();

    int ret;

    {
        World e("1", 1);
        TestWorld test_world(e);
        Anonymous attributes;

        EntityBuilder::init(test_world);
        Ruleset::init();

        assert(Ruleset::instance() != 0);

        assert(EntityBuilder::instance() != 0);

        assert(EntityBuilder::instance()->newEntity("1", 1, "world", attributes) == 0);
        assert(EntityBuilder::instance()->newEntity("1", 1, "nonexistant", attributes) == 0);
        assert(EntityBuilder::instance()->newEntity("1", 1, "thing", attributes) != 0);

        Ruleset::del();
        assert(Ruleset::instance() == 0);
        EntityBuilder::del();
        assert(EntityBuilder::instance() == 0);
        Inheritance::clear();
    }

    {
        World e("1", 1);
        TestWorld test_world(e);
        Anonymous attributes;
        Atlas::Message::Element val;

        EntityBuilder::init(test_world);
        Ruleset::init();

        assert(Ruleset::instance() != 0);

        Entity * test_ent = EntityBuilder::instance()->newEntity("1", 1, "thing", attributes);
        assert(test_ent != 0);
        assert(!test_ent->getAttr("funky", val));
        assert(val.isNone());

        attributes->setAttr("funky", "true");

        test_ent = EntityBuilder::instance()->newEntity("1", 1, "thing", attributes);
        assert(test_ent != 0);
        assert(test_ent->getAttr("funky", val));
        assert(val.isString());
        assert(val.String() == "true");

        Ruleset::del();
        assert(Ruleset::instance() == 0);
        EntityBuilder::del();
        assert(EntityBuilder::instance() == 0);
        Inheritance::clear();
    }

    {
        // Create a test world.
        World e("1", 1);
        TestWorld test_world(e);
        Atlas::Message::Element val;

        // Instance of EntityBuilder with all protected methods exposed
        // for testing
        ExposedEntityBuilder * entity_factory = new ExposedEntityBuilder(test_world);
        // Instance of Ruleset with all protected methods exposed
        // for testing
        EntityBuilder * test_eb = EntityBuilder::instance();
        assert(test_eb == entity_factory);
        ExposedRuleset test_ruleset(test_eb);

        // Attributes for test entities being created
        Anonymous attributes;

        // Create an entity which is an instance of one of the core classes
        Entity * test_ent = test_eb->newEntity("1", 1, "thing", attributes);
        assert(test_ent != 0);
        // Check the created entity does not have the attribute values we
        // will be testing later
        assert(!test_ent->getAttr("funky", val));
        assert(val.isNone());

        // Set a test attribute
        attributes->setAttr("funky", "true");

        // Create another entity, and check that it has picked up the new
        // attribute value
        test_ent = test_eb->newEntity("1", 1, "thing", attributes);
        assert(test_ent != 0);
        assert(test_ent->getAttr("funky", val));
        assert(val.isString());
        assert(val.String() == "true");

        // Check that creating an entity of a type we know we have not yet
        // installed results in a null pointer.
        assert(test_eb->newEntity("1", 1, "custom_type", attributes) == 0);

        // Set up a type description for a new type, and install it.
        {
            Root custom_type_description;
            MapType attrs;
            MapType test_custom_type_attr;
            test_custom_type_attr["default"] = "test_value";
            test_custom_type_attr["visibility"] = "public";
            attrs["test_custom_type_attr"] = test_custom_type_attr;
            custom_type_description->setAttr("attributes", attrs);
            custom_type_description->setId("custom_type");
            custom_type_description->setParents(std::list<std::string>(1, "thing"));

            std::string dependent, reason;
            ret = test_ruleset.installEntityClass("custom_type", "thing", custom_type_description, dependent, reason);

            assert(ret == 0);
            assert(dependent.empty());
            assert(reason.empty());
        }

        // Check that the factory dictionary now contains a factory for
        // the custom type we just installed.
        EntityKit * custom_type_factory = test_eb->getClassFactory("custom_type");
        assert(custom_type_factory != 0);

        // Check the factory has the attributes we described on the custom
        // type.
        MapType::const_iterator J = custom_type_factory->m_attributes.find("test_custom_type_attr");
        assert(J != custom_type_factory->m_attributes.end());
        assert(J->second.isString());
        assert(J->second.String() == "test_value");

        // Create an instance of our custom type, ensuring that it works.
        test_ent = test_eb->newEntity("1", 1, "custom_type", attributes);
        assert(test_ent != 0);

        // Reset val.
        val = Atlas::Message::Element();
        assert(val.isNone());

        // Check the custom type has the attribute we passed in when creating
        // the instance.
        assert(test_ent->getAttr("funky", val));
        assert(val.isString());
        assert(val.String() == "true");

        // Reset val.
        val = Atlas::Message::Element();
        assert(val.isNone());

        // Check the custom type has the attribute described when the
        // custom type was installed.
        assert(test_ent->getAttr("test_custom_type_attr", val));
        assert(val.isString());
        assert(val.String() == "test_value");

        // Check that creating an entity of a type we know we have not yet
        // installed results in a null pointer.
        assert(test_eb->newEntity("1", 1, "custom_inherited_type", attributes) == 0);

        // Set up a type description for a second new type which inherits
        // from the first, and install it.
        {
            Root custom_inherited_type_description;
            MapType attrs;
            MapType test_custom_type_attr;
            test_custom_type_attr["default"] = "test_inherited_value";
            test_custom_type_attr["visibility"] = "public";
            attrs["test_custom_inherited_type_attr"] = test_custom_type_attr;
            custom_inherited_type_description->setAttr("attributes", attrs);
            custom_inherited_type_description->setId("custom_inherited_type");
            custom_inherited_type_description->setParents(std::list<std::string>(1, "custom_type"));

            std::string dependent, reason;
            ret = test_ruleset.installEntityClass("custom_inherited_type", "custom_type", custom_inherited_type_description, dependent, reason);

            assert(ret == 0);
            assert(dependent.empty());
            assert(reason.empty());
        }

        // Check that the factory dictionary does contain the factory for
        // the second newly installed type
        EntityKit * custom_inherited_type_factory = test_eb->getClassFactory("custom_inherited_type");
        assert(custom_inherited_type_factory != 0);

        // Check that the factory has inherited the attributes from the
        // first custom type
        J = custom_inherited_type_factory->m_attributes.find("test_custom_type_attr");
        assert(J != custom_inherited_type_factory->m_attributes.end());
        assert(J->second.isString());
        assert(J->second.String() == "test_value");

        // Check that the factory has the attributes specified when installing
        // it
        J = custom_inherited_type_factory->m_attributes.find("test_custom_inherited_type_attr");
        assert(J != custom_inherited_type_factory->m_attributes.end());
        assert(J->second.isString());
        assert(J->second.String() == "test_inherited_value");

        // Creat an instance of the second custom type, ensuring it works.
        test_ent = test_eb->newEntity("1", 1, "custom_inherited_type", attributes);
        assert(test_ent != 0);

        // Reset val.
        val = Atlas::Message::Element();
        assert(val.isNone());

        // Check the custom type has the attribute we passed in when creating
        // the instance.
        assert(test_ent->getAttr("funky", val));
        assert(val.isString());
        assert(val.String() == "true");

        // Reset val.
        val = Atlas::Message::Element();
        assert(val.isNone());

        // Check the instance of the second custom type has the attribute
        // described when the first custom type was installed.
        assert(test_ent->getAttr("test_custom_type_attr", val));
        assert(val.isString());
        assert(val.String() == "test_value");

        // Reset val.
        val = Atlas::Message::Element();
        assert(val.isNone());

        // Check the custom type has the attribute described when the
        // second custom type was installed
        assert(test_ent->getAttr("test_custom_inherited_type_attr", val));
        assert(val.isString());
        assert(val.String() == "test_inherited_value");

        // FIXME TODO Modify a type, and ensure attribute propagate to inherited types.

        // Make sure than attempting to modify a non-existant type fails
        {
            Anonymous nonexistant_description;
            MapType attrs;
            MapType test_custom_type_attr;

            test_custom_type_attr["default"] = "no_value";
            test_custom_type_attr["visibility"] = "public";
            attrs["no_custom_type_attr"] = test_custom_type_attr;

            nonexistant_description->setId("nonexistant");
            nonexistant_description->setAttr("attributes", attrs);

            ret = test_ruleset.modifyRule("nonexistant", nonexistant_description);

            assert(ret != 0);
        }

        // Modify the second custom type removing its custom attribute
        {
            Anonymous new_custom_inherited_type_description;
            new_custom_inherited_type_description->setId("custom_inherited_type");
            new_custom_inherited_type_description->setAttr("attributes", MapType());

            // No parents
            ret = test_ruleset.modifyRule("custom_inherited_type",
                                          new_custom_inherited_type_description);
            assert(ret != 0);

            // empty parents
            new_custom_inherited_type_description->setParents(std::list<std::string>());

            ret = test_ruleset.modifyRule("custom_inherited_type",
                                          new_custom_inherited_type_description);
            assert(ret != 0);

            // wrong parents
            new_custom_inherited_type_description->setParents(std::list<std::string>(1, "wrong_parent"));

            ret = test_ruleset.modifyRule("custom_inherited_type",
                                          new_custom_inherited_type_description);
            assert(ret != 0);

            new_custom_inherited_type_description->setParents(std::list<std::string>(1, "custom_type"));

            ret = test_ruleset.modifyRule("custom_inherited_type",
                                          new_custom_inherited_type_description);

            assert(ret == 0);
        }

        // Check that the factory dictionary does contain the factory for
        // the second newly installed type
        custom_inherited_type_factory = test_eb->getClassFactory("custom_inherited_type");
        assert(custom_inherited_type_factory != 0);

        // Check that the factory has inherited the attributes from the
        // first custom type
        J = custom_inherited_type_factory->m_attributes.find("test_custom_type_attr");
        assert(J != custom_inherited_type_factory->m_attributes.end());
        assert(J->second.isString());
        assert(J->second.String() == "test_value");

        // Check that the factory no longer has the attributes we removed
        J = custom_inherited_type_factory->m_attributes.find("test_custom_inherited_type_attr");
        assert(J == custom_inherited_type_factory->m_attributes.end());

        // Creat an instance of the second custom type, ensuring it works.
        test_ent = test_eb->newEntity("1", 1, "custom_inherited_type", attributes);
        assert(test_ent != 0);

        // Reset val.
        val = Atlas::Message::Element();
        assert(val.isNone());

        // Make sure test nonexistant attribute isn't present
        assert(!test_ent->getAttr("nonexistant", val));
        // Make sure nonexistant attribute isn't present
        assert(!test_ent->getAttr("nonexistant_attribute", val));

        // Reset val.
        val = Atlas::Message::Element();
        assert(val.isNone());

        // Check the custom type has the attribute we passed in when creating
        // the instance.
        assert(test_ent->getAttr("funky", val));
        assert(val.isString());
        assert(val.String() == "true");

        // Reset val.
        val = Atlas::Message::Element();
        assert(val.isNone());

        // Check the instance of the second custom type has the attribute
        // described when the first custom type was installed.
        assert(test_ent->getAttr("test_custom_type_attr", val));
        assert(val.isString());
        assert(val.String() == "test_value");

        // Reset val.
        val = Atlas::Message::Element();
        assert(val.isNone());

        // Check the custom type has the attribute described when the
        // second custom type was installed
        assert(!test_ent->getAttr("test_custom_inherited_type_attr", val));

        // Modify the first custom type removing its custom attribute
        {
            Anonymous new_custom_type_description;
            new_custom_type_description->setId("custom_type");
            new_custom_type_description->setAttr("attributes", MapType());
            new_custom_type_description->setParents(std::list<std::string>(1, "thing"));

            ret = test_ruleset.modifyRule("custom_type", new_custom_type_description);

            assert(ret == 0);
        }

        // Check that the factory dictionary now contains a factory for
        // the custom type we just installed.
        custom_type_factory = test_eb->getClassFactory("custom_type");
        assert(custom_type_factory != 0);

        // Check the factory has the attributes we described on the custom
        // type.
        J = custom_type_factory->m_attributes.find("test_custom_type_attr");
        assert(J == custom_type_factory->m_attributes.end());

        // Create an instance of our custom type, ensuring that it works.
        test_ent = test_eb->newEntity("1", 1, "custom_type", attributes);
        assert(test_ent != 0);

        // Reset val.
        val = Atlas::Message::Element();
        assert(val.isNone());

        // Check the custom type has the attribute we passed in when creating
        // the instance.
        assert(test_ent->getAttr("funky", val));
        assert(val.isString());
        assert(val.String() == "true");

        // Reset val.
        val = Atlas::Message::Element();
        assert(val.isNone());

        // Check the custom type no longer has the custom attribute
        assert(!test_ent->getAttr("test_custom_type_attr", val));

        // Check that the factory dictionary does contain the factory for
        // the second newly installed type
        custom_inherited_type_factory = test_eb->getClassFactory("custom_inherited_type");
        assert(custom_inherited_type_factory != 0);

        // Check that the factory no longer has inherited the attributes
        // from the first custom type which we removed
        J = custom_inherited_type_factory->m_attributes.find("test_custom_type_attr");
        assert(J == custom_inherited_type_factory->m_attributes.end());

        // Check that the factory no longer has the attributes we removed
        J = custom_inherited_type_factory->m_attributes.find("test_custom_inherited_type_attr");
        assert(J == custom_inherited_type_factory->m_attributes.end());

        // Creat an instance of the second custom type, ensuring it works.
        test_ent = test_eb->newEntity("1", 1, "custom_inherited_type", attributes);
        assert(test_ent != 0);

        // Reset val.
        val = Atlas::Message::Element();
        assert(val.isNone());

        // Make sure test nonexistant attribute isn't present
        assert(!test_ent->getAttr("nonexistant", val));
        // Make sure nonexistant attribute isn't present
        assert(!test_ent->getAttr("nonexistant_attribute", val));

        // Reset val.
        val = Atlas::Message::Element();
        assert(val.isNone());

        // Check the custom type has the attribute we passed in when creating
        // the instance.
        assert(test_ent->getAttr("funky", val));
        assert(val.isString());
        assert(val.String() == "true");

        // Reset val.
        val = Atlas::Message::Element();
        assert(val.isNone());

        // Check the instance of the second custom type has the attribute
        // described when the first custom type was installed.
        assert(!test_ent->getAttr("test_custom_type_attr", val));

        // Reset val.
        val = Atlas::Message::Element();
        assert(val.isNone());

        // Check the custom type has the attribute described when the
        // second custom type was installed
        assert(!test_ent->getAttr("test_custom_inherited_type_attr", val));

        // Add more custom attributes to the first type
        {
            Anonymous new_custom_type_description;
            MapType attrs;
            MapType test_custom_type_attr;

            test_custom_type_attr["default"] = "test_value";
            test_custom_type_attr["visibility"] = "public";
            attrs["test_custom_type_attr"] = test_custom_type_attr;

            MapType new_custom_type_attr;

            new_custom_type_attr["default"] = "new_value";
            new_custom_type_attr["visibility"] = "public";
            attrs["new_custom_type_attr"] = new_custom_type_attr;

            new_custom_type_description->setId("custom_type");
            new_custom_type_description->setAttr("attributes", attrs);
            new_custom_type_description->setParents(std::list<std::string>(1, "thing"));

            ret = test_ruleset.modifyRule("custom_type", new_custom_type_description);

            assert(ret == 0);
            
        }

        // Check that the factory dictionary now contains a factory for
        // the custom type we just installed.
        custom_type_factory = test_eb->getClassFactory("custom_type");

        // Check the factory has the attributes we described on the custom
        // type.
        J = custom_type_factory->m_attributes.find("test_custom_type_attr");
        assert(J != custom_type_factory->m_attributes.end());
        assert(J->second.isString());
        assert(J->second.String() == "test_value");

        J = custom_type_factory->m_attributes.find("new_custom_type_attr");
        assert(J != custom_type_factory->m_attributes.end());
        assert(J->second.isString());
        assert(J->second.String() == "new_value");

        // Create an instance of our custom type, ensuring that it works.
        test_ent = test_eb->newEntity("1", 1, "custom_type", attributes);
        assert(test_ent != 0);

        // Reset val.
        val = Atlas::Message::Element();
        assert(val.isNone());

        // Check the custom type has the attribute we passed in when creating
        // the instance.
        assert(test_ent->getAttr("funky", val));
        assert(val.isString());
        assert(val.String() == "true");

        // Reset val.
        val = Atlas::Message::Element();
        assert(val.isNone());

        // Check the custom type now has the custom attributes
        assert(test_ent->getAttr("test_custom_type_attr", val));
        assert(val.isString());
        assert(val.String() == "test_value");

        assert(test_ent->getAttr("new_custom_type_attr", val));
        assert(val.isString());
        assert(val.String() == "new_value");

        // Check that the factory dictionary does contain the factory for
        // the second newly installed type
        custom_inherited_type_factory = test_eb->getClassFactory("custom_inherited_type");
        assert(custom_inherited_type_factory != 0);

        // Check that the factory now has inherited the attributes
        // from the first custom type
        J = custom_inherited_type_factory->m_attributes.find("test_custom_type_attr");
        assert(J != custom_inherited_type_factory->m_attributes.end());
        assert(J->second.isString());
        assert(J->second.String() == "test_value");

        J = custom_inherited_type_factory->m_attributes.find("new_custom_type_attr");
        assert(J != custom_inherited_type_factory->m_attributes.end());
        assert(J->second.isString());
        assert(J->second.String() == "new_value");

        // Check that the factory no longer has the attributes we removed
        J = custom_inherited_type_factory->m_attributes.find("test_custom_inherited_type_attr");
        assert(J == custom_inherited_type_factory->m_attributes.end());

        // Creat an instance of the second custom type, ensuring it works.
        test_ent = test_eb->newEntity("1", 1, "custom_inherited_type", attributes);
        assert(test_ent != 0);

        // Reset val.
        val = Atlas::Message::Element();
        assert(val.isNone());

        // Make sure test nonexistant attribute isn't present
        assert(!test_ent->getAttr("nonexistant", val));
        // Make sure nonexistant attribute isn't present
        assert(!test_ent->getAttr("nonexistant_attribute", val));

        // Reset val.
        val = Atlas::Message::Element();
        assert(val.isNone());

        // Check the custom type has the attribute we passed in when creating
        // the instance.
        assert(test_ent->getAttr("funky", val));
        assert(val.isString());
        assert(val.String() == "true");

        // Reset val.
        val = Atlas::Message::Element();
        assert(val.isNone());

        // Check the instance of the second custom type has the attribute
        // described when the first custom type was installed.
        assert(test_ent->getAttr("test_custom_type_attr", val));
        assert(val.isString());
        assert(val.String() == "test_value");

        assert(test_ent->getAttr("new_custom_type_attr", val));
        assert(val.isString());
        assert(val.String() == "new_value");

        // Reset val.
        val = Atlas::Message::Element();
        assert(val.isNone());

        // Check the custom type no longer has the attribute described when the
        // second custom type was installed
        assert(!test_ent->getAttr("test_custom_inherited_type_attr", val));

    }
}