Ejemplo n.º 1
0
mrb_value mrb_mongo_collection_init(mrb_state *mrb, mrb_value self) {
  mrb_value database, collection_name;
  mrb_mongo_database_data *db_data;
  mrb_mongo_collection_data *data;
  mongoc_collection_t *collection;

  //parse args
  mrb_get_args(mrb, "oS", &database, &collection_name);

  //prepare data structure
  data = (mrb_mongo_collection_data*)DATA_PTR(self);
  if (data) {
    mrb_free(mrb, data);
  }
  DATA_TYPE(self) = &mrb_mongo_collection_data_type;
  DATA_PTR(self) = NULL;
  data = (mrb_mongo_collection_data*)mrb_malloc(mrb, sizeof(mrb_mongo_collection_data));

  //get db data
  db_data = (mrb_mongo_database_data *)DATA_PTR(database);

  collection = mongoc_database_get_collection(db_data->db, mrb_str_to_cstr(mrb, collection_name));

  mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "database"), database);
  mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "name"), collection_name);

  //set data structure
  data->collection = collection;
  DATA_PTR(self) = data;

  return self;
}
Ejemplo n.º 2
0
int
main (int   argc,
      char *argv[])
{
   const char *default_uristr = "mongodb://localhost/test";
   char *uristr;
   const char *database_name;
   mongoc_uri_t *uri;
   mongoc_client_t *client;
   mongoc_database_t *db;
   mongoc_collection_t *collection;

   mongoc_init ();

   uristr = getenv ("MONGODB_URI");
   uristr = uristr ? uristr : (char*)default_uristr;
   uri = mongoc_uri_new (uristr);
   client = mongoc_client_new_from_uri (uri);
   database_name = mongoc_uri_get_database (uri);
   db = mongoc_client_get_database (client, database_name);
   collection = mongoc_database_get_collection (db, "test");

   test_suite (db, collection);

   mongoc_collection_destroy (collection);
   mongoc_database_destroy (db);
   mongoc_client_destroy (client);
   mongoc_uri_destroy (uri);

   mongoc_cleanup ();

   return 0;
}
Ejemplo n.º 3
0
mongoc_collection_t * dbproxy::get_collection(std::string collection_name) {
    auto it = collectiondict.find(collection_name);
    if (it != collectiondict.end()) {
        return it->second;
    }

    return mongoc_database_get_collection(_db, collection_name.c_str());
}
Ejemplo n.º 4
0
static void dump_message(ullong number, str_t type, msg_content_array_t* content)
{
    bson_t document;
    bson_error_t error;
    time_t t;
    mongoc_collection_t* collection = mongoc_database_get_collection(robot.mongoc_database, "message");
    char* json = msg_content_array_to_json_object_string(content, "content");

    time(&t);
    if (!bson_init_from_json(&document, json, strlen(json), &error)) MONGOC_WARNING("%s\n", error.message);
    BSON_APPEND_INT64(&document, "from", number);
    BSON_APPEND_UTF8(&document, "type", type.ptr);
    BSON_APPEND_TIME_T(&document, "time", t);
    if (!mongoc_collection_insert(collection, MONGOC_INSERT_NONE, &document, NULL, &error)) MONGOC_WARNING("%s\n", error.message);
    bson_destroy(&document);
    free(json);
}
Ejemplo n.º 5
0
int
lua_mongo_collection_new(lua_State *L)
{
    const char* collection_name;
    database_t *database;
    collection_t *collection;

    database = (database_t *)luaL_checkudata(L, 1, "lua_mongoc_database");

    collection_name = luaL_checkstring(L, 2);
    if (collection_name == NULL) {
        luaL_error(L, "collection name cannot be empty");
    }

    collection = (collection_t *)lua_newuserdata(L, sizeof(*collection));
    collection->c_collection = mongoc_database_get_collection(database->c_database, collection_name);
    collection->c_database = database->c_database;

    luaL_getmetatable(L, "lua_mongoc_collection");
    lua_setmetatable(L, -2);

    return 1;
}
Ejemplo n.º 6
0
int
main (int   argc,
      char *argv[])
{
   mongoc_database_t *database = NULL;
   mongoc_client_t *client = NULL;
   mongoc_collection_t *collection = NULL;
   char *host_and_port;
   int res = 0;
   char* other_host_and_port = NULL;

   if (argc < 2 || argc > 3) {
      fprintf (stderr, "usage: %s MONGOD-1-CONNECTION-STRING "
               "[MONGOD-2-HOST-NAME:MONGOD-2-PORT]\n",
               argv[0]);
      fprintf (stderr,
               "MONGOD-1-CONNECTION-STRING can be "
               "of the following forms:\n");
      fprintf (stderr, "localhost\t\t\t\tlocal machine\n");
      fprintf (stderr, "localhost:27018\t\t\t\tlocal machine on port 27018\n");
      fprintf (stderr,
               "mongodb://*****:*****@localhost:27017\t"
               "local machine on port 27017, and authenticate with username "
               "user and password pass\n");
      return 1;
   }

   mongoc_init ();

   if (strncmp (argv[1], "mongodb://", 10) == 0) {
      host_and_port = bson_strdup (argv [1]);
   } else {
      host_and_port = bson_strdup_printf ("mongodb://%s", argv[1]);
   }
   other_host_and_port = argc > 2 ? argv[2] : NULL;

   client = mongoc_client_new (host_and_port);

   if (!client) {
      fprintf(stderr, "Invalid hostname or port: %s\n", host_and_port);
      res = 2;
      goto cleanup;
   }

   database = mongoc_client_get_database (client, "test");
   collection = mongoc_database_get_collection (database, COLLECTION_NAME);

   printf ("Inserting data\n");
   if (!insert_data (collection)) {
      res = 3;
      goto cleanup;
   }

   printf ("explain\n");
   if (!explain (collection)) {
      res = 4;
      goto cleanup;
   }

   if (other_host_and_port) {
      printf ("copydb\n");
      if (!copydb (client, other_host_and_port)) {
         res = 5;
         goto cleanup;
      }

      printf ("clone collection\n");
      if (!clone_collection (database, other_host_and_port)) {
         res = 6;
         goto cleanup;
      }
   }

cleanup:
   if (collection) {
      mongoc_collection_destroy (collection);
   }

   if (database) {
      mongoc_database_destroy (database);
   }

   if (client) {
      mongoc_client_destroy (client);
   }

   bson_free (host_and_port);
   mongoc_cleanup ();
   return res;
}
Ejemplo n.º 7
0
static void
test_bypass_validation (void *context)
{
   mongoc_collection_t *collection;
   bson_t reply = BSON_INITIALIZER;
   mongoc_bulk_operation_t *bulk;
   mongoc_database_t *database;
   mongoc_write_concern_t *wr;
   mongoc_client_t *client;
   bson_error_t error;
   bson_t *options;
   char *collname;
   char *dbname;
   int r;
   int i;

   client = test_framework_client_new ();
   assert (client);

   dbname = gen_collection_name ("dbtest");
   collname = gen_collection_name ("bypass");
   database = mongoc_client_get_database (client, dbname);
   collection = mongoc_database_get_collection (database, collname);
   assert (collection);

   options = tmp_bson ("{'validator': {'number': {'$gte': 5}}, 'validationAction': 'error'}");
   ASSERT_OR_PRINT (mongoc_database_create_collection (database, collname, options, &error), error);

   /* {{{ Default fails validation */
   bulk = mongoc_collection_create_bulk_operation(collection, true, NULL);
   for (i = 0; i < 3; i++) {
      bson_t *doc = tmp_bson (bson_strdup_printf ("{'number': 3, 'high': %d }", i));

      mongoc_bulk_operation_insert (bulk, doc);
   }
   r = mongoc_bulk_operation_execute (bulk, &reply, &error);
   ASSERT(!r);

   ASSERT_ERROR_CONTAINS (error, MONGOC_ERROR_COMMAND, 121, "Document failed validation");
   mongoc_bulk_operation_destroy (bulk);
   /* }}} */

   /* {{{ bypass_document_validation=false Fails validation */
   bulk = mongoc_collection_create_bulk_operation(collection, true, NULL);
   mongoc_bulk_operation_set_bypass_document_validation (bulk, false);
   for (i = 0; i < 3; i++) {
      bson_t *doc = tmp_bson (bson_strdup_printf ("{'number': 3, 'high': %d }", i));

      mongoc_bulk_operation_insert (bulk, doc);
   }
   r = mongoc_bulk_operation_execute (bulk, &reply, &error);
   ASSERT(!r);

   ASSERT_ERROR_CONTAINS (error, MONGOC_ERROR_COMMAND, 121, "Document failed validation");
   mongoc_bulk_operation_destroy (bulk);
   /* }}} */

   /* {{{ bypass_document_validation=true ignores validation */
   bulk = mongoc_collection_create_bulk_operation(collection, true, NULL);
   mongoc_bulk_operation_set_bypass_document_validation (bulk, true);
   for (i = 0; i < 3; i++) {
      bson_t *doc = tmp_bson (bson_strdup_printf ("{'number': 3, 'high': %d }", i));

      mongoc_bulk_operation_insert (bulk, doc);
   }
   r = mongoc_bulk_operation_execute (bulk, &reply, &error);
   ASSERT_OR_PRINT(r, error);
   mongoc_bulk_operation_destroy (bulk);
   /* }}} */

   /* {{{ w=0 and bypass_document_validation=set fails */
   bulk = mongoc_collection_create_bulk_operation(collection, true, NULL);
   wr = mongoc_write_concern_new ();
   mongoc_write_concern_set_w (wr, 0);
   mongoc_bulk_operation_set_write_concern (bulk, wr);
   mongoc_bulk_operation_set_bypass_document_validation (bulk, true);
   for (i = 0; i < 3; i++) {
      bson_t *doc = tmp_bson (bson_strdup_printf ("{'number': 3, 'high': %d }", i));

      mongoc_bulk_operation_insert (bulk, doc);
   }
   r = mongoc_bulk_operation_execute (bulk, &reply, &error);
   ASSERT_OR_PRINT(!r, error);
   ASSERT_ERROR_CONTAINS (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG,
         "Cannot set bypassDocumentValidation for unacknowledged writes");
   mongoc_bulk_operation_destroy (bulk);
   mongoc_write_concern_destroy (wr);
   /* }}} */

   ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error);

   mongoc_collection_destroy (collection);
   mongoc_client_destroy (client);
}
Ejemplo n.º 8
0
static void route_result(cJSON* result)
{
    cJSON* cjson_current;
    size_t i;
    for (cjson_current = result->child; cjson_current; cjson_current = cjson_current->next)
    {
        if (strcmp(cJSON_GetObjectItem(cjson_current, "poll_type")->valuestring, "message") == 0)
        {
            cJSON* cjson_value = cJSON_GetObjectItem(cjson_current, "value");
            ullong from_uin = cJSON_GetObjectItem(cjson_value, "from_uin")->valuedouble;
            ullong number = get_friend_number(from_uin);
            msg_content_array_t content = fetch_content(cJSON_GetObjectItem(cjson_value, "content"));
            dump_message(number, str_from("friend_message"), &content);
#ifdef _DEBUG
            {
                char* str = msg_content_array_to_json_object_string(&content, "content");
                fprintf(stdout, "Received message from: %llu\nContent: %s\n", number, str);
                fflush(stdout);
                free(str);
            }
#endif

            for (i = 0; i < robot.received_message_funcs_count; ++i) robot.received_message_funcs[i](from_uin, number, &content);
            msg_content_array_free(&content);
        }
        else if (strcmp(cJSON_GetObjectItem(cjson_current, "poll_type")->valuestring, "group_message") == 0)
        {
            cJSON* cjson_value = cJSON_GetObjectItem(cjson_current, "value");
            ullong from_uin = cJSON_GetObjectItem(cjson_value, "from_uin")->valuedouble;
            ullong number = get_group_number(cJSON_GetObjectItem(cjson_value, "group_code")->valuedouble);
            msg_content_array_t content = fetch_content(cJSON_GetObjectItem(cjson_value, "content"));
            dump_message(number, str_from("group_message"), &content);
#ifdef _DEBUG
            {
                char* str = msg_content_array_to_json_object_string(&content, "content");
                fprintf(stdout, "Received group_message from: %llu\nContent: %s\n", number, str);
                fflush(stdout);
                free(str);
            }
#endif

            for (i = 0; i < robot.received_group_message_funcs_count; ++i) robot.received_group_message_funcs[i](from_uin, number, &content);
            msg_content_array_free(&content);
        }
        else
        {
            bson_t document;
            bson_t content;
            bson_error_t error;
            time_t t;
            char* ptr = cJSON_PrintUnformatted(cjson_current);
            mongoc_collection_t* collection = mongoc_database_get_collection(robot.mongoc_database, "unprocessed");

            time(&t);
            if (!bson_init_from_json(&content, ptr, strlen(ptr), &error))
            {
                MONGOC_WARNING("%s\n", error.message);
                return;
            }
            bson_init(&document);
            BSON_APPEND_TIME_T(&document, "time", t);
            BSON_APPEND_DOCUMENT(&document, "content", &content);
            if (!mongoc_collection_insert(collection, MONGOC_INSERT_NONE, &document, NULL, &error)) MONGOC_WARNING("%s\n", error.message);
            bson_destroy(&document);
            bson_destroy(&content);
        }
    }
}
Ejemplo n.º 9
0
static int init()
{
    str_t tmp = empty_str;
    str_t host = conf_lookup(&robot.conf, str_from("DB_HOST")).string;
    str_t name = conf_lookup(&robot.conf, str_from("DB_NAME")).string;
    size_t i;

    int rc = 1;

    str_cat(&tmp, "mongodb://");
    str_ncat(&tmp, host.ptr, host.len);
    robot.mongoc_client = mongoc_client_new(tmp.ptr);
    if (robot.mongoc_client == NULL)
    {
        rc = 0;
        fprintf(stderr, "mongoc_client_new(\"%s\") error!!!!\n", tmp.ptr);
        goto end;
    }

    robot.mongoc_database = mongoc_client_get_database(robot.mongoc_client, name.ptr);
    if (robot.mongoc_database == NULL)
    {
        rc = 0;
        fprintf(stderr, "mongoc_client_get_database(\"%s\") error!!!!\n", name.ptr);
        goto end;
    }

    {
        mongoc_collection_t* message_collection;
        mongoc_index_opt_t opt;
        bson_error_t error;
        bson_t keys;

        message_collection = mongoc_database_get_collection(robot.mongoc_database, "message");
        if (message_collection == NULL)
        {
            rc = 0;
            fprintf(stderr, "mongoc_database_get_collection(\"message\") error!!!!\n");
            goto end;
        }

        mongoc_index_opt_init(&opt);

        // from+type 做联合索引
        bson_init(&keys);
        BSON_APPEND_INT32(&keys, "from", 1);
        BSON_APPEND_INT32(&keys, "type", 1);

        if (!mongoc_collection_create_index(message_collection, &keys, &opt, &error)) MONGOC_WARNING("%s\n", error.message);

        bson_destroy(&keys);

        // time 做逆序索引
        bson_init(&keys);
        BSON_APPEND_INT32(&keys, "time", -1);

        if (!mongoc_collection_create_index(message_collection, &keys, &opt, &error)) MONGOC_WARNING("%s\n", error.message);

        bson_destroy(&keys);

        // content 做全文索引
        bson_init(&keys);
        BSON_APPEND_UTF8(&keys, "content", "text");

        if (!mongoc_collection_create_index(message_collection, &keys, &opt, &error)) MONGOC_WARNING("%s\n", error.message);

        bson_destroy(&keys);
    }

    {
        mongoc_collection_t* unprocessed_collection;
        mongoc_index_opt_t opt;
        bson_error_t error;
        bson_t keys;

        unprocessed_collection = mongoc_database_get_collection(robot.mongoc_database, "unprocessed");
        if (unprocessed_collection == NULL)
        {
            rc = 0;
            fprintf(stderr, "mongoc_database_get_collection(\"unprocessed\") error!!!!\n");
            goto end;
        }

        mongoc_index_opt_init(&opt);

        // time 做逆序索引
        bson_init(&keys);
        BSON_APPEND_INT32(&keys, "time", -1);

        if (!mongoc_collection_create_index(unprocessed_collection, &keys, &opt, &error)) MONGOC_WARNING("%s\n", error.message);

        bson_destroy(&keys);
    }

    for (i = 0; modules[i]; ++i)
    {
        if (modules[i]->module_init)
        {
            rc = modules[i]->module_init();
            if (!rc) goto end;
        }
    }
end:
    str_free(tmp);
    return rc;
}
bool map_reduce_basic (mongoc_database_t* database)
{
   bson_t reply;
   bson_t* command;
   bool res;
   bson_error_t error;
   mongoc_cursor_t* cursor;
   const bson_t* doc;

   bool map_reduce_done = false;
   bool query_done = false;

   const char* out_collection_name = "outCollection";
   mongoc_collection_t* out_collection;

   /* Empty find query */
   bson_t find_query = BSON_INITIALIZER;

   /* Construct the mapReduce command */

   /* Other arguments can also be specified here, like "query" or
      "limit" and so on */
   command = BCON_NEW ("mapReduce", BCON_UTF8 (COLLECTION_NAME),
                       "map", BCON_CODE (MAPPER),
                       "reduce", BCON_CODE (REDUCER),
                       "out", BCON_UTF8 (out_collection_name));
   res = mongoc_database_command_simple (database, command, NULL,
                                        &reply, &error);
   map_reduce_done = true;

   if (!res) {
      fprintf (stderr, "MapReduce failed: %s\n", error.message);
      goto cleanup;
   }

   /* Do something with the reply (it doesn't contain the mapReduce results) */
   print_res (&reply);

   /* Now we'll query outCollection to see what the results are */
   out_collection = mongoc_database_get_collection (database,
                                                    out_collection_name);
   cursor = mongoc_collection_find_with_opts (out_collection, &find_query,
                                              NULL, NULL);
   query_done = true;

   /* Do something with the results */
   while (mongoc_cursor_next (cursor, &doc)) {
      print_res (doc);
   }

   if (mongoc_cursor_error (cursor, &error)) {
      fprintf (stderr, "ERROR: %s\n", error.message);
      res = false;
      goto cleanup;
   }

cleanup:
   /* cleanup */
   if (query_done) {
      mongoc_cursor_destroy (cursor);
      mongoc_collection_destroy (out_collection);
   }

   if (map_reduce_done) {
      bson_destroy (&reply);
      bson_destroy (command);
   }

   return res;
}
Ejemplo n.º 11
0
int64_t
load_table (mongoc_database_t *db,
            const char        *table_name,
            bson_t            *bson_schema)
{
    int64_t ret = true;
    column_map_t *column_map, *column_map_p;
    int column_map_size, i;
    double start_time, end_time, delta_time;
    FILE *fp;
    mongoc_collection_t *collection;
    mongoc_bulk_operation_t *bulk;
    size_t n_docs = 0;
    char *token;
    bson_t bson, reply;
    int64_t count = 0;
    bson_error_t error;

    fprintf (stderr, "load_table table_name: \"%s\"\n", table_name);
    get_column_map (bson_schema, table_name, &column_map, &column_map_size) || DIE;
    snprintf (mbdump_file, MAXPATHLEN, "%s/%s", mbdump_dir, table_name);
    /* fprintf (stderr, "mbdump_file: \"%s\"\n", mbdump_file); */
    start_time = dtimeofday ();
    fp = fopen (mbdump_file, "r");
    if (!fp) DIE;
    collection = mongoc_database_get_collection (db, table_name);
    bulk = mongoc_collection_create_bulk_operation (collection, true, NULL);
    bson_init (&bson);
    while (ret && fgets (buf, BUFSIZ, fp)) {
        /*
        fputs (buf, stdout);
        */
        chomp (buf);
        for (i = 0, column_map_p = column_map, token = strtok_single (buf, "\t");
             i < column_map_size;
             i++, column_map_p++, token = strtok_single (NULL, "\t")) {
             bool ret;
             /*
             fprintf (stderr, "%s: \"%s\" [%d/%d](%s)\n", column_map_p->column_name, token, i, column_map_size, column_map_p->data_type);
             fflush (stdout);
             */
             ret = (*column_map_p->bson_append_from_s) (&bson, column_map_p->column_name, token);
             ret || fprintf (stderr, "WARNING: column_map_p->bson_append_from_s failed column %s: \"%s\" [%d/%d](%s)\n",
                            column_map_p->column_name, token, i, column_map_size, column_map_p->data_type);
        }
        /*
        bson_printf ("bson: %s\n", &bson);
        */
        mongoc_bulk_operation_insert (bulk, &bson);
        bson_reinit (&bson);
        if (++n_docs == BULK_OPS_SIZE) {
           ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
           if (ret) {
              count += n_docs;
              if (count % PROGRESS_SIZE == 0) {
                  fputc('.', stdout);
                  fflush(stdout);
              }
           }
           else
              fprintf (stderr, "mongoc_cursor_bulk_insert execute failure: %s\n", error.message);
           n_docs = 0;
           mongoc_bulk_operation_destroy (bulk);
           bulk = mongoc_collection_create_bulk_operation (collection, true, NULL);
        }
    }
    if (ret && n_docs > 0) {
       ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
       if (ret)
          count += n_docs;
       else
          fprintf (stderr, "mongoc_cursor_bulk_insert execute failure: %s\n", error.message);
    }
    fputc('.', stdout);
    fputc('\n', stdout);
    fflush(stdout);
    bson_destroy (&bson);
    mongoc_bulk_operation_destroy (bulk);
    mongoc_collection_destroy (collection);
    fclose (fp);
    end_time = dtimeofday ();
    delta_time = end_time - start_time + 0.0000001;
    fprintf (stderr, "info: real: %.2f, count: %"PRId64", %"PRId64" docs/sec\n", delta_time, count, (int64_t)round (count/delta_time));
    fflush (stderr);
    free (column_map);
    return ret ? count : -1;
}
Ejemplo n.º 12
0
static void
test_func_inherits_opts (void *ctx)
{
   opt_inheritance_test_t *test = (opt_inheritance_test_t *) ctx;

   /* for example, test mongoc_collection_find_with_opts with no read pref,
    * with a read pref set on the collection (OPT_SOURCE_COLL), with an explicit
    * read pref (OPT_SOURCE_FUNC), or with one read pref on the collection and
    * a different one passed explicitly */
   opt_source_t source_matrix[] = {OPT_SOURCE_NONE,
                                   test->opt_source,
                                   OPT_SOURCE_FUNC,
                                   test->opt_source | OPT_SOURCE_FUNC};

   size_t i;
   func_ctx_t func_ctx;
   mock_rs_t *rs;
   mongoc_client_t *client;
   mongoc_database_t *db;
   mongoc_collection_t *collection;
   bson_t opts = BSON_INITIALIZER;
   mongoc_read_prefs_t *func_prefs = NULL;
   future_t *future;
   request_t *request;
   bson_t cmd = BSON_INITIALIZER;
   bool expect_secondary;
   bson_error_t error;

   /* one primary, one secondary */
   rs = mock_rs_with_autoismaster (WIRE_VERSION_OP_MSG, true, 1, 0);
   /* we use read pref tags like "collection": "yes" to verify where the
    * pref was inherited from; ensure all secondaries match all tags */
   mock_rs_tag_secondary (rs,
                          0,
                          tmp_bson ("{'client': 'yes',"
                                    " 'database': 'yes',"
                                    " 'collection': 'yes',"
                                    " 'function': 'yes'}"));

   mock_rs_run (rs);

   /* iterate over all combinations of options sources: e.g., an option set on
    * collection and not function, on function not collection, both, neither */
   for (i = 0; i < sizeof (source_matrix) / (sizeof (opt_source_t)); i++) {
      expect_secondary = false;
      func_prefs = NULL;
      bson_reinit (&cmd);
      bson_reinit (&opts);

      client = mongoc_client_new_from_uri (mock_rs_get_uri (rs));
      if (source_matrix[i] & OPT_SOURCE_CLIENT) {
         set_client_opt (client, test->opt_type);
      }

      db = mongoc_client_get_database (client, "database");
      if (source_matrix[i] & OPT_SOURCE_DB) {
         set_database_opt (db, test->opt_type);
      }

      collection = mongoc_database_get_collection (db, "collection");
      if (source_matrix[i] & OPT_SOURCE_COLL) {
         set_collection_opt (collection, test->opt_type);
      }

      if (source_matrix[i] & OPT_SOURCE_FUNC) {
         set_func_opt (&opts, &func_prefs, test->opt_type);
      }

      func_ctx_init (
         &func_ctx, test, client, db, collection, func_prefs, &opts);

      /* func_with_opts creates expected "cmd", like {insert: 'collection'} */
      future = test->func_with_opts (&func_ctx, &cmd);

      if (source_matrix[i] != OPT_SOURCE_NONE) {
         add_expected_opt (source_matrix[i], test->opt_type, &cmd);
         if (test->opt_type == OPT_READ_PREFS) {
            expect_secondary = true;
         }
      }

      /* write commands send two OP_MSG sections */
      if (test->n_sections == 2) {
         request = mock_rs_receives_msg (rs, 0, &cmd, tmp_bson ("{}"));
      } else {
         request = mock_rs_receives_msg (rs, 0, &cmd);
      }

      if (expect_secondary) {
         BSON_ASSERT (mock_rs_request_is_to_secondary (rs, request));
      } else {
         BSON_ASSERT (mock_rs_request_is_to_primary (rs, request));
      }

      if (func_ctx.cursor) {
         mock_server_replies_simple (request,
                                     "{'ok': 1,"
                                     " 'cursor': {"
                                     "    'id': 0,"
                                     "    'ns': 'db.collection',"
                                     "    'firstBatch': []}}");

         BSON_ASSERT (!future_get_bool (future));
         future_destroy (future);
         ASSERT_OR_PRINT (!mongoc_cursor_error (func_ctx.cursor, &error),
                          error);
      } else {
         mock_server_replies_simple (request, "{'ok': 1}");
         cleanup_future (future);
      }

      request_destroy (request);
      mongoc_read_prefs_destroy (func_prefs);
      func_ctx_cleanup (&func_ctx);
      mongoc_collection_destroy (collection);
      mongoc_database_destroy (db);
      mongoc_client_destroy (client);
   }

   bson_destroy (&cmd);
   bson_destroy (&opts);
   mock_rs_destroy (rs);
}