示例#1
0
result_t MongoDB::error()
{
    static const char *s_msgs[] =
    {
        "Connection success!", "Could not create a socket.",
        "An error occured while calling connect().",
        "An error occured while calling getaddrinfo().",
        "Warning: connected to a non-master node (read-only).",
        "Given rs name doesn't match this replica set.",
        "Can't find primary in replica set. Connection closed.",
        "An error occurred while reading or writing on the socket.",
        "Other socket error.", "The response is not the expected length.",
        "The command returned with 'ok' value of 0.",
        "Write with given write_concern returned an error.",
        "The name for the ns (database or collection) is invalid.",
        "BSON not valid for the specified op.",
        "BSON object has not been finished.",
        "BSON object exceeds max BSON size.",
        "Supplied write concern object is invalid."
    };

    result_t hr = 0;

    if (m_conn.err == MONGO_IO_ERROR)
        hr = m_conn.errcode;
    else if (m_conn.err > 0 && m_conn.err <= MONGO_WRITE_CONCERN_INVALID)
        hr = Runtime::setError(s_msgs[m_conn.err]);
    else if (m_conn.lasterrcode != 0)
        hr = Runtime::setError(m_conn.lasterrstr);

    mongo_clear_errors(&m_conn);
    return hr;
}
示例#2
0
int test_namespace_validation_on_insert( void ) {
    mongo conn[1];
    bson b[1], b2[1];
    bson *objs[2];

    INIT_SOCKETS_FOR_WINDOWS;

    if ( mongo_connect( conn , TEST_SERVER, 27017 ) ) {
        printf( "failed to connect\n" );
        exit( 1 );
    }

    bson_init( b );
    bson_append_int( b, "foo", 1 );
    bson_finish( b );

    ASSERT( mongo_insert( conn, "tet.fo$o", b, NULL ) == MONGO_ERROR );
    ASSERT( conn->err == MONGO_NS_INVALID );
    ASSERT( strncmp( conn->errstr, "Collection may not contain '$'", 29 ) == 0 );
    mongo_clear_errors( conn );

    bson_init( b2 );
    bson_append_int( b2, "foo", 1 );
    bson_finish( b2 );

    objs[0] = b;
    objs[1] = b2;

    ASSERT( mongo_insert_batch( conn, "tet.fo$o",
          (const bson **)objs, 2, NULL, 0 ) == MONGO_ERROR );
    ASSERT( conn->err == MONGO_NS_INVALID );
    ASSERT( strncmp( conn->errstr, "Collection may not contain '$'", 29 ) == 0 );

    return 0;
}
int test_insert_limits( const char *set_name ) {
    char version[10];
    mongo conn[1];
    mongo_write_concern wc[1];
    int i;
    char key[10];
    int res = 0;
    bson b[1], b2[1];
    bson *objs[2];

    mongo_write_concern_init( wc );
    wc->w = 1;
    mongo_write_concern_finish( wc );

    /* We'll perform the full test if we're running v2.0 or later. */
    if( mongo_get_server_version( version ) != -1 && version[0] <= '1' )
        return 0;

    mongo_replset_init( conn, set_name );
    mongo_replset_add_seed( conn, TEST_SERVER, SEED_START_PORT + 1 );
    mongo_replset_add_seed( conn, TEST_SERVER, SEED_START_PORT );
    res = mongo_replset_connect( conn );

    if( res != MONGO_OK ) {
        res = conn->err;
        return res;
    }

    ASSERT( conn->max_bson_size > MONGO_DEFAULT_MAX_BSON_SIZE );

    bson_init( b );
    for(i=0; i<1200000; i++) {
        sprintf( key, "%d", i + 10000000 );
        bson_append_int( b, key, i );
    }
    bson_finish( b );

    ASSERT( bson_size( b ) > conn->max_bson_size );

    ASSERT( mongo_insert( conn, "test.foo", b, wc ) == MONGO_ERROR );
    ASSERT( conn->err == MONGO_BSON_TOO_LARGE );

    mongo_clear_errors( conn );
    ASSERT( conn->err == 0 );

    bson_init( b2 );
    bson_append_int( b2, "foo", 1 );
    bson_finish( b2 );

    objs[0] = b;
    objs[1] = b2;

    ASSERT( mongo_insert_batch( conn, "test.foo", (const bson**)objs, 2, wc, 0 ) == MONGO_ERROR );
    ASSERT( conn->err == MONGO_BSON_TOO_LARGE );

    mongo_write_concern_destroy( wc );

    return 0;
}
示例#4
0
static void test_write_concern_input( mongo *conn ) {
    mongo_write_concern wc[1], wcbad[1];
    bson b[1];

    mongo_cmd_drop_collection( conn, TEST_DB, TEST_COL, NULL );

    bson_init( b );
    bson_append_new_oid( b, "_id" );
    bson_finish( b );

    mongo_write_concern_init( wc );    
    mongo_write_concern_set_w( wc, 1 );

    /* Failure to finish write concern object. */
    ASSERT( mongo_insert( conn, TEST_NS, b, wc ) != MONGO_OK );
    ASSERT( conn->err == MONGO_WRITE_CONCERN_INVALID );
    ASSERT_EQUAL_STRINGS( conn->errstr,
        "Must call mongo_write_concern_finish() before using *write_concern." );

    mongo_write_concern_finish( wc );

    /* Use a bad write concern. */
    mongo_clear_errors( conn );
    mongo_write_concern_init( wcbad );    
    mongo_write_concern_set_w( wcbad, 2 );
    mongo_write_concern_finish( wcbad );
    mongo_set_write_concern( conn, wcbad );
    ASSERT( mongo_insert( conn, TEST_NS, b, NULL ) != MONGO_OK );
    ASSERT( conn->err == MONGO_WRITE_ERROR );
    ASSERT_EQUAL_STRINGS( conn->lasterrstr, "norepl" );

    /* Ensure that supplied write concern overrides default. */
    mongo_clear_errors( conn );
    ASSERT( mongo_insert( conn, TEST_NS, b, wc ) != MONGO_OK );
    ASSERT( conn->err == MONGO_WRITE_ERROR );
    ASSERT_EQUAL_STRINGS( conn->errstr, "See conn->lasterrstr for details." );
    ASSERT_EQUAL_STRINGS( conn->lasterrstr, "E11000 duplicate key error index" );
    ASSERT( conn->lasterrcode == 11000 );

    conn->write_concern = NULL;
    mongo_write_concern_destroy( wc );
    mongo_write_concern_destroy( wcbad );
    bson_destroy( b );
}
bool TMongoDriver::updateMulti(const QString &ns, const QVariantMap &criteria, const QVariantMap &object)
{
    mongo_clear_errors(mongoConnection);
    int status = mongo_update(mongoConnection, qPrintable(ns), (const bson *)TBson::toBson(criteria).data(),
                              (const bson *)TBson::toBson(object).data(), MONGO_UPDATE_MULTI, 0);
   if (status != MONGO_OK) {
        tSystemError("MongoDB Error: %s", mongoConnection->lasterrstr);
        return false;
    }
   return true;
}
bool TMongoDriver::remove(const QString &ns, const QVariantMap &object)
{
    mongo_clear_errors(mongoConnection);
    int status = mongo_remove(mongoConnection, qPrintable(ns),
                              (const bson *)TBson::toBson(object).data(), 0);
    if (status != MONGO_OK) {
        tSystemError("MongoDB Error: %s", mongoConnection->lasterrstr);
        return false;
    }
    return true;
}
示例#7
0
int test_insert_limits( void ) {
    char version[10];
    mongo conn[1];
    int i;
    char key[10];
    bson b[1], b2[1];
    bson *objs[2];

    /* Test the default max BSON size. */
    mongo_init( conn );
    ASSERT( conn->max_bson_size == MONGO_DEFAULT_MAX_BSON_SIZE );

    /* We'll perform the full test if we're running v2.0 or later. */
    if( mongo_get_server_version( version ) != -1 && version[0] <= '1' )
        return 0;

    if ( mongo_connect( conn , TEST_SERVER, 27017 ) ) {
        printf( "failed to connect\n" );
        exit( 1 );
    }

    ASSERT( conn->max_bson_size > MONGO_DEFAULT_MAX_BSON_SIZE );

    bson_init( b );
    for(i=0; i<1200000; i++) {
        sprintf( key, "%d", i + 10000000 );
        bson_append_int( b, key, i );
    }
    bson_finish( b );

    ASSERT( bson_size( b ) > conn->max_bson_size );

    ASSERT( mongo_insert( conn, "test.foo", b, NULL ) == MONGO_ERROR );
    ASSERT( conn->err == MONGO_BSON_TOO_LARGE );

    mongo_clear_errors( conn );
    ASSERT( conn->err == 0 );

    bson_init( b2 );
    bson_append_int( b2, "foo", 1 );
    bson_finish( b2 );

    objs[0] = b;
    objs[1] = b2;

    ASSERT( mongo_insert_batch( conn, "test.foo", (const bson **)objs, 2,
          NULL, 0 ) == MONGO_ERROR );
    ASSERT( conn->err == MONGO_BSON_TOO_LARGE );

    return 0;
}
QVariantMap TMongoDriver::findOne(const QString &ns, const QVariantMap &criteria,
                                  const QStringList &fields)
{
    TBson bs;

    mongo_clear_errors(mongoConnection);
    int status = mongo_find_one(mongoConnection, qPrintable(ns), (bson *)TBson::toBson(criteria).data(),
                                (bson *)TBson::toBson(fields).data(), (bson *)bs.data());
    if (status != MONGO_OK) {
        tSystemError("MongoDB Error: %s", mongoConnection->lasterrstr);
        return QVariantMap();
    }
    return TBson::fromBson(bs);
}
int TMongoDriver::count(const QString &ns, const QVariantMap &criteria)
{
    mongo_clear_errors(mongoConnection);
    int cnt = -1;
    int index = ns.indexOf('.');
    if (index < 0)
        return cnt;

    QString db = ns.mid(0, index);
    QString coll = ns.mid(index + 1);
    cnt = mongo_count(mongoConnection, qPrintable(db), qPrintable(coll), (const bson *)TBson::toBson(criteria).data());
    if (cnt == MONGO_ERROR) {
        tSystemError("MongoDB Error: %s", mongoConnection->lasterrstr);
        return -1;
    }
    return cnt;
}
int TMongoDriver::find(const QString &ns, const QVariantMap &criteria, const QVariantMap &orderBy,
                       const QStringList &fields, int limit, int skip, int options)
{
    int num = -1;
    mongo_clear_errors(mongoConnection);
    mongo_cursor *cursor = mongo_find(mongoConnection, qPrintable(ns), (bson *)TBson::toBson(criteria, orderBy).data(),
                                      (bson *)TBson::toBson(fields).data(), limit, skip, options);
    mongoCursor->setCursor(cursor);

    if (!cursor) {
        tSystemError("MongoDB Error: %s", mongoConnection->lasterrstr);
    } else {
        if (cursor->reply) {
            num = cursor->reply->fields.num;
        }
    }
    return num;
}
bool TMongoDriver::open(const QString &db, const QString &user, const QString &password, const QString &host, quint16 port, const QString &)
{
    if (host.isEmpty()) {
        return false;
    }

    if (!port)
        port = MONGO_DEFAULT_PORT;

    mongo_clear_errors(mongoConnection);
    mongo_set_op_timeout(mongoConnection, 1000);
    int status = mongo_client(mongoConnection, qPrintable(host), port);

    if (status != MONGO_OK) {
        switch (mongoConnection->err) {
        case MONGO_CONN_NO_SOCKET:
            tSystemError("MongoDB socket error: %s", mongoConnection->lasterrstr);
            break;

        case MONGO_CONN_FAIL:
            tSystemError("MongoDB connection failed: %s", mongoConnection->lasterrstr);
            break;

        case MONGO_CONN_NOT_MASTER:
            tSystemDebug("MongoDB not master: %s", mongoConnection->lasterrstr);
            break;

        default:
            tSystemError("MongoDB error: %s", mongoConnection->lasterrstr);
            break;
        }
        return false;
    }

    if (!user.isEmpty()) {
        status = mongo_cmd_authenticate(mongoConnection, qPrintable(db), qPrintable(user), qPrintable(password));
        if (status != MONGO_OK) {
            tSystemDebug("MongoDB authentication error: %s", mongoConnection->lasterrstr);
            return false;
        }
    }

    return (status == MONGO_OK);
}
示例#12
0
int mongo_env_socket_connect( mongo *conn, const char *host, int port ) {
    char port_str[NI_MAXSERV];
    char errstr[MONGO_ERR_LEN];
    int status;

    struct addrinfo ai_hints;
    struct addrinfo *ai_list = NULL;
    struct addrinfo *ai_ptr = NULL;

    conn->sock = 0;
    conn->connected = 0;

    bson_sprintf( port_str, "%d", port );

    memset( &ai_hints, 0, sizeof( ai_hints ) );
    ai_hints.ai_family = AF_UNSPEC;
    ai_hints.ai_socktype = SOCK_STREAM;
    ai_hints.ai_protocol = IPPROTO_TCP;

    status = getaddrinfo( host, port_str, &ai_hints, &ai_list );
    if ( status != 0 ) {
        bson_sprintf( errstr, "getaddrinfo failed with error %d", status );
        __mongo_set_error( conn, MONGO_CONN_ADDR_FAIL, errstr, WSAGetLastError() );
        return MONGO_ERROR;
    }

    for ( ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next ) {
        conn->sock = socket( ai_ptr->ai_family, ai_ptr->ai_socktype,
                             ai_ptr->ai_protocol );

        if ( conn->sock == INVALID_SOCKET ) {
            __mongo_set_error( conn, MONGO_SOCKET_ERROR, "socket() failed",
                               WSAGetLastError() );
            conn->sock = 0;
            continue;
        }

        status = connect( conn->sock, ai_ptr->ai_addr, ai_ptr->ai_addrlen );
        if ( status != 0 ) {
            __mongo_set_error( conn, MONGO_SOCKET_ERROR, "connect() failed",
                               WSAGetLastError() );
            mongo_env_close_socket( conn->sock );
            conn->sock = 0;
            continue;
        }

        if ( ai_ptr->ai_protocol == IPPROTO_TCP ) {
            int flag = 1;

            setsockopt( conn->sock, IPPROTO_TCP, TCP_NODELAY,
                        ( const char * ) &flag, sizeof( flag ) );

            if ( conn->op_timeout_ms > 0 )
                mongo_env_set_socket_op_timeout( conn, conn->op_timeout_ms );
        }

        conn->connected = 1;
        break;
    }

    freeaddrinfo( ai_list );

    if ( ! conn->connected ) {
        conn->err = MONGO_CONN_FAIL;
        return MONGO_ERROR;
    }
    else {
        mongo_clear_errors( conn );
        return MONGO_OK;
    }
}
示例#13
0
static void test_insert( mongo *conn ) {
    mongo_write_concern wc0[1], wc1[1];
    bson b[1], b2[1], b3[1], b4[1];
    bson *objs[2];

    mongo_cmd_drop_collection( conn, TEST_DB, TEST_COL, NULL );

    mongo_write_concern_init( wc0 );    
    mongo_write_concern_set_w( wc0, 0 );
    mongo_write_concern_finish( wc0 );
    mongo_write_concern_init( wc1 );    
    mongo_write_concern_set_w( wc1, 1 );
    mongo_write_concern_finish( wc1 );

    bson_init( b4 );
    bson_append_string( b4, "foo", "bar" );
    bson_finish( b4 );

    ASSERT( mongo_insert( conn, TEST_NS, b4, wc1 ) == MONGO_OK );

    ASSERT( mongo_remove( conn, TEST_NS, bson_shared_empty( ), wc1 ) == MONGO_OK );

    bson_init( b );
    bson_append_new_oid( b, "_id" );
    bson_finish( b );

    ASSERT( mongo_insert( conn, TEST_NS, b, NULL ) == MONGO_OK );

    /* This fails but returns OK with write concern w = 0 */
    ASSERT( mongo_insert( conn, TEST_NS, b, wc0 ) == MONGO_OK ); /* no getLastError request */

    ASSERT( mongo_insert( conn, TEST_NS, b, wc1 ) == MONGO_ERROR );
    ASSERT( conn->err == MONGO_WRITE_ERROR );
    ASSERT_EQUAL_STRINGS( conn->errstr, "See conn->lasterrstr for details." );
    ASSERT_EQUAL_STRINGS( conn->lasterrstr, "E11000 duplicate key error index" );
    ASSERT( conn->lasterrcode == 11000 );
    mongo_clear_errors( conn );

    /* Still fails but returns OK with write concern w = 0 */
    ASSERT( mongo_insert( conn, TEST_NS, b, wc0 ) == MONGO_OK );

    /* But not when we set a default write concern on the conn. */
    mongo_set_write_concern( conn, wc1 );
    ASSERT( mongo_insert( conn, TEST_NS, b, NULL ) != MONGO_OK );
    ASSERT( conn->err == MONGO_WRITE_ERROR );
    ASSERT_EQUAL_STRINGS( conn->errstr, "See conn->lasterrstr for details." );
    ASSERT_EQUAL_STRINGS( conn->lasterrstr, "E11000 duplicate key error index" );
    ASSERT( conn->lasterrcode == 11000 );

    /* Now test batch insert. */
    bson_init( b2 );
    bson_append_new_oid( b2, "_id" );
    bson_finish( b2 );

    bson_init( b3 );
    bson_append_new_oid( b3, "_id" );
    bson_finish( b3 );

    objs[0] = b2;
    objs[1] = b3;

    /* Insert two new documents by insert_batch. */
    conn->write_concern = NULL;
    ASSERT( mongo_count( conn, TEST_DB, TEST_COL, bson_shared_empty( ) ) == 1 );
    ASSERT( mongo_insert_batch( conn, TEST_NS, (const bson **)objs, 2, NULL, 0 ) == MONGO_OK );
    ASSERT( mongo_count( conn, TEST_DB, TEST_COL, bson_shared_empty( ) ) == 3 );

    /* This should definitely fail if we try again with write concern. */
    mongo_clear_errors( conn );
    ASSERT( mongo_insert_batch( conn, TEST_NS, (const bson **)objs, 2, wc1, 0 ) == MONGO_ERROR );
    ASSERT( conn->err == MONGO_WRITE_ERROR );
    ASSERT_EQUAL_STRINGS( conn->errstr, "See conn->lasterrstr for details." );
    ASSERT_EQUAL_STRINGS( conn->lasterrstr, "E11000 duplicate key error index" );
    ASSERT( conn->lasterrcode == 11000 );

    /* But it will succeed without the write concern set. */
    ASSERT( mongo_insert_batch( conn, TEST_NS, (const bson **)objs, 2, NULL, 0 ) == MONGO_OK );

    bson_destroy( b );
    bson_destroy( b2 );
    bson_destroy( b3 );
    bson_destroy( b4 );
    mongo_write_concern_destroy( wc0 );
    mongo_write_concern_destroy( wc1 );
}
示例#14
0
/* We can test write concern for update
 * and remove by doing operations on a capped collection. */
static void test_update_and_remove( mongo *conn ) {
    mongo_write_concern wc[1];
    bson *objs[5];
    bson query[1], update[1];
    int i;

    create_capped_collection( conn );

    for( i=0; i<5; i++ ) {
        objs[i] = bson_alloc();
        bson_init( objs[i] );
        bson_append_int( objs[i], "n", i );
        bson_finish( objs[i] );
    }

    ASSERT( mongo_insert_batch( conn, "test.wc", (const bson **)objs, 5,
        NULL, 0 ) == MONGO_OK );

    ASSERT( mongo_count( conn, "test", "wc", bson_shared_empty( ) ) == 5 );

    bson_init( query );
    bson_append_int( query, "n", 2 );
    bson_finish( query );

    ASSERT( mongo_find_one( conn, "test.wc", query, bson_shared_empty( ), NULL ) == MONGO_OK );

    bson_init( update );
        bson_append_start_object( update, "$set" );
            bson_append_string( update, "n", "a big long string" );
        bson_append_finish_object( update );
    bson_finish( update );

    /* Update will appear to succeed with no write concern specified, but doesn't. */
    ASSERT( mongo_find_one( conn, "test.wc", query, bson_shared_empty( ), NULL ) == MONGO_OK );
    ASSERT( mongo_update( conn, "test.wc", query, update, 0, NULL ) == MONGO_OK );
    ASSERT( mongo_find_one( conn, "test.wc", query, bson_shared_empty( ), NULL ) == MONGO_OK );

    /* Remove will appear to succeed with no write concern specified, but doesn't. */
    ASSERT( mongo_remove( conn, "test.wc", query, NULL ) == MONGO_OK );
    ASSERT( mongo_find_one( conn, "test.wc", query, bson_shared_empty( ), NULL ) == MONGO_OK );

    mongo_write_concern_init( wc );    
    mongo_write_concern_set_w( wc, 1 );
    mongo_write_concern_finish( wc );

    mongo_clear_errors( conn );
    ASSERT( mongo_update( conn, "test.wc", query, update, 0, wc ) == MONGO_ERROR );
    ASSERT( conn->err == MONGO_WRITE_ERROR );
    ASSERT_EQUAL_STRINGS( conn->lasterrstr, "failing update: objects in a capped ns cannot grow" );

    mongo_clear_errors( conn );
    ASSERT( mongo_remove( conn, "test.wc", query, wc ) == MONGO_ERROR );
    ASSERT( conn->err == MONGO_WRITE_ERROR );
    ASSERT_EQUAL_STRINGS( conn->lasterrstr, "can't remove from a capped collection" );

    mongo_write_concern_destroy( wc );
    bson_destroy( query );
    bson_destroy( update );
    for( i=0; i<5; i++ ) {
        bson_destroy( objs[i] );
        bson_dealloc( objs[i] );
    }
}
示例#15
0
int test_namespace_validation() {
    mongo conn[1];
    char longns[130] = "test.foo";
    int i;

    mongo_init( conn );

    /* Test a few legal namespaces. */
    ASSERT( mongo_validate_ns( conn, "test.foo" ) == MONGO_OK );
    ASSERT( conn->err == 0 );

    ASSERT( mongo_validate_ns( conn, "test.foo.bar" ) == MONGO_OK );
    ASSERT( conn->err == 0 );

    /* Test illegal namespaces. */
    ASSERT( mongo_validate_ns( conn, ".test.foo" ) == MONGO_ERROR );
    ASSERT( conn->err == MONGO_NS_INVALID );
    ASSERT( strncmp( conn->errstr, "ns cannot start with", 20 ) == 0 );
    mongo_clear_errors( conn );

    ASSERT( mongo_validate_ns( conn, "test..foo" ) == MONGO_ERROR );
    ASSERT( conn->err == MONGO_NS_INVALID );
    ASSERT( strncmp( conn->errstr, "ns cannot start with", 20 ) == 0 );
    mongo_clear_errors( conn );

    ASSERT( mongo_validate_ns( conn, "test" ) == MONGO_ERROR );
    ASSERT( conn->err == MONGO_NS_INVALID );
    ASSERT( strncmp( conn->errstr, "ns cannot start with", 20 ) == 0 );
    mongo_clear_errors( conn );

    ASSERT( mongo_validate_ns( conn, "." ) == MONGO_ERROR );
    ASSERT( conn->err == MONGO_NS_INVALID );
    ASSERT( strncmp( conn->errstr, "ns cannot start with", 20 ) == 0 );
    mongo_clear_errors( conn );

    ASSERT( mongo_validate_ns( conn, "tes t.foo" ) == MONGO_ERROR );
    ASSERT( conn->err == MONGO_NS_INVALID );
    ASSERT( strncmp( conn->errstr, "Database name may not contain", 28 ) == 0 );
    mongo_clear_errors( conn );

    ASSERT( mongo_validate_ns( conn, "te$st.foo" ) == MONGO_ERROR );
    ASSERT( conn->err == MONGO_NS_INVALID );
    ASSERT( strncmp( conn->errstr, "Database name may not contain", 28 ) == 0 );
    mongo_clear_errors( conn );

    ASSERT( mongo_validate_ns( conn, "te/st.foo" ) == MONGO_ERROR );
    ASSERT( conn->err == MONGO_NS_INVALID );
    ASSERT( strncmp( conn->errstr, "Database name may not contain", 28 ) == 0 );
    mongo_clear_errors( conn );

    ASSERT( mongo_validate_ns( conn, "te\\st.foo" ) == MONGO_ERROR );
    ASSERT( conn->err == MONGO_NS_INVALID );
    ASSERT( strncmp( conn->errstr, "Database name may not contain", 28 ) == 0 );
    mongo_clear_errors( conn );

    ASSERT( mongo_validate_ns( conn, "test.fo$o" ) == MONGO_ERROR );
    ASSERT( conn->err == MONGO_NS_INVALID );
    ASSERT( strncmp( conn->errstr, "Collection may not contain '$'", 29 ) == 0 );
    mongo_clear_errors( conn );

    ASSERT( mongo_validate_ns( conn, "test.fo..o" ) == MONGO_ERROR );
    ASSERT( conn->err == MONGO_NS_INVALID );
    ASSERT( strncmp( conn->errstr, "Collection may not contain two consecutive '.'", 46 ) == 0 );
    mongo_clear_errors( conn );

    ASSERT( mongo_validate_ns( conn, "test.fo.o." ) == MONGO_ERROR );
    ASSERT( conn->err == MONGO_NS_INVALID );
    ASSERT( strncmp( conn->errstr, "Collection may not end with '.'", 30 ) == 0 );
    mongo_clear_errors( conn );

    for(i = 8; i < 129; i++ )
        longns[i] = 'a';
    longns[129] = '\0';

    ASSERT( mongo_validate_ns( conn, longns ) == MONGO_ERROR );
    ASSERT( conn->err == MONGO_NS_INVALID );
    ASSERT( strncmp( conn->errstr, "Namespace too long; has 129 but must <= 128.", 32 ) == 0 );
    mongo_clear_errors( conn );

    return 0;
}