summaryrefslogtreecommitdiff
path: root/tests/unit/mongo/sync
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit/mongo/sync')
-rw-r--r--tests/unit/mongo/sync/sync_cmd_authenticate.c112
-rw-r--r--tests/unit/mongo/sync/sync_cmd_authenticate_cache.c60
-rw-r--r--tests/unit/mongo/sync/sync_cmd_count.c119
-rw-r--r--tests/unit/mongo/sync/sync_cmd_create.c78
-rw-r--r--tests/unit/mongo/sync/sync_cmd_custom.c100
-rw-r--r--tests/unit/mongo/sync/sync_cmd_delete.c135
-rw-r--r--tests/unit/mongo/sync/sync_cmd_drop.c93
-rw-r--r--tests/unit/mongo/sync/sync_cmd_exists.c85
-rw-r--r--tests/unit/mongo/sync/sync_cmd_get_last_error.c35
-rw-r--r--tests/unit/mongo/sync/sync_cmd_get_last_error_full.c35
-rw-r--r--tests/unit/mongo/sync/sync_cmd_get_more.c135
-rw-r--r--tests/unit/mongo/sync/sync_cmd_index_create.c62
-rw-r--r--tests/unit/mongo/sync/sync_cmd_index_drop.c51
-rw-r--r--tests/unit/mongo/sync/sync_cmd_index_drop_all.c49
-rw-r--r--tests/unit/mongo/sync/sync_cmd_insert.c78
-rw-r--r--tests/unit/mongo/sync/sync_cmd_insert_n.c100
-rw-r--r--tests/unit/mongo/sync/sync_cmd_is_master.c65
-rw-r--r--tests/unit/mongo/sync/sync_cmd_kill_cursors.c123
-rw-r--r--tests/unit/mongo/sync/sync_cmd_ping.c81
-rw-r--r--tests/unit/mongo/sync/sync_cmd_query.c125
-rw-r--r--tests/unit/mongo/sync/sync_cmd_reset_error.c31
-rw-r--r--tests/unit/mongo/sync/sync_cmd_update.c97
-rw-r--r--tests/unit/mongo/sync/sync_cmd_user_add.c95
-rw-r--r--tests/unit/mongo/sync/sync_cmd_user_add_with_roles.c89
-rw-r--r--tests/unit/mongo/sync/sync_cmd_user_remove.c92
-rw-r--r--tests/unit/mongo/sync/sync_conn_seed_add.c24
-rw-r--r--tests/unit/mongo/sync/sync_conn_seed_add_cache.c31
-rw-r--r--tests/unit/mongo/sync/sync_connect.c22
-rw-r--r--tests/unit/mongo/sync/sync_connect_cache.c42
-rw-r--r--tests/unit/mongo/sync/sync_connect_from_cache_enforce_primary.c47
-rw-r--r--tests/unit/mongo/sync/sync_disconnect.c22
-rw-r--r--tests/unit/mongo/sync/sync_get_set_auto_reconnect.c39
-rw-r--r--tests/unit/mongo/sync/sync_get_set_max_insert_size.c44
-rw-r--r--tests/unit/mongo/sync/sync_get_set_safe_mode.c38
-rw-r--r--tests/unit/mongo/sync/sync_get_set_slaveok.c38
-rw-r--r--tests/unit/mongo/sync/sync_reconnect.c143
36 files changed, 2615 insertions, 0 deletions
diff --git a/tests/unit/mongo/sync/sync_cmd_authenticate.c b/tests/unit/mongo/sync/sync_cmd_authenticate.c
new file mode 100644
index 0000000..a5c67cb
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_authenticate.c
@@ -0,0 +1,112 @@
+#include "test.h"
+#include "mongo.h"
+#include "config.h"
+
+#include <errno.h>
+#include <sys/socket.h>
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_cmd_authenticate_net_secondary (void)
+{
+ mongo_sync_connection *c;
+
+ skip (!config.secondary_host, 4,
+ "Secondary server not configured");
+
+ c = mongo_sync_connect (config.secondary_host, config.secondary_port, TRUE);
+ mongo_sync_conn_set_auto_reconnect (c, TRUE);
+ mongo_sync_cmd_is_master (c);
+
+ ok (mongo_sync_cmd_authenticate (c, config.db, "test", "s3kr1+") == TRUE,
+ "mongo_sync_cmd_authenticate() works");
+ ok (mongo_sync_cmd_authenticate (c, config.db, "test", "bad_pw") == FALSE,
+ "mongo_sync_cmd_authenticate() should fail with a bad password");
+ ok (mongo_sync_cmd_authenticate (c, config.db, "xxx", "s3kr1+") == FALSE,
+ "mongo_sync_cmd_authenticate() should fail with a bad username");
+
+ shutdown (c->super.fd, SHUT_RDWR);
+ sleep (3);
+
+ ok (mongo_sync_cmd_authenticate (c, config.db, "test", "s3kr1+") == TRUE,
+ "mongo_sync_cmd_authenticate() automatically reconnects");
+
+ mongo_sync_disconnect (c);
+
+ endskip;
+}
+
+void
+test_mongo_sync_cmd_authenticate_net (void)
+{
+ mongo_sync_connection *c;
+
+ begin_network_tests (8);
+
+ c = mongo_sync_connect (config.primary_host, config.primary_port, TRUE);
+ mongo_sync_conn_set_auto_reconnect (c, TRUE);
+
+ mongo_sync_cmd_user_add (c, config.db, "test", "s3kr1+");
+
+ ok (mongo_sync_cmd_authenticate (c, config.db, "test", "s3kr1+") == TRUE,
+ "mongo_sync_cmd_authenticate() works");
+ ok (mongo_sync_cmd_authenticate (c, config.db, "test", "bad_pw") == FALSE,
+ "mongo_sync_cmd_authenticate() should fail with a bad password");
+ ok (mongo_sync_cmd_authenticate (c, config.db, "xxx", "s3kr1+") == FALSE,
+ "mongo_sync_cmd_authenticate() should fail with a bad username");
+
+ shutdown (c->super.fd, SHUT_RDWR);
+ sleep (3);
+
+ ok (mongo_sync_cmd_authenticate (c, config.db, "test", "s3kr1+") == TRUE,
+ "mongo_sync_cmd_authenticate() automatically reconnects");
+
+ mongo_sync_disconnect (c);
+
+ test_mongo_sync_cmd_authenticate_net_secondary ();
+
+ end_network_tests ();
+}
+
+void
+test_mongo_sync_cmd_authenticate (void)
+{
+ mongo_sync_connection *c;
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+
+ errno = 0;
+ ok (mongo_sync_cmd_authenticate (NULL, "test", "test",
+ "s3kr1+") == FALSE,
+ "mongo_sync_cmd_authenticate() fails with a NULL connection");
+ cmp_ok (errno, "==", ENOTCONN,
+ "errno is set to ENOTCONN");
+
+ errno = 0;
+ ok (mongo_sync_cmd_authenticate (c, NULL, "test", "s3kr1+") == FALSE,
+ "mongo_sync_cmd_authenticate() fails with a NULL db");
+ cmp_ok (errno, "==", EINVAL,
+ "errno is set to EINVAL");
+
+ errno = 0;
+ ok (mongo_sync_cmd_authenticate (c, "test", NULL, "s3kr1+") == FALSE,
+ "mongo_sync_cmd_authenticate() fails with a NULL user");
+ cmp_ok (errno, "==", EINVAL,
+ "errno is set to EINVAL");
+
+ errno = 0;
+ ok (mongo_sync_cmd_authenticate (c, "test", "test", NULL) == FALSE,
+ "mongo_sync_cmd_authenticate() fails with a NULL password");
+ cmp_ok (errno, "==", EINVAL,
+ "errno is set to EINVAL");
+
+ ok (mongo_sync_cmd_authenticate (c, "test", "test",
+ "s3kr1+") == FALSE,
+ "mongo_sync_cmd_authenticate() fails with a bogus FD");
+
+ mongo_sync_disconnect (c);
+
+ test_mongo_sync_cmd_authenticate_net ();
+}
+
+RUN_TEST (17, mongo_sync_cmd_authenticate);
diff --git a/tests/unit/mongo/sync/sync_cmd_authenticate_cache.c b/tests/unit/mongo/sync/sync_cmd_authenticate_cache.c
new file mode 100644
index 0000000..c0581b0
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_authenticate_cache.c
@@ -0,0 +1,60 @@
+#include "test.h"
+#include "mongo.h"
+#include "config.h"
+
+#include <errno.h>
+#include <sys/socket.h>
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_cmd_authenticate_cache (void)
+{
+ mongo_sync_conn_recovery_cache *cache;
+ mongo_sync_connection *c;
+
+ begin_network_tests (8);
+
+ cache = mongo_sync_conn_recovery_cache_new ();
+ mongo_sync_conn_recovery_cache_seed_add (cache,
+ config.primary_host,
+ config.primary_port);
+
+ c = mongo_sync_connect_recovery_cache (cache, TRUE);
+
+ mongo_sync_cmd_user_add (c, config.db, "test", "s3kr1+");
+
+ ok (mongo_sync_cmd_authenticate (c, config.db, "test", "s3kr1+") == TRUE,
+ "mongo_sync_cmd_authenticate() works");
+
+ mongo_sync_disconnect (c);
+
+ ok ((cache->auth.db != NULL) && (strcmp (cache->auth.db, config.db) == 0),
+ "db is cached");
+
+ ok ((cache->auth.user != NULL) && (strcmp (cache->auth.user, "test") == 0),
+ "user is cached");
+
+ ok ((cache->auth.pw != NULL) && (strcmp (cache->auth.pw, "s3kr1+") == 0),
+ "pw is cached");
+
+ c = mongo_sync_connect_recovery_cache (cache, TRUE);
+
+ ok (c->auth.db != NULL, "db is loaded from cache");
+
+ ok (c->auth.user != NULL, "username is loaded from cache");
+
+ ok (c->auth.pw != NULL, "password is loaded from cache");
+
+ ok (mongo_sync_cmd_authenticate (c,
+ c->auth.db,
+ c->auth.user,
+ c->auth.pw) == TRUE,
+ "mongo_sync_cmd_authenticate() works with cached auth. credentials");
+
+ mongo_sync_disconnect (c);
+ mongo_sync_conn_recovery_cache_free (cache);
+
+ end_network_tests ();
+}
+
+RUN_TEST (8, mongo_sync_cmd_authenticate_cache);
diff --git a/tests/unit/mongo/sync/sync_cmd_count.c b/tests/unit/mongo/sync/sync_cmd_count.c
new file mode 100644
index 0000000..2cb8645
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_count.c
@@ -0,0 +1,119 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <sys/socket.h>
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_cmd_count_net_secondary (void)
+{
+ mongo_sync_connection *conn;
+ bson *b;
+ gdouble d;
+
+ skip (!config.secondary_host, 2,
+ "Secondary server not configured");
+
+ conn = mongo_sync_connect (config.secondary_host, config.secondary_port,
+ TRUE);
+ mongo_sync_cmd_is_master (conn);
+ mongo_sync_conn_set_auto_reconnect (conn, TRUE);
+
+ b = bson_new ();
+ bson_append_string (b, "test-name", __FILE__, -1);
+ bson_finish (b);
+
+ d = mongo_sync_cmd_count (conn, config.db, config.coll, b);
+ ok (d > 0,
+ "mongo_sync_cmd_count() works on the secondary too");
+
+ shutdown (conn->super.fd, SHUT_RDWR);
+ sleep (3);
+
+ d = mongo_sync_cmd_count (conn, config.db, config.coll, b);
+ ok (d > 0,
+ "mongo_sync_cmd_count() automatically reconnects");
+
+ bson_free (b);
+ mongo_sync_disconnect (conn);
+
+ endskip;
+}
+
+void
+test_mongo_sync_cmd_count_net (void)
+{
+ mongo_sync_connection *conn;
+ bson *b;
+ gdouble d;
+ gint i;
+
+ begin_network_tests (4);
+
+ conn = mongo_sync_connect (config.primary_host, config.primary_port, TRUE);
+ mongo_sync_conn_set_auto_reconnect (conn, TRUE);
+
+ b = bson_new ();
+ for (i = 0; i < 40; i++)
+ {
+ bson_reset (b);
+ bson_append_string (b, "test-name", __FILE__, -1);
+ bson_append_int32 (b, "seq", i);
+ bson_finish (b);
+
+ mongo_sync_cmd_insert (conn, config.ns, b, NULL);
+ }
+ bson_free (b);
+
+ b = bson_new ();
+ bson_append_string (b, "test-name", __FILE__, -1);
+ bson_finish (b);
+
+ d = mongo_sync_cmd_count (conn, config.db, config.coll, b);
+ ok (d > 0,
+ "mongo_sync_cmd_count() works");
+
+ shutdown (conn->super.fd, SHUT_RDWR);
+ sleep (3);
+
+ d = mongo_sync_cmd_count (conn, config.db, config.coll, b);
+ ok (d > 0,
+ "mongo_sync_cmd_count() automatically reconnects");
+
+ bson_free (b);
+ mongo_sync_disconnect (conn);
+
+ test_mongo_sync_cmd_count_net_secondary ();
+
+ end_network_tests ();
+}
+
+void
+test_mongo_sync_cmd_count (void)
+{
+ mongo_sync_connection *c;
+ bson *b;
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+ b = test_bson_generate_full ();
+
+ ok (mongo_sync_cmd_count (NULL, "test", "db", b) == -1,
+ "mongo_sync_cmd_count() fails with a NULL connection");
+ ok (mongo_sync_cmd_count (c, NULL, "db", b) == -1,
+ "mongo_sync_cmd_count() fails with a NULL db");
+ ok (mongo_sync_cmd_count (c, "test", NULL, b) == -1,
+ "mongo_sync_cmd_count() fails with a NULL collection");
+
+ ok (mongo_sync_cmd_count (c, "test", "db", b) == -1,
+ "mongo_sync_cmd_count() fails with a bogus FD");
+ mongo_sync_conn_set_slaveok (c, TRUE);
+ ok (mongo_sync_cmd_count (c, "test", "db", b) == -1,
+ "mongo_sync_cmd_count() fails with a bogus FD");
+
+ bson_free (b);
+ mongo_sync_disconnect (c);
+
+ test_mongo_sync_cmd_count_net ();
+}
+
+RUN_TEST (9, mongo_sync_cmd_count);
diff --git a/tests/unit/mongo/sync/sync_cmd_create.c b/tests/unit/mongo/sync/sync_cmd_create.c
new file mode 100644
index 0000000..c3334ea
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_create.c
@@ -0,0 +1,78 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <sys/socket.h>
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_cmd_create_net (void)
+{
+ mongo_sync_connection *conn;
+ gchar *cc;
+
+ begin_network_tests (5);
+
+ conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE);
+
+ cc = g_strconcat (config.coll, ".capped", NULL);
+
+ mongo_sync_cmd_drop (conn, config.db, config.coll);
+ mongo_sync_cmd_drop (conn, config.db, cc);
+
+ ok (mongo_sync_cmd_create (conn, config.db, config.coll,
+ MONGO_COLLECTION_DEFAULTS) == TRUE,
+ "mongo_sync_cmd_create() can create normal collections");
+ mongo_sync_cmd_drop (conn, config.db, config.coll);
+
+ ok (mongo_sync_cmd_create (conn, config.db, config.coll,
+ MONGO_COLLECTION_SIZED,
+ (gint64) 64 * 1024 * 10) == TRUE,
+ "mongo_sync_cmd_create() can create pre-allocated collections");
+
+ ok (mongo_sync_cmd_create (conn, config.db, cc,
+ MONGO_COLLECTION_CAPPED, (gint64) -1) == FALSE,
+ "mongo_sync_cmd_create() fails when trying to create a capped "
+ "collection with an invalid size");
+ ok (mongo_sync_cmd_create (conn, config.db, cc,
+ MONGO_COLLECTION_CAPPED_MAX,
+ (gint64) (64 * 1024 * 10), (gint64) -1) == FALSE,
+ "mongo_sync_cmd_create() fails when trying to create a capped "
+ "collection with invalid max.");
+ ok (mongo_sync_cmd_create (conn, config.db, cc,
+ MONGO_COLLECTION_CAPPED_MAX |
+ MONGO_COLLECTION_AUTO_INDEX_ID,
+ (gint64)(64 * 1024 * 10), (gint64) 10) == TRUE,
+ "mongo_sync_cmd_create() can create capped collections");
+
+ mongo_sync_cmd_drop (conn, config.db, cc);
+
+ g_free (cc);
+ mongo_sync_disconnect (conn);
+
+ end_network_tests ();
+}
+
+void
+test_mongo_sync_cmd_create (void)
+{
+ mongo_sync_connection *c;
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+
+ ok (mongo_sync_cmd_create (NULL, "test", "db",
+ MONGO_COLLECTION_DEFAULTS) == FALSE,
+ "mongo_sync_cmd_create() fails with a NULL connection");
+
+ ok (mongo_sync_cmd_create (c, NULL, "db",
+ MONGO_COLLECTION_DEFAULTS) == FALSE,
+ "mongo_sync_cmd_create() fails with a NULL db");
+ ok (mongo_sync_cmd_create (c, "test", NULL,
+ MONGO_COLLECTION_DEFAULTS) == FALSE,
+ "mongo_sync_cmd_create() fails with a NULL collection");
+
+ mongo_sync_disconnect (c);
+
+ test_mongo_sync_cmd_create_net ();
+}
+
+RUN_TEST (8, mongo_sync_cmd_create);
diff --git a/tests/unit/mongo/sync/sync_cmd_custom.c b/tests/unit/mongo/sync/sync_cmd_custom.c
new file mode 100644
index 0000000..1bd3f01
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_custom.c
@@ -0,0 +1,100 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <sys/socket.h>
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_cmd_custom_net_secondary (void)
+{
+ mongo_sync_connection *conn;
+ bson *cmd;
+ mongo_packet *p;
+
+ skip (!config.secondary_host, 1,
+ "Secondary server not configured");
+
+ conn = mongo_sync_connect (config.secondary_host, config.secondary_port,
+ TRUE);
+ cmd = bson_build (BSON_TYPE_INT32, "getnonce", 1,
+ BSON_TYPE_NONE);
+ bson_finish (cmd);
+
+ p = mongo_sync_cmd_custom (conn, config.db, cmd);
+ ok (p != NULL,
+ "mongo_sync_cmd_custom() works on the secondary too");
+ mongo_wire_packet_free (p);
+
+ bson_free (cmd);
+ mongo_sync_disconnect (conn);
+
+ endskip;
+}
+
+void
+test_mongo_sync_cmd_custom_net (void)
+{
+ mongo_sync_connection *conn;
+ bson *cmd;
+ mongo_packet *p;
+
+ begin_network_tests (3);
+
+ conn = mongo_sync_connect (config.primary_host, config.primary_port, TRUE);
+ mongo_sync_cmd_is_master (conn);
+ mongo_sync_conn_set_auto_reconnect (conn, TRUE);
+
+ cmd = bson_build (BSON_TYPE_INT32, "getnonce", 1,
+ BSON_TYPE_NONE);
+ bson_finish (cmd);
+
+ p = mongo_sync_cmd_custom (conn, config.db, cmd);
+ ok (p != NULL,
+ "mongo_sync_cmd_custom() works");
+ mongo_wire_packet_free (p);
+
+ shutdown (conn->super.fd, SHUT_RDWR);
+ sleep (3);
+
+ p = mongo_sync_cmd_custom (conn, config.db, cmd);
+ ok (p != NULL,
+ "mongo_sync_cmd_custom() automatically reconnects");
+ mongo_wire_packet_free (p);
+
+ bson_free (cmd);
+ mongo_sync_disconnect (conn);
+
+ test_mongo_sync_cmd_custom_net_secondary ();
+
+ end_network_tests ();
+}
+
+void
+test_mongo_sync_cmd_custom (void)
+{
+ mongo_sync_connection *c;
+ bson *cmd;
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+ cmd = bson_new ();
+ bson_append_int32 (cmd, "getnonce", 1);
+ bson_finish (cmd);
+
+ ok (mongo_sync_cmd_custom (NULL, "test", cmd) == NULL,
+ "mongo_sync_cmd_custom() fails with a NULL connection");
+ ok (mongo_sync_cmd_custom (c, NULL, cmd) == NULL,
+ "mongo_sync_cmd_custom() fails with a NULL namespace");
+
+ ok (mongo_sync_cmd_custom (c, "test", cmd) == NULL,
+ "mongo_sync_cmd_custom() fails with a bogus FD");
+ mongo_sync_conn_set_slaveok (c, TRUE);
+ ok (mongo_sync_cmd_custom (c, "test", cmd) == NULL,
+ "mongo_sync_cmd_custom() fails with a bogus FD");
+
+ bson_free (cmd);
+ mongo_sync_disconnect (c);
+
+ test_mongo_sync_cmd_custom_net ();
+}
+
+RUN_TEST (7, mongo_sync_cmd_custom);
diff --git a/tests/unit/mongo/sync/sync_cmd_delete.c b/tests/unit/mongo/sync/sync_cmd_delete.c
new file mode 100644
index 0000000..0c20ffe
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_delete.c
@@ -0,0 +1,135 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <sys/socket.h>
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_cmd_delete_net_secondary (void)
+{
+ mongo_sync_connection *conn;
+ bson *b;
+ GList *l;
+
+ skip (!config.secondary_host, 2,
+ "Secondary server not configured");
+
+ conn = mongo_sync_connect (config.primary_host, config.primary_port,
+ TRUE);
+
+ b = bson_new ();
+ bson_append_string (b, "unit-test", __FILE__, -1);
+ bson_append_boolean (b, "delete-me", TRUE);
+ bson_finish (b);
+ mongo_sync_cmd_insert (conn, config.ns, b, NULL);
+
+ mongo_sync_disconnect (conn);
+
+ conn = mongo_sync_connect (config.secondary_host, config.secondary_port,
+ TRUE);
+ mongo_sync_conn_set_auto_reconnect (conn, TRUE);
+
+ ok (mongo_sync_cmd_delete (conn, config.ns, 0, b) == TRUE,
+ "mongo_sync_cmd_delete() can reconnect to master");
+ mongo_sync_disconnect (conn);
+
+ conn = mongo_sync_connect (config.primary_host, config.primary_port,
+ TRUE);
+ mongo_sync_cmd_insert (conn, config.ns, b, NULL);
+ mongo_sync_disconnect (conn);
+
+ conn = mongo_sync_connect (config.secondary_host, config.secondary_port,
+ TRUE);
+ mongo_sync_conn_set_auto_reconnect (conn, TRUE);
+
+ shutdown (conn->super.fd, SHUT_RDWR);
+
+ l = conn->rs.hosts;
+ while (l)
+ {
+ g_free (l->data);
+ l = g_list_delete_link (l, l);
+ }
+ conn->rs.hosts = NULL;
+
+ l = conn->rs.seeds;
+ while (l)
+ {
+ g_free (l->data);
+ l = g_list_delete_link (l, l);
+ }
+ conn->rs.seeds = NULL;
+
+ sleep (3);
+
+ ok (mongo_sync_cmd_delete (conn, config.ns, 0, b) == FALSE,
+ "mongo_sync_cmd_delete() fails if it can't reconnect to master");
+
+ mongo_sync_disconnect (conn);
+ bson_free (b);
+
+ endskip;
+}
+
+void
+test_mongo_sync_cmd_delete_net (void)
+{
+ mongo_sync_connection *conn;
+ bson *b;
+
+ begin_network_tests (4);
+
+ conn = mongo_sync_connect (config.primary_host, config.primary_port, TRUE);
+ mongo_sync_conn_set_auto_reconnect (conn, TRUE);
+
+ b = bson_new ();
+ bson_append_string (b, "unit-test", __FILE__, -1);
+ bson_append_boolean (b, "delete-me", TRUE);
+ bson_finish (b);
+ mongo_sync_cmd_insert (conn, config.ns, b, NULL);
+
+ ok (mongo_sync_cmd_delete (conn, config.ns, 0, b) == TRUE,
+ "mongo_sync_cmd_delete() works");
+
+ mongo_sync_cmd_insert (conn, config.ns, b, NULL);
+
+ shutdown (conn->super.fd, SHUT_RDWR);
+ sleep (3);
+
+ ok (mongo_sync_cmd_delete (conn, config.ns, 0, b) == TRUE,
+ "mongo_sync_cmd_delete() automatically reconnects");
+
+ mongo_sync_disconnect (conn);
+ bson_free (b);
+
+ test_mongo_sync_cmd_delete_net_secondary ();
+
+ end_network_tests ();
+}
+
+void
+test_mongo_sync_cmd_delete (void)
+{
+ mongo_sync_connection *c;
+ bson *b;
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+ b = test_bson_generate_full ();
+
+ ok (mongo_sync_cmd_delete (NULL, "test.ns", 0, b) == FALSE,
+ "mongo_sync_cmd_delete() fails with a NULL connection");
+ ok (mongo_sync_cmd_delete (c, NULL, 0, b) == FALSE,
+ "mongo_sync_cmd_delete() fails with a NULL namespace");
+ ok (mongo_sync_cmd_delete (c, "test.ns", 0, NULL) == FALSE,
+ "mongo_sync_cmd_delete() fails with a NULL selector");
+
+ ok (mongo_sync_cmd_delete (c, "test.ns", 0, b) == FALSE,
+ "mongo_sync_cmd_delete() fails with a bogus FD");
+
+ bson_free (b);
+ mongo_sync_disconnect (c);
+
+ test_mongo_sync_cmd_delete_net ();
+}
+
+RUN_TEST (8, mongo_sync_cmd_delete);
diff --git a/tests/unit/mongo/sync/sync_cmd_drop.c b/tests/unit/mongo/sync/sync_cmd_drop.c
new file mode 100644
index 0000000..c7f9d9f
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_drop.c
@@ -0,0 +1,93 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <sys/socket.h>
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_cmd_drop_net_secondary (void)
+{
+ mongo_sync_connection *conn;
+ bson *b;
+ gboolean ret;
+
+ skip (!config.secondary_host, 1,
+ "Secondary server not configured");
+
+ conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE);
+ b = bson_build (BSON_TYPE_BOOLEAN, "filler", TRUE,
+ BSON_TYPE_NONE);
+ bson_finish (b);
+ mongo_sync_cmd_insert (conn, config.ns, b, NULL);
+ bson_free (b);
+ mongo_sync_disconnect (conn);
+
+ conn = mongo_sync_connect (config.secondary_host, config.secondary_port,
+ TRUE);
+ mongo_sync_cmd_is_master (conn);
+ mongo_sync_conn_set_auto_reconnect (conn, TRUE);
+
+ ret = mongo_sync_cmd_drop (conn, config.db, config.coll);
+ ok (ret && mongo_sync_cmd_is_master (conn),
+ "mongo_sync_cmd_drop() can reconnect to master");
+ mongo_sync_disconnect (conn);
+
+ endskip;
+}
+
+void
+test_mongo_sync_cmd_drop_net (void)
+{
+ mongo_sync_connection *conn;
+ bson *b;
+
+ begin_network_tests (3);
+
+ conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE);
+ mongo_sync_conn_set_auto_reconnect (conn, TRUE);
+
+ b = bson_build (BSON_TYPE_BOOLEAN, "filler", TRUE,
+ BSON_TYPE_NONE);
+ bson_finish (b);
+ mongo_sync_cmd_insert (conn, config.ns, b, NULL);
+
+ ok (mongo_sync_cmd_drop (conn, config.db, config.coll) == TRUE,
+ "mongo_sync_cmd_drop() works");
+
+ mongo_sync_cmd_insert (conn, config.ns, b, NULL);
+
+ shutdown (conn->super.fd, SHUT_RDWR);
+ sleep (3);
+
+ ok (mongo_sync_cmd_drop (conn, config.db, config.coll) == TRUE,
+ "mongo_sync_cmd_drop() automatically reconnects");
+
+ bson_free (b);
+ mongo_sync_disconnect (conn);
+
+ test_mongo_sync_cmd_drop_net_secondary ();
+
+ end_network_tests ();
+}
+
+void
+test_mongo_sync_cmd_drop (void)
+{
+ mongo_sync_connection *c;
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+
+ ok (mongo_sync_cmd_drop (NULL, "test", "db") == FALSE,
+ "mongo_sync_cmd_drop() fails with a NULL connection");
+ ok (mongo_sync_cmd_drop (c, NULL, "db") == FALSE,
+ "mongo_sync_cmd_drop() fails with a NULL db");
+
+ ok (mongo_sync_cmd_drop (c, "test", "db") == FALSE,
+ "mongo_sync_cmd_drop() fails with a bogus FD");
+
+ mongo_sync_disconnect (c);
+
+ test_mongo_sync_cmd_drop_net ();
+}
+
+RUN_TEST (6, mongo_sync_cmd_drop);
diff --git a/tests/unit/mongo/sync/sync_cmd_exists.c b/tests/unit/mongo/sync/sync_cmd_exists.c
new file mode 100644
index 0000000..f3c535f
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_exists.c
@@ -0,0 +1,85 @@
+#include "test.h"
+#include "mongo.h"
+
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_cmd_exists_net (void)
+{
+ mongo_sync_connection *conn;
+ gchar *cc, *ns;
+
+ bson *r;
+ bson_cursor *c;
+ const gchar *str = NULL;
+ gboolean capped = FALSE;
+
+ begin_network_tests (4);
+
+ conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE);
+
+ cc = g_strconcat (config.coll, ".capped", NULL);
+
+ mongo_sync_cmd_drop (conn, config.db, config.coll);
+ mongo_sync_cmd_drop (conn, config.db, cc);
+
+ mongo_sync_cmd_create (conn, config.db, config.coll,
+ MONGO_COLLECTION_DEFAULTS);
+ mongo_sync_cmd_create (conn, config.db, cc,
+ MONGO_COLLECTION_CAPPED,
+ (gint64) 64 * 1024 * 10);
+
+ r = mongo_sync_cmd_exists (conn, config.db, config.coll);
+ c = bson_find (r, "name");
+ bson_cursor_get_string (c, &str);
+ is (str, config.ns,
+ "mongo_sync_cmd_exists() works on normal collections");
+ bson_cursor_find (c, "capped");
+ bson_cursor_get_boolean (c, &capped);
+ cmp_ok (capped, "==", FALSE,
+ "mongo_sync_cmd_exists() returned correct info");
+ bson_cursor_free (c);
+ bson_free (r);
+
+ r = mongo_sync_cmd_exists (conn, config.db, cc);
+ ns = g_strconcat (config.db, ".", cc, NULL);
+ c = bson_find (r, "name");
+ bson_cursor_get_string (c, &str);
+ is (str, ns,
+ "mongo_sync_cmd_exists() works on capped collections");
+ bson_cursor_find (c, "capped");
+ bson_cursor_get_boolean (c, &capped);
+ cmp_ok (capped, "==", FALSE,
+ "mongo_sync_cmd_exists() returned correct info");
+ bson_cursor_free (c);
+ g_free (ns);
+ bson_free (r);
+
+ mongo_sync_cmd_drop (conn, config.db, cc);
+
+ g_free (cc);
+ mongo_sync_disconnect (conn);
+
+ end_network_tests ();
+}
+
+void
+test_mongo_sync_cmd_exists (void)
+{
+ mongo_sync_connection *c;
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+
+ ok (mongo_sync_cmd_exists (NULL, "test", "db") == NULL,
+ "mongo_sync_cmd_exists() fails with a NULL connection");
+ ok (mongo_sync_cmd_exists (c, NULL, "db") == NULL,
+ "mongo_sync_cmd_exists() fails with a NULL db");
+ ok (mongo_sync_cmd_exists (c, "test", NULL) == NULL,
+ "mongo_sync_cmd_exists() fails with a NULL collection");
+
+ mongo_sync_disconnect (c);
+
+ test_mongo_sync_cmd_exists_net ();
+}
+
+RUN_TEST (7, mongo_sync_cmd_exists);
diff --git a/tests/unit/mongo/sync/sync_cmd_get_last_error.c b/tests/unit/mongo/sync/sync_cmd_get_last_error.c
new file mode 100644
index 0000000..fef9f78
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_get_last_error.c
@@ -0,0 +1,35 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <errno.h>
+
+void
+test_mongo_sync_cmd_get_last_error (void)
+{
+ mongo_sync_connection *c;
+ gchar *error;
+
+ test_env_setup ();
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+
+ errno = 0;
+ ok (mongo_sync_cmd_get_last_error (NULL, config.db, &error) == FALSE,
+ "mongo_sync_cmd_get_last_error() returns FALSE with a NULL connection");
+ cmp_ok (errno, "==", ENOTCONN,
+ "errno is set to ENOTCONN");
+
+ ok (mongo_sync_cmd_get_last_error (c, NULL, &error) == FALSE,
+ "mongo_sync_cmd_get_last_error() fails with a NULL db");
+
+ errno = 0;
+ ok (mongo_sync_cmd_get_last_error (c, config.db, NULL) == FALSE,
+ "mongo_sync_cmd_get_last_error() fails with a NULL error destination");
+ cmp_ok (errno, "==", EINVAL,
+ "errno is set to EINVAL");
+
+ mongo_sync_disconnect (c);
+ test_env_free ();
+}
+
+RUN_TEST (5, mongo_sync_cmd_get_last_error);
diff --git a/tests/unit/mongo/sync/sync_cmd_get_last_error_full.c b/tests/unit/mongo/sync/sync_cmd_get_last_error_full.c
new file mode 100644
index 0000000..505fd3d
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_get_last_error_full.c
@@ -0,0 +1,35 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <errno.h>
+
+void
+test_mongo_sync_cmd_get_last_error_full (void)
+{
+ mongo_sync_connection *c;
+ bson *error;
+
+ test_env_setup ();
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+
+ errno = 0;
+ ok (mongo_sync_cmd_get_last_error_full (NULL, config.db, &error) == FALSE,
+ "mongo_sync_cmd_get_last_error_full() returns FALSE with a NULL connection");
+ cmp_ok (errno, "==", ENOTCONN,
+ "errno is set to ENOTCONN");
+
+ ok (mongo_sync_cmd_get_last_error_full (c, NULL, &error) == FALSE,
+ "mongo_sync_cmd_get_last_error_full() fails with a NULL db");
+
+ errno = 0;
+ ok (mongo_sync_cmd_get_last_error_full (c, config.db, NULL) == FALSE,
+ "mongo_sync_cmd_get_last_error_full() fails with a NULL error destination");
+ cmp_ok (errno, "==", EINVAL,
+ "errno is set to EINVAL");
+
+ mongo_sync_disconnect (c);
+ test_env_free ();
+}
+
+RUN_TEST (5, mongo_sync_cmd_get_last_error_full);
diff --git a/tests/unit/mongo/sync/sync_cmd_get_more.c b/tests/unit/mongo/sync/sync_cmd_get_more.c
new file mode 100644
index 0000000..18a2f97
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_get_more.c
@@ -0,0 +1,135 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <errno.h>
+#include <sys/socket.h>
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_cmd_get_more_net_secondary (void)
+{
+ mongo_packet *p;
+ mongo_sync_connection *conn;
+ bson *b;
+
+ mongo_reply_packet_header rh;
+ gint64 cid;
+
+ skip (!config.secondary_host, 2,
+ "Secondary server not configured");
+
+ conn = mongo_sync_connect (config.secondary_host, config.secondary_port,
+ TRUE);
+ b = bson_new ();
+ bson_append_string (b, "test-name", __FILE__, -1);
+ bson_finish (b);
+
+ p = mongo_sync_cmd_query (conn, config.ns,
+ MONGO_WIRE_FLAG_QUERY_NO_CURSOR_TIMEOUT,
+ 0, 2, b, NULL);
+ bson_free (b);
+ mongo_wire_reply_packet_get_header (p, &rh);
+ cid = rh.cursor_id;
+ mongo_wire_packet_free (p);
+
+ p = mongo_sync_cmd_get_more (conn, config.db, 3, cid);
+ ok (p != NULL,
+ "mongo_sync_cmd_get_more() works on secondary too");
+ mongo_wire_packet_free (p);
+
+ mongo_sync_reconnect (conn, TRUE);
+
+ p = mongo_sync_cmd_get_more (conn, config.db, 10, cid);
+ ok (p == NULL && errno == EPROTO,
+ "mongo_sync_cmd_get_more() can't jump servers");
+ mongo_wire_packet_free (p);
+
+ mongo_sync_disconnect (conn);
+
+ endskip;
+}
+
+void
+test_mongo_sync_cmd_get_more_net (void)
+{
+ mongo_packet *p;
+ mongo_sync_connection *conn;
+ bson *b;
+ gint i;
+ mongo_reply_packet_header rh;
+ gint64 cid;
+
+ begin_network_tests (4);
+
+ conn = mongo_sync_connect (config.primary_host, config.primary_port, TRUE);
+ mongo_sync_conn_set_auto_reconnect (conn, TRUE);
+
+ b = bson_new ();
+ for (i = 0; i < 40; i++)
+ {
+ bson_reset (b);
+ bson_append_string (b, "test-name", __FILE__, -1);
+ bson_append_int32 (b, "seq", i);
+ bson_finish (b);
+
+ mongo_sync_cmd_insert (conn, config.ns, b, NULL);
+ }
+ bson_free (b);
+
+ b = bson_new ();
+ bson_append_string (b, "test-name", __FILE__, -1);
+ bson_finish (b);
+
+ p = mongo_sync_cmd_query (conn, config.ns,
+ MONGO_WIRE_FLAG_QUERY_NO_CURSOR_TIMEOUT,
+ 0, 2, b, NULL);
+ bson_free (b);
+ mongo_wire_reply_packet_get_header (p, &rh);
+ cid = rh.cursor_id;
+ mongo_wire_packet_free (p);
+
+ p = mongo_sync_cmd_get_more (conn, config.ns, 3, cid);
+ ok (p != NULL,
+ "mongo_sync_cmd_get_more() works");
+ mongo_wire_packet_free (p);
+
+ errno = 0;
+ shutdown (conn->super.fd, SHUT_RDWR);
+ sleep (3);
+
+ p = mongo_sync_cmd_get_more (conn, config.ns, 10, cid);
+ ok (p != NULL,
+ "mongo_sync_cmd_get_more() automatically reconnects");
+ mongo_wire_packet_free (p);
+
+ mongo_sync_disconnect (conn);
+
+ test_mongo_sync_cmd_get_more_net_secondary ();
+
+ end_network_tests ();
+}
+
+void
+test_mongo_sync_cmd_get_more (void)
+{
+ mongo_sync_connection *c;
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+
+ ok (mongo_sync_cmd_get_more (NULL, "test.ns", 1, 1234) == NULL,
+ "mongo_sync_cmd_get_more() fails with a NULL connection");
+ ok (mongo_sync_cmd_get_more (c, NULL, 1, 1234) == NULL,
+ "mongo_sync_cmd_get_more() fails with a NULL namespace");
+
+ ok (mongo_sync_cmd_get_more (c, "test.ns", 1, 1234) == NULL,
+ "mongo_sync_cmd_get_more() fails with a bogus FD");
+ mongo_sync_conn_set_slaveok (c, TRUE);
+ ok (mongo_sync_cmd_get_more (c, "test.ns", 1, 1234) == NULL,
+ "mongo_sync_cmd_get_more() fails with a bogus FD");
+
+ mongo_sync_disconnect (c);
+
+ test_mongo_sync_cmd_get_more_net ();
+}
+
+RUN_TEST (8, mongo_sync_cmd_get_more);
diff --git a/tests/unit/mongo/sync/sync_cmd_index_create.c b/tests/unit/mongo/sync/sync_cmd_index_create.c
new file mode 100644
index 0000000..6603586
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_index_create.c
@@ -0,0 +1,62 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <sys/socket.h>
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_cmd_index_create (void)
+{
+ mongo_sync_connection *c;
+ bson *doc, *indexes, *bad_index;
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+ doc = test_bson_generate_full ();
+ indexes = bson_build (BSON_TYPE_INT32, "sex", 1,
+ BSON_TYPE_DOUBLE, "double", 1.0,
+ BSON_TYPE_BOOLEAN, "TRUE", TRUE,
+ BSON_TYPE_INT64, "print", (gint64)-1,
+ BSON_TYPE_INT32, "zero", 0,
+ BSON_TYPE_NONE);
+ bson_finish (indexes);
+
+ bad_index = bson_build (BSON_TYPE_STRING, "str", "teapot", -1,
+ BSON_TYPE_NONE);
+ bson_finish (bad_index);
+
+ ok (mongo_sync_cmd_index_create (NULL, "test.ns", indexes, 0) == FALSE,
+ "mongo_sync_cmd_index_create() fails with a NULL connection");
+ ok (mongo_sync_cmd_index_create (c, NULL, indexes, 0) == FALSE,
+ "mongo_sync_cmd_index_create() fails with a NULL namespace");
+ ok (mongo_sync_cmd_index_create (c, "test.ns", NULL, 0) == FALSE,
+ "mongo_sync_cmd_index_create() fails with NULL indexes");
+ ok (mongo_sync_cmd_index_create (c, "bogus", indexes, 0) == FALSE,
+ "mongo_sync_cmd_index_create() fails with a bogus namespace");
+ ok (mongo_sync_cmd_index_create (c, "test.ns", indexes, 0) == FALSE,
+ "mongo_sync_cmd_index_create() fails with a bogus FD");
+
+ mongo_sync_disconnect (c);
+
+ begin_network_tests (2);
+
+ c = mongo_sync_connect (config.primary_host, config.primary_port,
+ TRUE);
+ mongo_sync_cmd_insert (c, config.ns, doc, NULL);
+
+ ok (mongo_sync_cmd_index_create(c, config.ns, indexes,
+ MONGO_INDEX_UNIQUE | MONGO_INDEX_DROP_DUPS |
+ MONGO_INDEX_BACKGROUND | MONGO_INDEX_SPARSE),
+ "mongo_sync_cmd_index_create() works");
+
+ ok (mongo_sync_cmd_index_create(c, config.ns, bad_index, 0) == FALSE,
+ "mongo_sync_cmd_index_create() should refuse to work with an invalid index spec");
+
+ mongo_sync_disconnect (c);
+
+ bson_free (doc);
+ bson_free (indexes);
+
+ end_network_tests ();
+}
+
+RUN_TEST (7, mongo_sync_cmd_index_create);
diff --git a/tests/unit/mongo/sync/sync_cmd_index_drop.c b/tests/unit/mongo/sync/sync_cmd_index_drop.c
new file mode 100644
index 0000000..176de6d
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_index_drop.c
@@ -0,0 +1,51 @@
+#include "test.h"
+#include "mongo.h"
+
+void
+test_mongo_sync_cmd_index_drop (void)
+{
+ mongo_sync_connection *c;
+ bson *doc, *indexes;
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+ doc = test_bson_generate_full ();
+ indexes = bson_build (BSON_TYPE_INT32, "sex", 1,
+ BSON_TYPE_DOUBLE, "double", 1.0,
+ BSON_TYPE_BOOLEAN, "TRUE", TRUE,
+ BSON_TYPE_INT64, "print", (gint64)-1,
+ BSON_TYPE_NONE);
+ bson_finish (indexes);
+
+ ok (mongo_sync_cmd_index_drop (NULL, "test.ns", indexes) == FALSE,
+ "mongo_sync_cmd_index_drop() fails with a NULL connection");
+ ok (mongo_sync_cmd_index_drop (c, NULL, indexes) == FALSE,
+ "mongo_sync_cmd_index_drop() fails with a NULL namespace");
+ ok (mongo_sync_cmd_index_drop (c, "test.ns", NULL) == FALSE,
+ "mongo_sync_cmd_index_drop() fails with NULL indexes");
+ ok (mongo_sync_cmd_index_drop (c, "bogus", indexes) == FALSE,
+ "mongo_sync_cmd_index_drop() fails with a bogus namespace");
+ ok (mongo_sync_cmd_index_drop (c, "test.ns", indexes) == FALSE,
+ "mongo_sync_cmd_index_drop() fails with a bogus FD");
+
+ mongo_sync_disconnect (c);
+
+ begin_network_tests (1);
+
+ c = mongo_sync_connect (config.primary_host, config.primary_port,
+ TRUE);
+ mongo_sync_cmd_insert (c, config.ns, doc, NULL);
+
+ mongo_sync_cmd_index_create (c, config.ns, indexes, 0);
+
+ ok (mongo_sync_cmd_index_drop (c, config.ns, indexes) == TRUE,
+ "mongo_sync_cmd_index_drop() works");
+
+ mongo_sync_disconnect (c);
+
+ bson_free (doc);
+ bson_free (indexes);
+
+ end_network_tests ();
+}
+
+RUN_TEST (6, mongo_sync_cmd_index_drop);
diff --git a/tests/unit/mongo/sync/sync_cmd_index_drop_all.c b/tests/unit/mongo/sync/sync_cmd_index_drop_all.c
new file mode 100644
index 0000000..782fd93
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_index_drop_all.c
@@ -0,0 +1,49 @@
+#include "test.h"
+#include "mongo.h"
+
+void
+test_mongo_sync_cmd_index_drop_all (void)
+{
+ mongo_sync_connection *c;
+ bson *doc, *indexes;
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+ doc = test_bson_generate_full ();
+ indexes = bson_build (BSON_TYPE_INT32, "sex", 1,
+ BSON_TYPE_DOUBLE, "double", 1.0,
+ BSON_TYPE_BOOLEAN, "TRUE", TRUE,
+ BSON_TYPE_INT64, "print", (gint64)-1,
+ BSON_TYPE_NONE);
+ bson_finish (indexes);
+
+ ok (mongo_sync_cmd_index_drop_all (NULL, "test.ns") == FALSE,
+ "mongo_sync_cmd_index_drop_all() fails with a NULL connection");
+ ok (mongo_sync_cmd_index_drop_all (c, NULL) == FALSE,
+ "mongo_sync_cmd_index_drop_all() fails with a NULL namespace");
+ ok (mongo_sync_cmd_index_drop_all (c, "bogus") == FALSE,
+ "mongo_sync_cmd_index_drop_all() fails with a bogus namespace");
+ ok (mongo_sync_cmd_index_drop_all (c, "test.ns") == FALSE,
+ "mongo_sync_cmd_index_drop_all() fails with a bogus FD");
+
+ mongo_sync_disconnect (c);
+
+ begin_network_tests (1);
+
+ c = mongo_sync_connect (config.primary_host, config.primary_port,
+ TRUE);
+ mongo_sync_cmd_insert (c, config.ns, doc, NULL);
+
+ mongo_sync_cmd_index_create (c, config.ns, indexes, 0);
+
+ ok (mongo_sync_cmd_index_drop_all (c, config.ns) == TRUE,
+ "mongo_sync_cmd_index_drop_all() works");
+
+ mongo_sync_disconnect (c);
+
+ bson_free (doc);
+ bson_free (indexes);
+
+ end_network_tests ();
+}
+
+RUN_TEST (5, mongo_sync_cmd_index_drop_all);
diff --git a/tests/unit/mongo/sync/sync_cmd_insert.c b/tests/unit/mongo/sync/sync_cmd_insert.c
new file mode 100644
index 0000000..f9a0f6b
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_insert.c
@@ -0,0 +1,78 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <sys/socket.h>
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_cmd_insert (void)
+{
+ mongo_sync_connection *c;
+ bson *b1, *b2;
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+ b1 = test_bson_generate_full ();
+ b2 = test_bson_generate_full ();
+
+ ok (mongo_sync_cmd_insert (NULL, "test.ns", b1, b2, NULL) == FALSE,
+ "mongo_sync_cmd_insert() fails with a NULL connection");
+ ok (mongo_sync_cmd_insert (c, NULL, b1, b2, NULL) == FALSE,
+ "mongo_sync_cmd_insert() fails with a NULL namespace");
+ ok (mongo_sync_cmd_insert (c, "test.ns", NULL) == FALSE,
+ "mongo_sync_cmd_insert() fails with no documents to insert");
+ ok (mongo_sync_cmd_insert (c, "test.ns", b1, b2, NULL) == FALSE,
+ "mongo_sync_cmd_insert() fails with a bogus FD");
+
+ mongo_sync_disconnect (c);
+ bson_free (b1);
+ bson_free (b2);
+
+ begin_network_tests (4);
+
+ b1 = bson_new ();
+ bson_append_string (b1, "sync_cmd_insert", "works", -1);
+ bson_finish (b1);
+ b2 = bson_new ();
+ bson_append_int32 (b2, "int32", 1984);
+ bson_finish (b2);
+
+ c = mongo_sync_connect (config.primary_host, config.primary_port,
+ TRUE);
+ mongo_sync_conn_set_auto_reconnect (c, TRUE);
+
+ ok (mongo_sync_cmd_insert (c, config.ns, b1, b2, NULL) == TRUE,
+ "mongo_sync_cmd_insert() works");
+
+ shutdown (c->super.fd, SHUT_RDWR);
+ sleep (3);
+
+ ok (mongo_sync_cmd_insert (c, config.ns, b1, b2, NULL) == TRUE,
+ "mongo_sync_cmd_insert() automatically reconnects");
+
+ mongo_sync_disconnect (c);
+
+ /*
+ * Tests involving a secondary
+ */
+ skip (!config.secondary_host, 2, "Secondary host not set up");
+
+ c = mongo_sync_connect (config.secondary_host, config.secondary_port,
+ TRUE);
+ mongo_sync_conn_set_auto_reconnect (c, TRUE);
+
+ ok (c && mongo_sync_cmd_is_master (c) == FALSE,
+ "Connected to a secondary");
+
+ ok (mongo_sync_cmd_insert (c, config.ns, b1, b2, NULL) == TRUE,
+ "mongo_sync_cmd_insert() automatically reconnects to master");
+ mongo_sync_disconnect (c);
+
+ endskip;
+
+ bson_free (b1);
+ bson_free (b2);
+
+ end_network_tests ();
+}
+
+RUN_TEST (8, mongo_sync_cmd_insert);
diff --git a/tests/unit/mongo/sync/sync_cmd_insert_n.c b/tests/unit/mongo/sync/sync_cmd_insert_n.c
new file mode 100644
index 0000000..9281c17
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_insert_n.c
@@ -0,0 +1,100 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <sys/socket.h>
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_cmd_insert_n (void)
+{
+ mongo_sync_connection *c;
+ bson *b1, *b2, *b3;
+ const bson *docs[10];
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+ b1 = test_bson_generate_full ();
+ b2 = test_bson_generate_full ();
+ b3 = bson_new ();
+
+ docs[0] = b1;
+ docs[1] = b2;
+ docs[2] = b3;
+ docs[3] = NULL;
+ docs[4] = b1;
+
+ ok (mongo_sync_cmd_insert_n (NULL, "test.ns", 3, docs) == FALSE,
+ "mongo_sync_cmd_insert_n() fails with a NULL connection");
+ ok (mongo_sync_cmd_insert_n (c, NULL, 3, docs) == FALSE,
+ "mongo_sync_cmd_insert_n() fails with a NULL namespace");
+ ok (mongo_sync_cmd_insert_n (c, "test.ns", 0, docs) == FALSE,
+ "mongo_sync_cmd_insert_n() fails with no documents to insert");
+ ok (mongo_sync_cmd_insert_n (c, "test.ns", 3, NULL) == FALSE,
+ "mongo_sync_cmd_insert_n() fails with no documents to insert");
+ ok (mongo_sync_cmd_insert_n (c, "test.ns", 3, docs) == FALSE,
+ "mongo_sync_cmd_insert_n() fails when the array contains an "
+ "unfinished document");
+ bson_finish (b3);
+ ok (mongo_sync_cmd_insert_n (c, "test.ns", 5, docs) == FALSE,
+ "mongo_sync_cmd_insert_n() fails when the array contains a "
+ "NULL document");
+ ok (mongo_sync_cmd_insert_n (c, "test.ns", 3, docs) == FALSE,
+ "mongo_sync_cmd_insert_n() fails with a bogus FD");
+
+ mongo_sync_disconnect (c);
+ bson_free (b1);
+ bson_free (b2);
+ bson_free (b3);
+
+ begin_network_tests (4);
+
+ b1 = bson_new ();
+ bson_append_string (b2, "sync_cmd_insert_n", "works", -1);
+ bson_finish (b1);
+
+ b2 = bson_new ();
+ bson_append_int32 (b2, "int32", 1984);
+ bson_finish (b2);
+
+ docs[0] = b1;
+ docs[1] = b2;
+
+ c = mongo_sync_connect (config.primary_host, config.primary_port,
+ TRUE);
+ mongo_sync_conn_set_auto_reconnect (c, TRUE);
+
+ ok (mongo_sync_cmd_insert_n (c, config.ns, 2, docs) == TRUE,
+ "mongo_sync_cmd_insert_n() works");
+
+ shutdown (c->super.fd, SHUT_RDWR);
+ sleep (3);
+
+ ok (mongo_sync_cmd_insert_n (c, config.ns, 2, docs) == TRUE,
+ "mongo_sync_cmd_insert_n() automatically reconnects");
+
+ mongo_sync_disconnect (c);
+
+ /*
+ * Tests involving a secondary
+ */
+ skip (!config.secondary_host, 2, "Secondary host not set up");
+
+ c = mongo_sync_connect (config.secondary_host, config.secondary_port,
+ TRUE);
+ mongo_sync_conn_set_auto_reconnect (c, TRUE);
+
+ ok (c && mongo_sync_cmd_is_master (c) == FALSE,
+ "Connected to a secondary");
+
+ ok (mongo_sync_cmd_insert_n (c, config.ns, 2, docs) == TRUE,
+ "mongo_sync_cmd_insert_n() automatically reconnects to master");
+ mongo_sync_disconnect (c);
+
+ endskip;
+
+ bson_free (b1);
+ bson_free (b2);
+
+ end_network_tests ();
+}
+
+RUN_TEST (11, mongo_sync_cmd_insert_n);
diff --git a/tests/unit/mongo/sync/sync_cmd_is_master.c b/tests/unit/mongo/sync/sync_cmd_is_master.c
new file mode 100644
index 0000000..6fa8bb4
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_is_master.c
@@ -0,0 +1,65 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <errno.h>
+
+void
+test_mongo_sync_cmd_is_master_net_secondary (void)
+{
+ mongo_sync_connection *conn;
+
+ skip (!config.secondary_host, 1,
+ "Secondary server not configured");
+
+ errno = 0;
+ conn = mongo_sync_connect (config.secondary_host, config.secondary_port,
+ TRUE);
+ ok (mongo_sync_cmd_is_master (conn) == FALSE && errno == 0,
+ "mongo_sync_cmd_is_master() works correctly on a secondary");
+ mongo_sync_disconnect (conn);
+
+ endskip;
+}
+
+void
+test_mongo_sync_cmd_is_master_net (void)
+{
+ mongo_sync_connection *conn;
+
+ begin_network_tests (2);
+
+ conn = mongo_sync_connect (config.primary_host, config.primary_port, TRUE);
+ ok (mongo_sync_cmd_is_master (conn) == TRUE,
+ "mongo_sync_cmd_is_master() works");
+ mongo_sync_disconnect (conn);
+
+ test_mongo_sync_cmd_is_master_net_secondary ();
+
+ end_network_tests ();
+}
+
+void
+test_mongo_sync_cmd_is_master (void)
+{
+ mongo_sync_connection *c;
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+
+ errno = 0;
+ ok (mongo_sync_cmd_is_master (NULL) == FALSE,
+ "mongo_sync_cmd_is_master fails with a NULL connection");
+ cmp_ok (errno, "==", ENOTCONN,
+ "errno is set to ENOTCONN");
+
+ errno = 0;
+ ok (mongo_sync_cmd_is_master (c) == FALSE,
+ "mongo_sync_cmd_is_master() works");
+ cmp_ok (errno, "!=", 0,
+ "errno is not 0");
+
+ mongo_sync_disconnect (c);
+
+ test_mongo_sync_cmd_is_master_net ();
+}
+
+RUN_TEST (6, mongo_sync_cmd_is_master);
diff --git a/tests/unit/mongo/sync/sync_cmd_kill_cursors.c b/tests/unit/mongo/sync/sync_cmd_kill_cursors.c
new file mode 100644
index 0000000..c23a5d8
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_kill_cursors.c
@@ -0,0 +1,123 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <sys/socket.h>
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_cmd_kill_cursors_net_secondary (void)
+{
+ mongo_packet *p;
+ mongo_sync_connection *conn;
+ bson *b;
+
+ mongo_reply_packet_header rh;
+ gint64 cid;
+
+ skip (!config.secondary_host, 1,
+ "Secondary server not configured");
+
+ conn = mongo_sync_connect (config.secondary_host, config.secondary_port,
+ TRUE);
+ b = bson_new ();
+ bson_append_string (b, "test-name", __FILE__, -1);
+ bson_finish (b);
+
+ p = mongo_sync_cmd_query (conn, config.ns,
+ MONGO_WIRE_FLAG_QUERY_NO_CURSOR_TIMEOUT,
+ 0, 2, b, NULL);
+ bson_free (b);
+ mongo_wire_reply_packet_get_header (p, &rh);
+ cid = rh.cursor_id;
+ mongo_wire_packet_free (p);
+
+ ok (mongo_sync_cmd_kill_cursors (conn, 1, cid) == TRUE,
+ "mongo_sync_cmd_kill_cursors() works on secondary too");
+
+ mongo_sync_disconnect (conn);
+
+ endskip;
+}
+
+void
+test_mongo_sync_cmd_kill_cursors_net (void)
+{
+ mongo_packet *p;
+ mongo_sync_connection *conn;
+ bson *b;
+ gint i;
+ mongo_reply_packet_header rh;
+ gint64 cid;
+
+ begin_network_tests (3);
+
+ conn = mongo_sync_connect (config.primary_host, config.primary_port, TRUE);
+ mongo_sync_conn_set_auto_reconnect (conn, TRUE);
+
+ b = bson_new ();
+ for (i = 0; i < 40; i++)
+ {
+ bson_reset (b);
+ bson_append_string (b, "test-name", __FILE__, -1);
+ bson_append_int32 (b, "seq", i);
+ bson_finish (b);
+
+ mongo_sync_cmd_insert (conn, config.ns, b, NULL);
+ }
+ bson_free (b);
+
+ b = bson_new ();
+ bson_append_string (b, "test-name", __FILE__, -1);
+ bson_finish (b);
+
+ p = mongo_sync_cmd_query (conn, config.ns,
+ MONGO_WIRE_FLAG_QUERY_NO_CURSOR_TIMEOUT,
+ 0, 2, b, NULL);
+ mongo_wire_reply_packet_get_header (p, &rh);
+ cid = rh.cursor_id;
+ mongo_wire_packet_free (p);
+
+ ok (mongo_sync_cmd_kill_cursors (conn, 1, cid) == TRUE,
+ "mongo_sync_kill_cursors() works");
+
+ p = mongo_sync_cmd_query (conn, config.ns,
+ MONGO_WIRE_FLAG_QUERY_NO_CURSOR_TIMEOUT,
+ 0, 2, b, NULL);
+ bson_free (b);
+ mongo_wire_reply_packet_get_header (p, &rh);
+ cid = rh.cursor_id;
+ mongo_wire_packet_free (p);
+ shutdown (conn->super.fd, SHUT_RDWR);
+ sleep (3);
+
+ ok (mongo_sync_cmd_kill_cursors (conn, 1, cid) == TRUE,
+ "mongo_sync_cmd_kill_cursors() automatically reconnects");
+
+ mongo_sync_disconnect (conn);
+
+ test_mongo_sync_cmd_kill_cursors_net_secondary ();
+
+ end_network_tests ();
+}
+
+void
+test_mongo_sync_cmd_kill_cursors (void)
+{
+ mongo_sync_connection *c;
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+
+ ok (mongo_sync_cmd_kill_cursors (NULL, 1, (gint64)1234) == FALSE,
+ "mongo_sync_cmd_kill_cursors() fails with a NULL connection");
+ ok (mongo_sync_cmd_kill_cursors (c, 0, (gint64)1234) == FALSE,
+ "mongo_sync_cmd_kill_cursors() fails with a negative number of cursors");
+
+ ok (mongo_sync_cmd_kill_cursors (c, 1, (gint64)1234) == FALSE,
+ "mongo_sync_cmd_kill_cursors() fails with a bogus FD");
+
+ mongo_sync_disconnect (c);
+
+ test_mongo_sync_cmd_kill_cursors_net ();
+}
+
+RUN_TEST (6, mongo_sync_cmd_kill_cursors);
diff --git a/tests/unit/mongo/sync/sync_cmd_ping.c b/tests/unit/mongo/sync/sync_cmd_ping.c
new file mode 100644
index 0000000..51a8aaf
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_ping.c
@@ -0,0 +1,81 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <errno.h>
+#include <sys/socket.h>
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_cmd_ping_net_secondary (void)
+{
+ mongo_sync_connection *c;
+
+ skip (!config.secondary_host, 2,
+ "Secondary server not configured");
+
+ c = mongo_sync_connect (config.secondary_host, config.secondary_port, TRUE);
+
+ ok (mongo_sync_cmd_ping (c) == TRUE,
+ "mongo_sync_cmd_ping() works");
+
+ shutdown (c->super.fd, SHUT_RDWR);
+ sleep (3);
+
+ ok (mongo_sync_cmd_ping (c) == FALSE,
+ "mongo_sync_cmd_ping() returns FALSE when not connected");
+
+ mongo_sync_disconnect (c);
+
+ endskip;
+}
+
+void
+test_mongo_sync_cmd_ping_net (void)
+{
+ mongo_sync_connection *c;
+
+ begin_network_tests (4);
+
+ c = mongo_sync_connect (config.primary_host, config.primary_port, TRUE);
+
+ ok (mongo_sync_cmd_ping (c) == TRUE,
+ "mongo_sync_cmd_ping() works");
+
+ shutdown (c->super.fd, SHUT_RDWR);
+ sleep (3);
+
+ ok (mongo_sync_cmd_ping (c) == FALSE,
+ "mongo_sync_cmd_ping() returns FALSE when not connected");
+
+ mongo_sync_disconnect (c);
+
+ test_mongo_sync_cmd_ping_net_secondary ();
+
+ end_network_tests ();
+}
+
+void
+test_mongo_sync_cmd_ping (void)
+{
+ mongo_sync_connection *c;
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+
+ errno = 0;
+ ok (mongo_sync_cmd_ping (NULL) == FALSE,
+ "mongo_sync_cmd_ping(NULL) returns FALSE");
+ cmp_ok (errno, "==", ENOTCONN,
+ "errno is set to ENOTCONN");
+
+ errno = 0;
+ ok (mongo_sync_cmd_ping (c) == FALSE,
+ "Pinging a bogus connection fails");
+ cmp_ok (errno, "!=", 0,
+ "errno is not 0");
+
+ mongo_sync_disconnect (c);
+
+ test_mongo_sync_cmd_ping_net ();
+}
+
+RUN_TEST (8, mongo_sync_cmd_ping);
diff --git a/tests/unit/mongo/sync/sync_cmd_query.c b/tests/unit/mongo/sync/sync_cmd_query.c
new file mode 100644
index 0000000..da7c693
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_query.c
@@ -0,0 +1,125 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <errno.h>
+#include <sys/socket.h>
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_cmd_query (void)
+{
+ mongo_packet *p;
+ mongo_sync_connection *c;
+ bson *q, *s;
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+ q = test_bson_generate_full ();
+ s = test_bson_generate_full ();
+
+ ok (mongo_sync_cmd_query (NULL, "test.ns", 0, 0, 1, q, s) == NULL,
+ "mongo_sync_cmd_query() fails with a NULL connection");
+ ok (mongo_sync_cmd_query (c, NULL, 0, 0, 1, q, s) == NULL,
+ "mongo_sync_cmd_query() fails with a NULL namespace");
+ ok (mongo_sync_cmd_query (c, "test.ns", 0, 0, 1, NULL, s) == NULL,
+ "mongo_sync_cmd_query() fails with a NULL query");
+
+ ok (mongo_sync_cmd_query (c, "test.ns", 0, 0, 1, q, s) == NULL,
+ "mongo_sync_cmd_query() fails with a bogus FD");
+ mongo_sync_conn_set_slaveok (c, TRUE);
+ ok (mongo_sync_cmd_query (c, "test.ns", 0, 0, 1, q, s) == NULL,
+ "mongo_sync_cmd_query() fails with a bogus FD");
+
+ mongo_sync_disconnect (c);
+
+ bson_free (q);
+ bson_free (s);
+
+ begin_network_tests (7);
+
+ q = bson_new ();
+ bson_append_boolean (q, "sync_cmd_query_test", TRUE);
+ bson_finish (q);
+
+ s = bson_new ();
+ bson_append_boolean (s, "sync_cmd_query_test", FALSE);
+ bson_finish (s);
+
+ c = mongo_sync_connect (config.primary_host, config.primary_port, TRUE);
+ mongo_sync_conn_set_auto_reconnect (c, TRUE);
+ mongo_sync_cmd_insert (c, config.ns, q, NULL);
+
+ p = mongo_sync_cmd_query (c, config.ns, 0, 0, 1, q, NULL);
+ ok (p != NULL,
+ "mongo_sync_cmd_query() works");
+ mongo_wire_packet_free (p);
+
+ errno = 0;
+ p = mongo_sync_cmd_query (c, config.ns, 0, 0, 1, s, NULL);
+ ok (p == NULL && errno == ENOENT,
+ "mongo_sync_cmd_query() sets errno to ENOENT when there's "
+ "nothing to return");
+ mongo_wire_packet_free (p);
+
+ shutdown (c->super.fd, SHUT_RDWR);
+ sleep (3);
+
+ p = mongo_sync_cmd_query (c, config.ns, 0, 0, 1, q, NULL);
+ ok (p != NULL,
+ "mongo_sync_cmd_query() automatically reconnects");
+ mongo_wire_packet_free (p);
+
+ mongo_sync_disconnect (c);
+
+ /*
+ * Test request/response pairing, by sending a crafted query first,
+ * and another, without reading the response for the first before
+ * that.
+ */
+ c = mongo_sync_connect (config.primary_host, config.primary_port, TRUE);
+ p = mongo_wire_cmd_query (12345, config.ns, MONGO_WIRE_FLAG_QUERY_SLAVE_OK,
+ 0, 1, s, NULL);
+ mongo_packet_send ((mongo_connection *)c, p);
+ mongo_wire_packet_free (p);
+
+ errno = 0;
+ p = mongo_sync_cmd_query (c, config.ns, 0, 0, 1, s, NULL);
+ ok (p == NULL && errno == EPROTO,
+ "mongo_sync_cmd_query() fails if the reply is not a response to "
+ "the current query");
+ mongo_wire_packet_free (p);
+
+ mongo_sync_disconnect (c);
+
+ /*
+ * Tests involving a secondary
+ */
+ skip (!config.secondary_host, 3, "Secondary host not set up");
+
+ c = mongo_sync_connect (config.secondary_host, config.secondary_port, TRUE);
+ mongo_sync_conn_set_auto_reconnect (c, TRUE);
+
+ ok (c && mongo_sync_cmd_is_master (c) == FALSE,
+ "Connected to a secondary");
+ p = mongo_sync_cmd_query (c, config.ns, 0, 0, 1, q, NULL);
+ ok (p != NULL,
+ "mongo_sync_cmd_query() works on secondary");
+ mongo_wire_packet_free (p);
+
+ mongo_sync_conn_set_slaveok (c, FALSE);
+
+ p = mongo_sync_cmd_query (c, config.ns, 0, 0, 1, q, NULL);
+ ok (p != NULL && mongo_sync_cmd_is_master (c) == TRUE,
+ "mongo_sync_cmd_query() can resync to master");
+ mongo_wire_packet_free (p);
+
+ mongo_sync_disconnect (c);
+
+ endskip;
+
+ bson_free (q);
+ bson_free (s);
+
+ end_network_tests ();
+}
+
+RUN_TEST (12, mongo_sync_cmd_query);
diff --git a/tests/unit/mongo/sync/sync_cmd_reset_error.c b/tests/unit/mongo/sync/sync_cmd_reset_error.c
new file mode 100644
index 0000000..8f92fcf
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_reset_error.c
@@ -0,0 +1,31 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <errno.h>
+
+void
+test_mongo_sync_cmd_reset_error (void)
+{
+ mongo_sync_connection *c;
+
+ test_env_setup ();
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+
+ errno = 0;
+ ok (mongo_sync_cmd_reset_error (NULL, config.db) == FALSE,
+ "mongo_sync_cmd_reset_error() fails with a NULL connection");
+ cmp_ok (errno, "==", ENOTCONN,
+ "errno is set to ENOTCONN");
+
+ ok (mongo_sync_cmd_reset_error (c, NULL) == FALSE,
+ "mongo_sync_cmd_reset_error() fails with a NULL db");
+
+ ok (mongo_sync_cmd_reset_error (c, config.db) == FALSE,
+ "mongo_sync_cmd_reset_error() fails with a bogus FD");
+
+ mongo_sync_disconnect (c);
+ test_env_free ();
+}
+
+RUN_TEST (4, mongo_sync_cmd_reset_error);
diff --git a/tests/unit/mongo/sync/sync_cmd_update.c b/tests/unit/mongo/sync/sync_cmd_update.c
new file mode 100644
index 0000000..21b981f
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_update.c
@@ -0,0 +1,97 @@
+#include "test.h"
+#include "mongo.h"
+
+#include "libmongo-private.h"
+
+#include <sys/socket.h>
+
+void
+test_mongo_sync_cmd_update (void)
+{
+ mongo_sync_connection *c;
+ bson *sel, *upd;
+ guint8 *oid;
+
+ mongo_util_oid_init (0);
+
+ sel = bson_new ();
+ oid = mongo_util_oid_new (0);
+ bson_append_oid (sel, "_id", oid);
+ g_free (oid);
+ bson_finish (sel);
+
+ upd = test_bson_generate_full ();
+ c = test_make_fake_sync_conn (-1, FALSE);
+
+ ok (mongo_sync_cmd_update (NULL, "test.ns", 0, sel, upd) == FALSE,
+ "mongo_sync_cmd_update() fails with a NULL connection");
+ ok (mongo_sync_cmd_update (c, NULL, 0, sel, upd) == FALSE,
+ "mongo_sync_cmd_update() fails with a NULL namespace");
+ ok (mongo_sync_cmd_update (c, "test.ns", 0, NULL, upd) == FALSE,
+ "mongo_sync_cmd_update() fails with a NULL selector");
+ ok (mongo_sync_cmd_update (c, "test.ns", 0, sel, NULL) == FALSE,
+ "mongo_sync_cmd_update() fails with a NULL update");
+
+ ok (mongo_sync_cmd_update (c, "test.ns", 0, sel, upd) == FALSE,
+ "mongo_sync_cmd_update() fails with a bogus FD");
+
+ mongo_sync_disconnect (c);
+ bson_free (sel);
+ bson_free (upd);
+
+ begin_network_tests (4);
+
+ sel = bson_new ();
+ oid = mongo_util_oid_new (1);
+ bson_append_oid (sel, "_id", oid);
+ g_free (oid);
+ bson_finish (sel);
+
+ upd = bson_new ();
+ oid = mongo_util_oid_new (1);
+ bson_append_oid (upd, "_id", oid);
+ g_free (oid);
+ bson_finish (upd);
+
+ c = mongo_sync_connect (config.primary_host, config.primary_port,
+ FALSE);
+ mongo_sync_conn_set_auto_reconnect (c, TRUE);
+
+ ok (mongo_sync_cmd_update (c, config.ns,
+ MONGO_WIRE_FLAG_UPDATE_UPSERT, sel, upd) == TRUE,
+ "mongo_sync_cmd_update() works");
+
+ shutdown (c->super.fd, SHUT_RDWR);
+ sleep (3);
+
+ ok (mongo_sync_cmd_update (c, config.ns,
+ MONGO_WIRE_FLAG_UPDATE_UPSERT, sel, upd) == TRUE,
+ "mongo_sync_cmd_update() automatically reconnects");
+
+ mongo_sync_disconnect (c);
+
+ /*
+ * Tests involving a secondary
+ */
+ skip (!config.secondary_host, 2,
+ "Secondary host not set up");
+
+ c = mongo_sync_connect (config.secondary_host, config.secondary_port,
+ TRUE);
+ mongo_sync_conn_set_auto_reconnect (c, TRUE);
+
+ ok (mongo_sync_cmd_is_master (c) == FALSE,
+ "Connected to a secondary");
+
+ ok (mongo_sync_cmd_update (c, config.ns,
+ MONGO_WIRE_FLAG_UPDATE_UPSERT, sel, upd) == TRUE,
+ "mongo_sync_cmd_update() automatically reconnects to master");
+ mongo_sync_disconnect (c);
+ endskip;
+
+ bson_free (sel);
+ bson_free (upd);
+ end_network_tests ();
+}
+
+RUN_TEST (9, mongo_sync_cmd_update);
diff --git a/tests/unit/mongo/sync/sync_cmd_user_add.c b/tests/unit/mongo/sync/sync_cmd_user_add.c
new file mode 100644
index 0000000..9cdc542
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_user_add.c
@@ -0,0 +1,95 @@
+#include "test.h"
+#include "mongo.h"
+#include "config.h"
+
+#include <errno.h>
+#include <sys/socket.h>
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_cmd_user_add_net_secondary (void)
+{
+ mongo_sync_connection *c;
+ gboolean ret;
+
+ skip (!config.secondary_host, 1,
+ "Secondary server not configured");
+
+ c = mongo_sync_connect (config.secondary_host, config.secondary_port, TRUE);
+ mongo_sync_conn_set_auto_reconnect (c, TRUE);
+
+ ret = mongo_sync_cmd_user_add (c, config.db, "test", "s3kr1+");
+ ok (ret && mongo_sync_cmd_is_master (c),
+ "mongo_sync_cmd_user_add() automatically reconnects to master");
+
+ mongo_sync_disconnect (c);
+
+ endskip;
+}
+
+void
+test_mongo_sync_cmd_user_add_net (void)
+{
+ mongo_sync_connection *c;
+
+ begin_network_tests (3);
+
+ c = mongo_sync_connect (config.primary_host, config.primary_port, TRUE);
+ mongo_sync_conn_set_auto_reconnect (c, TRUE);
+
+ ok (mongo_sync_cmd_user_add (c, config.db, "test", "s3kr1+") == TRUE,
+ "mongo_sync_cmd_user_add() works");
+
+ shutdown (c->super.fd, SHUT_RDWR);
+ sleep (3);
+
+ ok (mongo_sync_cmd_user_add (c, config.db, "test", "s3kr1+") == TRUE,
+ "mongo_sync_cmd_user_add() automatically reconnects");
+
+ mongo_sync_disconnect (c);
+
+ test_mongo_sync_cmd_user_add_net_secondary ();
+
+ end_network_tests ();
+}
+
+void
+test_mongo_sync_cmd_user_add (void)
+{
+ mongo_sync_connection *c;
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+
+ errno = 0;
+ ok (mongo_sync_cmd_user_add (NULL, "test", "test", "s3kr1+") == FALSE,
+ "mongo_sync_cmd_user_add() fails with a NULL connection");
+ cmp_ok (errno, "==", ENOTCONN,
+ "errno is set to ENOTCONN");
+
+ errno = 0;
+ ok (mongo_sync_cmd_user_add (c, NULL, "test", "s3kr1+") == FALSE,
+ "mongo_sync_cmd_user_add() fails with a NULL db");
+ cmp_ok (errno, "==", EINVAL,
+ "errno is set to EINVAL");
+
+ errno = 0;
+ ok (mongo_sync_cmd_user_add (c, "test", NULL, "s3kr1+") == FALSE,
+ "mongo_sync_cmd_user_add() fails with a NULL user");
+ cmp_ok (errno, "==", EINVAL,
+ "errno is set to EINVAL");
+
+ errno = 0;
+ ok (mongo_sync_cmd_user_add (c, "test", "test", NULL) == FALSE,
+ "mongo_sync_cmd_user_add() fails with a NULL password");
+ cmp_ok (errno, "==", EINVAL,
+ "errno is set to EINVAL");
+
+ ok (mongo_sync_cmd_user_add (c, "test", "test", "s3kr1+") == FALSE,
+ "mongo_sync_cmd_user_add() fails with a bogus FD");
+
+ mongo_sync_disconnect (c);
+
+ test_mongo_sync_cmd_user_add_net ();
+}
+
+RUN_TEST (12, mongo_sync_cmd_user_add);
diff --git a/tests/unit/mongo/sync/sync_cmd_user_add_with_roles.c b/tests/unit/mongo/sync/sync_cmd_user_add_with_roles.c
new file mode 100644
index 0000000..04bb842
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_user_add_with_roles.c
@@ -0,0 +1,89 @@
+#include "test.h"
+#include "mongo.h"
+#include "config.h"
+
+#include <errno.h>
+#include <sys/socket.h>
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_cmd_user_add_with_roles_net (const bson *roles)
+{
+ mongo_sync_connection *c;
+
+ begin_network_tests (2);
+
+ c = mongo_sync_connect (config.primary_host, config.primary_port, TRUE);
+ mongo_sync_conn_set_auto_reconnect (c, TRUE);
+
+ ok (mongo_sync_cmd_user_add_with_roles (c, config.db,
+ "test", "s3kr1+", roles) == TRUE,
+ "mongo_sync_cmd_user_add_with_roles() works");
+
+ shutdown (c->super.fd, SHUT_RDWR);
+ sleep (3);
+
+ ok (mongo_sync_cmd_user_add_with_roles (c, config.db,
+ "test", "s3kr1+", roles) == TRUE,
+ "mongo_sync_cmd_user_add_with_roles() automatically reconnects");
+
+ mongo_sync_disconnect (c);
+
+ end_network_tests ();
+}
+
+void
+test_mongo_sync_cmd_user_add_with_roles (void)
+{
+ mongo_sync_connection *c;
+ bson *roles = bson_build (BSON_TYPE_STRING, "0", "readWrite", -1,
+ BSON_TYPE_NONE);
+
+ bson_finish (roles);
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+
+ errno = 0;
+ ok (mongo_sync_cmd_user_add_with_roles (NULL, "test",
+ "test", "s3kr1+", roles) == FALSE,
+ "mongo_sync_cmd_user_add_with_roles() fails with a NULL connection");
+ cmp_ok (errno, "==", ENOTCONN,
+ "errno is set to ENOTCONN");
+
+ errno = 0;
+ ok (mongo_sync_cmd_user_add_with_roles (c, NULL,
+ "test", "s3kr1+", roles) == FALSE,
+ "mongo_sync_cmd_user_add_with_roles() fails with a NULL db");
+ cmp_ok (errno, "==", EINVAL,
+ "errno is set to EINVAL");
+
+ errno = 0;
+ ok (mongo_sync_cmd_user_add_with_roles (c, "test",
+ NULL, "s3kr1+", roles) == FALSE,
+ "mongo_sync_cmd_user_add_with_roles() fails with a NULL user");
+ cmp_ok (errno, "==", EINVAL,
+ "errno is set to EINVAL");
+
+ errno = 0;
+ ok (mongo_sync_cmd_user_add_with_roles (c, "test",
+ "test", NULL, roles) == FALSE,
+ "mongo_sync_cmd_user_add_with_roles() fails with a NULL password");
+ cmp_ok (errno, "==", EINVAL,
+ "errno is set to EINVAL");
+
+ ok (mongo_sync_cmd_user_add_with_roles (c, "test",
+ "test", "s3kr1+", NULL) == FALSE,
+ "mongo_sync_cmd_user_add() fails with a bogus FD and empty roles");
+
+ ok (mongo_sync_cmd_user_add_with_roles (c, "test",
+ "test", "s3kr1+", roles) == FALSE,
+ "mongo_sync_cmd_user_add() fails with a bogus FD");
+
+ mongo_sync_disconnect (c);
+
+ test_mongo_sync_cmd_user_add_with_roles_net (roles);
+
+ bson_free (roles);
+}
+
+RUN_TEST (12, mongo_sync_cmd_user_add_with_roles);
diff --git a/tests/unit/mongo/sync/sync_cmd_user_remove.c b/tests/unit/mongo/sync/sync_cmd_user_remove.c
new file mode 100644
index 0000000..dc66063
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_cmd_user_remove.c
@@ -0,0 +1,92 @@
+#include "test.h"
+#include "mongo.h"
+#include "config.h"
+
+#include <errno.h>
+#include <sys/socket.h>
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_cmd_user_remove_net_secondary (void)
+{
+ mongo_sync_connection *c;
+ gboolean ret;
+
+ skip (!config.secondary_host, 1,
+ "Secondary server not configured");
+
+ c = mongo_sync_connect (config.secondary_host, config.secondary_port, TRUE);
+ mongo_sync_conn_set_auto_reconnect (c, TRUE);
+
+ mongo_sync_cmd_user_add (c, config.db, "test", "s3kr1+");
+ ret = mongo_sync_cmd_user_remove (c, config.db, "test");
+ ok (ret && mongo_sync_cmd_is_master (c),
+ "mongo_sync_cmd_user_remove() automatically reconnects to master");
+
+ mongo_sync_disconnect (c);
+
+ endskip;
+}
+
+void
+test_mongo_sync_cmd_user_remove_net (void)
+{
+ mongo_sync_connection *c;
+
+ begin_network_tests (3);
+
+ c = mongo_sync_connect (config.primary_host, config.primary_port, TRUE);
+ mongo_sync_conn_set_auto_reconnect (c, TRUE);
+
+ mongo_sync_cmd_user_add (c, config.db, "test", "s3kr1+");
+ ok (mongo_sync_cmd_user_remove (c, config.db, "test") == TRUE,
+ "mongo_sync_cmd_user_remove() works");
+
+ mongo_sync_cmd_user_add (c, config.db, "test", "s3kr1+");
+ shutdown (c->super.fd, SHUT_RDWR);
+ sleep (3);
+
+ ok (mongo_sync_cmd_user_remove (c, config.db, "test") == TRUE,
+ "mongo_sync_cmd_user_remove() automatically reconnects");
+
+ mongo_sync_disconnect (c);
+
+ test_mongo_sync_cmd_user_remove_net_secondary ();
+
+ end_network_tests ();
+}
+
+void
+test_mongo_sync_cmd_user_remove (void)
+{
+ mongo_sync_connection *c;
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+
+ errno = 0;
+ ok (mongo_sync_cmd_user_remove (NULL, "test", "test") == FALSE,
+ "mongo_sync_cmd_user_remove() fails with a NULL connection");
+ cmp_ok (errno, "==", ENOTCONN,
+ "errno is set to ENOTCONN");
+
+ errno = 0;
+ ok (mongo_sync_cmd_user_remove (c, NULL, "test") == FALSE,
+ "mongo_sync_cmd_user_remove() fails with a NULL db");
+ cmp_ok (errno, "==", EINVAL,
+ "errno is set to EINVAL");
+
+ errno = 0;
+ ok (mongo_sync_cmd_user_remove (c, "test", NULL) == FALSE,
+ "mongo_sync_cmd_user_remove() fails with a NULL user");
+ cmp_ok (errno, "==", EINVAL,
+ "errno is set to EINVAL");
+
+ ok (mongo_sync_cmd_user_remove (c, "test", "test") == FALSE,
+ "mongo_sync_cmd_user_remove() fails with a bogus FD");
+
+ mongo_sync_disconnect (c);
+
+ test_mongo_sync_cmd_user_remove_net ();
+}
+
+RUN_TEST (10, mongo_sync_cmd_user_remove);
diff --git a/tests/unit/mongo/sync/sync_conn_seed_add.c b/tests/unit/mongo/sync/sync_conn_seed_add.c
new file mode 100644
index 0000000..fb9f10a
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_conn_seed_add.c
@@ -0,0 +1,24 @@
+#include "test.h"
+#include "mongo.h"
+
+void
+test_mongo_sync_conn_seed_add (void)
+{
+ mongo_sync_connection *c;
+
+ c = test_make_fake_sync_conn (42, TRUE);
+
+ ok (mongo_sync_conn_seed_add (NULL, "localhost", 27017) == FALSE,
+ "mongo_sync_conn_seed_add() should fail with a NULL connection");
+ ok (mongo_sync_conn_seed_add (c, NULL, 27017) == FALSE,
+ "mongo_sync_conn_seed_add() should fail with a NULL host");
+ ok (mongo_sync_conn_seed_add (c, "localhost", -1) == FALSE,
+ "mongo_sync_conn_seed_add() should fail with an invalid port");
+
+ ok (mongo_sync_conn_seed_add (c, "localhost", 27017),
+ "mongo_sync_conn_seed_add() works");
+
+ mongo_sync_disconnect (c);
+}
+
+RUN_TEST (4, mongo_sync_conn_seed_add);
diff --git a/tests/unit/mongo/sync/sync_conn_seed_add_cache.c b/tests/unit/mongo/sync/sync_conn_seed_add_cache.c
new file mode 100644
index 0000000..e049691
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_conn_seed_add_cache.c
@@ -0,0 +1,31 @@
+#include "test.h"
+#include "mongo.h"
+
+void
+test_mongo_sync_connection_cache_seed_add (void)
+{
+ mongo_sync_conn_recovery_cache *cache;
+
+ cache = mongo_sync_conn_recovery_cache_new ();
+
+ ok (mongo_sync_conn_recovery_cache_seed_add (cache,
+ "localhost",
+ 27017) == TRUE,
+ "mongo_sync_connection_cache_seed_add() works");
+
+ ok (mongo_sync_conn_recovery_cache_seed_add (cache,
+ NULL,
+ 27017) == FALSE,
+ "mongo_sync_connection_cache_seed_add() should fail with a NULL host");
+
+ mongo_sync_conn_recovery_cache_discard (cache);
+
+ ok (mongo_sync_conn_recovery_cache_seed_add (cache,
+ "localhost",
+ 27017) == TRUE,
+ "mongo_sync_connection_cache_seed_add() works");
+
+ mongo_sync_conn_recovery_cache_free (cache);
+}
+
+RUN_TEST (3, mongo_sync_connection_cache_seed_add);
diff --git a/tests/unit/mongo/sync/sync_connect.c b/tests/unit/mongo/sync/sync_connect.c
new file mode 100644
index 0000000..418c2bf
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_connect.c
@@ -0,0 +1,22 @@
+#include "test.h"
+#include "mongo.h"
+
+void
+test_mongo_sync_connect (void)
+{
+ mongo_sync_connection *c;
+
+ ok (mongo_sync_connect (NULL, 27017, FALSE) == NULL,
+ "mongo_sync_connect() fails with a NULL host");
+
+ begin_network_tests (1);
+
+ ok ((c = mongo_sync_connect (config.primary_host,
+ config.primary_port, FALSE)) != NULL,
+ "mongo_sync_connect() works");
+ mongo_sync_disconnect (c);
+
+ end_network_tests ();
+}
+
+RUN_TEST (2, mongo_sync_connect);
diff --git a/tests/unit/mongo/sync/sync_connect_cache.c b/tests/unit/mongo/sync/sync_connect_cache.c
new file mode 100644
index 0000000..1618899
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_connect_cache.c
@@ -0,0 +1,42 @@
+#include "test.h"
+#include "mongo.h"
+
+void
+test_mongo_sync_conn_recovery_cache_connection (void)
+{
+ mongo_sync_conn_recovery_cache *cache;
+ mongo_sync_connection *c = NULL;
+
+ cache = mongo_sync_conn_recovery_cache_new ();
+
+ ok (mongo_sync_connect_recovery_cache (cache, FALSE) == NULL,
+ "mongo_sync_connect_recovery_cache() should fail when cache is empty");
+
+ begin_network_tests (4);
+
+ ok (mongo_sync_conn_recovery_cache_seed_add (cache,
+ config.primary_host,
+ config.primary_port) == TRUE,
+ "mongo_sync_conn_recovery_cache_seed_add() works");
+
+ ok ((c = mongo_sync_connect_recovery_cache (cache, FALSE)) != NULL,
+ "mongo_sync_connect_recovery_cache() works");
+
+ mongo_sync_disconnect (c);
+
+ ok ((c = mongo_sync_connect_recovery_cache (cache, FALSE)) != NULL,
+ "mongo_sync_connect_recovery_cache() works after disconnect");
+
+ mongo_sync_disconnect (c);
+
+ mongo_sync_conn_recovery_cache_discard (cache);
+
+ ok (mongo_sync_connect_recovery_cache (cache, TRUE) == NULL,
+ "mongo_sync_connect_recovery_cache() should fail when cache is discarded");
+
+ mongo_sync_conn_recovery_cache_free (cache);
+
+ end_network_tests ();
+}
+
+RUN_TEST (5, mongo_sync_conn_recovery_cache_connection);
diff --git a/tests/unit/mongo/sync/sync_connect_from_cache_enforce_primary.c b/tests/unit/mongo/sync/sync_connect_from_cache_enforce_primary.c
new file mode 100644
index 0000000..5c48ae9
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_connect_from_cache_enforce_primary.c
@@ -0,0 +1,47 @@
+#include "test.h"
+#include "mongo.h"
+
+#define NETWORK_TESTS_NUM 5
+
+void
+test_mongo_sync_connect_from_cache_enforce_primary (void)
+{
+ mongo_sync_conn_recovery_cache *cache;
+ mongo_sync_connection *c;
+
+ begin_network_tests (NETWORK_TESTS_NUM);
+
+ cache = mongo_sync_conn_recovery_cache_new ();
+
+ skip (!config.secondary_host,
+ NETWORK_TESTS_NUM,
+ "Secondary server not configured");
+
+ ok (mongo_sync_conn_recovery_cache_seed_add (cache, config.secondary_host,
+ config.secondary_port) == TRUE,
+ "mongo_sync_conn_recovery_seed_add() works");
+
+ ok ((c = mongo_sync_connect_recovery_cache (cache, TRUE)) != NULL,
+ "mongo_sync_connect_recovery_cache() works");
+
+ ok (mongo_sync_cmd_is_master(c) == FALSE,
+ "Secondary server should not be The Master.");
+
+ mongo_sync_disconnect (c);
+
+ ok ((c = mongo_sync_connect_recovery_cache (cache, FALSE)) != NULL,
+ "mongo_sync_connect_recovery_cache() works");
+
+ ok (mongo_sync_cmd_is_master (c) == TRUE,\
+ "Retrieved connection should be The Master when it is forced to be.");
+
+ mongo_sync_disconnect (c);
+
+ endskip;
+
+ mongo_sync_conn_recovery_cache_free (cache);
+
+ end_network_tests ();
+}
+
+RUN_TEST (NETWORK_TESTS_NUM, mongo_sync_connect_from_cache_enforce_primary);
diff --git a/tests/unit/mongo/sync/sync_disconnect.c b/tests/unit/mongo/sync/sync_disconnect.c
new file mode 100644
index 0000000..f7783e7
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_disconnect.c
@@ -0,0 +1,22 @@
+#include "test.h"
+#include "mongo.h"
+
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_disconnect (void)
+{
+ mongo_sync_connection *conn;
+
+ mongo_sync_disconnect (NULL);
+ pass ("mongo_sync_disconnect(NULL) does not crash");
+
+ conn = test_make_fake_sync_conn (-1, FALSE);
+ conn->rs.hosts = g_list_append (conn->rs.hosts,
+ g_strdup ("invalid.example.com:-42"));
+
+ mongo_sync_disconnect (conn);
+ pass ("mongo_sync_disconnect() works");
+}
+
+RUN_TEST (2, mongo_sync_disconnect);
diff --git a/tests/unit/mongo/sync/sync_get_set_auto_reconnect.c b/tests/unit/mongo/sync/sync_get_set_auto_reconnect.c
new file mode 100644
index 0000000..bfe2719
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_get_set_auto_reconnect.c
@@ -0,0 +1,39 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <errno.h>
+
+void
+test_mongo_sync_get_set_auto_reconnect (void)
+{
+ mongo_sync_connection *c;
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+
+ errno = 0;
+ ok (mongo_sync_conn_get_auto_reconnect (NULL) == FALSE,
+ "mongo_sync_conn_get_auto_reconnect() returns FALSE with a "
+ "NULL connection");
+ cmp_ok (errno, "==", ENOTCONN,
+ "errno is now set to ENOTCONN");
+
+ ok (mongo_sync_conn_get_auto_reconnect (c) == FALSE,
+ "mongo_sync_get_auto_reconnect() works");
+ cmp_ok (errno, "==", 0,
+ "errno is now cleared");
+
+ errno = 0;
+ mongo_sync_conn_set_auto_reconnect (NULL, TRUE);
+ cmp_ok (errno, "==", ENOTCONN,
+ "errno is set to ENOTCONN after "
+ "mongo_sync_conn_set_auto_reconnect(NULL)");
+
+ ok (mongo_sync_conn_set_auto_reconnect (c, TRUE),
+ "mongo_sync_auto_reconnect() works");
+ ok (mongo_sync_conn_get_auto_reconnect (c) == TRUE,
+ "mongo_sync_set_auto_reconnect() worked");
+
+ mongo_sync_disconnect (c);
+}
+
+RUN_TEST (7, mongo_sync_get_set_auto_reconnect);
diff --git a/tests/unit/mongo/sync/sync_get_set_max_insert_size.c b/tests/unit/mongo/sync/sync_get_set_max_insert_size.c
new file mode 100644
index 0000000..51970a3
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_get_set_max_insert_size.c
@@ -0,0 +1,44 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <errno.h>
+
+void
+test_mongo_sync_get_set_max_insert_size (void)
+{
+ mongo_sync_connection *c;
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+
+ errno = 0;
+ ok (mongo_sync_conn_get_max_insert_size (NULL) == -1,
+ "mongo_sync_conn_get_max_insert_size() returns -1 with "
+ "a NULL connection");
+
+ cmp_ok (mongo_sync_conn_get_max_insert_size (c), "==",
+ MONGO_SYNC_DEFAULT_MAX_INSERT_SIZE,
+ "mongo_sync_get_max_insert_size() works");
+
+ errno = 0;
+ mongo_sync_conn_set_max_insert_size (NULL, 1024);
+ cmp_ok (errno, "==", ENOTCONN,
+ "errno is set to ENOTCONN after "
+ "mongo_sync_conn_set_max_insert_size(NULL)");
+
+ mongo_sync_conn_set_max_insert_size (c, 1024);
+ cmp_ok (errno, "==", 0,
+ "errno is cleared");
+ ok (mongo_sync_conn_get_max_insert_size (c) == 1024,
+ "mongo_sync_set_max_insert_size() worked");
+
+ mongo_sync_conn_set_max_insert_size (c, -1);
+ cmp_ok (errno, "==", ERANGE,
+ "errno is set to ERANGE");
+ ok (mongo_sync_conn_get_max_insert_size (c) == 1024,
+ "mongo_sync_set_max_insert_size() with a negative value should "
+ "not work");
+
+ mongo_sync_disconnect (c);
+}
+
+RUN_TEST (7, mongo_sync_get_set_max_insert_size);
diff --git a/tests/unit/mongo/sync/sync_get_set_safe_mode.c b/tests/unit/mongo/sync/sync_get_set_safe_mode.c
new file mode 100644
index 0000000..b444105
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_get_set_safe_mode.c
@@ -0,0 +1,38 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <errno.h>
+
+void
+test_mongo_sync_get_set_safe_mode (void)
+{
+ mongo_sync_connection *c;
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+
+ errno = 0;
+ ok (mongo_sync_conn_get_safe_mode (NULL) == FALSE,
+ "mongo_sync_conn_get_safe_mode() returns FALSE with a NULL connection");
+ cmp_ok (errno, "==", ENOTCONN,
+ "errno is now set to ENOTCONN");
+
+ ok (mongo_sync_conn_get_safe_mode (c) == FALSE,
+ "mongo_sync_get_safe_mode() works");
+ cmp_ok (errno, "==", 0,
+ "errno is now cleared");
+
+ errno = 0;
+ mongo_sync_conn_set_safe_mode (NULL, TRUE);
+ cmp_ok (errno, "==", ENOTCONN,
+ "errno is set to ENOTCONN after mongo_sync_conn_get_safe_mode(NULL)");
+
+ mongo_sync_conn_set_safe_mode (c, TRUE);
+ cmp_ok (errno, "==", 0,
+ "errno is cleared");
+ ok (mongo_sync_conn_get_safe_mode (c) == TRUE,
+ "mongo_sync_set_safe_mode() worked");
+
+ mongo_sync_disconnect (c);
+}
+
+RUN_TEST (7, mongo_sync_get_set_safe_mode);
diff --git a/tests/unit/mongo/sync/sync_get_set_slaveok.c b/tests/unit/mongo/sync/sync_get_set_slaveok.c
new file mode 100644
index 0000000..7a43979
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_get_set_slaveok.c
@@ -0,0 +1,38 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <errno.h>
+
+void
+test_mongo_sync_get_set_slaveok (void)
+{
+ mongo_sync_connection *c;
+
+ c = test_make_fake_sync_conn (-1, FALSE);
+
+ errno = 0;
+ ok (mongo_sync_conn_get_slaveok (NULL) == FALSE,
+ "mongo_sync_conn_get_slaveok() returns FALSE with a NULL connection");
+ cmp_ok (errno, "==", ENOTCONN,
+ "errno is now set to ENOTCONN");
+
+ ok (mongo_sync_conn_get_slaveok (c) == FALSE,
+ "mongo_sync_get_slaveok() works");
+ cmp_ok (errno, "==", 0,
+ "errno is now cleared");
+
+ errno = 0;
+ mongo_sync_conn_set_slaveok (NULL, TRUE);
+ cmp_ok (errno, "==", ENOTCONN,
+ "errno is set to ENOTCONN after mongo_sync_conn_get_slaveok(NULL)");
+
+ mongo_sync_conn_set_slaveok (c, TRUE);
+ cmp_ok (errno, "==", 0,
+ "errno is cleared");
+ ok (mongo_sync_conn_get_slaveok (c) == TRUE,
+ "mongo_sync_set_slaveok() worked");
+
+ mongo_sync_disconnect (c);
+}
+
+RUN_TEST (7, mongo_sync_get_set_slaveok);
diff --git a/tests/unit/mongo/sync/sync_reconnect.c b/tests/unit/mongo/sync/sync_reconnect.c
new file mode 100644
index 0000000..a81e4da
--- /dev/null
+++ b/tests/unit/mongo/sync/sync_reconnect.c
@@ -0,0 +1,143 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <errno.h>
+#include <sys/socket.h>
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_reconnect (void)
+{
+ mongo_sync_connection *conn, *o;
+ GList *l;
+
+ ok (mongo_sync_reconnect (NULL, FALSE) == NULL,
+ "mongo_sync_reconnect() fails with a NULL connection");
+ cmp_ok (errno, "==", ENOTCONN,
+ "errno is ENOTCONN");
+
+ conn = test_make_fake_sync_conn (-1, FALSE);
+ ok (mongo_sync_reconnect (conn, FALSE) == NULL,
+ "mongo_sync_reconnect() fails with a bogus FD");
+ cmp_ok (errno, "==", EHOSTUNREACH,
+ "errno is EHOSTUNREACH");
+
+ mongo_sync_disconnect (conn);
+
+ begin_network_tests (15);
+
+ /* Connect & reconnect to master */
+ o = conn = mongo_sync_connect (config.primary_host,
+ config.primary_port, TRUE);
+ ok ((conn = mongo_sync_reconnect (conn, TRUE)) != NULL,
+ "mongo_sync_reconnect() works when reconnecting to self");
+ ok (o == conn,
+ "Reconnect to an existing master results in the same object");
+ mongo_sync_disconnect (conn);
+
+ /* Connect to master, kill FD, reconnect */
+ conn = mongo_sync_connect (config.primary_host,
+ config.primary_port, TRUE);
+ mongo_sync_cmd_is_master (conn);
+
+ shutdown (conn->super.fd, SHUT_RDWR);
+ sleep (3);
+
+ ok ((conn = mongo_sync_reconnect (conn, TRUE)) != NULL,
+ "mongo_sync_reconnect() succeed when the connection drops");
+ mongo_sync_disconnect (conn);
+
+ /* Connect, kill, reconnect; w/o knowing other hosts */
+ o = conn = mongo_sync_connect (config.primary_host,
+ config.primary_port, TRUE);
+ shutdown (conn->super.fd, SHUT_RDWR);
+ sleep (3);
+ l = conn->rs.hosts;
+ while (l)
+ {
+ g_free (l->data);
+ l = g_list_delete_link (l, l);
+ }
+ conn->rs.hosts = NULL;
+
+ l = conn->rs.seeds;
+ while (l)
+ {
+ g_free (l->data);
+ l = g_list_delete_link (l, l);
+ }
+ conn->rs.seeds = NULL;
+
+ conn = mongo_sync_reconnect (conn, FALSE);
+
+ ok (conn != o && conn == NULL,
+ "mongo_sync_reconnect() fails if it can't reconnect anywhere");
+ mongo_sync_disconnect (o);
+
+ /* Gracefully ignore unparsable hosts during reconnect */
+ o = conn = mongo_sync_connect (config.primary_host,
+ config.primary_port, TRUE);
+ mongo_sync_cmd_is_master (conn);
+ conn->rs.hosts = g_list_prepend (conn->rs.hosts,
+ g_strdup ("invalid:-42"));
+ shutdown (conn->super.fd, SHUT_RDWR);
+ sleep (3);
+ conn = mongo_sync_reconnect (conn, TRUE);
+
+ ok (conn == o,
+ "mongo_sync_reconnect() gracefully ignores unparsable hosts "
+ "during reconnect");
+ mongo_sync_disconnect (conn);
+
+ /* Ignore unreachable hosts during reconnect */
+ o = conn = mongo_sync_connect (config.primary_host,
+ config.primary_port, TRUE);
+ mongo_sync_cmd_is_master (conn);
+ conn->rs.hosts = g_list_prepend (conn->rs.hosts,
+ g_strdup ("example.com:27017"));
+ shutdown (conn->super.fd, SHUT_RDWR);
+ sleep (3);
+ conn = mongo_sync_reconnect (conn, TRUE);
+
+ ok (conn == o,
+ "mongo_sync_reconnect() gracefully ignores unparsable hosts "
+ "during reconnect");
+ mongo_sync_disconnect (conn);
+
+ /*
+ * Tests involving a secondary
+ */
+
+ skip (!config.secondary_host, 9,
+ "Secondary host not set up");
+
+ /* Connect to secondary & reconnect to master */
+ o = conn = mongo_sync_connect (config.secondary_host,
+ config.secondary_port, TRUE);
+ ok (conn != NULL, "Connecting to secondary");
+ ok (mongo_sync_cmd_is_master (conn) == FALSE,
+ "Connected to a secondary");
+ ok ((conn = mongo_sync_reconnect (conn, TRUE)) != NULL,
+ "Reconnecting from slave to master succeeds");
+ ok (conn == o, "Connection object updated in-place");
+ ok (mongo_sync_cmd_is_master (conn),
+ "Correctly reconnected to master");
+ mongo_sync_disconnect (conn);
+
+ /* Connect to secondary & reconnect to self */
+ o = conn = mongo_sync_connect (config.secondary_host,
+ config.secondary_port, TRUE);
+ ok (conn != NULL, "Connecting to secondary");
+ ok ((conn = mongo_sync_reconnect (conn, FALSE)) != NULL,
+ "Reconnecting from slave to self succeeds");
+ ok (conn == o, "Connection object updated in-place");
+ ok (mongo_sync_cmd_is_master (conn) == FALSE,
+ "Correctly reconnected to self");
+ mongo_sync_disconnect (conn);
+
+ endskip;
+
+ end_network_tests ();
+}
+
+RUN_TEST (19, mongo_sync_reconnect);