summaryrefslogtreecommitdiff
path: root/tests/unit/mongo
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit/mongo')
-rw-r--r--tests/unit/mongo/client/connect.c34
-rw-r--r--tests/unit/mongo/client/connection_get_requestid.c44
-rw-r--r--tests/unit/mongo/client/connection_set_timeout.c33
-rw-r--r--tests/unit/mongo/client/disconnect.c32
-rw-r--r--tests/unit/mongo/client/packet_recv.c56
-rw-r--r--tests/unit/mongo/client/packet_send.c75
-rw-r--r--tests/unit/mongo/sync-cursor/sync_cursor_free.c34
-rw-r--r--tests/unit/mongo/sync-cursor/sync_cursor_get_data.c51
-rw-r--r--tests/unit/mongo/sync-cursor/sync_cursor_new.c40
-rw-r--r--tests/unit/mongo/sync-cursor/sync_cursor_next.c40
-rw-r--r--tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_cursor_get_chunk.c15
-rw-r--r--tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_cursor_new.c19
-rw-r--r--tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_free.c16
-rw-r--r--tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_new_from_buffer.c71
-rw-r--r--tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_find.c38
-rw-r--r--tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_close.c41
-rw-r--r--tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_find.c36
-rw-r--r--tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_new.c43
-rw-r--r--tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_read.c44
-rw-r--r--tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_seek.c65
-rw-r--r--tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_write.c50
-rw-r--r--tests/unit/mongo/sync-gridfs/sync_gridfs_file_get_metadata.c23
-rw-r--r--tests/unit/mongo/sync-gridfs/sync_gridfs_free.c35
-rw-r--r--tests/unit/mongo/sync-gridfs/sync_gridfs_get_set_chunk_size.c33
-rw-r--r--tests/unit/mongo/sync-gridfs/sync_gridfs_list.c34
-rw-r--r--tests/unit/mongo/sync-gridfs/sync_gridfs_new.c54
-rw-r--r--tests/unit/mongo/sync-gridfs/sync_gridfs_remove.c34
-rw-r--r--tests/unit/mongo/sync-pool/sync_pool_free.c11
-rw-r--r--tests/unit/mongo/sync-pool/sync_pool_new.c19
-rw-r--r--tests/unit/mongo/sync-pool/sync_pool_pick.c11
-rw-r--r--tests/unit/mongo/sync-pool/sync_pool_return.c22
-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
-rw-r--r--tests/unit/mongo/utils/oid_as_string.c26
-rw-r--r--tests/unit/mongo/utils/oid_init.c19
-rw-r--r--tests/unit/mongo/utils/oid_new.c49
-rw-r--r--tests/unit/mongo/utils/oid_new_with_time.c46
-rw-r--r--tests/unit/mongo/utils/parse_addr.c244
-rw-r--r--tests/unit/mongo/wire/cmd_custom.c67
-rw-r--r--tests/unit/mongo/wire/cmd_delete.c73
-rw-r--r--tests/unit/mongo/wire/cmd_get_more.c50
-rw-r--r--tests/unit/mongo/wire/cmd_insert.c83
-rw-r--r--tests/unit/mongo/wire/cmd_insert_n.c95
-rw-r--r--tests/unit/mongo/wire/cmd_kill_cursors.c58
-rw-r--r--tests/unit/mongo/wire/cmd_query.c117
-rw-r--r--tests/unit/mongo/wire/cmd_update.c97
-rw-r--r--tests/unit/mongo/wire/packet_get_set_data.c65
-rw-r--r--tests/unit/mongo/wire/packet_get_set_header.c58
-rw-r--r--tests/unit/mongo/wire/packet_get_set_header_raw.c56
-rw-r--r--tests/unit/mongo/wire/packet_new.c20
-rw-r--r--tests/unit/mongo/wire/reply_packet_get_data.c52
-rw-r--r--tests/unit/mongo/wire/reply_packet_get_header.c54
-rw-r--r--tests/unit/mongo/wire/reply_packet_get_nth_document.c68
87 files changed, 5165 insertions, 0 deletions
diff --git a/tests/unit/mongo/client/connect.c b/tests/unit/mongo/client/connect.c
new file mode 100644
index 0000000..fc390ea
--- /dev/null
+++ b/tests/unit/mongo/client/connect.c
@@ -0,0 +1,34 @@
+#include "test.h"
+#include "tap.h"
+#include "mongo-client.h"
+
+#include <errno.h>
+
+void
+test_mongo_connect (void)
+{
+ mongo_connection *c;
+
+ ok (mongo_connect (NULL, 27010) == NULL,
+ "mongo_connect() fails with a NULL host");
+ ok (errno == EINVAL,
+ "mongo_connect() should fail with EINVAL if host is NULL");
+
+ begin_network_tests (4);
+
+ ok (mongo_connect ("invalid.example.com", 27017) == NULL,
+ "Connecting to an invalid host fails");
+ ok (mongo_connect ("example.com", 27017) == NULL,
+ "Connecting to an unavailable host/port fails");
+ ok (mongo_connect ("/does/not/exist.sock", MONGO_CONN_LOCAL) == NULL,
+ "Connecting to an unavailable unix socket fails");
+
+ ok ((c = mongo_connect (config.primary_host,
+ config.primary_port)) != NULL,
+ "Connecting to the primary server works");
+ mongo_disconnect (c);
+
+ end_network_tests ();
+}
+
+RUN_TEST (6, mongo_connect);
diff --git a/tests/unit/mongo/client/connection_get_requestid.c b/tests/unit/mongo/client/connection_get_requestid.c
new file mode 100644
index 0000000..9232689
--- /dev/null
+++ b/tests/unit/mongo/client/connection_get_requestid.c
@@ -0,0 +1,44 @@
+#include "test.h"
+#include "mongo.h"
+
+#include "libmongo-private.h"
+
+void
+test_mongo_connection_get_requestid (void)
+{
+ mongo_connection c, *conn;
+ mongo_packet *p;
+ bson *b;
+ gint reqid;
+
+ c.request_id = 42;
+
+ ok (mongo_connection_get_requestid (NULL) == -1,
+ "mongo_connection_get_requestid() fails with a NULL connection");
+ ok (mongo_connection_get_requestid (&c) == 42,
+ "mongo_connection_get_requestid() works");
+
+ begin_network_tests (2);
+
+ b = bson_new ();
+ bson_append_int32 (b, "getnonce", 1);
+ bson_finish (b);
+
+ p = mongo_wire_cmd_custom (42, config.db, 0, b);
+ bson_free (b);
+
+ conn = mongo_connect (config.primary_host, config.primary_port);
+ cmp_ok ((reqid = mongo_connection_get_requestid (conn)), "==", 0,
+ "Initial request id is 0");
+ mongo_packet_send (conn, p);
+ mongo_wire_packet_free (p);
+
+ cmp_ok (reqid, "<", mongo_connection_get_requestid (conn),
+ "Old request ID is smaller than the new one");
+
+ mongo_disconnect (conn);
+
+ end_network_tests ();
+}
+
+RUN_TEST (4, mongo_connection_get_requestid);
diff --git a/tests/unit/mongo/client/connection_set_timeout.c b/tests/unit/mongo/client/connection_set_timeout.c
new file mode 100644
index 0000000..02468bf
--- /dev/null
+++ b/tests/unit/mongo/client/connection_set_timeout.c
@@ -0,0 +1,33 @@
+#include "test.h"
+#include "mongo.h"
+
+#include "libmongo-private.h"
+
+void
+test_mongo_connection_set_timeout (void)
+{
+ mongo_connection c, *conn;
+
+ c.fd = -1;
+
+ ok (mongo_connection_set_timeout (NULL, 100) == FALSE,
+ "mongo_connection_set_timeout() should fail with a NULL connection");
+ ok (mongo_connection_set_timeout (&c, -1) == FALSE,
+ "mongo_connection_set_timeout() should fail with a negative timeout");
+ ok (mongo_connection_set_timeout (&c, 100) == FALSE,
+ "mongo_connection_set_timeout() should fail with an invalid FD");
+
+ begin_network_tests (0);
+
+ conn = mongo_connect (config.primary_host, config.primary_port);
+
+ /* No verification here, as some systems may or may not support
+ this, thus, failing in a test is not fatal. */
+ mongo_connection_set_timeout (conn, 100);
+
+ mongo_disconnect (conn);
+
+ end_network_tests ();
+}
+
+RUN_TEST (3, mongo_connection_set_timeout);
diff --git a/tests/unit/mongo/client/disconnect.c b/tests/unit/mongo/client/disconnect.c
new file mode 100644
index 0000000..1b0be93
--- /dev/null
+++ b/tests/unit/mongo/client/disconnect.c
@@ -0,0 +1,32 @@
+#include "test.h"
+#include "tap.h"
+#include "mongo-client.h"
+
+#include "libmongo-private.h"
+#include <errno.h>
+
+void
+test_mongo_disconnect (void)
+{
+ mongo_connection *conn;
+
+ conn = g_new0 (mongo_connection, 1);
+ conn->fd = -1;
+
+ errno = 0;
+ mongo_disconnect (NULL);
+ ok (errno == ENOTCONN,
+ "mongo_disconnect() fails with ENOTCONN when passed a NULL connection");
+
+ mongo_disconnect (conn);
+ ok (errno == 0,
+ "mongo_disconnect() works");
+
+ conn = g_new0 (mongo_connection, 1);
+ conn->fd = 100;
+ mongo_disconnect (conn);
+ ok (errno == 0,
+ "mongo_disconnect() works, even with a bogus FD");
+}
+
+RUN_TEST (3, mongo_disconnect);
diff --git a/tests/unit/mongo/client/packet_recv.c b/tests/unit/mongo/client/packet_recv.c
new file mode 100644
index 0000000..51ccb3d
--- /dev/null
+++ b/tests/unit/mongo/client/packet_recv.c
@@ -0,0 +1,56 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <errno.h>
+#include <sys/socket.h>
+
+#include "libmongo-private.h"
+
+void
+test_mongo_packet_recv (void)
+{
+ mongo_connection c, *conn;
+ mongo_packet *p;
+ bson *b;
+
+ c.fd = -1;
+
+ ok (mongo_packet_recv (NULL) == NULL,
+ "mongo_packet_recv() fails with a NULL connection");
+ ok (errno == ENOTCONN,
+ "mongo_packet_recv() sets errno to ENOTCONN if connection is NULL");
+
+ ok (mongo_packet_recv (&c) == NULL,
+ "mongo_packet_recv() fails if the FD is less than zero");
+ ok (errno == EBADF,
+ "mongo_packet_recv() sets errno to EBADF is the FD is bad");
+
+ begin_network_tests (2);
+
+ b = bson_new ();
+ bson_append_int32 (b, "getnonce", 1);
+ bson_finish (b);
+
+ p = mongo_wire_cmd_custom (42, config.db, 0, b);
+ bson_free (b);
+
+ conn = mongo_connect (config.primary_host, config.primary_port);
+ mongo_packet_send (conn, p);
+ mongo_wire_packet_free (p);
+
+ ok ((p = mongo_packet_recv (conn)) != NULL,
+ "mongo_packet_recv() works");
+ mongo_wire_packet_free (p);
+
+ close (conn->fd);
+ sleep (3);
+
+ ok (mongo_packet_recv (conn) == NULL,
+ "mongo_packet_recv() fails on a closed socket");
+
+ mongo_disconnect (conn);
+
+ end_network_tests ();
+}
+
+RUN_TEST (6, mongo_packet_recv);
diff --git a/tests/unit/mongo/client/packet_send.c b/tests/unit/mongo/client/packet_send.c
new file mode 100644
index 0000000..e501a3c
--- /dev/null
+++ b/tests/unit/mongo/client/packet_send.c
@@ -0,0 +1,75 @@
+#include "test.h"
+#include "tap.h"
+#include "mongo-wire.h"
+#include "mongo-client.h"
+
+#include <errno.h>
+#include <sys/socket.h>
+
+#include "libmongo-private.h"
+
+void
+test_mongo_packet_send (void)
+{
+ mongo_packet *p;
+ mongo_connection c, *conn;
+ mongo_packet_header h;
+ bson *b;
+
+ p = mongo_wire_cmd_kill_cursors (1, 2, (gint64)3, (gint64)4);
+ c.fd = -1;
+
+ ok (mongo_packet_send (NULL, p) == FALSE,
+ "mongo_packet_send() fails with a NULL connection");
+ ok (errno == ENOTCONN,
+ "mongo_packet_send() with a NULL connection sets errno to ENOTCONN");
+ ok (mongo_packet_send (&c, NULL) == FALSE,
+ "mongo_packet_send() fails with a NULL packet");
+ ok (errno == EINVAL,
+ "mongo_packet_send() with a NULL packet sets errno to EINVAL");
+ ok (mongo_packet_send (&c, p) == FALSE,
+ "mongo_packet_send() fails if the FD is less than zero");
+ ok (errno == EBADF,
+ "mongo_packet_send() sets errno to EBADF is the FD is bad");
+ mongo_wire_packet_free (p);
+
+ p = mongo_wire_packet_new ();
+
+ h.id = 42;
+ h.resp_to = 0;
+ h.opcode = 1;
+ h.length = sizeof (mongo_packet_header);
+ mongo_wire_packet_set_header (p, &h);
+
+ c.fd = 1;
+ ok (mongo_packet_send (&c, p) == FALSE,
+ "mongo_packet_send() fails with an unfinished packet");
+
+ mongo_wire_packet_free (p);
+
+ begin_network_tests (2);
+
+ b = bson_new ();
+ bson_append_int32 (b, "getnonce", 1);
+ bson_finish (b);
+
+ p = mongo_wire_cmd_custom (42, config.db, 0, b);
+ bson_free (b);
+
+ conn = mongo_connect (config.primary_host, config.primary_port);
+ ok (mongo_packet_send (conn, p),
+ "mongo_packet_send() works");
+
+ close (conn->fd);
+ sleep (3);
+
+ ok (mongo_packet_send (conn, p) == FALSE,
+ "mongo_packet_send() fails on a closed socket");
+ mongo_wire_packet_free (p);
+
+ mongo_disconnect (conn);
+
+ end_network_tests ();
+}
+
+RUN_TEST (9, mongo_packet_send);
diff --git a/tests/unit/mongo/sync-cursor/sync_cursor_free.c b/tests/unit/mongo/sync-cursor/sync_cursor_free.c
new file mode 100644
index 0000000..bd01cb5
--- /dev/null
+++ b/tests/unit/mongo/sync-cursor/sync_cursor_free.c
@@ -0,0 +1,34 @@
+#include "test.h"
+#include "mongo.h"
+#include "config.h"
+
+#include "libmongo-private.h"
+
+#include <errno.h>
+
+void
+test_mongo_sync_cursor_free (void)
+{
+ mongo_sync_connection *conn;
+ mongo_packet *p;
+ mongo_sync_cursor *c;
+
+ test_env_setup ();
+
+ p = mongo_wire_packet_new ();
+ conn = test_make_fake_sync_conn (-1, FALSE);
+
+ c = mongo_sync_cursor_new (conn, config.ns, p);
+
+ errno = 0;
+ mongo_sync_cursor_free (NULL);
+ ok (errno == ENOTCONN,
+ "mongo_sync_cursor_free(NULL) sets errno to ENOTCONN");
+ mongo_sync_cursor_free (c);
+ pass ("mongo_sync_cursor_free() works");
+
+ mongo_sync_disconnect (conn);
+ test_env_free ();
+}
+
+RUN_TEST (2, mongo_sync_cursor_free);
diff --git a/tests/unit/mongo/sync-cursor/sync_cursor_get_data.c b/tests/unit/mongo/sync-cursor/sync_cursor_get_data.c
new file mode 100644
index 0000000..0dd391c
--- /dev/null
+++ b/tests/unit/mongo/sync-cursor/sync_cursor_get_data.c
@@ -0,0 +1,51 @@
+#include "test.h"
+#include "mongo.h"
+#include "config.h"
+
+#include "libmongo-private.h"
+
+#include <errno.h>
+
+void
+test_mongo_sync_cursor_get_data (void)
+{
+ mongo_sync_connection *conn;
+ mongo_packet *p;
+ bson *b;
+ mongo_sync_cursor *c;
+
+ test_env_setup ();
+
+ p = test_mongo_wire_generate_reply (TRUE, 4, TRUE);
+ conn = test_make_fake_sync_conn (-1, FALSE);
+
+ c = mongo_sync_cursor_new (conn, config.ns, p);
+
+ errno = 0;
+ b = mongo_sync_cursor_get_data (NULL);
+ ok (b == NULL && errno == EINVAL,
+ "mongo_sync_cursor_get_data(NULL) should fail");
+
+ b = mongo_sync_cursor_get_data (c);
+ ok (b == NULL,
+ "mongo_sync_cursor_get_data() should fail without _cursor_next()");
+
+ mongo_sync_cursor_next (c);
+ b = mongo_sync_cursor_get_data (c);
+ ok (b != NULL,
+ "mongo_sync_cursor_get_data() works");
+
+ c->offset = 5;
+
+ errno = 0;
+ b = mongo_sync_cursor_get_data (c);
+ ok (b == NULL && errno == ERANGE,
+ "mongo_sync_cursor_get_data() should fail if the cursor is "
+ "out of range");
+
+ mongo_sync_cursor_free (c);
+ mongo_sync_disconnect (conn);
+ test_env_free ();
+}
+
+RUN_TEST (4, mongo_sync_cursor_get_data);
diff --git a/tests/unit/mongo/sync-cursor/sync_cursor_new.c b/tests/unit/mongo/sync-cursor/sync_cursor_new.c
new file mode 100644
index 0000000..642d826
--- /dev/null
+++ b/tests/unit/mongo/sync-cursor/sync_cursor_new.c
@@ -0,0 +1,40 @@
+#include "test.h"
+#include "mongo.h"
+#include "config.h"
+
+#include "libmongo-private.h"
+
+#include <errno.h>
+
+void
+test_mongo_sync_cursor_new (void)
+{
+ mongo_sync_connection *conn;
+ mongo_packet *p;
+ mongo_sync_cursor *c;
+
+ test_env_setup ();
+
+ p = mongo_wire_packet_new ();
+ conn = test_make_fake_sync_conn (-1, FALSE);
+
+ c = mongo_sync_cursor_new (conn, config.ns, NULL);
+ ok (c == NULL,
+ "mongo_sync_cursor_new() fails with a NULL packet");
+ c = mongo_sync_cursor_new (conn, NULL, p);
+ ok (c == NULL,
+ "mongo_sync_cursor_new() fails with a NULL namespace");
+ c = mongo_sync_cursor_new (NULL, config.ns, p);
+ ok (c == NULL,
+ "mongo_sync_cursor_new() fails with a NULL connection");
+
+ c = mongo_sync_cursor_new (conn, config.ns, p);
+ ok (c != NULL,
+ "mongo_sync_cursor_new() works");
+
+ mongo_sync_cursor_free (c);
+ mongo_sync_disconnect (conn);
+ test_env_free ();
+}
+
+RUN_TEST (4, mongo_sync_cursor_new);
diff --git a/tests/unit/mongo/sync-cursor/sync_cursor_next.c b/tests/unit/mongo/sync-cursor/sync_cursor_next.c
new file mode 100644
index 0000000..442df96
--- /dev/null
+++ b/tests/unit/mongo/sync-cursor/sync_cursor_next.c
@@ -0,0 +1,40 @@
+#include "test.h"
+#include "mongo.h"
+#include "config.h"
+
+#include "libmongo-private.h"
+
+#include <errno.h>
+
+void
+test_mongo_sync_cursor_next (void)
+{
+ mongo_sync_connection *conn;
+ mongo_packet *p;
+ mongo_sync_cursor *c;
+ gboolean r = TRUE;
+ gint i;
+
+ test_env_setup ();
+
+ p = test_mongo_wire_generate_reply (TRUE, 2, TRUE);
+ conn = test_make_fake_sync_conn (-1, FALSE);
+
+ c = mongo_sync_cursor_new (conn, config.ns, p);
+
+ ok (mongo_sync_cursor_next (NULL) == FALSE,
+ "mongo_sync_cursor_next() should fail with a NULL cursor");
+ for (i = 0; i < 2; i++)
+ r &= mongo_sync_cursor_next (c);
+
+ ok (r == TRUE,
+ "mongo_sync_cursor_next() works");
+ ok (mongo_sync_cursor_next (c) == FALSE,
+ "mongo_sync_cursor_next() should fail past the end of the resultset");
+
+ mongo_sync_cursor_free (c);
+ mongo_sync_disconnect (conn);
+ test_env_free ();
+}
+
+RUN_TEST (3, mongo_sync_cursor_next);
diff --git a/tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_cursor_get_chunk.c b/tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_cursor_get_chunk.c
new file mode 100644
index 0000000..f16378a
--- /dev/null
+++ b/tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_cursor_get_chunk.c
@@ -0,0 +1,15 @@
+#include "test.h"
+#include "mongo.h"
+
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_gridfs_chunked_file_cursor_get_chunk (void)
+{
+ gint32 size;
+
+ ok (mongo_sync_gridfs_chunked_file_cursor_get_chunk (NULL, &size) == NULL,
+ "mongo_sync_gridfs_file_cursor_get_chunk() fails with a NULL cursor");
+}
+
+RUN_TEST (1, mongo_sync_gridfs_chunked_file_cursor_get_chunk);
diff --git a/tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_cursor_new.c b/tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_cursor_new.c
new file mode 100644
index 0000000..22210f8
--- /dev/null
+++ b/tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_cursor_new.c
@@ -0,0 +1,19 @@
+#include "test.h"
+#include "mongo.h"
+
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_gridfs_chunked_file_cursor_new (void)
+{
+ mongo_sync_gridfs_chunked_file f;
+
+ ok (mongo_sync_gridfs_chunked_file_cursor_new (NULL, 0, 0) == NULL,
+ "mongo_sync_gridfs_file_cursor_new() fails with a NULL file");
+ ok (mongo_sync_gridfs_chunked_file_cursor_new (&f, -1, 0) == NULL,
+ "mongo_sync_gridfs_file_cursor_new() fails with an invalid start position");
+ ok (mongo_sync_gridfs_chunked_file_cursor_new (&f, 0, -1) == NULL,
+ "mongo_sync_gridfs_file_cursor_new() fails with an invalid max number");
+}
+
+RUN_TEST (3, mongo_sync_gridfs_chunked_file_cursor_new);
diff --git a/tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_free.c b/tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_free.c
new file mode 100644
index 0000000..c9fddfa
--- /dev/null
+++ b/tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_free.c
@@ -0,0 +1,16 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <errno.h>
+
+void
+test_mongo_sync_gridfs_chunked_file_free (void)
+{
+ errno = 0;
+ mongo_sync_gridfs_chunked_file_free (NULL);
+
+ cmp_ok (errno, "==", ENOTCONN,
+ "mongo_sync_gridfs_chunked_file_free() fails with a NULL file");
+}
+
+RUN_TEST (1, mongo_sync_gridfs_chunked_file_free);
diff --git a/tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_new_from_buffer.c b/tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_new_from_buffer.c
new file mode 100644
index 0000000..ba3fa2e
--- /dev/null
+++ b/tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_new_from_buffer.c
@@ -0,0 +1,71 @@
+#include "test.h"
+#include "mongo.h"
+
+#define BUFFER_SIZE 256 * 1024 + 42
+
+void
+test_mongo_sync_gridfs_chunked_file_new_from_buffer (void)
+{
+ mongo_sync_connection *conn;
+ mongo_sync_gridfs *gfs;
+ bson *metadata;
+ guint8 *buffer;
+ mongo_sync_gridfs_chunked_file *gfile;
+
+ buffer = g_malloc (BUFFER_SIZE);
+ memset (buffer, 'a', BUFFER_SIZE);
+
+ conn = test_make_fake_sync_conn (4, TRUE);
+ gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix);
+
+ metadata = bson_build (BSON_TYPE_STRING, "filename",
+ "gridfs_file_new_from_buffer", -1,
+ BSON_TYPE_NONE);
+ bson_finish (metadata);
+
+ ok (mongo_sync_gridfs_chunked_file_new_from_buffer (NULL, metadata,
+ buffer, BUFFER_SIZE) == FALSE,
+ "mongo_sync_gridfs_chunked_file_new_from_buffer() fails with a NULL GridFS");
+
+ mongo_sync_gridfs_free (gfs, TRUE);
+
+ begin_network_tests (5);
+
+ conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE);
+ gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix);
+
+ ok (mongo_sync_gridfs_chunked_file_new_from_buffer (gfs, metadata,
+ NULL, BUFFER_SIZE) == FALSE,
+ "mongo_sync_gridfs_chunked_file_new_from_buffer() fails with NULL data");
+
+ ok (mongo_sync_gridfs_chunked_file_new_from_buffer (gfs, metadata,
+ buffer, 0) == FALSE,
+ "mongo_sync_gridfs_chunked_file_new_from_buffer() fails with an invalid data size");
+
+ ok (mongo_sync_gridfs_chunked_file_new_from_buffer (gfs, metadata, buffer,
+ BUFFER_SIZE) == FALSE,
+ "mongo_sync_gridfs_chunked_file_new_from_buffer() fails with uninitialized OID");
+
+ mongo_util_oid_init (0);
+
+ gfile = mongo_sync_gridfs_chunked_file_new_from_buffer (gfs, metadata,
+ buffer, BUFFER_SIZE);
+ ok (gfile != NULL,
+ "mongo_sync_gridfs_chunked_file_new_from_buffer() works with metadata");
+ mongo_sync_gridfs_chunked_file_free (gfile);
+
+ gfile = mongo_sync_gridfs_chunked_file_new_from_buffer (gfs, NULL,
+ buffer, BUFFER_SIZE);
+ ok (gfile != NULL,
+ "mongo_sync_gridfs_chunked_file_new_from_buffer() works without metadata");
+ mongo_sync_gridfs_chunked_file_free (gfile);
+
+ mongo_sync_gridfs_free (gfs, TRUE);
+
+ end_network_tests ();
+
+ bson_free (metadata);
+ g_free (buffer);
+}
+
+RUN_TEST (6, mongo_sync_gridfs_chunked_file_new_from_buffer);
diff --git a/tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_find.c b/tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_find.c
new file mode 100644
index 0000000..91514f9
--- /dev/null
+++ b/tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_find.c
@@ -0,0 +1,38 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <errno.h>
+
+void
+test_mongo_sync_gridfs_chunked_find (void)
+{
+ mongo_sync_connection *conn;
+ mongo_sync_gridfs *gfs;
+ bson *query;
+
+ query = bson_build (BSON_TYPE_STRING, "filename", "bogus-fn", -1,
+ BSON_TYPE_NONE);
+ bson_finish (query);
+
+ ok (mongo_sync_gridfs_chunked_find (NULL, query) == NULL,
+ "mongo_sync_gridfs_chunked_find() fails with a NULL GridFS");
+
+ begin_network_tests (2);
+
+ conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE);
+ gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix);
+
+ ok (mongo_sync_gridfs_chunked_find (gfs, NULL) == NULL,
+ "mongo_sync_gridfs_chunked_find() fails with a NULL query");
+
+ ok (mongo_sync_gridfs_chunked_find (gfs, query) == NULL,
+ "mongo_sync_gridfs_chunked_find() fails when the file is not found");
+
+ mongo_sync_gridfs_free (gfs, TRUE);
+
+ end_network_tests ();
+
+ bson_free (query);
+}
+
+RUN_TEST (3, mongo_sync_gridfs_chunked_find);
diff --git a/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_close.c b/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_close.c
new file mode 100644
index 0000000..3c8a7b3
--- /dev/null
+++ b/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_close.c
@@ -0,0 +1,41 @@
+#include "test.h"
+#include "mongo.h"
+
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_gridfs_stream_close (void)
+{
+ mongo_sync_connection *conn;
+ mongo_sync_gridfs *gfs;
+ mongo_sync_gridfs_stream *stream;
+
+ mongo_util_oid_init (0);
+
+ ok (mongo_sync_gridfs_stream_close (NULL) == FALSE,
+ "mongo_sync_gridfs_stream_close() fails with a NULL stream");
+
+ begin_network_tests (3);
+
+ conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE);
+ gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix);
+
+ stream = mongo_sync_gridfs_stream_new (gfs, NULL);
+ ok (mongo_sync_gridfs_stream_close (stream) == TRUE,
+ "mongo_sync_gridfs_stream_close() works with a write stream");
+
+ stream = mongo_sync_gridfs_stream_new (gfs, NULL);
+ stream->file.type = LMC_GRIDFS_FILE_CHUNKED;
+ ok (mongo_sync_gridfs_stream_close (stream) == FALSE,
+ "mongo_sync_gridfs_stream_close() should fail with a chunked file");
+
+ stream->file.type = LMC_GRIDFS_FILE_STREAM_READER;
+ ok (mongo_sync_gridfs_stream_close (stream) == TRUE,
+ "mongo_sync_gridfs_stream_close() works with a read stream");
+
+ mongo_sync_gridfs_free (gfs, TRUE);
+
+ end_network_tests ();
+}
+
+RUN_TEST (4, mongo_sync_gridfs_stream_close);
diff --git a/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_find.c b/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_find.c
new file mode 100644
index 0000000..643a8b2
--- /dev/null
+++ b/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_find.c
@@ -0,0 +1,36 @@
+#include "test.h"
+#include "mongo.h"
+
+void
+test_mongo_sync_gridfs_stream_find (void)
+{
+ mongo_sync_connection *conn;
+ mongo_sync_gridfs *gfs;
+ bson *query;
+
+ query = bson_build (BSON_TYPE_STRING, "filename", "bogus-fn", -1,
+ BSON_TYPE_NONE);
+ bson_finish (query);
+
+ ok (mongo_sync_gridfs_stream_find (NULL, query) == NULL,
+ "mongo_sync_gridfs_stream_find() should fail with a NULL connection");
+
+ begin_network_tests (2);
+
+ conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE);
+ gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix);
+
+ ok (mongo_sync_gridfs_stream_find (gfs, NULL) == NULL,
+ "mongo_sync_gridfs_stream_find() fails with a NULL query");
+
+ ok (mongo_sync_gridfs_stream_find (gfs, query) == NULL,
+ "mongo_sync_gridfs_stream_find() fails if the file is not found");
+
+ mongo_sync_gridfs_free (gfs, TRUE);
+
+ end_network_tests ();
+
+ bson_free (query);
+}
+
+RUN_TEST (3, mongo_sync_gridfs_stream_find);
diff --git a/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_new.c b/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_new.c
new file mode 100644
index 0000000..75e4419
--- /dev/null
+++ b/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_new.c
@@ -0,0 +1,43 @@
+#include "test.h"
+#include "mongo.h"
+
+void
+test_mongo_sync_gridfs_stream_new (void)
+{
+ mongo_sync_connection *conn;
+ mongo_sync_gridfs *gfs;
+ mongo_sync_gridfs_stream *stream;
+ bson *meta;
+
+ mongo_util_oid_init (0);
+
+ meta = bson_build (BSON_TYPE_STRING, "my-id", "sync_gridfs_stream_new", -1,
+ BSON_TYPE_NONE);
+ bson_finish (meta);
+
+ ok (mongo_sync_gridfs_stream_new (NULL, meta) == FALSE,
+ "mongo_sync_gridfs_stream_new() should fail with a NULL connection");
+
+ begin_network_tests (2);
+
+ conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE);
+ gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix);
+
+ stream = mongo_sync_gridfs_stream_new (gfs, NULL);
+ ok (stream != NULL,
+ "mongo_sync_gridfs_stream_new() works with NULL metadata");
+ mongo_sync_gridfs_stream_close (stream);
+
+ stream = mongo_sync_gridfs_stream_new (gfs, meta);
+ ok (stream != NULL,
+ "mongo_sync_gridfs_stream_new() works with metadata");
+ mongo_sync_gridfs_stream_close (stream);
+
+ mongo_sync_gridfs_free (gfs, TRUE);
+
+ end_network_tests ();
+
+ bson_free (meta);
+}
+
+RUN_TEST (3, mongo_sync_gridfs_stream_new);
diff --git a/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_read.c b/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_read.c
new file mode 100644
index 0000000..a53aa88
--- /dev/null
+++ b/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_read.c
@@ -0,0 +1,44 @@
+#include "test.h"
+#include "mongo.h"
+
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_gridfs_stream_read (void)
+{
+ mongo_sync_connection *conn;
+ mongo_sync_gridfs *gfs;
+ mongo_sync_gridfs_stream *stream;
+ guint8 buffer[4096];
+
+ mongo_util_oid_init (0);
+
+ ok (mongo_sync_gridfs_stream_read (NULL, buffer, sizeof (buffer)) == -1,
+ "mongo_sync_gridfs_stream_read() should fail with a NULL connection");
+
+ begin_network_tests (3);
+
+ conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE);
+ gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix);
+
+ stream = mongo_sync_gridfs_stream_new (gfs, NULL);
+
+ ok (mongo_sync_gridfs_stream_read (stream, buffer, sizeof (buffer)) == -1,
+ "mongo-sync_gridfs_stream_read() should fail when the stream is "
+ "write-only");
+
+ stream->file.type = LMC_GRIDFS_FILE_STREAM_READER;
+
+ ok (mongo_sync_gridfs_stream_read (stream, NULL, sizeof (buffer)) == -1,
+ "mongo_sync_gridfs_stream_read() should fail with a NULL buffer");
+ ok (mongo_sync_gridfs_stream_read (stream, buffer, 0) == -1,
+ "mongo_sync_gridfs_stream_read() should fail with a 0 size");
+
+ mongo_sync_gridfs_stream_close (stream);
+
+ mongo_sync_gridfs_free (gfs, TRUE);
+
+ end_network_tests ();
+}
+
+RUN_TEST (4, mongo_sync_gridfs_stream_read);
diff --git a/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_seek.c b/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_seek.c
new file mode 100644
index 0000000..49547bc
--- /dev/null
+++ b/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_seek.c
@@ -0,0 +1,65 @@
+#include "test.h"
+#include "mongo.h"
+
+#include "libmongo-private.h"
+
+#include <unistd.h>
+
+void
+test_mongo_sync_gridfs_stream_seek (void)
+{
+ mongo_sync_connection *conn;
+ mongo_sync_gridfs *gfs;
+ mongo_sync_gridfs_stream *stream;
+
+ mongo_util_oid_init (0);
+
+ ok (mongo_sync_gridfs_stream_seek (NULL, 0, SEEK_SET) == FALSE,
+ "mongo_sync_gridfs_stream_seek() fails with a NULL stream");
+
+ begin_network_tests (8);
+
+ conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE);
+ gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix);
+
+ stream = mongo_sync_gridfs_stream_new (gfs, NULL);
+
+ ok (mongo_sync_gridfs_stream_seek (stream, 0, SEEK_SET) == FALSE,
+ "mongo_sync_gridfs_stream_seek() fails with a write stream");
+
+ stream->file.type = LMC_GRIDFS_FILE_STREAM_READER;
+
+ ok (mongo_sync_gridfs_stream_seek (stream, -1, SEEK_SET) == FALSE,
+ "mongo_sync_gridfs_stream_seek() fails with SEEK_SET and a negative "
+ "position");
+
+ ok (mongo_sync_gridfs_stream_seek (stream, 10, SEEK_SET) == FALSE,
+ "mongo_sync_gridfs_stream_seek() fails with SEEK_SET and a position "
+ "past EOF");
+
+ ok (mongo_sync_gridfs_stream_seek (stream, -1, SEEK_CUR) == FALSE,
+ "mongo_sync_gridfs_stream_seek() fails with SEEK_CUR and a position "
+ "before the start");
+
+ ok (mongo_sync_gridfs_stream_seek (stream, 10, SEEK_CUR) == FALSE,
+ "mongo_sync_gridfs_stream_seek() fails with SEEK_CUR and a position "
+ "past EOF");
+
+ ok (mongo_sync_gridfs_stream_seek (stream, 1, SEEK_END) == FALSE,
+ "mongo_sync_gridfs_stream_seek() fails with SEEK_END and a position "
+ "past EOF");
+
+ ok (mongo_sync_gridfs_stream_seek (stream, -1, SEEK_END) == FALSE,
+ "mongo_sync_gridfs_stream_seek() fails with SEEK_END and a position "
+ "before the start");
+
+ ok (mongo_sync_gridfs_stream_seek (stream, 0, 42) == FALSE,
+ "mongo_sync_gridfs_stream_seek() fails with an invalid whence");
+
+ mongo_sync_gridfs_stream_close (stream);
+ mongo_sync_gridfs_free (gfs, TRUE);
+
+ end_network_tests ();
+}
+
+RUN_TEST (9, mongo_sync_gridfs_stream_seek);
diff --git a/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_write.c b/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_write.c
new file mode 100644
index 0000000..562c7b4
--- /dev/null
+++ b/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_write.c
@@ -0,0 +1,50 @@
+#include "test.h"
+#include "mongo.h"
+
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_gridfs_stream_write (void)
+{
+ mongo_sync_connection *conn;
+ mongo_sync_gridfs *gfs;
+ mongo_sync_gridfs_stream *stream;
+ bson *meta;
+ guint8 buffer[4096];
+
+ mongo_util_oid_init (0);
+
+ meta = bson_build (BSON_TYPE_STRING, "my-id", "sync_gridfs_stream_write", -1,
+ BSON_TYPE_NONE);
+ bson_finish (meta);
+
+ ok (mongo_sync_gridfs_stream_write (NULL, buffer, sizeof (buffer)) == FALSE,
+ "mongo_sync_gridfs_stream_write() should fail with a NULL connection");
+
+ begin_network_tests (4);
+
+ conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE);
+ gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix);
+
+ stream = mongo_sync_gridfs_stream_new (gfs, meta);
+
+ ok (mongo_sync_gridfs_stream_write (stream, NULL, sizeof (buffer)) == FALSE,
+ "mongo_sync_gridfs_stream_write() should fail with a NULL buffer");
+ ok (mongo_sync_gridfs_stream_write (stream, buffer, 0) == FALSE,
+ "mongo_sync_gridfs_stream_write() should fail with 0 size");
+ ok (mongo_sync_gridfs_stream_write (stream, buffer, sizeof (buffer)) == TRUE,
+ "mongo_sync_gridfs_stream_write() works");
+
+ stream->file.type = LMC_GRIDFS_FILE_STREAM_READER;
+ ok (mongo_sync_gridfs_stream_write (stream, buffer, sizeof (buffer)) == FALSE,
+ "mongo_sync_gridfs_stream_write() should fail with a read stream");
+
+ mongo_sync_gridfs_stream_close (stream);
+ mongo_sync_gridfs_free (gfs, TRUE);
+
+ end_network_tests ();
+
+ bson_free (meta);
+}
+
+RUN_TEST (5, mongo_sync_gridfs_stream_write);
diff --git a/tests/unit/mongo/sync-gridfs/sync_gridfs_file_get_metadata.c b/tests/unit/mongo/sync-gridfs/sync_gridfs_file_get_metadata.c
new file mode 100644
index 0000000..2be34e5
--- /dev/null
+++ b/tests/unit/mongo/sync-gridfs/sync_gridfs_file_get_metadata.c
@@ -0,0 +1,23 @@
+#include "test.h"
+#include "mongo.h"
+
+void
+test_mongo_sync_gridfs_file_get_metadata (void)
+{
+ ok (mongo_sync_gridfs_file_get_id (NULL) == NULL,
+ "mongo_sync_gridfs_file_get_id() fails with a NULL file");
+ ok (mongo_sync_gridfs_file_get_length (NULL) == -1,
+ "mongo_sync_gridfs_file_get_length() fails with a NULL file");
+ ok (mongo_sync_gridfs_file_get_chunk_size (NULL) == -1,
+ "mongo_sync_gridfs_file_get_chunk_size() fails with a NULL file");
+ ok (mongo_sync_gridfs_file_get_md5 (NULL) == NULL,
+ "mongo_sync_gridfs_file_get_md5() fails with a NULL file");
+ ok (mongo_sync_gridfs_file_get_date (NULL) == -1,
+ "mongo_sync_gridfs_file_get_date() fails with a NULL file");
+ ok (mongo_sync_gridfs_file_get_metadata (NULL) == NULL,
+ "mongo_sync_gridfs_file_get_metadata() fails with a NULL file");
+ ok (mongo_sync_gridfs_file_get_chunks (NULL) == -1,
+ "mongo_sync_gridfs_file_get_chunks() fails with a NULL file");
+}
+
+RUN_TEST (7, mongo_sync_gridfs_file_get_metadata);
diff --git a/tests/unit/mongo/sync-gridfs/sync_gridfs_free.c b/tests/unit/mongo/sync-gridfs/sync_gridfs_free.c
new file mode 100644
index 0000000..1c8c2d6
--- /dev/null
+++ b/tests/unit/mongo/sync-gridfs/sync_gridfs_free.c
@@ -0,0 +1,35 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <errno.h>
+
+void
+test_mongo_sync_gridfs_free (void)
+{
+ mongo_sync_connection *conn;
+ mongo_sync_gridfs *gfs;
+
+ errno = 0;
+ mongo_sync_gridfs_free (NULL, FALSE);
+ cmp_ok (errno, "==", ENOTCONN,
+ "mongo_sync_gridfs_free() with a NULL connection shall set errno");
+
+ begin_network_tests (2);
+
+ conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE);
+ gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix);
+
+ mongo_sync_gridfs_free (gfs, FALSE);
+ cmp_ok (errno, "==", 0,
+ "mongo_sync_gridfs_free() should clear errno on success");
+
+ gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix);
+ mongo_sync_gridfs_free (gfs, TRUE);
+ cmp_ok (errno, "==", 0,
+ "mongo_sync_gridfs_free() works when asked to free the "
+ "connection too");
+
+ end_network_tests ();
+}
+
+RUN_TEST (3, mongo_sync_gridfs_free);
diff --git a/tests/unit/mongo/sync-gridfs/sync_gridfs_get_set_chunk_size.c b/tests/unit/mongo/sync-gridfs/sync_gridfs_get_set_chunk_size.c
new file mode 100644
index 0000000..5d17986
--- /dev/null
+++ b/tests/unit/mongo/sync-gridfs/sync_gridfs_get_set_chunk_size.c
@@ -0,0 +1,33 @@
+#include "test.h"
+#include "mongo.h"
+
+void
+test_mongo_sync_gridfs_get_set_chunk_size (void)
+{
+ mongo_sync_gridfs *gfs;
+
+ ok (mongo_sync_gridfs_get_chunk_size (NULL) == -1,
+ "mongo_sync_gridfs_get_chunk_size() fails with a NULL gfs");
+ ok (mongo_sync_gridfs_set_chunk_size (NULL, 16 * 1024) == FALSE,
+ "mongo_sync_gridfs_set_chunk_size() fails with a NULL gfs");
+
+ begin_network_tests (3);
+
+ gfs = mongo_sync_gridfs_new (mongo_sync_connect (config.primary_host,
+ config.primary_port,
+ FALSE),
+ config.gfs_prefix);
+
+ ok (mongo_sync_gridfs_set_chunk_size (gfs, -1) == FALSE,
+ "mongo_sync_gridfs_set_chunk_size() fails if the size is invalid");
+ ok (mongo_sync_gridfs_set_chunk_size (gfs, 12345),
+ "mongo_sync_gridfs_set_chunk_size() works");
+ cmp_ok (mongo_sync_gridfs_get_chunk_size (gfs), "==", 12345,
+ "mongo_sync_gridfs_get_chunk_size() works");
+
+ mongo_sync_gridfs_free (gfs, TRUE);
+
+ end_network_tests ();
+}
+
+RUN_TEST (5, mongo_sync_gridfs_get_set_chunk_size);
diff --git a/tests/unit/mongo/sync-gridfs/sync_gridfs_list.c b/tests/unit/mongo/sync-gridfs/sync_gridfs_list.c
new file mode 100644
index 0000000..e5857ea
--- /dev/null
+++ b/tests/unit/mongo/sync-gridfs/sync_gridfs_list.c
@@ -0,0 +1,34 @@
+#include "test.h"
+#include "mongo.h"
+
+void
+test_mongo_sync_gridfs_list (void)
+{
+ mongo_sync_gridfs *gfs;
+ bson *query;
+
+ query = bson_build (BSON_TYPE_STRING, "bogus-key", "bogus-value", -1,
+ BSON_TYPE_NONE);
+ bson_finish (query);
+
+ ok (mongo_sync_gridfs_list (NULL, NULL) == NULL,
+ "mongo_sync_gridfs_list() fails with a NULL GridFS");
+
+ begin_network_tests (1);
+
+ gfs = mongo_sync_gridfs_new
+ (mongo_sync_connect (config.primary_host, config.primary_port, FALSE),
+ config.gfs_prefix);
+
+ ok (mongo_sync_gridfs_list (gfs, query) == NULL,
+ "mongo_sync_gridfs_list() fails with a query that does not match "
+ "anything");
+
+ mongo_sync_gridfs_free (gfs, TRUE);
+
+ end_network_tests ();
+
+ bson_free (query);
+}
+
+RUN_TEST (2, mongo_sync_gridfs_list);
diff --git a/tests/unit/mongo/sync-gridfs/sync_gridfs_new.c b/tests/unit/mongo/sync-gridfs/sync_gridfs_new.c
new file mode 100644
index 0000000..20d6fea
--- /dev/null
+++ b/tests/unit/mongo/sync-gridfs/sync_gridfs_new.c
@@ -0,0 +1,54 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <errno.h>
+
+void
+test_mongo_sync_gridfs_new (void)
+{
+ mongo_sync_connection *conn;
+ mongo_sync_gridfs *gfs;
+ gchar *f, *c;
+
+ conn = test_make_fake_sync_conn (4, TRUE);
+
+ ok (mongo_sync_gridfs_new (NULL, "test.fs") == NULL,
+ "mongo_sync_gridfs_new() should fail with a NULL connection");
+
+ ok (mongo_sync_gridfs_new (conn, "test.fs") == NULL,
+ "mongo_sync_gridfs_new() should fail with a bogus connection");
+
+ ok (mongo_sync_gridfs_new (conn, NULL) == NULL,
+ "mongo_sync_gridfs_new() should fail with a NULL ns prefix");
+
+ ok (mongo_sync_gridfs_new (conn, "bogus") == NULL,
+ "mongo_sync_gridfs_new() should fail with a bogus ns prefix");
+
+ mongo_sync_disconnect (conn);
+
+ begin_network_tests (4);
+
+ f = g_strconcat (config.gfs_prefix, ".files", NULL);
+ c = g_strconcat (config.gfs_prefix, ".chunks", NULL);
+
+ conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE);
+
+ gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix);
+ ok (gfs != NULL,
+ "mongo_sync_gridfs_new() works");
+ is (gfs->ns.prefix, config.gfs_prefix,
+ "The namespace prefix is as specified");
+ is (gfs->ns.files, f,
+ "The files namespace is correct");
+ is (gfs->ns.chunks, c,
+ "The chunks namespace is correct");
+ mongo_sync_gridfs_free (gfs, FALSE);
+
+ mongo_sync_disconnect (conn);
+
+ g_free (f);
+ g_free (c);
+ end_network_tests ();
+}
+
+RUN_TEST (8, mongo_sync_gridfs_new);
diff --git a/tests/unit/mongo/sync-gridfs/sync_gridfs_remove.c b/tests/unit/mongo/sync-gridfs/sync_gridfs_remove.c
new file mode 100644
index 0000000..88eb40b
--- /dev/null
+++ b/tests/unit/mongo/sync-gridfs/sync_gridfs_remove.c
@@ -0,0 +1,34 @@
+#include "test.h"
+#include "mongo.h"
+
+void
+test_mongo_sync_gridfs_remove (void)
+{
+ mongo_sync_gridfs *gfs;
+ bson *query;
+
+ query = bson_build (BSON_TYPE_STRING, "bogus-key", "bogus-value", -1,
+ BSON_TYPE_NONE);
+ bson_finish (query);
+
+ ok (mongo_sync_gridfs_remove (NULL, NULL) == FALSE,
+ "mongo_sync_gridfs_remove() fails with a NULL GridFS");
+
+ begin_network_tests (1);
+
+ gfs = mongo_sync_gridfs_new
+ (mongo_sync_connect (config.primary_host, config.primary_port, FALSE),
+ config.gfs_prefix);
+
+ ok (mongo_sync_gridfs_remove (gfs, query) == FALSE,
+ "mongo_sync_gridfs_remove() fails with a query that does not match "
+ "anything");
+
+ mongo_sync_gridfs_free (gfs, TRUE);
+
+ end_network_tests ();
+
+ bson_free (query);
+}
+
+RUN_TEST (2, mongo_sync_gridfs_remove);
diff --git a/tests/unit/mongo/sync-pool/sync_pool_free.c b/tests/unit/mongo/sync-pool/sync_pool_free.c
new file mode 100644
index 0000000..5f64621
--- /dev/null
+++ b/tests/unit/mongo/sync-pool/sync_pool_free.c
@@ -0,0 +1,11 @@
+#include "test.h"
+#include "mongo.h"
+
+void
+test_mongo_sync_pool_free (void)
+{
+ mongo_sync_pool_free (NULL);
+ pass ("mongo_sync_pool_free(NULL) works");
+}
+
+RUN_TEST (1, mongo_sync_pool_free);
diff --git a/tests/unit/mongo/sync-pool/sync_pool_new.c b/tests/unit/mongo/sync-pool/sync_pool_new.c
new file mode 100644
index 0000000..b9758d2
--- /dev/null
+++ b/tests/unit/mongo/sync-pool/sync_pool_new.c
@@ -0,0 +1,19 @@
+#include "test.h"
+#include "mongo.h"
+
+void
+test_mongo_sync_pool_new (void)
+{
+ ok (mongo_sync_pool_new ("example.com", 27017, 0, 0) == NULL,
+ "mongo_sync_pool_new() needs at least one connection");
+ ok (mongo_sync_pool_new (NULL, 27017, 1, 0) == NULL,
+ "mongo_sync_pool_new() should fail without a HOST");
+ ok (mongo_sync_pool_new ("example.com", -1, 1, 0) == NULL,
+ "mongo_sync_pool_new() should fail with an invalid port");
+ ok (mongo_sync_pool_new ("example.com", 27017, -1, 0) == NULL,
+ "mongo_sync_pool_new() should fail with an invalid number of masters");
+ ok (mongo_sync_pool_new ("example.com", 27017, 10, -1) == NULL,
+ "mongo_sync_pool_new() should fail with an invalid number of slaves");
+}
+
+RUN_TEST (5, mongo_sync_pool_new);
diff --git a/tests/unit/mongo/sync-pool/sync_pool_pick.c b/tests/unit/mongo/sync-pool/sync_pool_pick.c
new file mode 100644
index 0000000..352ba04
--- /dev/null
+++ b/tests/unit/mongo/sync-pool/sync_pool_pick.c
@@ -0,0 +1,11 @@
+#include "test.h"
+#include "mongo.h"
+
+void
+test_mongo_sync_pool_pick (void)
+{
+ ok (mongo_sync_pool_pick (NULL, TRUE) == NULL,
+ "mongo_sync_pool_pick() should fail without a pool");
+}
+
+RUN_TEST (1, mongo_sync_pool_pick);
diff --git a/tests/unit/mongo/sync-pool/sync_pool_return.c b/tests/unit/mongo/sync-pool/sync_pool_return.c
new file mode 100644
index 0000000..d622ede
--- /dev/null
+++ b/tests/unit/mongo/sync-pool/sync_pool_return.c
@@ -0,0 +1,22 @@
+#include "test.h"
+#include "mongo.h"
+
+#include <string.h>
+#include "libmongo-private.h"
+
+void
+test_mongo_sync_pool_return (void)
+{
+ mongo_sync_pool_connection c;
+ void *pool;
+
+ pool = g_malloc (1024);
+
+ ok (mongo_sync_pool_return (NULL, &c) == FALSE,
+ "mongo_sync_pool_return() should fail without a pool");
+ ok (mongo_sync_pool_return ((mongo_sync_pool *)pool, NULL) == FALSE,
+ "mongo_sync_pool_return() should fail without a connection");
+ g_free (pool);
+}
+
+RUN_TEST (2, mongo_sync_pool_return);
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);
diff --git a/tests/unit/mongo/utils/oid_as_string.c b/tests/unit/mongo/utils/oid_as_string.c
new file mode 100644
index 0000000..9cf740c
--- /dev/null
+++ b/tests/unit/mongo/utils/oid_as_string.c
@@ -0,0 +1,26 @@
+#include "test.h"
+#include "mongo.h"
+
+void
+test_mongo_utils_oid_as_string (void)
+{
+ guint8 *oid;
+ gchar *oid_str;
+
+ mongo_util_oid_init (0);
+
+ oid = mongo_util_oid_new (1);
+
+ ok (mongo_util_oid_as_string (NULL) == NULL,
+ "mongo_util_oid_as_string() should fail with a NULL oid");
+
+ oid_str = mongo_util_oid_as_string (oid);
+
+ ok (oid_str != NULL,
+ "mongo_util_oid_as_string() works");
+
+ g_free (oid_str);
+ g_free (oid);
+}
+
+RUN_TEST (2, mongo_utils_oid_as_string);
diff --git a/tests/unit/mongo/utils/oid_init.c b/tests/unit/mongo/utils/oid_init.c
new file mode 100644
index 0000000..42d0db1
--- /dev/null
+++ b/tests/unit/mongo/utils/oid_init.c
@@ -0,0 +1,19 @@
+#include "tap.h"
+#include "test.h"
+#include "mongo-utils.h"
+
+void
+test_mongo_utils_oid_init (void)
+{
+ mongo_util_oid_init (0);
+ mongo_util_oid_init (1234);
+
+ /* We don't do any real testing here, only check if it does not
+ crash. To verify that it works, we need to create a new OID, and
+ that will be tested by other unit tests.
+ */
+ ok (TRUE,
+ "mongo_util_oid_init() does not crash.");
+}
+
+RUN_TEST (1, mongo_utils_oid_init);
diff --git a/tests/unit/mongo/utils/oid_new.c b/tests/unit/mongo/utils/oid_new.c
new file mode 100644
index 0000000..b8f7f0a
--- /dev/null
+++ b/tests/unit/mongo/utils/oid_new.c
@@ -0,0 +1,49 @@
+#include "tap.h"
+#include "test.h"
+#include "mongo-utils.h"
+
+#include <string.h>
+#include <unistd.h>
+
+void
+test_mongo_utils_oid_new (void)
+{
+ guint8 *oid1, *oid2, *oid3;
+ gchar *oid1_s, *oid2_s;
+
+ ok (mongo_util_oid_new (0) == NULL,
+ "mongo_util_oid_new() should fail before mongo_util_oid_init()");
+
+ mongo_util_oid_init (0);
+ ok ((oid1 = mongo_util_oid_new (1)) != NULL,
+ "mongo_util_oid_new() works");
+ cmp_ok (oid1[11], "==", 1,
+ "mongo_util_oid_new() returns an OID with the currect seq ID");
+
+ oid2 = mongo_util_oid_new (2);
+ oid3 = mongo_util_oid_new (2);
+
+ ok (memcmp (oid2, oid1, 12) > 0,
+ "OIDs with higher sequence ID sort higher");
+ ok (memcmp (oid2, oid3, 12) == 0,
+ "OIDs with the same sequence ID are equal (within a second)");
+ g_free (oid2);
+ g_free (oid3);
+
+ sleep (2);
+ oid2 = mongo_util_oid_new (0);
+
+ oid1_s = mongo_util_oid_as_string (oid1);
+ oid2_s = mongo_util_oid_as_string (oid2);
+
+ ok (memcmp (oid2, oid1, 12) > 0,
+ "OIDs with the same sequence ID, a few seconds later sort higher; "
+ "oid1=%s; oid2=%s", oid1_s, oid2_s);
+
+ g_free (oid2_s);
+ g_free (oid1_s);
+ g_free (oid2);
+ g_free (oid1);
+}
+
+RUN_TEST (6, mongo_utils_oid_new);
diff --git a/tests/unit/mongo/utils/oid_new_with_time.c b/tests/unit/mongo/utils/oid_new_with_time.c
new file mode 100644
index 0000000..290fdab
--- /dev/null
+++ b/tests/unit/mongo/utils/oid_new_with_time.c
@@ -0,0 +1,46 @@
+#include "tap.h"
+#include "test.h"
+#include "mongo-utils.h"
+
+#include <string.h>
+
+void
+test_mongo_utils_oid_new_with_time (void)
+{
+ guint8 *oid1, *oid2, *oid3;
+ gchar *oid1_s, *oid2_s;
+
+ ok (mongo_util_oid_new_with_time (0, 0) == NULL,
+ "mongo_util_oid_new_with_time() should fail before mongo_util_oid_init()");
+
+ mongo_util_oid_init (0);
+ ok ((oid1 = mongo_util_oid_new_with_time (0, 1)) != NULL,
+ "mongo_util_oid_new_with_time() works");
+ cmp_ok (oid1[11], "==", 1,
+ "mongo_util_oid_new_with_time() returns an OID with the currect seq ID");
+
+ oid2 = mongo_util_oid_new_with_time (0, 2);
+ oid3 = mongo_util_oid_new_with_time (0, 2);
+
+ ok (memcmp (oid2, oid1, 12) > 0,
+ "OIDs with higher sequence ID sort higher");
+ ok (memcmp (oid2, oid3, 12) == 0,
+ "OIDs with the same sequence ID are equal (within a second)");
+ g_free (oid2);
+ g_free (oid3);
+
+ oid2 = mongo_util_oid_new_with_time (1, 0);
+
+ oid1_s = mongo_util_oid_as_string (oid1);
+ oid2_s = mongo_util_oid_as_string (oid2);
+
+ ok (memcmp (oid2, oid1, 12) > 0,
+ "OIDs with the same sequence ID, a few seconds later sort higher; "
+ "oid1=%s; oid2=%s", oid1_s, oid2_s);
+ g_free (oid2_s);
+ g_free (oid1_s);
+ g_free (oid2);
+ g_free (oid1);
+}
+
+RUN_TEST (6, mongo_utils_oid_new_with_time);
diff --git a/tests/unit/mongo/utils/parse_addr.c b/tests/unit/mongo/utils/parse_addr.c
new file mode 100644
index 0000000..13b16d1
--- /dev/null
+++ b/tests/unit/mongo/utils/parse_addr.c
@@ -0,0 +1,244 @@
+#include "tap.h"
+#include "test.h"
+#include "mongo-utils.h"
+
+#include <string.h>
+
+void
+test_mongo_utils_parse_addr (void)
+{
+ gchar *host = "deadbeef";
+ gint port = 42;
+
+ ok (mongo_util_parse_addr (NULL, &host, &port) == FALSE,
+ "mongo_util_parse_addr() fails with a NULL address");
+ is (host, NULL,
+ "Failed parsing sets host to NULL");
+ cmp_ok (port, "==", -1,
+ "Failed parsing sets port to -1");
+ host = "deadbeef";
+ port = 42;
+
+ ok (mongo_util_parse_addr ("127.0.0.1:27017", &host, NULL) == FALSE,
+ "mongo_util_parse_addr() fails when port is NULL");
+ is (host, NULL,
+ "Failed parsing sets host to NULL");
+ host = "deadbeef";
+ port = 42;
+
+ ok (mongo_util_parse_addr ("127.0.0.1:27017", NULL, &port) == FALSE,
+ "mongo_util_parse_addr() fails when host is NULL");
+ cmp_ok (port, "==", -1,
+ "Failed parsing sets port to -1");
+ host = "deadbeef";
+ port = 42;
+
+ ok (mongo_util_parse_addr ("127.0.0.1:27017", &host, &port),
+ "mongo_util_parse_addr() can parse HOST:PORT pairs");
+ is (host, "127.0.0.1",
+ "Host parsed successfully");
+ cmp_ok (port, "==", 27017,
+ "Port parsed successfully");
+ g_free (host);
+ host = "deadbeef";
+ port = 42;
+
+ ok (mongo_util_parse_addr (":27017", &host, &port) == FALSE,
+ "mongo_util_parse_addr() should fail when no host is specified");
+ is (host, NULL,
+ "Failed parsing sets host to NULL");
+ cmp_ok (port, "==", -1,
+ "Failed parsing sets port to -1");
+ host = "deadbeef";
+ port = 42;
+
+ ok (mongo_util_parse_addr ("localhost:27017garbage", &host, &port) == FALSE,
+ "mongo_util_parse_addr() should fail if there is garbage after "
+ "the port");
+ is (host, NULL,
+ "Failed parsing sets host to NULL");
+ cmp_ok (port, "==", -1,
+ "Failed parsing sets port to -1");
+ host = "deadbeef";
+ port = 42;
+
+ ok (mongo_util_parse_addr ("localhost:garbage", &host, &port) == FALSE,
+ "mongo_util_parse_addr() should fail if the port is not a number");
+ is (host, NULL,
+ "Failed parsing sets host to NULL");
+ cmp_ok (port, "==", -1,
+ "Failed parsing sets port to -1");
+ host = "deadbeef";
+ port = 42;
+
+ ok (mongo_util_parse_addr ("localhost:-10", &host, &port) == FALSE,
+ "mongo_util_parse_addr() should fail if the port is out of bounds");
+ is (host, NULL,
+ "Failed parsing sets host to NULL");
+ cmp_ok (port, "==", -1,
+ "Failed parsing sets port to -1");
+ host = "deadbeef";
+ port = 42;
+
+ ok (mongo_util_parse_addr ("localhost:9999999999999999999",
+ &host, &port) == FALSE,
+ "mongo_util_parse_addr() should fail if the port is out of bounds");
+ is (host, NULL,
+ "Failed parsing sets host to NULL");
+ cmp_ok (port, "==", -1,
+ "Failed parsing sets port to -1");
+ host = "deadbeef";
+ port = 42;
+
+ ok (mongo_util_parse_addr ("localhost:9999999999",
+ &host, &port) == FALSE,
+ "mongo_util_parse_addr() should fail if the port is out of bounds");
+ is (host, NULL,
+ "Failed parsing sets host to NULL");
+ cmp_ok (port, "==", -1,
+ "Failed parsing sets port to -1");
+ host = "deadbeef";
+ port = 42;
+
+ /* IPv6 */
+ ok (mongo_util_parse_addr ("::1:27017", &host, &port),
+ "mongo_util_parse_addr() can deal with IPv6 addresses");
+ is (host, "::1",
+ "Host parsed successfully");
+ cmp_ok (port, "==", 27017,
+ "Port parsed successfully");
+ g_free (host);
+ host = "deadbeef";
+ port = 42;
+
+ ok (mongo_util_parse_addr ("::1", &host, &port),
+ "mongo_util_parse_addr() should silently misparse ambigous "
+ "IPv6 addresses");
+ isnt (host, "::1",
+ "Host is misparsed, as expected");
+ cmp_ok (port, "==", 1,
+ "Port is misparsed, as expected");
+ g_free (host);
+ host = "deadbeef";
+ port = 42;
+
+ ok (mongo_util_parse_addr ("[::1", &host, &port) == FALSE,
+ "mongo_util_parse_addr() should fail on invalid IPv6 literals");
+ is (host, NULL,
+ "Host should be NULL");
+ cmp_ok (port, "==", -1,
+ "Port should be -1");
+ g_free (host);
+ host = "deadbeef";
+ port = 42;
+
+ ok (mongo_util_parse_addr ("[::1]:1", &host, &port),
+ "mongo_util_parse_addr() works with IPv6 literal + port");
+ is (host, "::1",
+ "Host should be ::1");
+ cmp_ok (port, "==", 1,
+ "Port should be 1");
+ g_free (host);
+ host = "deadbeef";
+ port = 42;
+
+ ok (mongo_util_parse_addr ("[::1]:27017", &host, &port),
+ "mongo_util_parse_addr() works with IPv6 literal + port");
+ is (host, "::1",
+ "Host should be ::1");
+ cmp_ok (port, "==", 27017,
+ "Port should be 27017");
+ g_free (host);
+ host = "deadbeef";
+ port = 42;
+
+ ok (mongo_util_parse_addr ("[]:27017", &host, &port) == FALSE,
+ "mongo_util_parse_addr() should fail when no host is specified");
+ is (host, NULL,
+ "Failed parsing sets host to NULL");
+ cmp_ok (port, "==", -1,
+ "Failed parsing sets port to -1");
+ host = "deadbeef";
+ port = 42;
+
+ ok (mongo_util_parse_addr ("[::1]:27017garbage", &host, &port) == FALSE,
+ "mongo_util_parse_addr() should fail if there is garbage after "
+ "the port");
+ is (host, NULL,
+ "Failed parsing sets host to NULL");
+ cmp_ok (port, "==", -1,
+ "Failed parsing sets port to -1");
+ host = "deadbeef";
+ port = 42;
+
+ ok (mongo_util_parse_addr ("[::1]:garbage", &host, &port) == FALSE,
+ "mongo_util_parse_addr() should fail if the port is not a number");
+ is (host, NULL,
+ "Failed parsing sets host to NULL");
+ cmp_ok (port, "==", -1,
+ "Failed parsing sets port to -1");
+ host = "deadbeef";
+ port = 42;
+
+ ok (mongo_util_parse_addr ("[::1]:-10", &host, &port) == FALSE,
+ "mongo_util_parse_addr() should fail if the port is out of bounds");
+ is (host, NULL,
+ "Failed parsing sets host to NULL");
+ cmp_ok (port, "==", -1,
+ "Failed parsing sets port to -1");
+ host = "deadbeef";
+ port = 42;
+
+ ok (mongo_util_parse_addr ("[::1]:9999999999999999999",
+ &host, &port) == FALSE,
+ "mongo_util_parse_addr() should fail if the port is out of bounds");
+ is (host, NULL,
+ "Failed parsing sets host to NULL");
+ cmp_ok (port, "==", -1,
+ "Failed parsing sets port to -1");
+ host = "deadbeef";
+ port = 42;
+
+ ok (mongo_util_parse_addr ("[::1]:9999999999",
+ &host, &port) == FALSE,
+ "mongo_util_parse_addr() should fail if the port is out of bounds");
+ is (host, NULL,
+ "Failed parsing sets host to NULL");
+ cmp_ok (port, "==", -1,
+ "Failed parsing sets port to -1");
+ host = "deadbeef";
+ port = 42;
+
+ ok (mongo_util_parse_addr ("/var/run/mongodb/mongodb.socket",
+ &host, &port) == TRUE,
+ "mongo_util_parse_addr() works with unix domain sockets");
+ is (host, "/var/run/mongodb/mongodb.socket",
+ "Parsing a Unix domain socket sets host to the socket name");
+ cmp_ok (port, "==", -1,
+ "Port is set to -1");
+ host = "deadbeef";
+ port = 42;
+
+ ok (mongo_util_parse_addr ("[::1]", &host, &port),
+ "mongo_util_parse_addr() can handle IPv6 literals without port set");
+ is (host, "::1",
+ "Host parsed successfully");
+ cmp_ok (port, "==", -1,
+ "Port is set to -1");
+ g_free (host);
+ host = "deadbeef";
+ port = 42;
+
+ ok (mongo_util_parse_addr ("/var/run/mongodb/mongodb.socket:-1",
+ &host, &port) == TRUE,
+ "mongo_util_parse_addr() can parse unix domain sockets with -1 port");
+ is (host, "/var/run/mongodb/mongodb.socket",
+ "Parsing a unix domain socket sets host to the socket name");
+ cmp_ok (port, "==", -1,
+ "Parsing a unix domain socket with a port set to -1, works");
+ g_free (host);
+ host = "deadbeef";
+ port = 42;
+}
+
+RUN_TEST (70, mongo_utils_parse_addr);
diff --git a/tests/unit/mongo/wire/cmd_custom.c b/tests/unit/mongo/wire/cmd_custom.c
new file mode 100644
index 0000000..7970aaa
--- /dev/null
+++ b/tests/unit/mongo/wire/cmd_custom.c
@@ -0,0 +1,67 @@
+#include "test.h"
+#include "tap.h"
+#include "mongo-wire.h"
+
+#include <string.h>
+
+void
+test_mongo_wire_cmd_custom (void)
+{
+ bson *cmd;
+ mongo_packet *p;
+
+ mongo_packet_header hdr;
+ const guint8 *data;
+ gint32 data_size;
+
+ bson_cursor *c;
+ gint32 pos;
+
+ cmd = bson_new ();
+ bson_append_int32 (cmd, "getnonce", 1);
+
+ ok (mongo_wire_cmd_custom (1, "test", 0, NULL) == NULL,
+ "mongo_wire_cmd_custom() fails with a NULL command");
+ ok (mongo_wire_cmd_custom (1, "test", 0, cmd) == NULL,
+ "mongo_wire_cmd_custom() fails with an unfinished command");
+ bson_finish (cmd);
+ ok (mongo_wire_cmd_custom (1, NULL, 0, cmd) == NULL,
+ "mongo_wire_cmd_custom() fails with a NULL db");
+
+ ok ((p = mongo_wire_cmd_custom (1, "test", 0, cmd)) != NULL,
+ "mongo_wire_cmd_custom() works");
+ bson_free (cmd);
+
+ /* Verify the header */
+ mongo_wire_packet_get_header (p, &hdr);
+ cmp_ok ((data_size = mongo_wire_packet_get_data (p, &data)), "!=", -1,
+ "Packet data size looks fine");
+ cmp_ok (hdr.length, "==", sizeof (mongo_packet_header) + data_size,
+ "Packet header length is OK");
+ cmp_ok (hdr.id, "==", 1, "Packet request ID is ok");
+ cmp_ok (hdr.resp_to, "==", 0, "Packet reply ID is ok");
+
+ /*
+ * Test the created request
+ */
+
+ /* pos = zero + collection_name + NULL + skip + ret */
+ pos = sizeof (gint32) + strlen ("test.$cmd") + 1 + sizeof (gint32) * 2;
+ ok ((cmd = bson_new_from_data (data + pos,
+ bson_stream_doc_size (data, pos) - 1)) != NULL,
+ "Packet contains a BSON document");
+ bson_finish (cmd);
+
+ ok ((c = bson_find (cmd, "getnonce")) != NULL,
+ "BSON object contains a 'getnonce' key");
+ cmp_ok (bson_cursor_type (c), "==", BSON_TYPE_INT32,
+ "'getnonce' key has the correct type");
+ ok (bson_cursor_next (c) == FALSE,
+ "'getnonce' key is the last in the object");
+
+ bson_cursor_free (c);
+ bson_free (cmd);
+ mongo_wire_packet_free (p);
+}
+
+RUN_TEST (12, mongo_wire_cmd_custom);
diff --git a/tests/unit/mongo/wire/cmd_delete.c b/tests/unit/mongo/wire/cmd_delete.c
new file mode 100644
index 0000000..9399046
--- /dev/null
+++ b/tests/unit/mongo/wire/cmd_delete.c
@@ -0,0 +1,73 @@
+#include "test.h"
+#include "tap.h"
+#include "mongo-wire.h"
+
+#include <string.h>
+
+void
+test_mongo_wire_cmd_delete (void)
+{
+ mongo_packet *p;
+ bson *s, *tmp;
+
+ mongo_packet_header hdr;
+ const guint8 *data;
+ gint32 data_size;
+
+ gint32 pos;
+ bson_cursor *c;
+
+ s = test_bson_generate_full ();
+ tmp = bson_new ();
+
+ ok (mongo_wire_cmd_delete (1, NULL, 0, s) == NULL,
+ "mongo_wire_cmd_delete() fails with a NULL namespace");
+ ok (mongo_wire_cmd_delete (1, "test.ns", 0, NULL) == NULL,
+ "mongo_wire_cmd_delete() fails with a NULL selector");
+ ok (mongo_wire_cmd_delete (1, "test.ns", 0, tmp) == NULL,
+ "mongo_wire_cmd_delete() fails with an unfinished selector");
+ bson_free (tmp);
+
+ ok ((p = mongo_wire_cmd_delete (1, "test.ns", 0, s)) != NULL,
+ "mongo_wire_cmd_delete() works");
+ bson_free (s);
+
+ /* Test basic header data */
+ mongo_wire_packet_get_header (p, &hdr);
+ cmp_ok ((data_size = mongo_wire_packet_get_data (p, &data)), "!=", -1,
+ "Packet data size appears fine");
+
+ cmp_ok (hdr.length, "==", sizeof (mongo_packet_header) + data_size,
+ "Packet header length is correct");
+ cmp_ok (hdr.id, "==", 1, "Header ID is ok");
+ cmp_ok (hdr.resp_to, "==", 0, "Response ID is ok");
+
+ /*
+ * Test the constructed request
+ */
+
+ /* pos = zero + ns + NULL + flags */
+ pos = sizeof (gint32) + strlen ("test.ns") + 1 + sizeof (gint32);
+
+ ok ((s = bson_new_from_data (data + pos,
+ bson_stream_doc_size (data, pos) - 1)) != NULL,
+ "Packet contains a valid BSON update document");
+ bson_finish (s);
+
+ ok ((c = bson_find (s, "int32")) != NULL,
+ "BSON contains 'int32'");
+ cmp_ok (bson_cursor_type (c), "==", BSON_TYPE_INT32,
+ "int32 has correct type");
+ bson_cursor_next (c);
+ cmp_ok (bson_cursor_type (c), "==", BSON_TYPE_INT64,
+ "next element has correct type too");
+ ok (bson_cursor_next (c) == FALSE,
+ "No more data after the update BSON object");
+
+ bson_cursor_free (c);
+ bson_free (s);
+
+ mongo_wire_packet_free (p);
+}
+
+RUN_TEST (13, mongo_wire_cmd_delete);
diff --git a/tests/unit/mongo/wire/cmd_get_more.c b/tests/unit/mongo/wire/cmd_get_more.c
new file mode 100644
index 0000000..5f56821
--- /dev/null
+++ b/tests/unit/mongo/wire/cmd_get_more.c
@@ -0,0 +1,50 @@
+#include "test.h"
+#include "tap.h"
+#include "mongo-wire.h"
+
+#include <string.h>
+
+void
+test_mongo_wire_cmd_get_more (void)
+{
+ mongo_packet *p;
+
+ mongo_packet_header hdr;
+ const guint8 *data;
+ gint32 data_size;
+
+ gint32 pos;
+ gint64 cid = 9876543210;
+
+ ok (mongo_wire_cmd_get_more (1, NULL, 1, cid) == NULL,
+ "mongo_wire_cmd_get_more() fails with a NULL namespace");
+ ok ((p = mongo_wire_cmd_get_more (1, "test.ns", 1, cid)) != NULL,
+ "mongo_wire_cmd_get_more() works");
+
+ /* Test basic header data */
+ mongo_wire_packet_get_header (p, &hdr);
+ cmp_ok ((data_size = mongo_wire_packet_get_data (p, &data)), "!=", -1,
+ "Packet data size appears fine");
+
+ cmp_ok (hdr.length, "==", sizeof (mongo_packet_header) + data_size,
+ "Packet header length is correct");
+ cmp_ok (hdr.id, "==", 1, "Header ID is ok");
+ cmp_ok (hdr.resp_to, "==", 0, "Response ID is ok");
+
+ /*
+ * Test the request itself.
+ */
+
+ /* pos = zero + ns + NULL + ret */
+ pos = sizeof (gint32) + strlen ("test.ns") + 1 + sizeof (gint32);
+ cid = 0;
+ memcpy (&cid, data + pos, sizeof (cid));
+ cid = GINT64_FROM_LE (cid);
+
+ ok (cid == 9876543210,
+ "Included CID is correct");
+
+ mongo_wire_packet_free (p);
+}
+
+RUN_TEST (7, mongo_wire_cmd_get_more);
diff --git a/tests/unit/mongo/wire/cmd_insert.c b/tests/unit/mongo/wire/cmd_insert.c
new file mode 100644
index 0000000..3e84847
--- /dev/null
+++ b/tests/unit/mongo/wire/cmd_insert.c
@@ -0,0 +1,83 @@
+#include "test.h"
+#include "tap.h"
+#include "mongo-wire.h"
+
+#include <string.h>
+
+void
+test_mongo_wire_cmd_insert (void)
+{
+ bson *ins, *tmp;
+ mongo_packet *p;
+
+ mongo_packet_header hdr;
+ const guint8 *data;
+ gint32 data_size;
+
+ bson_cursor *c;
+ gint32 pos;
+
+ ins = test_bson_generate_full ();
+ tmp = bson_new ();
+
+ ok (mongo_wire_cmd_insert (1, NULL, ins, NULL) == NULL,
+ "mongo_wire_cmd_insert() fails with a NULL namespace");
+ ok (mongo_wire_cmd_insert (1, "test.ns", NULL) == NULL,
+ "mongo_wire_cmd_insert() fails with no documents");
+ ok (mongo_wire_cmd_insert (1, "test.ns", tmp, NULL) == NULL,
+ "mongo_wire_cmd_insert() with an unfinished document");
+ bson_finish (tmp);
+ ok ((p = mongo_wire_cmd_insert (1, "test.ns", ins, tmp, NULL)) != NULL,
+ "mongo_wire_cmd_insert() works");
+ bson_free (ins);
+ bson_free (tmp);
+
+ /* Test basic header data */
+ mongo_wire_packet_get_header (p, &hdr);
+ cmp_ok ((data_size = mongo_wire_packet_get_data (p, &data)), "!=", -1,
+ "Packet data size appears fine");
+
+ cmp_ok (hdr.length, "==", sizeof (mongo_packet_header) + data_size,
+ "Packet header length is correct");
+ cmp_ok (hdr.id, "==", 1, "Header ID is ok");
+ cmp_ok (hdr.resp_to, "==", 0, "Response ID is ok");
+
+ /*
+ * Test the first document
+ */
+
+ /* pos = zero + collection_name + NULL */
+ pos = sizeof (gint32) + strlen ("test.ns") + 1;
+ ok ((ins = bson_new_from_data (data + pos,
+ bson_stream_doc_size (data, pos) - 1)) != NULL,
+ "First document is included");
+ bson_finish (ins);
+
+ ok ((c = bson_find (ins, "int32")) != NULL,
+ "BSON contains 'int32'");
+ cmp_ok (bson_cursor_type (c), "==", BSON_TYPE_INT32,
+ "int32 has correct type");
+ bson_cursor_next (c);
+ cmp_ok (bson_cursor_type (c), "==", BSON_TYPE_INT64,
+ "next element has correct type too");
+ ok (bson_cursor_next (c) == FALSE,
+ "No more data after the update BSON object");
+ bson_cursor_free (c);
+
+ /*
+ * Test the second document
+ */
+ pos += bson_size (ins);
+ ok ((tmp = bson_new_from_data (data + pos,
+ bson_stream_doc_size (data, pos) - 1)) != NULL,
+ "Second document is included");
+ bson_finish (tmp);
+ cmp_ok (bson_size (tmp), "==", 5,
+ "Second document is empty");
+
+ bson_free (ins);
+ bson_free (tmp);
+ mongo_wire_packet_free (p);
+}
+
+RUN_TEST (15, mongo_wire_cmd_insert);
diff --git a/tests/unit/mongo/wire/cmd_insert_n.c b/tests/unit/mongo/wire/cmd_insert_n.c
new file mode 100644
index 0000000..1c00193
--- /dev/null
+++ b/tests/unit/mongo/wire/cmd_insert_n.c
@@ -0,0 +1,95 @@
+#include "test.h"
+#include "tap.h"
+#include "mongo-wire.h"
+
+#include <string.h>
+
+void
+test_mongo_wire_cmd_insert_n (void)
+{
+ bson *ins, *tmp;
+ const bson *docs[10];
+ mongo_packet *p;
+
+ mongo_packet_header hdr;
+ const guint8 *data;
+ gint32 data_size;
+
+ bson_cursor *c;
+ gint32 pos;
+
+ ins = test_bson_generate_full ();
+ tmp = bson_new ();
+
+ docs[0] = ins;
+ docs[1] = tmp;
+ docs[2] = ins;
+ docs[3] = ins;
+ docs[4] = NULL;
+ docs[5] = ins;
+
+ ok (mongo_wire_cmd_insert_n (1, NULL, 1, docs) == NULL,
+ "mongo_wire_cmd_insert_n() fails with a NULL namespace");
+ ok (mongo_wire_cmd_insert_n (1, "test.ns", 1, NULL) == NULL,
+ "mongo_wire_cmd_insert_n() fails with no documents");
+ ok (mongo_wire_cmd_insert_n (1, "test.ns", 0, docs) == NULL,
+ "mongo_wire_cmd_insert_n() fails with no documents");
+ ok (mongo_wire_cmd_insert_n (1, "test.ns", 2, docs) == NULL,
+ "mongo_wire_cmd_insert_n() fails with an unfinished document");
+ bson_finish (tmp);
+ ok (mongo_wire_cmd_insert_n (1, "test.ns", 5, docs) == NULL,
+ "mongo_wire_cmd_insert_n() fails with a NULL document in the array");
+ ok ((p = mongo_wire_cmd_insert_n (1, "test.ns", 3, docs)) != NULL,
+ "mongo_wire_cmd_insert() works");
+ bson_free (ins);
+ bson_free (tmp);
+
+ /* Test basic header data */
+ mongo_wire_packet_get_header (p, &hdr);
+ cmp_ok ((data_size = mongo_wire_packet_get_data (p, &data)), "!=", -1,
+ "Packet data size appears fine");
+
+ cmp_ok (hdr.length, "==", sizeof (mongo_packet_header) + data_size,
+ "Packet header length is correct");
+ cmp_ok (hdr.id, "==", 1, "Header ID is ok");
+ cmp_ok (hdr.resp_to, "==", 0, "Response ID is ok");
+
+ /*
+ * Test the first document
+ */
+
+ /* pos = zero + collection_name + NULL */
+ pos = sizeof (gint32) + strlen ("test.ns") + 1;
+ ok ((ins = bson_new_from_data (data + pos,
+ bson_stream_doc_size (data, pos) - 1)) != NULL,
+ "First document is included");
+ bson_finish (ins);
+
+ ok ((c = bson_find (ins, "int32")) != NULL,
+ "BSON contains 'int32'");
+ cmp_ok (bson_cursor_type (c), "==", BSON_TYPE_INT32,
+ "int32 has correct type");
+ bson_cursor_next (c);
+ cmp_ok (bson_cursor_type (c), "==", BSON_TYPE_INT64,
+ "next element has correct type too");
+ ok (bson_cursor_next (c) == FALSE,
+ "No more data after the update BSON object");
+ bson_cursor_free (c);
+
+ /*
+ * Test the second document
+ */
+ pos += bson_size (ins);
+ ok ((tmp = bson_new_from_data (data + pos,
+ bson_stream_doc_size (data, pos) - 1)) != NULL,
+ "Second document is included");
+ bson_finish (tmp);
+ cmp_ok (bson_size (tmp), "==", 5,
+ "Second document is empty");
+
+ bson_free (ins);
+ bson_free (tmp);
+ mongo_wire_packet_free (p);
+}
+
+RUN_TEST (17, mongo_wire_cmd_insert_n);
diff --git a/tests/unit/mongo/wire/cmd_kill_cursors.c b/tests/unit/mongo/wire/cmd_kill_cursors.c
new file mode 100644
index 0000000..a8a8fd9
--- /dev/null
+++ b/tests/unit/mongo/wire/cmd_kill_cursors.c
@@ -0,0 +1,58 @@
+#include "test.h"
+#include "tap.h"
+#include "mongo-wire.h"
+
+#include <string.h>
+
+void
+test_mongo_wire_cmd_kill_cursors (void)
+{
+ mongo_packet *p;
+
+ mongo_packet_header hdr;
+ const guint8 *data;
+ gint32 data_size;
+
+ gint32 pos, n = 0;
+ gint64 c1 = 9876543210, c2 = 1234567890;
+
+ ok (mongo_wire_cmd_kill_cursors (1, 0) == NULL,
+ "mongo_wire_cmd_kill_cursors() should fail with zero cursors");
+ ok (mongo_wire_cmd_kill_cursors (1, -1) == NULL,
+ "mongo_wire_cmd_kill_cursors() should fail with negative amount of "
+ "cursors");
+ ok ((p = mongo_wire_cmd_kill_cursors (1, 2, c1, c2)) != NULL,
+ "mongo_wire_cmd_kill_cursors() works");
+
+ /* Verify the header */
+ mongo_wire_packet_get_header (p, &hdr);
+ cmp_ok ((data_size = mongo_wire_packet_get_data (p, &data)), "!=", -1,
+ "Packet data size looks fine");
+ cmp_ok (hdr.length, "==", sizeof (mongo_packet_header) + data_size,
+ "Packet header length is OK");
+ cmp_ok (hdr.id, "==", 1, "Packet request ID is ok");
+ cmp_ok (hdr.resp_to, "==", 0, "Packet reply ID is ok");
+
+ /*
+ * Test the request contents
+ */
+ c1 = c2 = 0;
+ /* pos = zero + n */
+ pos = sizeof (gint32) + sizeof (n);
+
+ memcpy (&n, data + sizeof (gint32), sizeof (gint32));
+ memcpy (&c1, data + pos, sizeof (c1));
+ memcpy (&c2, data + pos + sizeof (c1), sizeof (c2));
+
+ n = GINT32_FROM_LE (n);
+ c1 = GINT64_FROM_LE (c1);
+ c2 = GINT64_FROM_LE (c2);
+
+ ok (n == 2, "Number of cursors are OK");
+ ok (c1 == 9876543210, "First cursor is OK");
+ ok (c2 == 1234567890, "Second cursor is OK");
+
+ mongo_wire_packet_free (p);
+}
+
+RUN_TEST (10, mongo_wire_cmd_kill_cursors);
diff --git a/tests/unit/mongo/wire/cmd_query.c b/tests/unit/mongo/wire/cmd_query.c
new file mode 100644
index 0000000..58eb960
--- /dev/null
+++ b/tests/unit/mongo/wire/cmd_query.c
@@ -0,0 +1,117 @@
+#include "test.h"
+#include "tap.h"
+#include "mongo-wire.h"
+
+#include <string.h>
+
+void
+test_mongo_wire_cmd_query (void)
+{
+ bson *q, *s, *tmp;
+ mongo_packet *p;
+
+ mongo_packet_header hdr;
+ const guint8 *data;
+ gint32 data_size;
+
+ bson_cursor *c;
+ gint32 pos;
+
+ q = test_bson_generate_full ();
+ s = bson_new ();
+ bson_append_boolean (s, "_id", TRUE);
+ bson_append_boolean (s, "double", TRUE);
+ bson_finish (s);
+
+ tmp = bson_new ();
+
+ ok (mongo_wire_cmd_query (1, NULL, 0, 0, 0, q, s) == NULL,
+ "mongo_wire_cmd_query() fails whith a NULL namespace");
+ ok (mongo_wire_cmd_query (1, "test.ns", 0, 0, 0, NULL, s) == NULL,
+ "mongo_wire_cmd_query() fails with a NULL query");
+ ok (mongo_wire_cmd_query (1, "test.ns", 0, 0, 0, tmp, s) == NULL,
+ "mongo_wire_cmd_query() fails with an unfinished query");
+ ok (mongo_wire_cmd_query (1, "test.ns", 0, 0, 0, q, tmp) == NULL,
+ "mongo_wire_cmd_query() fails with an unfinished selector");
+ bson_free (tmp);
+
+ ok ((p = mongo_wire_cmd_query (1, "test.ns", 0, 0, 10, q, NULL)) != NULL,
+ "mongo_wire_cmd_query() works with a NULL selector");
+
+ mongo_wire_packet_get_header (p, &hdr);
+ cmp_ok ((data_size = mongo_wire_packet_get_data (p, &data)), "!=", -1,
+ "Packet data size looks fine");
+ cmp_ok (hdr.length, "==", sizeof (mongo_packet_header) + data_size,
+ "Packet header length is OK");
+ cmp_ok (hdr.id, "==", 1, "Packet request ID is ok");
+ cmp_ok (hdr.resp_to, "==", 0, "Packet reply ID is ok");
+
+ /* pos = zero + collection_name + NULL + skip + ret */
+ pos = sizeof (gint32) + strlen ("test.ns") + 1 + sizeof (gint32) * 2;
+ ok ((tmp = bson_new_from_data (data + pos,
+ bson_stream_doc_size (data, pos) - 1)) != NULL,
+ "Packet contains a valid BSON query document");
+ bson_finish (tmp);
+
+ ok ((c = bson_find (tmp, "int32")) != NULL,
+ "BSON contains 'int32'");
+ cmp_ok (bson_cursor_type (c), "==", BSON_TYPE_INT32,
+ "int32 has correct type");
+ bson_cursor_next (c);
+ cmp_ok (bson_cursor_type (c), "==", BSON_TYPE_INT64,
+ "next element has correct type too");
+ ok (bson_cursor_next (c) == FALSE,
+ "No more data after the update BSON object");
+ bson_cursor_free (c);
+
+ cmp_ok (hdr.length, "==", sizeof (mongo_packet_header) + pos +
+ bson_size (q),
+ "Packet header lenght is correct");
+ bson_free (tmp);
+ mongo_wire_packet_free (p);
+
+ /*
+ * Test again with a selector document
+ */
+
+ ok ((p = mongo_wire_cmd_query (1, "test.ns", 0, 0, 10, q, s)) != NULL,
+ "mongo_wire_cmd_query() works with a NULL selector");
+
+ mongo_wire_packet_get_header (p, &hdr);
+ cmp_ok ((data_size = mongo_wire_packet_get_data (p, &data)), "!=", -1,
+ "Packet data size looks fine");
+ cmp_ok (hdr.length, "==", sizeof (mongo_packet_header) + data_size,
+ "Packet header length is OK");
+ cmp_ok (hdr.id, "==", 1, "Packet request ID is ok");
+ cmp_ok (hdr.resp_to, "==", 0, "Packet reply ID is ok");
+
+ /* pos = zero + collection_name + NULL + skip + ret */
+ pos = sizeof (gint32) + strlen ("test.ns") + 1 + sizeof (gint32) * 2;
+ ok ((tmp = bson_new_from_data (data + pos,
+ bson_stream_doc_size (data, pos) - 1)) != NULL,
+ "Packet contains a valid BSON query document");
+ bson_finish (tmp);
+ pos += bson_size (tmp);
+ bson_free (tmp);
+ bson_free (q);
+ bson_free (s);
+
+ ok ((s = bson_new_from_data (data + pos,
+ bson_stream_doc_size (data, pos) - 1)) != NULL,
+ "Packet contains a valid BSON selector document");
+ bson_finish (s);
+
+ ok ((c = bson_find (s, "_id")) != NULL,
+ "BSON contains '_id'");
+ cmp_ok (bson_cursor_type (c), "==", BSON_TYPE_BOOLEAN,
+ "_id has correct type");
+ bson_cursor_next (c);
+ cmp_ok (bson_cursor_type (c), "==", BSON_TYPE_BOOLEAN,
+ "next element has correct type too");
+
+ bson_cursor_free (c);
+ bson_free (s);
+ mongo_wire_packet_free (p);
+}
+
+RUN_TEST (25, mongo_wire_cmd_query);
diff --git a/tests/unit/mongo/wire/cmd_update.c b/tests/unit/mongo/wire/cmd_update.c
new file mode 100644
index 0000000..95a2a50
--- /dev/null
+++ b/tests/unit/mongo/wire/cmd_update.c
@@ -0,0 +1,97 @@
+#include "test.h"
+#include "tap.h"
+#include "mongo-wire.h"
+
+#include <string.h>
+
+void
+test_mongo_wire_cmd_update (void)
+{
+ bson *sel, *upd, *tmp;
+ mongo_packet *p;
+
+ mongo_packet_header hdr;
+ const guint8 *data;
+ gint32 data_size;
+
+ bson_cursor *c;
+ gint32 pos;
+
+ sel = bson_new ();
+ bson_append_null (sel, "_id");
+ bson_finish (sel);
+
+ upd = test_bson_generate_full ();
+
+ ok (mongo_wire_cmd_update (1, NULL, 0, sel, upd) == NULL,
+ "mongo_wire_cmd_update() with a NULL namespace should fail");
+ ok (mongo_wire_cmd_update (1, "test.ns", 0, NULL, upd) == NULL,
+ "mongo_wire_cmd_update() with a NULL selector should fail");
+ ok (mongo_wire_cmd_update (1, "test.ns", 0, sel, NULL) == NULL,
+ "mongo_wire_cmd_update() with a NULL update should fail");
+
+ tmp = bson_new ();
+ ok (mongo_wire_cmd_update (1, "test.ns", 0, tmp, upd) == NULL,
+ "mongo_wire_cmd_update() fails with an unfinished selector");
+ ok (mongo_wire_cmd_update (1, "test.ns", 0, sel, tmp) == NULL,
+ "mongo_wire_cmd_update() fails with an unfinished update");
+ bson_free (tmp);
+
+ ok ((p = mongo_wire_cmd_update (1, "test.ns", 0, sel, upd)) != NULL,
+ "mongo_wire_cmd_update() works");
+
+ bson_free (sel);
+
+ mongo_wire_packet_get_header (p, &hdr);
+ cmp_ok ((data_size = mongo_wire_packet_get_data (p, &data)), "!=", -1,
+ "Packet data size looks fine");
+ cmp_ok (hdr.length, "==", sizeof (mongo_packet_header) + data_size,
+ "Packet header length is OK");
+ cmp_ok (hdr.id, "==", 1, "Packet request ID is ok");
+ cmp_ok (hdr.resp_to, "==", 0, "Packet reply ID is ok");
+
+ /*
+ * Verify the selector object.
+ */
+
+ /* pos = zero + collection_name + NULL + flags */
+ pos = sizeof (gint32) + strlen ("test.ns") + 1 + sizeof (gint32);
+ ok ((sel = bson_new_from_data (data + pos, (gint32)data[pos] - 1)) != NULL,
+ "Packet contains a valid BSON selector document");
+ bson_finish (sel);
+
+ ok ((c = bson_find (sel, "_id")) != NULL,
+ "BSON contains an _id");
+ cmp_ok (bson_cursor_type (c), "==", BSON_TYPE_NULL,
+ "_id has correct type");
+ bson_cursor_free (c);
+ bson_free (sel);
+
+ /*
+ * Verify the update object
+ */
+ pos += (gint32)data[pos];
+ ok ((tmp = bson_new_from_data (data + pos,
+ bson_stream_doc_size (data, pos) - 1)) != NULL,
+ "Packet contains a valid BSON update document");
+ bson_finish (tmp);
+ cmp_ok (bson_size (upd), "==", bson_size (tmp),
+ "Packet's update document has the correct size");
+
+ ok ((c = bson_find (tmp, "int32")) != NULL,
+ "BSON contains 'int32'");
+ cmp_ok (bson_cursor_type (c), "==", BSON_TYPE_INT32,
+ "int32 has correct type");
+ bson_cursor_next (c);
+ cmp_ok (bson_cursor_type (c), "==", BSON_TYPE_INT64,
+ "next element has correct type too");
+ ok (bson_cursor_next (c) == FALSE,
+ "No more data after the update BSON object");
+
+ bson_cursor_free (c);
+ bson_free (tmp);
+ bson_free (upd);
+ mongo_wire_packet_free (p);
+}
+
+RUN_TEST (19, mongo_wire_cmd_update);
diff --git a/tests/unit/mongo/wire/packet_get_set_data.c b/tests/unit/mongo/wire/packet_get_set_data.c
new file mode 100644
index 0000000..2f06b8f
--- /dev/null
+++ b/tests/unit/mongo/wire/packet_get_set_data.c
@@ -0,0 +1,65 @@
+#include "tap.h"
+#include "test.h"
+#include "mongo-wire.h"
+
+#include <string.h>
+
+void
+test_mongo_wire_packet_get_set_data (void)
+{
+ mongo_packet *p;
+ mongo_packet_header h;
+ guint8 data[32768];
+ const guint8 *idata;
+
+ p = mongo_wire_packet_new ();
+ memset (data, 'x', sizeof (data));
+
+ ok (mongo_wire_packet_get_data (NULL, &idata) == -1,
+ "mongo_wire_packet_get_data() with a NULL packet should fail");
+ ok (mongo_wire_packet_get_data (p, NULL) == -1,
+ "mongo_wire_packet_get_data() with NULL destination should fail");
+ ok (mongo_wire_packet_get_data (p, &idata) == -1,
+ "mongo_wire_packet_get_data() with an empty packet should fail");
+ ok (mongo_wire_packet_set_data (NULL, (const guint8 *)&data,
+ sizeof (data)) == FALSE,
+ "mongo_wire_packet_set_data() with a NULL packet should fail");
+ ok (mongo_wire_packet_set_data (p, NULL, sizeof (data)) == FALSE,
+ "mongo_wire_packet_set_data() with NULL data should fail");
+ ok (mongo_wire_packet_set_data (p, (const guint8 *)&data, 0) == FALSE,
+ "mongo_wire_packet_set_data() with zero size should fail");
+ ok (mongo_wire_packet_set_data (p, (const guint8 *)&data, -1) == FALSE,
+ "mongo_wire_packet_set_data() with negative size should fail");
+
+ ok (mongo_wire_packet_set_data (p, (const guint8 *)&data,
+ sizeof (data)),
+ "mongo_wire_packet_set_data() works");
+ cmp_ok (mongo_wire_packet_get_data (p, &idata), "==", sizeof (data),
+ "mongo_wire_packet_get_data() works");
+
+ mongo_wire_packet_get_header (p, &h);
+
+ cmp_ok (h.length, "==", sizeof (data) + sizeof (mongo_packet_header),
+ "Packet length is updated properly");
+ ok (memcmp (data, idata, sizeof (data)) == 0,
+ "Setting & retrieving data works");
+
+ memset (data, 'a', sizeof (data));
+
+ ok (mongo_wire_packet_set_data (p, (const guint8 *)&data,
+ sizeof (data) / 2),
+ "Re-setting the data works");
+ cmp_ok (mongo_wire_packet_get_data (p, &idata), "==", sizeof (data) / 2,
+ "Retrieving the data works still");
+
+ mongo_wire_packet_get_header (p, &h);
+
+ cmp_ok (h.length, "==", sizeof (data) / 2 + sizeof (mongo_packet_header),
+ "Packet length is updated properly");
+ ok (memcmp (data, idata, sizeof (data) / 2) == 0,
+ "Setting & retrieving data works");
+
+ mongo_wire_packet_free (p);
+}
+
+RUN_TEST (15, mongo_wire_packet_get_set_data);
diff --git a/tests/unit/mongo/wire/packet_get_set_header.c b/tests/unit/mongo/wire/packet_get_set_header.c
new file mode 100644
index 0000000..38e0ea7
--- /dev/null
+++ b/tests/unit/mongo/wire/packet_get_set_header.c
@@ -0,0 +1,58 @@
+#include "tap.h"
+#include "test.h"
+#include "mongo-wire.h"
+
+#include <string.h>
+
+void
+test_mongo_wire_packet_get_set_header (void)
+{
+ mongo_packet *p;
+ mongo_packet_header ph1, ph2;
+
+ p = mongo_wire_packet_new ();
+
+ ok (mongo_wire_packet_get_header (NULL, &ph2) == FALSE,
+ "mongo_wire_packet_get_header() should fail with a NULL packet");
+ ok (mongo_wire_packet_get_header (p, NULL) == FALSE,
+ "mongo_wire_packet_get_header() should fail with a NULL header");
+ ok (mongo_wire_packet_set_header (NULL, &ph1) == FALSE,
+ "mongo_wire_packet_set_header() should fail with a NULL packet");
+ ok (mongo_wire_packet_set_header (p, NULL) == FALSE,
+ "mongo_wire_packet_set_header() should fail with a NULL header");
+
+ ok (mongo_wire_packet_get_header (p, &ph2),
+ "mongo_wire_packet_get_header() works on a fresh packet");
+ cmp_ok (ph2.length, "==", sizeof (mongo_packet_header),
+ "Initial packet length is the length of the header");
+
+ ph1.length = sizeof (mongo_packet_header);
+ ph1.id = 1;
+ ph1.resp_to = 0;
+ ph1.opcode = 1000;
+
+ memset (&ph2, 0, sizeof (mongo_packet_header));
+
+ ok (mongo_wire_packet_set_header (p, &ph1),
+ "mongo_wire_packet_set_header() works");
+ ok (mongo_wire_packet_get_header (p, &ph2),
+ "mongo_wire_packet_get_header() works");
+
+ cmp_ok (ph1.length, "==", ph2.length,
+ "Packet lengths match");
+ cmp_ok (ph1.id, "==", ph2.id,
+ "Sequence IDs match");
+ cmp_ok (ph1.resp_to, "==", ph2.resp_to,
+ "Response IDs match");
+ cmp_ok (ph1.opcode, "==", ph2.opcode,
+ "OPCodes match");
+
+ ph1.length = GINT32_TO_LE (1);
+ ok (mongo_wire_packet_set_header (p, &ph1) == FALSE,
+ "Setting a packet with length shorter than the header "
+ "returns an error");
+
+ mongo_wire_packet_free (p);
+}
+
+RUN_TEST (13, mongo_wire_packet_get_set_header);
diff --git a/tests/unit/mongo/wire/packet_get_set_header_raw.c b/tests/unit/mongo/wire/packet_get_set_header_raw.c
new file mode 100644
index 0000000..d97a8b3
--- /dev/null
+++ b/tests/unit/mongo/wire/packet_get_set_header_raw.c
@@ -0,0 +1,56 @@
+#include "tap.h"
+#include "test.h"
+#include "mongo-wire.h"
+
+#include "libmongo-private.h"
+
+#include <string.h>
+
+void
+test_mongo_wire_packet_get_set_header_raw (void)
+{
+ mongo_packet *p;
+ mongo_packet_header ph1, ph2;
+
+ p = mongo_wire_packet_new ();
+
+ ok (mongo_wire_packet_get_header_raw (NULL, &ph2) == FALSE,
+ "mongo_wire_packet_get_header_raw() should fail with a NULL packet");
+ ok (mongo_wire_packet_get_header_raw (p, NULL) == FALSE,
+ "mongo_wire_packet_get_header_raw() should fail with a NULL header");
+ ok (mongo_wire_packet_set_header_raw (NULL, &ph1) == FALSE,
+ "mongo_wire_packet_set_header_raw() should fail with a NULL packet");
+ ok (mongo_wire_packet_set_header_raw (p, NULL) == FALSE,
+ "mongo_wire_packet_set_header_raw() should fail with a NULL header");
+
+ ok (mongo_wire_packet_get_header_raw (p, &ph2),
+ "mongo_wire_packet_get_header_raw() works on a fresh packet");
+ /* Need to convert from LE, because _new() sets the length to LE. */
+ cmp_ok (GINT32_FROM_LE (ph2.length), "==", sizeof (mongo_packet_header),
+ "Initial packet length is the length of the header");
+
+ ph1.length = sizeof (mongo_packet_header);
+ ph1.id = 1;
+ ph1.resp_to = 0;
+ ph1.opcode = 1000;
+
+ memset (&ph2, 0, sizeof (mongo_packet_header));
+
+ ok (mongo_wire_packet_set_header_raw (p, &ph1),
+ "mongo_wire_packet_set_header_raw() works");
+ ok (mongo_wire_packet_get_header_raw (p, &ph2),
+ "mongo_wire_packet_get_header_raw() works");
+
+ cmp_ok (ph1.length, "==", ph2.length,
+ "Packet lengths match");
+ cmp_ok (ph1.id, "==", ph2.id,
+ "Sequence IDs match");
+ cmp_ok (ph1.resp_to, "==", ph2.resp_to,
+ "Response IDs match");
+ cmp_ok (ph1.opcode, "==", ph2.opcode,
+ "OPCodes match");
+
+ mongo_wire_packet_free (p);
+}
+
+RUN_TEST (12, mongo_wire_packet_get_set_header_raw);
diff --git a/tests/unit/mongo/wire/packet_new.c b/tests/unit/mongo/wire/packet_new.c
new file mode 100644
index 0000000..4940542
--- /dev/null
+++ b/tests/unit/mongo/wire/packet_new.c
@@ -0,0 +1,20 @@
+#include "tap.h"
+#include "test.h"
+#include "mongo-wire.h"
+
+#include <string.h>
+
+void
+test_mongo_wire_packet_new (void)
+{
+ mongo_packet *p;
+
+ ok ((p = mongo_wire_packet_new ()) != NULL,
+ "mongo_wire_packet_new() works");
+ mongo_wire_packet_free (NULL);
+ pass ("mongo_wire_packet_free(NULL) works");
+ mongo_wire_packet_free (p);
+ pass ("mongo_wire_packet_free() works");
+}
+
+RUN_TEST (3, mongo_wire_packet_new);
diff --git a/tests/unit/mongo/wire/reply_packet_get_data.c b/tests/unit/mongo/wire/reply_packet_get_data.c
new file mode 100644
index 0000000..e22f142
--- /dev/null
+++ b/tests/unit/mongo/wire/reply_packet_get_data.c
@@ -0,0 +1,52 @@
+#include "test.h"
+#include "tap.h"
+#include "bson.h"
+#include "mongo-wire.h"
+
+#include <string.h>
+
+void
+test_mongo_wire_reply_packet_get_data (void)
+{
+ mongo_packet *p;
+ mongo_packet_header h;
+ const guint8 *data;
+ bson *b;
+
+ p = mongo_wire_packet_new ();
+ memset (&h, 0, sizeof (mongo_packet_header));
+ h.opcode = 0;
+ h.length = sizeof (mongo_packet_header);
+ mongo_wire_packet_set_header (p, &h);
+
+ ok (mongo_wire_reply_packet_get_data (NULL, &data) == FALSE,
+ "mongo_wire_reply_packet_get_data() fails with a NULL packet");
+ ok (mongo_wire_reply_packet_get_data (p, NULL) == FALSE,
+ "mongo_wire_reply_packet_get_data() fails with a NULL destination");
+ ok (mongo_wire_reply_packet_get_data (p, &data) == FALSE,
+ "mongo_wire_reply_packet_get_data() fails with a non-reply packet");
+
+ h.opcode = 1;
+ mongo_wire_packet_set_header (p, &h);
+
+ ok (mongo_wire_reply_packet_get_data (p, &data) == FALSE,
+ "mongo_wire_reply_packet_get_data() fails if the packet has "
+ "no data");
+
+ mongo_wire_packet_free (p);
+
+ p = test_mongo_wire_generate_reply (TRUE, 2, TRUE);
+
+ ok (mongo_wire_reply_packet_get_data (p, &data),
+ "mongo_wire_reply_packet_get_data() works");
+
+ b = test_bson_generate_full ();
+
+ ok (memcmp (data, bson_data (b), bson_size (b)) == 0,
+ "The returned data is correct");
+
+ bson_free (b);
+ mongo_wire_packet_free (p);
+}
+
+RUN_TEST (6, mongo_wire_reply_packet_get_data);
diff --git a/tests/unit/mongo/wire/reply_packet_get_header.c b/tests/unit/mongo/wire/reply_packet_get_header.c
new file mode 100644
index 0000000..36b548c
--- /dev/null
+++ b/tests/unit/mongo/wire/reply_packet_get_header.c
@@ -0,0 +1,54 @@
+#include "test.h"
+#include "tap.h"
+#include "mongo-wire.h"
+
+#include <string.h>
+
+void
+test_mongo_wire_reply_packet_get_header (void)
+{
+ mongo_packet *p;
+ mongo_packet_header h;
+ mongo_reply_packet_header rh;
+
+ p = mongo_wire_packet_new ();
+ memset (&h, 0, sizeof (mongo_packet_header));
+ h.opcode = 1;
+ h.length = sizeof (mongo_packet_header);
+
+ mongo_wire_packet_set_header (p, &h);
+
+ ok (mongo_wire_reply_packet_get_header (NULL, &rh) == FALSE,
+ "mongo_wire_reply_packet_get_header() fails with a NULL packet");
+ ok (mongo_wire_reply_packet_get_header (p, NULL) == FALSE,
+ "mongo_wire_reply_packet_get_header() fails with a NULL header");
+
+ ok (mongo_wire_reply_packet_get_header (p, &rh) == FALSE,
+ "mongo_wire_reply_packet_get_header() fails if the packet has "
+ "no reply header");
+
+ h.opcode = 2;
+ mongo_wire_packet_set_header (p, &h);
+ ok (mongo_wire_reply_packet_get_header (p, &rh) == FALSE,
+ "mongo_wire_reply_packet_get_header() fails if the packet is "
+ "not a reply packet");
+
+ mongo_wire_packet_free (p);
+
+ p = test_mongo_wire_generate_reply (TRUE, 0, FALSE);
+
+ ok (mongo_wire_reply_packet_get_header (p, &rh),
+ "mongo_wire_reply_packet_get_header() works");
+ cmp_ok (rh.flags, "==", 0,
+ "Reply flags are correct");
+ ok (rh.cursor_id == (gint64)12345,
+ "Cursor ID is correct");
+ cmp_ok (rh.start, "==", 0,
+ "Reply start document is OK");
+ cmp_ok (rh.returned, "==", 0,
+ "Number of documents returned is OK");
+
+ mongo_wire_packet_free (p);
+}
+
+RUN_TEST (9, mongo_wire_reply_packet_get_header);
diff --git a/tests/unit/mongo/wire/reply_packet_get_nth_document.c b/tests/unit/mongo/wire/reply_packet_get_nth_document.c
new file mode 100644
index 0000000..68d9fed
--- /dev/null
+++ b/tests/unit/mongo/wire/reply_packet_get_nth_document.c
@@ -0,0 +1,68 @@
+#include "test.h"
+#include "tap.h"
+#include "mongo-wire.h"
+#include "bson.h"
+
+#include <string.h>
+
+void
+test_mongo_wire_reply_packet_get_nth_document (void)
+{
+ mongo_packet *p;
+ bson *b, *doc;
+ mongo_packet_header h;
+
+ p = mongo_wire_packet_new ();
+ memset (&h, 0, sizeof (mongo_packet_header));
+ h.opcode = 2;
+ h.length = sizeof (mongo_packet_header);
+ mongo_wire_packet_set_header (p, &h);
+
+ ok (mongo_wire_reply_packet_get_nth_document (NULL, 1, &doc) == FALSE,
+ "mongo_wire_reply_packet_get_nth_document() fails with a NULL packet");
+ ok (mongo_wire_reply_packet_get_nth_document (p, 0, &doc) == FALSE,
+ "mongo_wire_reply_packet_get_nth_document() fails with n = 0");
+ ok (mongo_wire_reply_packet_get_nth_document (p, -42, &doc) == FALSE,
+ "mongo_wire_reply_packet_get_nth_document() fails with n < 0");
+ ok (mongo_wire_reply_packet_get_nth_document (p, 1, NULL) == FALSE,
+ "mongo_wire_reply_packet_get_nth_document() fails with a NULL "
+ "destination");
+
+ ok (mongo_wire_reply_packet_get_nth_document (p, 1, &doc) == FALSE,
+ "mongo_wire_reply_packet_get_nth_document() fails with a "
+ "non-reply packet");
+
+ h.opcode = 1;
+ mongo_wire_packet_set_header (p, &h);
+
+ ok (mongo_wire_reply_packet_get_nth_document (p, 1, &doc) == FALSE,
+ "mongo_wire_reply_packet_get_nth_document() fails with an "
+ "incomplete reply packet");
+
+ mongo_wire_packet_free (p);
+
+ p = test_mongo_wire_generate_reply (TRUE, 0, FALSE);
+ ok (mongo_wire_reply_packet_get_nth_document (p, 1, &doc) == FALSE,
+ "mongo_wire_reply_packet_get_nth_document() fails if there are "
+ "no documents to return");
+ mongo_wire_packet_free (p);
+
+ p = test_mongo_wire_generate_reply (TRUE, 2, TRUE);
+ ok (mongo_wire_reply_packet_get_nth_document (p, 2, &doc),
+ "mongo_wire_reply_packet_get_nth_document() works");
+ b = test_bson_generate_full ();
+ bson_finish (doc);
+
+ ok (memcmp (bson_data (b), bson_data (doc), bson_size (doc)) == 0,
+ "Returned document is correct");
+ bson_free (doc);
+ bson_free (b);
+
+ ok (mongo_wire_reply_packet_get_nth_document (p, 3, &doc) == FALSE,
+ "mongo_wire_reply_packet_get_nth_document() fails if the requested "
+ "document does not exist");
+
+ mongo_wire_packet_free (p);
+}
+
+RUN_TEST (10, mongo_wire_reply_packet_get_nth_document);