mock_server_t * mock_server_down (void) { mock_server_t *server = mock_server_new (); mock_server_autoresponds (server, hangup, NULL, NULL); return server; }
static mock_server_t * _run_server (read_pref_test_type_t test_type, int32_t max_wire_version) { mock_server_t *server; server = mock_server_new (); mock_server_run (server); switch (test_type) { case READ_PREF_TEST_STANDALONE: mock_server_auto_ismaster (server, "{'ok': 1," " 'maxWireVersion': %d," " 'ismaster': true}", max_wire_version); break; case READ_PREF_TEST_MONGOS: mock_server_auto_ismaster (server, "{'ok': 1," " 'maxWireVersion': %d," " 'ismaster': true," " 'msg': 'isdbgrid'}", max_wire_version); break; case READ_PREF_TEST_PRIMARY: mock_server_auto_ismaster (server, "{'ok': 1," " 'maxWireVersion': %d," " 'ismaster': true," " 'setName': 'rs'," " 'hosts': ['%s']}", max_wire_version, mock_server_get_host_and_port (server)); break; case READ_PREF_TEST_SECONDARY: mock_server_auto_ismaster (server, "{'ok': 1," " 'maxWireVersion': %d," " 'ismaster': false," " 'secondary': true," " 'setName': 'rs'," " 'hosts': ['%s']}", max_wire_version, mock_server_get_host_and_port (server)); break; default: fprintf (stderr, "Invalid test_type: : %d\n", test_type); abort (); } return server; }
static void test_wire_version (void) { mongoc_collection_t *collection; mongoc_cursor_t *cursor; mongoc_client_t *client; mock_server_t *server; uint16_t port; const bson_t *doc; bson_error_t error; bool r; bson_t q = BSON_INITIALIZER; char *uristr; port = 20000 + (rand () % 1000); server = mock_server_new ("127.0.0.1", port, NULL, NULL); mock_server_set_wire_version (server, 10, 11); mock_server_run_in_thread (server); usleep (5000); uristr = bson_strdup_printf ("mongodb://127.0.0.1:%hu/", port); client = mongoc_client_new (uristr); collection = mongoc_client_get_collection (client, "test", "test"); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 1, 0, &q, NULL, NULL); r = mongoc_cursor_next (cursor, &doc); assert (!r); r = mongoc_cursor_error (cursor, &error); assert (r); assert (error.domain == MONGOC_ERROR_PROTOCOL); assert (error.code == MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); mock_server_quit (server, 0); mongoc_client_destroy (client); bson_free (uristr); }
mock_server_t * mock_server_with_autoismaster (int32_t max_wire_version) { mock_server_t *server = mock_server_new (); char *ismaster = bson_strdup_printf ("{'ok': 1.0," " 'ismaster': true," " 'minWireVersion': 0," " 'maxWireVersion': %d}", max_wire_version); mock_server_auto_ismaster (server, ismaster); bson_free (ismaster); return server; }
static void _test_heartbeat_events (bool pooled, bool succeeded) { context_t context; mock_server_t *server; mongoc_uri_t *uri; mongoc_client_t *client; mongoc_client_pool_t *pool = NULL; future_t *future; request_t *request; char *expected_json; bson_error_t error; context_init (&context); /* auto-respond to "foo" command */ server = mock_server_new (); mock_server_run (server); mock_server_autoresponds (server, responder, NULL, NULL); uri = mongoc_uri_copy (mock_server_get_uri (server)); mongoc_uri_set_option_as_int32 (uri, "serverSelectionTimeoutMS", 400); if (pooled) { pool = mongoc_client_pool_new (uri); pool_set_heartbeat_event_callbacks (pool, &context); client = mongoc_client_pool_pop (pool); } else { client = mongoc_client_new_from_uri (uri); client_set_heartbeat_event_callbacks (client, &context); } /* trigger "ismaster" handshake */ future = future_client_command_simple (client, "admin", tmp_bson ("{'foo': 1}"), NULL, NULL, &error); /* topology scanner calls ismaster once */ request = mock_server_receives_ismaster (server); if (succeeded) { mock_server_replies_ok_and_destroys (request); } else { mock_server_hangs_up (request); request_destroy (request); } /* pooled client opens new socket, handshakes it by calling ismaster again */ if (pooled && succeeded) { request = mock_server_receives_ismaster (server); mock_server_replies_ok_and_destroys (request); } if (succeeded) { /* "foo" command succeeds */ ASSERT_OR_PRINT (future_get_bool (future), error); } else { ASSERT (!future_get_bool (future)); } if (pooled) { mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); } else { mongoc_client_destroy (client); } /* even if pooled, only topology scanner sends events, so we get one pair */ if (succeeded) { expected_json = bson_strdup_printf ( "{'0': {'heartbeat_started_event': {'host': '%s'}}," " '1': {'heartbeat_succeeded_event': {'host': '%s'}}}", mock_server_get_host_and_port (server), mock_server_get_host_and_port (server)); } else { expected_json = bson_strdup_printf ( "{'0': {'heartbeat_started_event': {'host': '%s'}}," " '1': {'heartbeat_failed_event': {'host': '%s'}}}", mock_server_get_host_and_port (server), mock_server_get_host_and_port (server)); } check_json_apm_events (&context.events, tmp_bson (expected_json)); future_destroy (future); bson_free (expected_json); mongoc_uri_destroy (uri); mock_server_destroy (server); context_destroy (&context); }
static void test_find_and_modify_bypass (bool bypass) { mongoc_collection_t *collection; mongoc_client_t *client; mock_server_t *server; request_t *request; future_t *future; bson_error_t error; bson_t *update; bson_t doc = BSON_INITIALIZER; bson_t reply; mongoc_find_and_modify_opts_t *opts; server = mock_server_new (); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); ASSERT (client); collection = mongoc_client_get_collection (client, "test", "test_find_and_modify"); auto_ismaster (server, WIRE_VERSION_FAM_WRITE_CONCERN, /* max_wire_version */ 48000000, /* max_message_size */ 16777216, /* max_bson_size */ 1000); /* max_write_batch_size */ BSON_APPEND_INT32 (&doc, "superduper", 77889); update = BCON_NEW ("$set", "{", "superduper", BCON_INT32 (1234), "}"); opts = mongoc_find_and_modify_opts_new (); mongoc_find_and_modify_opts_set_bypass_document_validation (opts, bypass); mongoc_find_and_modify_opts_set_update (opts, update); mongoc_find_and_modify_opts_set_flags (opts, MONGOC_FIND_AND_MODIFY_RETURN_NEW); future = future_collection_find_and_modify_with_opts ( collection, &doc, opts, &reply, &error); if (bypass) { request = mock_server_receives_command ( server, "test", MONGOC_QUERY_NONE, "{ 'findAndModify' : 'test_find_and_modify', " "'query' : { 'superduper' : 77889 }," "'update' : { '$set' : { 'superduper' : 1234 } }," "'new' : true," "'bypassDocumentValidation' : true }"); } else { request = mock_server_receives_command ( server, "test", MONGOC_QUERY_NONE, "{ 'findAndModify' : 'test_find_and_modify', " "'query' : { 'superduper' : 77889 }," "'update' : { '$set' : { 'superduper' : 1234 } }," "'new' : true," "'bypassDocumentValidation' : false }"); } mock_server_replies_simple (request, "{ 'value' : null, 'ok' : 1 }"); ASSERT_OR_PRINT (future_get_bool (future), error); future_destroy (future); mongoc_find_and_modify_opts_destroy (opts); bson_destroy (&reply); bson_destroy (update); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mock_server_destroy (server); bson_destroy (&doc); }
static void test_mongoc_client_read_prefs (void) { mongoc_collection_t *collection; mongoc_read_prefs_t *read_prefs; mongoc_cursor_t *cursor; mongoc_client_t *client; mock_server_t *server; uint16_t port; const bson_t *doc; bson_error_t error; bool success = false; bson_t b = BSON_INITIALIZER; bson_t q = BSON_INITIALIZER; char *uristr; port = 20000 + (rand () % 1000); server = mock_server_new ("127.0.0.1", port, read_prefs_handler, &success); mock_server_run_in_thread (server); usleep (5000); uristr = bson_strdup_printf ("mongodb://127.0.0.1:%hu/", port); client = mongoc_client_new (uristr); if (!_mongoc_client_warm_up (client, &error)) { assert (false); } collection = mongoc_client_get_collection (client, "test", "test"); bson_append_utf8 (&b, "dc", 2, "ny", 2); read_prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY_PREFERRED); mongoc_read_prefs_add_tag (read_prefs, &b); mongoc_read_prefs_add_tag (read_prefs, NULL); mongoc_collection_set_read_prefs (collection, read_prefs); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 1, 0, &q, NULL, read_prefs); mongoc_cursor_next (cursor, &doc); usleep (50000); assert (success); mongoc_read_prefs_destroy (read_prefs); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mock_server_quit (server, 0); bson_destroy (&b); bson_free (uristr); }
static void test_mongoc_metadata_append_success (void) { mock_server_t *server; mongoc_uri_t *uri; mongoc_client_t *client; mongoc_client_pool_t *pool; request_t *request; const bson_t *request_doc; bson_iter_t iter; bson_iter_t md_iter; bson_iter_t inner_iter; const char *val; const char *driver_name = "php driver"; const char *driver_version = "version abc"; const char *platform = "./configure -nottoomanyflags"; char big_string [METADATA_MAX_SIZE]; memset (big_string, 'a', METADATA_MAX_SIZE - 1); big_string [METADATA_MAX_SIZE - 1] = '\0'; _reset_metadata (); /* Make sure setting the metadata works */ ASSERT (mongoc_metadata_append (driver_name, driver_version, platform)); server = mock_server_new (); mock_server_run (server); uri = mongoc_uri_copy (mock_server_get_uri (server)); mongoc_uri_set_option_as_int32 (uri, "heartbeatFrequencyMS", 500); pool = mongoc_client_pool_new (uri); /* Force topology scanner to start */ client = mongoc_client_pool_pop (pool); request = mock_server_receives_ismaster (server); ASSERT (request); request_doc = request_get_doc (request, 0); ASSERT (request_doc); ASSERT (bson_has_field (request_doc, "isMaster")); ASSERT (bson_has_field (request_doc, METADATA_FIELD)); ASSERT (bson_iter_init_find (&iter, request_doc, METADATA_FIELD)); ASSERT (bson_iter_recurse (&iter, &md_iter)); /* Make sure driver.name and driver.version and platform are all right */ ASSERT (bson_iter_find (&md_iter, "driver")); ASSERT (BSON_ITER_HOLDS_DOCUMENT (&md_iter)); ASSERT (bson_iter_recurse (&md_iter, &inner_iter)); ASSERT (bson_iter_find (&inner_iter, "name")); ASSERT (BSON_ITER_HOLDS_UTF8 (&inner_iter)); val = bson_iter_utf8 (&inner_iter, NULL); ASSERT (val); ASSERT (strstr (val, driver_name) != NULL); ASSERT (bson_iter_find (&inner_iter, "version")); ASSERT (BSON_ITER_HOLDS_UTF8 (&inner_iter)); val = bson_iter_utf8 (&inner_iter, NULL); ASSERT (val); ASSERT (strstr (val, driver_version)); /* Check os type not empty */ ASSERT (bson_iter_find (&md_iter, "os")); ASSERT (BSON_ITER_HOLDS_DOCUMENT (&md_iter)); ASSERT (bson_iter_recurse (&md_iter, &inner_iter)); ASSERT (bson_iter_find (&inner_iter, "type")); ASSERT (BSON_ITER_HOLDS_UTF8 (&inner_iter)); val = bson_iter_utf8 (&inner_iter, NULL); ASSERT (val); ASSERT (strlen (val) > 0); /* Not checking os_name, as the spec says it can be NULL. */ /* Check platform field ok */ ASSERT (bson_iter_find (&md_iter, "platform")); ASSERT (BSON_ITER_HOLDS_UTF8 (&md_iter)); val = bson_iter_utf8 (&md_iter, NULL); ASSERT (val); ASSERT (strstr (val, platform) != NULL); mock_server_replies_simple (request, "{'ok': 1, 'ismaster': true}"); request_destroy (request); /* Cleanup */ mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); mongoc_uri_destroy (uri); mock_server_destroy (server); _reset_metadata (); }
/* Test the case where we can't prevent the metadata doc being too big * and so we just don't send it */ static void test_mongoc_metadata_cannot_send (void) { mock_server_t *server; mongoc_uri_t *uri; mongoc_client_t *client; mongoc_client_pool_t *pool; request_t *request; const char *const server_reply = "{'ok': 1, 'ismaster': true}"; const bson_t *request_doc; char big_string[METADATA_MAX_SIZE]; mongoc_metadata_t *md; _reset_metadata (); /* Mess with our global metadata struct so the metadata doc will be * way too big */ memset (big_string, 'a', METADATA_MAX_SIZE - 1); big_string[METADATA_MAX_SIZE - 1] = '\0'; md = _mongoc_metadata_get (); bson_free (md->os_name); md->os_name = bson_strdup (big_string); server = mock_server_new (); mock_server_run (server); uri = mongoc_uri_copy (mock_server_get_uri (server)); mongoc_uri_set_option_as_int32 (uri, "heartbeatFrequencyMS", 500); pool = mongoc_client_pool_new (uri); /* Pop a client to trigger the topology scanner */ client = mongoc_client_pool_pop (pool); request = mock_server_receives_ismaster (server); /* Make sure the isMaster request DOESN'T have a metadata field: */ ASSERT (request); request_doc = request_get_doc (request, 0); ASSERT (request_doc); ASSERT (bson_has_field (request_doc, "isMaster")); ASSERT (!bson_has_field (request_doc, METADATA_FIELD)); mock_server_replies_simple (request, server_reply); request_destroy (request); /* Cause failure on client side */ request = mock_server_receives_ismaster (server); ASSERT (request); mock_server_hangs_up (request); request_destroy (request); /* Make sure the isMaster request still DOESN'T have a metadata field * on subsequent heartbeats. */ request = mock_server_receives_ismaster (server); ASSERT (request); request_doc = request_get_doc (request, 0); ASSERT (request_doc); ASSERT (bson_has_field (request_doc, "isMaster")); ASSERT (!bson_has_field (request_doc, METADATA_FIELD)); mock_server_replies_simple (request, server_reply); request_destroy (request); /* cleanup */ mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); mongoc_uri_destroy (uri); mock_server_destroy (server); /* Reset again so the next tests don't have a metadata doc which * is too big */ _reset_metadata (); }
/* * Append to the platform field a huge string * Make sure that it gets truncated */ static void test_mongoc_metadata_too_big (void) { mongoc_client_t *client; mock_server_t *server; mongoc_uri_t *uri; future_t *future; request_t *request; const bson_t *ismaster_doc; bson_iter_t iter; enum { BUFFER_SIZE = METADATA_MAX_SIZE }; char big_string[BUFFER_SIZE]; uint32_t len; const uint8_t *dummy; server = mock_server_new (); mock_server_run (server); _reset_metadata (); memset (big_string, 'a', BUFFER_SIZE - 1); big_string[BUFFER_SIZE - 1] = '\0'; ASSERT (mongoc_metadata_append (NULL, NULL, big_string)); uri = mongoc_uri_copy (mock_server_get_uri (server)); client = mongoc_client_new_from_uri (uri); ASSERT (mongoc_client_set_appname (client, "my app")); /* Send a ping, mock server deals with it */ future = future_client_command_simple (client, "admin", tmp_bson ("{'ping': 1}"), NULL, NULL, NULL); request = mock_server_receives_ismaster (server); /* Make sure the isMaster request has a metadata field, and it's not huge */ ASSERT (request); ismaster_doc = request_get_doc (request, 0); ASSERT (ismaster_doc); ASSERT (bson_has_field (ismaster_doc, "isMaster")); ASSERT (bson_has_field (ismaster_doc, METADATA_FIELD)); /* isMaster with metadata isn't too big */ bson_iter_init_find (&iter, ismaster_doc, METADATA_FIELD); ASSERT (BSON_ITER_HOLDS_DOCUMENT (&iter)); bson_iter_document (&iter, &len, &dummy); /* Should have truncated the platform field so it fits exactly */ ASSERT (len == METADATA_MAX_SIZE); mock_server_replies_simple (request, "{'ok': 1}"); request_destroy (request); request = mock_server_receives_command (server, "admin", MONGOC_QUERY_SLAVE_OK, "{'ping': 1}"); mock_server_replies_simple (request, "{'ok': 1}"); ASSERT (future_get_bool (future)); future_destroy (future); request_destroy (request); mongoc_client_destroy (client); mongoc_uri_destroy (uri); mock_server_destroy (server); /* So later tests don't have "aaaaa..." as the md platform string */ _reset_metadata (); }