diff options
Diffstat (limited to 'tests')
166 files changed, 11047 insertions, 0 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am new file mode 100644 index 0000000..b6328e0 --- /dev/null +++ b/tests/Makefile.am @@ -0,0 +1,241 @@ +SUBDIRS = libtap + +bson_unit_tests = \ + unit/bson/bson_new \ + unit/bson/bson_empty \ + unit/bson/bson_validate_key \ + \ + unit/bson/bson_append_string \ + unit/bson/bson_append_double \ + unit/bson/bson_append_boolean \ + unit/bson/bson_append_utc_datetime \ + unit/bson/bson_append_null \ + unit/bson/bson_append_int32 \ + unit/bson/bson_append_int64 \ + unit/bson/bson_append_regexp \ + unit/bson/bson_append_binary \ + unit/bson/bson_append_js_code \ + unit/bson/bson_append_symbol \ + unit/bson/bson_append_js_code_w_scope \ + unit/bson/bson_append_timestamp \ + unit/bson/bson_append_oid \ + unit/bson/bson_append_document \ + unit/bson/bson_append_array \ + \ + unit/bson/bson_reset \ + unit/bson/bson_new_from_data \ + \ + unit/bson/bson_build \ + unit/bson/bson_build_full \ + \ + unit/bson/bson_type_as_string \ + \ + unit/bson/bson_cursor_new \ + unit/bson/bson_find \ + unit/bson/bson_cursor_next \ + unit/bson/bson_cursor_find_next \ + unit/bson/bson_cursor_find \ + unit/bson/bson_cursor_type \ + unit/bson/bson_cursor_type_as_string \ + unit/bson/bson_cursor_key \ + \ + unit/bson/bson_cursor_get_string \ + unit/bson/bson_cursor_get_double \ + unit/bson/bson_cursor_get_document \ + unit/bson/bson_cursor_get_array \ + unit/bson/bson_cursor_get_binary \ + unit/bson/bson_cursor_get_oid \ + unit/bson/bson_cursor_get_boolean \ + unit/bson/bson_cursor_get_utc_datetime \ + unit/bson/bson_cursor_get_regex \ + unit/bson/bson_cursor_get_javascript \ + unit/bson/bson_cursor_get_symbol \ + unit/bson/bson_cursor_get_javascript_w_scope \ + unit/bson/bson_cursor_get_int32 \ + unit/bson/bson_cursor_get_timestamp \ + unit/bson/bson_cursor_get_int64 + +bson_func_tests = \ + func/bson/huge_doc \ + func/bson/f_weird_types + +bson_perf_tests = \ + perf/bson/p_bson_find + +mongo_utils_unit_tests = \ + unit/mongo/utils/oid_init \ + unit/mongo/utils/oid_new \ + unit/mongo/utils/oid_new_with_time \ + unit/mongo/utils/oid_as_string \ + unit/mongo/utils/parse_addr + +mongo_wire_unit_tests = \ + unit/mongo/wire/packet_new \ + unit/mongo/wire/packet_get_set_header \ + unit/mongo/wire/packet_get_set_header_raw \ + unit/mongo/wire/packet_get_set_data \ + \ + unit/mongo/wire/reply_packet_get_header \ + unit/mongo/wire/reply_packet_get_data \ + unit/mongo/wire/reply_packet_get_nth_document \ + \ + unit/mongo/wire/cmd_update \ + unit/mongo/wire/cmd_insert \ + unit/mongo/wire/cmd_insert_n \ + unit/mongo/wire/cmd_query \ + unit/mongo/wire/cmd_get_more \ + unit/mongo/wire/cmd_delete \ + unit/mongo/wire/cmd_kill_cursors \ + unit/mongo/wire/cmd_custom + +mongo_client_unit_tests = \ + unit/mongo/client/connect \ + unit/mongo/client/disconnect \ + unit/mongo/client/packet_send \ + unit/mongo/client/packet_recv \ + unit/mongo/client/connection_set_timeout \ + unit/mongo/client/connection_get_requestid + +mongo_client_func_tests = \ + func/mongo/client/f_client_big_packet + +mongo_sync_unit_tests = \ + unit/mongo/sync/sync_connect \ + unit/mongo/sync/sync_connect_cache \ + unit/mongo/sync/sync_conn_seed_add \ + unit/mongo/sync/sync_conn_seed_add_cache \ + unit/mongo/sync/sync_reconnect \ + unit/mongo/sync/sync_disconnect \ + unit/mongo/sync/sync_get_set_auto_reconnect \ + unit/mongo/sync/sync_get_set_safe_mode \ + unit/mongo/sync/sync_get_set_slaveok \ + unit/mongo/sync/sync_get_set_max_insert_size \ + unit/mongo/sync/sync_cmd_update \ + unit/mongo/sync/sync_cmd_insert \ + unit/mongo/sync/sync_cmd_insert_n \ + unit/mongo/sync/sync_cmd_query \ + unit/mongo/sync/sync_cmd_get_more \ + unit/mongo/sync/sync_cmd_delete \ + unit/mongo/sync/sync_cmd_kill_cursors \ + unit/mongo/sync/sync_cmd_custom \ + unit/mongo/sync/sync_cmd_count \ + unit/mongo/sync/sync_cmd_create \ + unit/mongo/sync/sync_cmd_exists \ + unit/mongo/sync/sync_cmd_drop \ + unit/mongo/sync/sync_cmd_get_last_error \ + unit/mongo/sync/sync_cmd_get_last_error_full \ + unit/mongo/sync/sync_cmd_reset_error \ + unit/mongo/sync/sync_cmd_is_master \ + unit/mongo/sync/sync_cmd_ping \ + unit/mongo/sync/sync_cmd_user_add \ + unit/mongo/sync/sync_cmd_user_add_with_roles \ + unit/mongo/sync/sync_cmd_user_remove \ + unit/mongo/sync/sync_cmd_authenticate \ + unit/mongo/sync/sync_cmd_authenticate_cache \ + unit/mongo/sync/sync_cmd_index_create \ + unit/mongo/sync/sync_cmd_index_drop \ + unit/mongo/sync/sync_cmd_index_drop_all \ + unit/mongo/sync/sync_connect_from_cache_enforce_primary + +mongo_sync_func_tests = \ + func/mongo/sync/f_sync_max_insert_size \ + func/mongo/sync/f_sync_conn_seed_add \ + func/mongo/sync/f_sync_safe_mode \ + func/mongo/sync/f_sync_safe_mode_cache \ + func/mongo/sync/f_sync_auto_reconnect \ + func/mongo/sync/f_sync_auto_reconnect_cache \ + func/mongo/sync/f_sync_oidtest \ + func/mongo/sync/f_sync_auto_reauth \ + func/mongo/sync/f_sync_invalid_getlasterror \ + func/mongo/sync/f_sync_write_error + +mongo_sync_cursor_unit_tests = \ + unit/mongo/sync-cursor/sync_cursor_new \ + unit/mongo/sync-cursor/sync_cursor_next \ + unit/mongo/sync-cursor/sync_cursor_get_data \ + unit/mongo/sync-cursor/sync_cursor_free + +mongo_sync_cursor_func_tests = \ + func/mongo/sync-cursor/f_sync_cursor_iterate \ + func/mongo/sync-cursor/f_sync_cursor_tailable + +mongo_sync_pool_unit_tests = \ + unit/mongo/sync-pool/sync_pool_new \ + unit/mongo/sync-pool/sync_pool_free \ + unit/mongo/sync-pool/sync_pool_pick \ + unit/mongo/sync-pool/sync_pool_return + +mongo_sync_pool_func_tests = \ + func/mongo/sync-pool/f_sync_pool + +mongo_sync_gridfs_unit_tests = \ + unit/mongo/sync-gridfs/sync_gridfs_new \ + unit/mongo/sync-gridfs/sync_gridfs_free \ + unit/mongo/sync-gridfs/sync_gridfs_get_set_chunk_size \ + unit/mongo/sync-gridfs/sync_gridfs_list \ + unit/mongo/sync-gridfs/sync_gridfs_remove \ + unit/mongo/sync-gridfs/sync_gridfs_file_get_metadata + +mongo_sync_gridfs_chunk_unit_tests = \ + unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_find \ + unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_new_from_buffer \ + unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_free \ + unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_cursor_new \ + unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_cursor_get_chunk + +mongo_sync_gridfs_chunk_func_tests = \ + func/mongo/sync-gridfs-chunk/f_sync_gridfs_chunk + +mongo_sync_gridfs_stream_unit_tests = \ + unit/mongo/sync-gridfs-stream/sync_gridfs_stream_find \ + unit/mongo/sync-gridfs-stream/sync_gridfs_stream_new \ + unit/mongo/sync-gridfs-stream/sync_gridfs_stream_read \ + unit/mongo/sync-gridfs-stream/sync_gridfs_stream_write \ + unit/mongo/sync-gridfs-stream/sync_gridfs_stream_seek \ + unit/mongo/sync-gridfs-stream/sync_gridfs_stream_close + +mongo_sync_gridfs_stream_func_tests = \ + func/mongo/sync-gridfs-stream/f_sync_gridfs_stream + +UNIT_TESTS = ${bson_unit_tests} ${mongo_utils_unit_tests} \ + ${mongo_wire_unit_tests} ${mongo_client_unit_tests} \ + ${mongo_sync_unit_tests} ${mongo_sync_cursor_unit_tests} \ + ${mongo_sync_pool_unit_tests} ${mongo_sync_gridfs_unit_tests} \ + ${mongo_sync_gridfs_chunk_unit_tests} \ + ${mongo_sync_gridfs_stream_unit_tests} +FUNC_TESTS = ${bson_func_tests} ${mongo_sync_func_tests} \ + ${mongo_client_func_tests} \ + ${mongo_sync_cursor_func_tests} ${mongo_sync_pool_func_tests} \ + ${mongo_sync_gridfs_func_tests} \ + ${mongo_sync_gridfs_chunk_func_tests} \ + ${mongo_sync_gridfs_stream_func_tests} +PERF_TESTS = ${bson_perf_tests} +TESTCASES = ${UNIT_TESTS} ${FUNC_TESTS} ${PERF_TESTS} + +check_PROGRAMS = ${TESTCASES} test_cleanup + +AM_CFLAGS = -I$(top_srcdir)/src/ -I${top_srcdir}/tests/libtap/ @GLIB_CFLAGS@ +AM_LDFLAGS = -no-install +LDADD = $(top_builddir)/src/libmongo-client.la ${top_builddir}/tests/libtap/libtap.la @GLIB_LIBS@ + +EXTRA_DIST = README \ + runall \ + coverage.sh \ + tools/coverage-report-entry.pl tools/coverage-report.pl \ + tools/coverage-report.xsl + +PROVE = prove -e "${PROVE_ENV}" ${PROVE_OPTIONS} + +check-%: BASE=$(subst -,_,$(subst check-,,$@)) +check-%: TESTCASES=$(value $(BASE)_unit_tests) $(value $(BASE)_func_tests) $(value $(BASE)_tests) +check-%: check-recursive test_cleanup ${TESTCASES} + $(AM_V_at) ${builddir}/test_cleanup + $(AM_V_GEN) srcdir=${srcdir} ${PROVE} ${TESTCASES} + $(AM_V_at) ${builddir}/test_cleanup + +check: check-recursive test_cleanup ${TESTCASES} + $(AM_V_at) ${builddir}/test_cleanup + $(AM_V_GEN) srcdir=${srcdir} ${PROVE} ${TESTCASES} + $(AM_V_at) ${builddir}/test_cleanup + +.PHONY: check diff --git a/tests/README b/tests/README new file mode 100644 index 0000000..f8a2c08 --- /dev/null +++ b/tests/README @@ -0,0 +1,28 @@ +About the test suite -*- org -*- +==================== + +The test suite has two parts: the basic tests, which do not require +anything outside of this library, and networked tests, which require a +certain network setup if one wants to run them all. + +The basic tests are run as part of `make check', while to run the +network tests, one must do a few other things, after which the +networked tests will be run aswell: + +* Set up a mongodb server, and set up variables for the test suite + +One must set the `TEST_PRIMARY' variable to the "IP:PORT" of the +mongodb server. + +For example, assuming a bourne shell: + + $ TEST_PRIMARY="127.0.0.1:27017"; export TEST_PRIMARY + +* To test replica sets, point the test suite to a secondary node + +First of all, one will need to set up a Replica Set (see the mongodb +documentation for examples and a tutorial), and point the test suite +to a *secondary* node by setting the `TEST_SECONDARY' environment +variable: + + $ TEST_SECONDARY="127.0.0.1:27018"; export TEST_SECONDARY diff --git a/tests/coverage.sh b/tests/coverage.sh new file mode 100755 index 0000000..f3a32f4 --- /dev/null +++ b/tests/coverage.sh @@ -0,0 +1,43 @@ +#! /bin/sh + +install -d coverage +rm -f coverage/report.txt + +for src in ${SOURCES}; do + case "$src" in + *.c) + obj=`echo $src | sed 's|\.c|.o|'` + gc=`echo $src | sed 's|\.c|.gcno|'` + if test -f "${builddir}/.libs/libmongo_client_la-$obj"; then + objdir=${builddir}/.libs + else + objdir=${builddir} + fi + if ! test -f "${objdir}/libmongo_client_la-${gc}"; then + continue + fi + gcov -b -f ${srcdir}/$src -o $objdir/libmongo_client_la-$obj >coverage/$src.cov + ;; + esac +done + +perl ${top_srcdir}/tests/tools/coverage-report.pl coverage/*.cov >coverage/index.xml +xsltproc ${top_srcdir}/tests/tools/coverage-report.xsl coverage/index.xml >coverage/index.html + +for src in ${SOURCES}; do + case "$src" in + *.c) + if ! test -f "${src}.gcov"; then + continue + fi + + perl ${top_srcdir}/tests/tools/coverage-report-entry.pl ${src}.gcov > coverage/${src}.gcov.html + grep -A4 -m 1 "File '${srcdir}/$src'" coverage/$src.cov | grep -v "^--" >>coverage/report.txt + echo >>coverage/report.txt + ;; + esac +done + +coverage=`(echo "scale=2"; echo -n "("; echo -n $(grep "Lines executed" coverage/report.txt | cut -d: -f2 | cut -d "%" -f 1) | sed -e "s, , + ,g"; echo ") / " $(grep -c "Lines executed" coverage/report.txt)) | bc -q` +lines=`(echo -n "("; echo -n $(grep "Lines executed" coverage/report.txt | cut -d% -f2- | cut -d " " -f3-) | sed -e "s, , + ,g"; echo ")") | bc -q` +echo "Overall coverage: $coverage% of $lines source lines" >>coverage/report.txt diff --git a/tests/func/bson/f_weird_types.c b/tests/func/bson/f_weird_types.c new file mode 100644 index 0000000..100db8c --- /dev/null +++ b/tests/func/bson/f_weird_types.c @@ -0,0 +1,71 @@ +#include "bson.h" +#include "tap.h" +#include "test.h" + +#include "libmongo-private.h" + +#include <string.h> + +static void +test_func_weird_types (void) +{ + bson *b; + bson_cursor *c; + guint8 type = BSON_TYPE_DBPOINTER; + gint32 slen; + + b = bson_new (); + bson_append_int32 (b, "int32", 42); + + /* Append weird stuff */ + b->data = g_byte_array_append (b->data, (const guint8 *)&type, sizeof (type)); + b->data = g_byte_array_append (b->data, (const guint8 *)"dbpointer", + strlen ("dbpointer") + 1); + slen = GINT32_TO_LE (strlen ("refname") + 1); + b->data = g_byte_array_append (b->data, (const guint8 *)&slen, sizeof (gint32)); + b->data = g_byte_array_append (b->data, (const guint8 *)"refname", + strlen ("refname") + 1); + b->data = g_byte_array_append (b->data, (const guint8 *)"0123456789ABCDEF", + 12); + + bson_append_boolean (b, "Here be dragons?", TRUE); + bson_finish (b); + + c = bson_find (b, "Here be dragons?"); + ok (c != NULL, + "bson_find() can find elements past unsupported BSON types"); + bson_cursor_free (c); + bson_free (b); + + /* Now do it again, but append a type we can't iterate over */ + b = bson_new (); + bson_append_int32 (b, "int32", 42); + + /* Append BSON_TYPE_NONE */ + type = BSON_TYPE_NONE; + b->data = g_byte_array_append (b->data, (const guint8 *)&type, sizeof (type)); + b->data = g_byte_array_append (b->data, (const guint8 *)"dbpointer", + strlen ("dbpointer") + 1); + b->data = g_byte_array_append (b->data, (const guint8 *)"0123456789ABCDEF", + 12); + + bson_append_boolean (b, "Here be dragons?", TRUE); + bson_finish (b); + + c = bson_find (b, "Here be dragons?"); + ok (c == NULL, + "bson_find() should bail out when encountering an invalid element."); + bson_cursor_free (c); + + c = bson_cursor_new (b); + bson_cursor_next (c); /* This will find the first element, and + position us there. */ + bson_cursor_next (c); /* This positions after the first element. */ + ok (bson_cursor_next (c) == FALSE, + "bson_cursor_next() should bail out when encountering an invalid element."); + bson_cursor_free (c); + + bson_free (b); +} + +RUN_TEST (3, func_weird_types); diff --git a/tests/func/bson/huge_doc.c b/tests/func/bson/huge_doc.c new file mode 100644 index 0000000..d5daafe --- /dev/null +++ b/tests/func/bson/huge_doc.c @@ -0,0 +1,51 @@ +#include "bson.h" +#include "tap.h" +#include "test.h" + +#ifndef HUGE_DOC_SIZE +#define HUGE_DOC_SIZE (1024 * 1024) +#endif + +#include <string.h> + +static void +test_bson_huge_doc (void) +{ + bson *b, *s; + bson_cursor *c; + gchar *buffer; + gint32 ds1; + + buffer = (gchar *)g_malloc (HUGE_DOC_SIZE); + memset (buffer, 'a', HUGE_DOC_SIZE); + buffer[HUGE_DOC_SIZE - 1] = '\0'; + + b = bson_new (); + bson_append_int32 (b, "preamble", 1); + bson_append_string (b, "huge", buffer, -1); + bson_append_int32 (b, "post", 1234); + bson_finish (b); + ds1 = bson_size (b); + + g_free (buffer); + + s = bson_new (); + bson_append_document (s, "hugedoc", b); + bson_finish (s); + bson_free (b); + + cmp_ok (bson_size (s), ">", ds1, + "Document embedding another huge one, has bigger size"); + + c = bson_find (s, "hugedoc"); + bson_cursor_get_document (c, &b); + + cmp_ok (bson_size (b), "==", ds1, + "The embedded document has the correct, huge size"); + + bson_cursor_free (c); + bson_free (s); + bson_free (b); +} + +RUN_TEST (2, bson_huge_doc); diff --git a/tests/func/mongo/client/f_client_big_packet.c b/tests/func/mongo/client/f_client_big_packet.c new file mode 100644 index 0000000..38176ff --- /dev/null +++ b/tests/func/mongo/client/f_client_big_packet.c @@ -0,0 +1,57 @@ +#include "test.h" +#include "mongo.h" + +#define BIG_PACKET_SIZE 2 * 1024 * 1024 + +void +test_func_client_big_packet (void) +{ + mongo_connection *conn; + mongo_packet *p; + + guint8 *data; + bson *b; + gint32 exp_size; + + conn = mongo_connect (config.primary_host, config.primary_port); + + b = bson_new_sized (BIG_PACKET_SIZE + 1024); + data = g_malloc (BIG_PACKET_SIZE); + memset (data, 'z', BIG_PACKET_SIZE); + bson_append_boolean (b, "big_packet_size", TRUE); + bson_append_binary (b, "bighead", BSON_BINARY_SUBTYPE_GENERIC, + data, BIG_PACKET_SIZE); + bson_finish (b); + exp_size = bson_size (b); + + p = mongo_wire_cmd_insert (1, config.ns, b, NULL); + mongo_packet_send (conn, p); + bson_free (b); + mongo_wire_packet_free (p); + + b = bson_new (); + bson_append_boolean (b, "big_packet_size", TRUE); + bson_finish (b); + + p = mongo_wire_cmd_query (2, config.ns, 0, 0, 1, b, NULL); + mongo_packet_send (conn, p); + mongo_wire_packet_free (p); + bson_free (b); + + p = mongo_packet_recv (conn); + ok (p != NULL, + "mongo_packet_recv() works with a huge packet"); + + mongo_wire_reply_packet_get_nth_document (p, 1, &b); + bson_finish (b); + mongo_wire_packet_free (p); + + cmp_ok (exp_size + 17, "==", bson_size (b), /* +17: _id + value */ + "Huge packet receiving works, and returns a same sized packet"); + + bson_free (b); + + mongo_disconnect (conn); +} + +RUN_NET_TEST (2, func_client_big_packet); diff --git a/tests/func/mongo/sync-cursor/f_sync_cursor_iterate.c b/tests/func/mongo/sync-cursor/f_sync_cursor_iterate.c new file mode 100644 index 0000000..56ccb77 --- /dev/null +++ b/tests/func/mongo/sync-cursor/f_sync_cursor_iterate.c @@ -0,0 +1,88 @@ +#include "test.h" +#include <mongo.h> + +#include <errno.h> +#include <string.h> + +void +test_func_mongo_sync_cursor_iterate (void) +{ + mongo_sync_connection *conn; + bson *query, *result; + mongo_sync_cursor *sc; + bson_cursor *c; + gint i; + gint32 first_i32 = -1, last_i32 = -1, current_i32 = -1; + gboolean early_break = FALSE, continous = TRUE; + + conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE); + + for (i = 0; i < 10; i++) + { + bson *data = bson_new (); + bson_append_boolean (data, "f_sync_cursor_iterate", TRUE); + bson_append_int32 (data, "i32", 42 * 100 + i); + bson_finish (data); + + mongo_sync_cmd_insert (conn, config.ns, data, NULL); + bson_free (data); + } + + query = bson_new (); + bson_append_boolean (query, "f_sync_cursor_iterate", TRUE); + bson_finish (query); + + sc = mongo_sync_cursor_new (conn, config.ns, + mongo_sync_cmd_query (conn, config.ns, 0, 0, 3, + query, NULL)); + bson_free (query); + + ok (sc != NULL, + "mongo_sync_cursor_new() works"); + + result = mongo_sync_cursor_get_data (sc); + ok (result == NULL, + "mongo_sync_cursor_get_data() should fail without _cursor_next()"); + + i = 0; + while (mongo_sync_cursor_next (sc) && i < 10) + { + result = mongo_sync_cursor_get_data (sc); + + if (!result) + { + early_break = TRUE; + break; + } + i++; + c = bson_find (result, "i32"); + bson_cursor_get_int32 (c, ¤t_i32); + bson_cursor_free (c); + bson_free (result); + + if (first_i32 == -1) + { + first_i32 = current_i32; + last_i32 = first_i32 - 1; + } + + if (current_i32 != last_i32 + 1) + continous = FALSE; + last_i32 = current_i32; + } + + ok (early_break == FALSE, + "mongo_sync_cursor_next() can iterate over the whole stuff"); + ok (continous == TRUE, + "mongo_sync_cursor_next() iterates over all elements"); + + cmp_ok (first_i32, "!=", last_i32, + "Iteration returns different elements, as expected"); + cmp_ok (i, ">=", 10, + "Iteration really does return all documents"); + + mongo_sync_cursor_free (sc); + mongo_sync_disconnect (conn); +} + +RUN_NET_TEST (6, func_mongo_sync_cursor_iterate); diff --git a/tests/func/mongo/sync-cursor/f_sync_cursor_tailable.c b/tests/func/mongo/sync-cursor/f_sync_cursor_tailable.c new file mode 100644 index 0000000..c200ed8 --- /dev/null +++ b/tests/func/mongo/sync-cursor/f_sync_cursor_tailable.c @@ -0,0 +1,115 @@ +#include "test.h" +#include <mongo.h> + +#include <errno.h> +#include <string.h> + +void +test_func_mongo_sync_cursor_tailable (void) +{ + mongo_sync_connection *conn; + bson *query, *data; + mongo_sync_cursor *sc, *tc; + mongo_packet *p; + gint i; + gchar *capped_ns, *capped_coll; + + bson_cursor *c; + gboolean tailed = FALSE; + + conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE); + + query = bson_new (); + bson_finish (query); + + p = mongo_sync_cmd_query (conn, config.ns, + MONGO_WIRE_FLAG_QUERY_TAILABLE_CURSOR | + MONGO_WIRE_FLAG_QUERY_NO_CURSOR_TIMEOUT, + 0, 3, query, NULL); + ok (p == NULL, + "Tailable cursors should not work on non-capped collections"); + + capped_coll = g_strconcat (config.coll, ".capped", NULL); + capped_ns = g_strconcat (config.ns, ".capped", NULL); + + query = bson_build (BSON_TYPE_STRING, "create", capped_coll, -1, + BSON_TYPE_BOOLEAN, "capped", TRUE, + BSON_TYPE_INT32, "size", 64 * 1024 * 10, + BSON_TYPE_NONE); + bson_finish (query); + + mongo_sync_cmd_drop (conn, config.db, capped_coll); + p = mongo_sync_cmd_custom (conn, config.db, query); + bson_free (query); + + ok (p != NULL, + "Creating a capped collection works"); + mongo_wire_packet_free (p); + + for (i = 0; i < 10; i++) + { + data = bson_new (); + bson_append_boolean (data, "f_sync_cursor_tailable", TRUE); + bson_append_int32 (data, "i32", 42 * 1000 + i); + bson_finish (data); + + mongo_sync_cmd_insert (conn, capped_ns, data, NULL); + bson_free (data); + } + + query = bson_new (); + bson_append_boolean (query, "f_sync_cursor_tailable", TRUE); + bson_finish (query); + + tc = mongo_sync_cursor_new (conn, capped_ns, + mongo_sync_cmd_query (conn, capped_ns, + MONGO_WIRE_FLAG_QUERY_TAILABLE_CURSOR | + MONGO_WIRE_FLAG_QUERY_NO_CURSOR_TIMEOUT, + 0, 3, query, NULL)); + + sc = mongo_sync_cursor_new (conn, capped_ns, + mongo_sync_cmd_query (conn, capped_ns, + 0, + 0, 3, query, NULL)); + + bson_free (query); + + /* Exhaust both queries */ + for (i = 0; i < 10; i++) + { + mongo_sync_cursor_next (tc); + mongo_sync_cursor_next (sc); + } + + data = bson_new (); + bson_append_boolean (data, "f_sync_cursor_tailable", TRUE); + bson_append_boolean (data, "tailed", TRUE); + bson_finish (data); + + mongo_sync_cmd_insert (conn, capped_ns, data, NULL); + bson_free (data); + + ok (mongo_sync_cursor_next (tc) == TRUE, + "mongo_sync_cursor_next() works after a tailable cursor got new data"); + ok (mongo_sync_cursor_next (sc) == FALSE, + "mongo_sync_cursor_next() fails on a non-tailable cursor"); + + data = mongo_sync_cursor_get_data (tc); + ok (data != NULL, + "mongo_sync_cursor_get_data() works on a tailable cursor"); + c = bson_find (data, "tailed"); + bson_cursor_get_boolean (c, &tailed); + ok (tailed == TRUE, + "We got the appropriate data back!"); + bson_cursor_free (c); + + mongo_sync_cursor_free (sc); + mongo_sync_cursor_free (tc); + + mongo_sync_cmd_drop (conn, config.db, capped_coll); + g_free (capped_ns); + g_free (capped_coll); + mongo_sync_disconnect (conn); +} + +RUN_NET_TEST (6, func_mongo_sync_cursor_tailable); diff --git a/tests/func/mongo/sync-gridfs-chunk/f_sync_gridfs_chunk.c b/tests/func/mongo/sync-gridfs-chunk/f_sync_gridfs_chunk.c new file mode 100644 index 0000000..cac6e28 --- /dev/null +++ b/tests/func/mongo/sync-gridfs-chunk/f_sync_gridfs_chunk.c @@ -0,0 +1,499 @@ +#include "test.h" +#include "mongo.h" + +#define FILE_SIZE 1024 * 1024 + 12345 + +static guint8 noname_oid[12]; +static guint8 named_oid[12]; +static guint8 binsub_oid[12]; + +void +test_func_sync_gridfs_put (void) +{ + mongo_sync_connection *conn; + mongo_sync_gridfs *gfs; + mongo_sync_gridfs_chunked_file *gfile; + bson *meta; + guint8 *data, *oid; + gchar *oid_s; + + conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE); + gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix); + oid = mongo_util_oid_new (1); + meta = bson_build (BSON_TYPE_STRING, "filename", "libmongo-test", -1, + BSON_TYPE_OID, "_id", oid, + BSON_TYPE_NONE); + g_free (oid); + bson_finish (meta); + + data = g_malloc (FILE_SIZE); + memset (data, 'x', FILE_SIZE); + + gfile = mongo_sync_gridfs_chunked_file_new_from_buffer (gfs, meta, + data, FILE_SIZE); + ok (gfile != NULL, + "GridFS file upload (with metadata) works!"); + memcpy (named_oid, mongo_sync_gridfs_file_get_id (gfile), 12); + oid_s = mongo_util_oid_as_string (named_oid); + note ("Named file ID : %s\n", oid_s); + g_free (oid_s); + mongo_sync_gridfs_chunked_file_free (gfile); + + gfile = mongo_sync_gridfs_chunked_file_new_from_buffer (gfs, NULL, + data, FILE_SIZE); + ok (gfile != NULL, + "GridFS file upload (w/o metadata) works!"); + memcpy (noname_oid, mongo_sync_gridfs_file_get_id (gfile), 12); + oid_s = mongo_util_oid_as_string (noname_oid); + note ("Noname file ID: %s\n", oid_s); + g_free (oid_s); + mongo_sync_gridfs_chunked_file_free (gfile); + + g_free (data); + bson_free (meta); + mongo_sync_gridfs_free (gfs, TRUE); +} + +void +test_func_sync_gridfs_put_invalid (void) +{ + mongo_sync_connection *conn; + bson *meta; + gchar *ns; + + conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE); + ns = g_strconcat (config.gfs_prefix, ".files", NULL); + + /* Insert metadata without any of the required fields but ID. */ + meta = bson_build (BSON_TYPE_STRING, "my-id", "id-only", -1, + BSON_TYPE_NONE); + bson_finish (meta); + + mongo_sync_cmd_insert (conn, ns, meta, NULL); + bson_free (meta); + + /* Insert metadata with an ID that's not an ObjectID. */ + meta = bson_build (BSON_TYPE_STRING, "_id", "I'm a teapot", -1, + BSON_TYPE_STRING, "my-id", "string-id", -1, + BSON_TYPE_NONE); + bson_finish (meta); + + mongo_sync_cmd_insert (conn, ns, meta, NULL); + bson_free (meta); + + /* Insert metadata with invalid length type. */ + meta = bson_build (BSON_TYPE_DOUBLE, "length", 1.0, + BSON_TYPE_STRING, "my-id", "invalid-length", -1, + BSON_TYPE_NONE); + bson_finish (meta); + + mongo_sync_cmd_insert (conn, ns, meta, NULL); + bson_free (meta); + + /* Insert metadata with invalid chunkSize type. */ + meta = bson_build (BSON_TYPE_INT32, "length", 10, + BSON_TYPE_DOUBLE, "chunkSize", 12.5, + BSON_TYPE_STRING, "my-id", "invalid-chunkSize", -1, + BSON_TYPE_NONE); + bson_finish (meta); + + mongo_sync_cmd_insert (conn, ns, meta, NULL); + bson_free (meta); + + /* Insert metadata with invalid uploadDate type. */ + meta = bson_build (BSON_TYPE_INT32, "length", 10, + BSON_TYPE_INT32, "chunkSize", 12, + BSON_TYPE_STRING, "my-id", "invalid-date", -1, + BSON_TYPE_INT32, "uploadDate", 1234, + BSON_TYPE_NONE); + bson_finish (meta); + + mongo_sync_cmd_insert (conn, ns, meta, NULL); + bson_free (meta); + + /* Insert metadata with invalid md5 type. */ + meta = bson_build (BSON_TYPE_INT32, "length", 32, + BSON_TYPE_INT32, "chunkSize", 12, + BSON_TYPE_UTC_DATETIME, "uploadDate", (gint64)1234, + BSON_TYPE_INT32, "md5", 0, + BSON_TYPE_STRING, "my-id", "invalid-md5", -1, + BSON_TYPE_NONE); + bson_finish (meta); + + mongo_sync_cmd_insert (conn, ns, meta, NULL); + bson_free (meta); + + /* Insert a valid metadata, without chunks. */ + meta = bson_build (BSON_TYPE_INT32, "length", 32, + BSON_TYPE_INT32, "chunkSize", 12, + BSON_TYPE_UTC_DATETIME, "uploadDate", (gint64)1234, + BSON_TYPE_STRING, "md5", "deadbeef", -1, + BSON_TYPE_STRING, "my-id", "no-chunks", -1, + BSON_TYPE_NONE); + bson_finish (meta); + + mongo_sync_cmd_insert (conn, ns, meta, NULL); + bson_free (meta); + + g_free (ns); + mongo_sync_disconnect (conn); +} + +void +validate_file (mongo_sync_gridfs *gfs, const bson *query, guint8 *oid, + gboolean validate_md5) +{ + mongo_sync_gridfs_chunked_file *f; + mongo_sync_cursor *cursor; + gint64 n = 0, tsize = 0; + const bson *meta; + gchar *oid_s; + + f = mongo_sync_gridfs_chunked_find (gfs, query); + + ok (f != NULL, + "File not found"); + ok (memcmp (mongo_sync_gridfs_file_get_id (f), oid, 12) == 0, + "File _id matches"); + cmp_ok (mongo_sync_gridfs_file_get_length (f), "==", FILE_SIZE, + "File length matches"); + cmp_ok (mongo_sync_gridfs_file_get_chunk_size (f), "==", + mongo_sync_gridfs_get_chunk_size (gfs), + "File chunk size matches"); + + oid_s = mongo_util_oid_as_string (mongo_sync_gridfs_file_get_id (f)); + note ("File info:\n\tid = %s; length = %" G_GINT64_FORMAT "; " + "chunk_size = %d; date = %" G_GINT64_FORMAT "; " + "md5 = %s; n = %" G_GINT64_FORMAT "\n", + + oid_s, + mongo_sync_gridfs_file_get_length (f), + mongo_sync_gridfs_file_get_chunk_size (f), + mongo_sync_gridfs_file_get_date (f), + mongo_sync_gridfs_file_get_md5 (f), + mongo_sync_gridfs_file_get_chunks (f)); + g_free (oid_s); + meta = mongo_sync_gridfs_file_get_metadata (f); + ok (meta != NULL, + "mongo_sync_gridfs_file_get_metadata() works"); + + cursor = mongo_sync_gridfs_chunked_file_cursor_new (f, 0, 0); + while (mongo_sync_cursor_next (cursor)) + { + gint32 size; + guint8 *data; + + data = mongo_sync_gridfs_chunked_file_cursor_get_chunk (cursor, &size); + g_free (data); + + tsize += size; + n++; + } + mongo_sync_cursor_free (cursor); + + if (validate_md5) + cmp_ok (mongo_sync_gridfs_file_get_length (f), "==", tsize, + "File size matches the sum of its chunks"); + cmp_ok (mongo_sync_gridfs_file_get_chunks (f), "==", n, + "Number of chunks matches the expected number"); + + mongo_sync_gridfs_chunked_file_free (f); +} + +void +test_func_sync_gridfs_get (void) +{ + mongo_sync_connection *conn; + mongo_sync_gridfs *gfs; + bson *query; + + conn = mongo_sync_connect (config.primary_host, config.primary_port, TRUE); + gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix); + + query = bson_build (BSON_TYPE_STRING, "filename", "libmongo-test", -1, + BSON_TYPE_NONE); + bson_finish (query); + validate_file (gfs, query, named_oid, TRUE); + bson_free (query); + + query = bson_build (BSON_TYPE_OID, "_id", noname_oid, + BSON_TYPE_NONE); + bson_finish (query); + validate_file (gfs, query, noname_oid, TRUE); + bson_free (query); + + mongo_sync_gridfs_free (gfs, TRUE); +} + +void +test_get_invalid (mongo_sync_gridfs *gfs, gchar *name, gchar *msg) +{ + bson *query; + + query = bson_build (BSON_TYPE_STRING, "my-id", name, -1, + BSON_TYPE_NONE); + bson_finish (query); + ok (mongo_sync_gridfs_chunked_find (gfs, query) == NULL, msg); + bson_free (query); +} + +void +test_func_sync_gridfs_get_invalid (void) +{ + mongo_sync_connection *conn; + mongo_sync_gridfs *gfs; + mongo_sync_cursor *cursor; + bson *query; + gchar *ns; + + conn = mongo_sync_connect (config.primary_host, config.primary_port, TRUE); + gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix); + + test_get_invalid (gfs, "unknown", + "mongo_sync_gridfs_chunked_find() should fail when no file " + "is found"); + test_get_invalid (gfs, "id-only", + "mongo_sync_gridfs_chunked__find() should fail if the metadata " + "is incomplete"); + test_get_invalid (gfs, "string-id", + "mongo_sync_gridfs_chunked__find() should fail if the _id is " + "not an ObjectID"); + test_get_invalid (gfs, "invalid-length", + "mongo_sync_gridfs_chunked__find() should fail if length is " + "of inappropriate type"); + test_get_invalid (gfs, "invalid-chunkSize", + "mongo_sync_gridfs_chunked__find() should fail if chunkSize is " + "of inappropriate type"); + test_get_invalid (gfs, "invalid-date", + "mongo_sync_gridfs_chunked__find() should fail if uploadDate is " + "of inappropriate type"); + test_get_invalid (gfs, "invalid-md5", + "mongo_sync_gridfs_chunked__find() should fail if md5 is of " + "inappropriate type"); + + ns = g_strconcat (config.gfs_prefix, ".files", NULL); + query = bson_build (BSON_TYPE_STRING, "my-id", "id-only", -1, + BSON_TYPE_NONE); + bson_finish (query); + + cursor = mongo_sync_cursor_new (conn, ns, + mongo_sync_cmd_query (conn, ns, 0, 0, 0, + query, NULL)); + bson_free (query); + mongo_sync_cursor_next (cursor); + ok (mongo_sync_gridfs_chunked_file_cursor_get_chunk (cursor, NULL) == NULL, + "mongo_sync_gridfs_chunked_file_cursor_get_chunk() should fail with " + "invalid data"); + + mongo_sync_gridfs_free (gfs, TRUE); +} + +void +test_func_sync_gridfs_list (void) +{ + mongo_sync_gridfs *gfs; + bson *query, *data; + mongo_sync_cursor *cursor; + bson_cursor *c; + const gchar *str; + gboolean found_named = FALSE, found_noname = FALSE; + const guint8 *oid; + + gfs = mongo_sync_gridfs_new + (mongo_sync_connect (config.primary_host, config.primary_port, TRUE), + config.gfs_prefix); + + /* Test list with an invalid query */ + query = bson_build (BSON_TYPE_STRING, "no-such-field", + "You're not seeing this field.", -1, + BSON_TYPE_NONE); + bson_finish (query); + + cursor = mongo_sync_gridfs_list (gfs, query); + ok (cursor == NULL, + "mongo_sync_gridfs_list() should fail if there query " + "does not match anything"); + bson_free (query); + + /* Test list with a query */ + query = bson_build (BSON_TYPE_OID, "_id", named_oid, + BSON_TYPE_NONE); + bson_finish (query); + + cursor = mongo_sync_gridfs_list (gfs, query); + ok (cursor != NULL, + "mongo_sync_gridfs_list() correctly finds files by query"); + + mongo_sync_cursor_next (cursor); + data = mongo_sync_cursor_get_data (cursor); + c = bson_find (data, "filename"); + bson_cursor_get_string (c, &str); + bson_cursor_free (c); + + is (str, "libmongo-test", + "The listed file is named correctly"); + bson_free (data); + mongo_sync_cursor_free (cursor); + + bson_free (query); + + /* Test list without a query */ + cursor = mongo_sync_gridfs_list (gfs, NULL); + while (mongo_sync_cursor_next (cursor)) + { + data = mongo_sync_cursor_get_data (cursor); + + c = bson_find (data, "_id"); + bson_cursor_get_oid (c, (const guint8 **)&oid); + bson_cursor_free (c); + + if (memcmp (oid, named_oid, 12) == 0) + found_named = TRUE; + if (memcmp (oid, noname_oid, 12) == 0) + found_noname = TRUE; + + bson_free (data); + } + mongo_sync_cursor_free (cursor); + + ok (found_named == TRUE && found_noname == TRUE, + "mongo_sync_gridfs_list() finds both uploaded files without a query"); + + mongo_sync_gridfs_free (gfs, TRUE); +} + +void +test_fync_sync_gridfs_remove (void) +{ + mongo_sync_gridfs *gfs; + bson *query; + + gfs = mongo_sync_gridfs_new + (mongo_sync_connect (config.primary_host, config.primary_port, TRUE), + config.gfs_prefix); + + /* Test with a non-matching query */ + query = bson_build (BSON_TYPE_STRING, "no-such-field", + "You're not seeing this field.", -1, + BSON_TYPE_NONE); + bson_finish (query); + + ok (mongo_sync_gridfs_remove (gfs, query) == FALSE, + "mongo_sync_gridfs_remove() should fail if there's nothing to delete."); + bson_free (query); + + /* Test with a non-string id */ + query = bson_build (BSON_TYPE_STRING, "my-id", "string-id", -1, + BSON_TYPE_NONE); + bson_finish (query); + + ok (mongo_sync_gridfs_remove (gfs, query) == FALSE, + "mongo_sync_gridfs_remove() should fail if the file id is not " + "an ObjectId"); + bson_free (query); + + /* Test with a working query */ + query = bson_build (BSON_TYPE_OID, "_id", named_oid, + BSON_TYPE_NONE); + bson_finish (query); + + ok (mongo_sync_gridfs_remove (gfs, query) == TRUE, + "mongo_sync_gridfs_remove() works"); + bson_finish (query); + + mongo_sync_gridfs_free (gfs, TRUE); +} + +void +test_func_sync_gridfs_put_binary_subtype (void) +{ + mongo_sync_connection *conn; + mongo_sync_gridfs *gfs; + mongo_sync_gridfs_chunked_file *gfile; + bson *meta, *query, *update; + guint8 *data; + gchar *chunk_ns; + guint32 size = GINT32_TO_LE(FILE_SIZE); + + conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE); + gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix); + meta = bson_build (BSON_TYPE_STRING, "filename", "binsub-libmongo-test", -1, + BSON_TYPE_NONE); + bson_finish (meta); + + data = g_malloc (FILE_SIZE + 4); + memcpy (data, &size, 4); + memset (data + 4, 'x', FILE_SIZE); + + gfile = mongo_sync_gridfs_chunked_file_new_from_buffer (gfs, meta, + data + 4, FILE_SIZE); + memcpy (binsub_oid, mongo_sync_gridfs_file_get_id (gfile), 12); + + query = bson_build (BSON_TYPE_OID, "files_id", + mongo_sync_gridfs_file_get_id (gfile), + BSON_TYPE_NONE); + bson_finish (query); + + mongo_sync_gridfs_chunked_file_free (gfile); + bson_free (meta); + + update = bson_build_full (BSON_TYPE_DOCUMENT, "$set", TRUE, + bson_build (BSON_TYPE_BINARY, "data", + BSON_BINARY_SUBTYPE_BINARY, + data, FILE_SIZE + 4, + BSON_TYPE_NONE), + BSON_TYPE_NONE); + bson_finish (update); + g_free (data); + + chunk_ns = g_strconcat (config.gfs_prefix, ".chunks", NULL); + mongo_sync_cmd_update (conn, chunk_ns, MONGO_WIRE_FLAG_UPDATE_UPSERT, + query, update); + + bson_free (query); + bson_free (update); + g_free (chunk_ns); + + mongo_sync_gridfs_free (gfs, TRUE); +} + +void +test_func_sync_gridfs_get_binary_subtype (void) +{ + mongo_sync_connection *conn; + mongo_sync_gridfs *gfs; + bson *query; + + conn = mongo_sync_connect (config.primary_host, config.primary_port, TRUE); + gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix); + + query = bson_build (BSON_TYPE_STRING, "filename", "binsub-libmongo-test", -1, + BSON_TYPE_NONE); + bson_finish (query); + validate_file (gfs, query, binsub_oid, FALSE); + bson_free (query); + + mongo_sync_gridfs_free (gfs, TRUE); +} + +void +test_func_sync_gridfs_chunk (void) +{ + mongo_util_oid_init (0); + + test_func_sync_gridfs_put (); + test_func_sync_gridfs_get (); + test_func_sync_gridfs_list (); + + sleep (2); + + test_func_sync_gridfs_put_binary_subtype (); + test_func_sync_gridfs_get_binary_subtype (); + + test_func_sync_gridfs_put_invalid (); + test_func_sync_gridfs_get_invalid (); + + test_fync_sync_gridfs_remove (); +} + +RUN_NET_TEST (37, func_sync_gridfs_chunk); diff --git a/tests/func/mongo/sync-gridfs-stream/f_sync_gridfs_stream.c b/tests/func/mongo/sync-gridfs-stream/f_sync_gridfs_stream.c new file mode 100644 index 0000000..a2c3690 --- /dev/null +++ b/tests/func/mongo/sync-gridfs-stream/f_sync_gridfs_stream.c @@ -0,0 +1,501 @@ +#include "test.h" +#include "mongo.h" +#include "compat.h" + +#define FILE_SIZE 1024 * 1024 + 12345 +#define BUFFER_SIZE 64 * 1024 + +gchar *write_md5 = NULL; +static gint seq = 1; + +void +test_func_sync_gridfs_stream_without_oid_init (void) +{ + mongo_sync_connection *conn; + mongo_sync_gridfs *gfs; + mongo_sync_gridfs_stream *stream; + + 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() fails without mongo_util_oid_init()"); + + mongo_sync_gridfs_free (gfs, TRUE); +} + +void +test_func_sync_gridfs_stream_write (void) +{ + mongo_sync_connection *conn; + mongo_sync_gridfs *gfs; + mongo_sync_gridfs_stream *stream; + bson *meta; + guint8 *data, *oid; + gint pos = 0; + gint filler = 0; + gboolean write_ok = TRUE; + GChecksum *chk; + + conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE); + gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix); + + oid = mongo_util_oid_new (seq++); + meta = bson_build (BSON_TYPE_STRING, "filename", "libmongo-test-stream", -1, + BSON_TYPE_OID, "_id", oid, + BSON_TYPE_NONE); + bson_finish (meta); + g_free (oid); + + stream = mongo_sync_gridfs_stream_new (gfs, meta); + ok (stream != NULL, + "mongo_sync_gridfs_stream_new() works"); + bson_free (meta); + + data = g_malloc (BUFFER_SIZE); + + chk = g_checksum_new (G_CHECKSUM_MD5); + + while (pos < FILE_SIZE) + { + gint csize = BUFFER_SIZE; + + if (csize + pos > FILE_SIZE) + csize = FILE_SIZE - pos; + + memset (data, filler++, BUFFER_SIZE); + + g_checksum_update (chk, data, csize); + + write_ok &= mongo_sync_gridfs_stream_write (stream, data, csize); + pos += csize; + } + ok (write_ok == TRUE, + "All stream_write()s succeeded"); + + write_md5 = g_strdup (g_checksum_get_string (chk)); + g_checksum_free (chk); + + note ("File MD5: %s\n", write_md5); + + g_free (data); + ok (mongo_sync_gridfs_stream_close (stream) == TRUE, + "mongo_sync_gridfs_stream_close() works"); + + mongo_sync_gridfs_free (gfs, TRUE); +} + +void +test_func_sync_gridfs_stream_write_binary_subtype (void) +{ + mongo_sync_connection *conn; + mongo_sync_gridfs *gfs; + mongo_sync_gridfs_stream *stream; + bson *meta, *update; + guint8 *data, *oid; + gboolean write_ok = TRUE; + guint32 size = GINT32_TO_LE(BUFFER_SIZE); + gchar *ns; + + conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE); + gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix); + + oid = mongo_util_oid_new (seq++); + meta = bson_build (BSON_TYPE_STRING, "filename", "libmongo-test-stream-bintype", -1, + BSON_TYPE_OID, "_id", oid, + BSON_TYPE_NONE); + bson_finish (meta); + + + stream = mongo_sync_gridfs_stream_new (gfs, meta); + ok (stream != NULL, + "mongo_sync_gridfs_stream_new() works"); + bson_free (meta); + + data = g_malloc (BUFFER_SIZE + 4); + memcpy (data, &size, 4); + memset (data + 4, 'x', BUFFER_SIZE); + write_ok = mongo_sync_gridfs_stream_write (stream, data + 4, BUFFER_SIZE); + ok (write_ok == TRUE, + "All stream_write()s succeeded"); + + ok (mongo_sync_gridfs_stream_close (stream) == TRUE, + "mongo_sync_gridfs_stream_close() works"); + + meta = bson_build (BSON_TYPE_OID, "files_id", oid, + BSON_TYPE_NONE); + bson_finish (meta); + + update = bson_build_full (BSON_TYPE_DOCUMENT, "$set", TRUE, + bson_build (BSON_TYPE_BINARY, "data", + BSON_BINARY_SUBTYPE_BINARY, + data, BUFFER_SIZE + 4, + BSON_TYPE_NONE), + BSON_TYPE_NONE); + bson_finish (update); + g_free (data); + + ns = g_strconcat (config.gfs_prefix, ".chunks", NULL); + mongo_sync_cmd_update (conn, ns, MONGO_WIRE_FLAG_UPDATE_UPSERT, + meta, update); + bson_free (meta); + bson_free (update); + g_free (ns); + g_free (oid); + mongo_sync_gridfs_free (gfs, TRUE); +} + +void +test_func_sync_gridfs_stream_write_invalid (void) +{ + mongo_sync_connection *conn; + mongo_sync_gridfs *gfs; + mongo_sync_gridfs_stream *stream; + bson *meta; + gchar *ns; + + conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE); + gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix); + ns = g_strconcat (config.gfs_prefix, ".files", NULL); + + /* Try to write a file with a custom, non-OID _id */ + meta = bson_build (BSON_TYPE_STRING, "filename", "lmc-invalid-id", -1, + BSON_TYPE_STRING, "_id", "Short and stout", -1, + BSON_TYPE_NONE); + bson_finish (meta); + + stream = mongo_sync_gridfs_stream_new (gfs, meta); + ok (stream == NULL, + "mongo_sync_gridfs_stream_new() should fail if meta has an invalid _id"); + bson_free (meta); + + /* Write a file with a non-OID _id, bypassing the GridFS API. */ + meta = bson_build (BSON_TYPE_STRING, "_id", "Short and stout", -1, + BSON_TYPE_STRING, "my-id", "stream:string-id", -1, + BSON_TYPE_NONE); + bson_finish (meta); + + mongo_sync_cmd_insert (conn, ns, meta, NULL); + bson_free (meta); + + /* Insert metadata with invalid length type. */ + meta = bson_build (BSON_TYPE_DOUBLE, "length", 1.0, + BSON_TYPE_STRING, "my-id", "stream:invalid-length", -1, + BSON_TYPE_NONE); + bson_finish (meta); + + mongo_sync_cmd_insert (conn, ns, meta, NULL); + bson_free (meta); + + /* Insert metadata with invalid chunkSize type. */ + meta = bson_build (BSON_TYPE_INT32, "length", 10, + BSON_TYPE_DOUBLE, "chunkSize", 12.5, + BSON_TYPE_STRING, "my-id", "stream:invalid-chunkSize", -1, + BSON_TYPE_NONE); + bson_finish (meta); + + mongo_sync_cmd_insert (conn, ns, meta, NULL); + bson_free (meta); + + /* Insert a valid metadata, without chunks. */ + meta = bson_build (BSON_TYPE_INT32, "length", 32, + BSON_TYPE_INT32, "chunkSize", 12, + BSON_TYPE_UTC_DATETIME, "uploadDate", (gint64)1234, + BSON_TYPE_STRING, "md5", "deadbeef", -1, + BSON_TYPE_STRING, "my-id", "stream:no-chunks", -1, + BSON_TYPE_NONE); + bson_finish (meta); + + mongo_sync_cmd_insert (conn, ns, meta, NULL); + bson_free (meta); + + mongo_sync_gridfs_free (gfs, TRUE); +} + +void +test_func_sync_gridfs_stream_read (void) +{ + mongo_sync_connection *conn; + mongo_sync_gridfs *gfs; + mongo_sync_gridfs_stream *stream; + guint8 data[12345]; + gint64 pos = 0; + bson *meta; + + GChecksum *chk; + + conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE); + gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix); + meta = bson_build (BSON_TYPE_STRING, "filename", "libmongo-test-stream", -1, + BSON_TYPE_NONE); + bson_finish (meta); + + stream = mongo_sync_gridfs_stream_find (gfs, meta); + ok (stream != NULL, + "mongo_sync_gridfs_stream_find() works"); + bson_free (meta); + + chk = g_checksum_new (G_CHECKSUM_MD5); + + while (pos < FILE_SIZE) + { + gint64 r; + + r = mongo_sync_gridfs_stream_read (stream, data, sizeof (data)); + if (r == -1) + break; + + g_checksum_update (chk, data, r); + pos += r; + } + + cmp_ok (pos, "==", FILE_SIZE, + "mongo_sync_gridfs_stream_read() works"); + is (g_checksum_get_string (chk), write_md5, + "md5sums match"); + + g_checksum_free (chk); + ok (mongo_sync_gridfs_stream_close (stream) == TRUE, + "mongo_sync_gridfs_stream_close() works"); + mongo_sync_gridfs_free (gfs, TRUE); +} + +void +test_func_sync_gridfs_stream_read_binary_subtype (void) +{ + mongo_sync_connection *conn; + mongo_sync_gridfs *gfs; + mongo_sync_gridfs_stream *stream; + guint8 *data; + gint64 r; + bson *meta; + + conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE); + gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix); + meta = bson_build (BSON_TYPE_STRING, "filename", "libmongo-test-stream-bintype", -1, + BSON_TYPE_NONE); + bson_finish (meta); + + stream = mongo_sync_gridfs_stream_find (gfs, meta); + ok (stream != NULL, + "mongo_sync_gridfs_stream_find() works"); + bson_free (meta); + + data = g_malloc (BUFFER_SIZE); + r = mongo_sync_gridfs_stream_read (stream, data, BUFFER_SIZE); + cmp_ok (r, "==", BUFFER_SIZE, + "mongo_sync_gridfs_stream_read() works"); + + ok (mongo_sync_gridfs_stream_close (stream) == TRUE, + "mongo_sync_gridfs_stream_close() works"); + mongo_sync_gridfs_free (gfs, TRUE); +} + +void +test_func_sync_gridfs_stream_meta (void) +{ + mongo_sync_connection *conn; + mongo_sync_gridfs *gfs; + mongo_sync_gridfs_stream *stream; + bson *meta; + const guint8 *id; + + conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE); + gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix); + meta = bson_build (BSON_TYPE_STRING, "filename", "libmongo-test-stream", -1, + BSON_TYPE_NONE); + bson_finish (meta); + + stream = mongo_sync_gridfs_stream_find (gfs, meta); + bson_free (meta); + + id = mongo_sync_gridfs_file_get_id (stream); + ok (id != NULL, + "mongo_sync_gridfs_file_get_id() works on streams"); + + ok (mongo_sync_gridfs_file_get_md5 (stream) == NULL, + "mongo_sync_gridfs_file_get_md5() fails on streams"); + ok (mongo_sync_gridfs_file_get_date (stream) == -1, + "mongo_sync_gridfs_file_get_date() fails on streams"); + ok (mongo_sync_gridfs_file_get_metadata (stream) == NULL, + "mongo_sync_gridfs_file_get_metadata() fails on streams"); + + mongo_sync_gridfs_stream_close (stream); + + mongo_sync_gridfs_free (gfs, TRUE); +} + +void +test_func_sync_gridfs_stream_read_invalid (void) +{ + mongo_sync_connection *conn; + mongo_sync_gridfs *gfs; + mongo_sync_gridfs_stream *stream; + guint8 data[1245]; + gint64 r; + bson *meta; + + conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE); + gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix); + + /* ---- */ + meta = bson_build (BSON_TYPE_STRING, "my-id", "stream:string-id", -1, + BSON_TYPE_NONE); + bson_finish (meta); + + stream = mongo_sync_gridfs_stream_find (gfs, meta); + ok (stream == NULL, + "mongo_sync_gridfs_stream_find() should fail if _id is non-OID"); + bson_free (meta); + + /* ---- */ + meta = bson_build (BSON_TYPE_STRING, "my-id", "stream:invalid-length", -1, + BSON_TYPE_NONE); + bson_finish (meta); + + stream = mongo_sync_gridfs_stream_find (gfs, meta); + ok (stream == NULL, + "mongo_sync_gridfs_stream_find() should fail with invalid metadata"); + bson_free (meta); + + /* ---- */ + meta = bson_build (BSON_TYPE_STRING, "my-id", "stream:invalid-chunkSize", -1, + BSON_TYPE_NONE); + bson_finish (meta); + + stream = mongo_sync_gridfs_stream_find (gfs, meta); + ok (stream == NULL, + "mongo_sync_gridfs_stream_find() should fail with invalid metadata"); + bson_free (meta); + + /* no-chunk test */ + meta = bson_build (BSON_TYPE_STRING, "my-id", "stream:no-chunks", -1, + BSON_TYPE_NONE); + bson_finish (meta); + + stream = mongo_sync_gridfs_stream_find (gfs, meta); + ok (stream != NULL, + "mongo_sync_gridfs_stream_find() works [stream:no-chunks]"); + bson_free (meta); + + r = mongo_sync_gridfs_stream_read (stream, data, sizeof (data)); + cmp_ok (r, "==", -1, + "Reading from a chunk-less file should fail"); + + mongo_sync_gridfs_stream_close (stream); + + mongo_sync_gridfs_free (gfs, TRUE); +} + +void +test_func_sync_gridfs_stream_seek (void) +{ + mongo_sync_connection *conn; + mongo_sync_gridfs *gfs; + mongo_sync_gridfs_stream *stream; + bson *meta; + guint8 *chunk1, *chunk2, *chunk3; + + conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE); + gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix); + meta = bson_build (BSON_TYPE_STRING, "filename", "libmongo-test-stream", -1, + BSON_TYPE_NONE); + bson_finish (meta); + + stream = mongo_sync_gridfs_stream_find (gfs, meta); + bson_free (meta); + + chunk1 = g_malloc (300 * 1024); + chunk2 = g_malloc (300 * 1024); + chunk3 = g_malloc (300 * 1024); + + cmp_ok (mongo_sync_gridfs_stream_read (stream, chunk1, 300 * 1024), "==", + 300 * 1024, + "reading the first chunk works"); + cmp_ok (mongo_sync_gridfs_stream_read (stream, chunk2, 300 * 1024), "==", + 300 * 1024, + "reading the second chunk works"); + ok (memcmp (chunk1, chunk2, 300 * 1024) != 0, + "The two chunks differ, as they should"); + + ok (mongo_sync_gridfs_stream_seek (stream, 0, SEEK_END) == TRUE, + "mongo_sync_gridfs_stream_seek() works, with SEEK_END"); + cmp_ok (stream->file.offset, "==", stream->file.length, + "mongo_sync_gridfs_stream_seek() can seek to the end"); + + ok (mongo_sync_gridfs_stream_seek (stream, 1, SEEK_SET) == TRUE, + "mongo_sync_gridfs_stream_seek() works, with SEEK_SET"); + cmp_ok (stream->file.offset, "==", 1, + "mongo_sync_gridfs_stream_seek()'s SEEK_SET works"); + ok (mongo_sync_gridfs_stream_seek (stream, 1, SEEK_SET) == TRUE, + "mongo_sync_gridfs_stream_seek() works, with SEEK_SET"); + + ok (mongo_sync_gridfs_stream_seek (stream, -1, SEEK_CUR) == TRUE, + "mongo_sync_gridfs_stream_seek() works, with SEEK_CUR"); + cmp_ok (stream->file.offset, "==", 0, + "mongo_sync_gridfs_stream_seek()'s SEEK_CUR works"); + ok (mongo_sync_gridfs_stream_seek (stream, 0, SEEK_CUR) == TRUE, + "mongo_sync_gridfs_stream_seek() works, with SEEK_CUR"); + + cmp_ok (mongo_sync_gridfs_stream_read (stream, chunk3, 300 * 1024), "==", + 300 * 1024, + "reading after seeking works"); + + ok (memcmp (chunk1, chunk3, 300 * 1024) == 0, + "After seeking, we're at the beginning"); + + mongo_sync_gridfs_stream_close (stream); + g_free (chunk3); + g_free (chunk2); + g_free (chunk1); + + mongo_sync_gridfs_free (gfs, TRUE); +} + +void +test_func_sync_gridfs_stream_seek_invalid (void) +{ + mongo_sync_connection *conn; + mongo_sync_gridfs *gfs; + mongo_sync_gridfs_stream *stream; + bson *meta; + + conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE); + gfs = mongo_sync_gridfs_new (conn, config.gfs_prefix); + meta = bson_build (BSON_TYPE_STRING, "my-id", "stream:no-chunks", -1, + BSON_TYPE_NONE); + bson_finish (meta); + + stream = mongo_sync_gridfs_stream_find (gfs, meta); + bson_free (meta); + + ok (mongo_sync_gridfs_stream_seek (stream, 1, SEEK_SET) == FALSE, + "mongo_sync_gridfs_stream_seek() should fail with no chunks"); + + mongo_sync_gridfs_stream_close (stream); + + mongo_sync_gridfs_free (gfs, TRUE); +} + +void +test_func_sync_gridfs_stream (void) +{ + test_func_sync_gridfs_stream_without_oid_init (); + + mongo_util_oid_init (0); + + test_func_sync_gridfs_stream_write (); + test_func_sync_gridfs_stream_write_binary_subtype (); + test_func_sync_gridfs_stream_write_invalid (); + test_func_sync_gridfs_stream_read (); + test_func_sync_gridfs_stream_read_binary_subtype (); + test_func_sync_gridfs_stream_read_invalid (); + test_func_sync_gridfs_stream_seek (); + test_func_sync_gridfs_stream_seek_invalid (); + test_func_sync_gridfs_stream_meta (); + + g_free (write_md5); +} + +RUN_NET_TEST (38, func_sync_gridfs_stream); diff --git a/tests/func/mongo/sync-pool/f_sync_pool.c b/tests/func/mongo/sync-pool/f_sync_pool.c new file mode 100644 index 0000000..28a2497 --- /dev/null +++ b/tests/func/mongo/sync-pool/f_sync_pool.c @@ -0,0 +1,169 @@ +#include "test.h" +#include <mongo.h> + +#include <errno.h> + +#include "libmongo-private.h" + +void +test_func_mongo_sync_pool_secondary (void) +{ + mongo_sync_pool *pool; + mongo_sync_pool_connection *conn[11], *m, *s1, *s2, *t; + gint i = 0; + gboolean ret = TRUE; + + skip (!config.secondary_host, 14, + "Secondary server not configured"); + + ok (mongo_sync_pool_new (config.secondary_host, + config.secondary_port, 1, 10) == NULL, + "mongo_sync_pool_new() should fail when connecting to a secondary"); + + pool = mongo_sync_pool_new (config.primary_host, + config.primary_port, 1, 10); + ok (pool != NULL, + "mongo_sync_pool_new() works with slaves too"); + + m = mongo_sync_pool_pick (pool, TRUE); + ok (m != NULL, + "mongo_sync_pool_pick() can pick a master from a mixed pool"); + ok (mongo_sync_pool_pick (pool, TRUE) == NULL, + "mongo_sync_pool_pick() should fail if there are no more masters, and " + "a master was requested"); + + while ((conn[i] = mongo_sync_pool_pick (pool, FALSE)) != NULL) + i++; + cmp_ok (i, "==", 10, + "Successfully connect to secondaries on 10 sockets"); + ok (mongo_sync_pool_pick (pool, FALSE) == NULL, + "mongo_sync_pool_pick() should fail if there are no free connections"); + + ok (mongo_sync_pool_return (pool, m) == TRUE, + "Returning the master to the pool works"); + + m = mongo_sync_pool_pick (pool, FALSE); + ok (m != NULL, + "mongo_sync_pool_pick() will return a master, if no more slaves are " + "available"); + + for (i = 0; i < 10; i++) + ret = ret && mongo_sync_pool_return (pool, conn[i]); + + ok (ret == TRUE, + "mongo_sync_pool_return() works when returning slaves"); + + mongo_sync_pool_return (pool, m); + + t = mongo_sync_pool_pick (pool, FALSE); + t->pool_id = 4242; + + errno = 0; + ret = mongo_sync_pool_return (pool, t); + ok (ret == FALSE && errno == ERANGE, + "mongo_sync_pool_return() should fail if the connection ID is " + "out of range"); + + /* Test whether masters and slaves are different. */ + m = mongo_sync_pool_pick (pool, TRUE); + s1 = mongo_sync_pool_pick (pool, FALSE); + s2 = mongo_sync_pool_pick (pool, FALSE); + + ok (m != s1 && m != s2, + "Picked master and slaves are different"); + + ok (mongo_sync_cmd_is_master ((mongo_sync_connection *)m) == TRUE, + "Picked master is, indeed, a master"); + ok (mongo_sync_cmd_is_master ((mongo_sync_connection *)s1) == FALSE, + "Picked secondary is a secondary"); + ok (mongo_sync_cmd_is_master ((mongo_sync_connection *)s2) == FALSE, + "Picked secondary is a secondary"); + + mongo_sync_pool_free (pool); + + endskip; +} + +void +test_func_mongo_sync_pool (void) +{ + mongo_sync_pool *pool; + mongo_sync_pool_connection *conn[11], *t; + gint c = 0; + gboolean ret = TRUE; + bson *b; + mongo_packet *p; + + /* + * First we test that connecting to an invalid host fails. + */ + pool = mongo_sync_pool_new ("invalid.example.com", + config.primary_port, 10, 10); + ok (pool == NULL, + "mongo_sync_pool_new() should fail with an invalid host"); + + /* + * Next, we test whether the basics work, like connecting, picking + * & returning. + */ + + pool = mongo_sync_pool_new (config.primary_host, + config.primary_port, + 10, 0); + + ok (pool != NULL, + "mongo_sync_pool_new() works"); + + while ((conn[c] = mongo_sync_pool_pick (pool, TRUE)) != NULL) + c++; + cmp_ok (c, "==", 10, + "Successfully connect to the master on 10 sockets"); + + t = mongo_sync_pool_pick (pool, TRUE); + ok (t == NULL && errno == EAGAIN, + "Connected to the master only on 10 sockets"); + + for (c = 0; c < 10; c++) + ret = ret && mongo_sync_pool_return (pool, conn[c]); + ok (ret == TRUE, + "mongo_sync_pool_return() works"); + + t = mongo_sync_pool_pick (pool, TRUE); + ok (t != NULL, + "mongo_sync_pool_pick() works after returning connections"); + mongo_sync_pool_return (pool, t); + + /* + * Then we test whether we can perform commands on random + * connections. + */ + conn[0] = mongo_sync_pool_pick (pool, TRUE); + conn[1] = mongo_sync_pool_pick (pool, TRUE); + + ok (conn[0] != conn[1], + "Two picked connections are not the same"); + + b = bson_build (BSON_TYPE_STRING, "test-name", __FILE__, -1, + BSON_TYPE_INT32, "i32", 1984, + BSON_TYPE_NONE); + bson_finish (b); + + ok (mongo_sync_cmd_insert ((mongo_sync_connection *)conn[0], + config.ns, b, NULL) == TRUE, + "mongo_sync_cmd_insert() works on a picked connection"); + + p = mongo_sync_cmd_query ((mongo_sync_connection *)conn[1], + config.ns, 0, 0, 1, b, NULL); + ok (p != NULL, + "mongo_sync_cmd_query() works on a different picked connection"); + mongo_wire_packet_free (p); + + mongo_sync_pool_free (pool); + + /* + * Test pools with a secondary aswell. + */ + test_func_mongo_sync_pool_secondary (); +} + +RUN_NET_TEST (23, func_mongo_sync_pool); diff --git a/tests/func/mongo/sync/f_sync_auto_reauth.c b/tests/func/mongo/sync/f_sync_auto_reauth.c new file mode 100644 index 0000000..477dd25 --- /dev/null +++ b/tests/func/mongo/sync/f_sync_auto_reauth.c @@ -0,0 +1,58 @@ +#include "test.h" +#include <mongo.h> + +#include <errno.h> +#include <sys/socket.h> + +#include "libmongo-private.h" + + +/* + * This test requires that the "lmcUser" user (password "lmcPass") has + * RW access to the test db. It must be set up prior to running this + * test. + */ +void +test_func_mongo_sync_auto_reauth (void) +{ + mongo_sync_connection *conn; + bson *b; + + b = bson_new (); + bson_append_int32 (b, "f_sync_auto_reauth", 1); + bson_finish (b); + + conn = mongo_sync_connect (config.primary_host, config.primary_port, + TRUE); + + mongo_sync_conn_set_safe_mode (conn, TRUE); + + skip (mongo_sync_cmd_insert (conn, config.ns, b, NULL) == TRUE, 3, + "Authentication not configured."); + + skip (mongo_sync_cmd_authenticate (conn, config.db, "lmcUser", "lmcPass")== FALSE, 3, + "Authentication environment not set up for testing."); + + ok (mongo_sync_cmd_insert (conn, config.ns, b, NULL) == TRUE, + "Inserting works after authentication."); + + shutdown (conn->super.fd, SHUT_RDWR); + sleep (1); + + ok (mongo_sync_cmd_insert (conn, config.ns, b, NULL) == FALSE, + "Inserting fails with auto-reconnect turned off, and a broken " + "connection"); + + mongo_sync_conn_set_auto_reconnect (conn, TRUE); + + ok (mongo_sync_cmd_insert (conn, config.ns, b, NULL) == TRUE, + "Inserting works with auto-reconnect turned on, and auto-auth, " + "and a broken connection."); + + endskip; + endskip; + + mongo_sync_disconnect (conn); +} + +RUN_NET_TEST (3, func_mongo_sync_auto_reauth); diff --git a/tests/func/mongo/sync/f_sync_auto_reconnect.c b/tests/func/mongo/sync/f_sync_auto_reconnect.c new file mode 100644 index 0000000..45ec28d --- /dev/null +++ b/tests/func/mongo/sync/f_sync_auto_reconnect.c @@ -0,0 +1,61 @@ +#include "test.h" +#include <mongo.h> + +#include <errno.h> +#include <sys/socket.h> + +#include "libmongo-private.h" + +void +test_func_mongo_sync_auto_reconnect (void) +{ + mongo_sync_connection *conn; + bson *b; + mongo_packet *p; + + b = bson_new (); + bson_append_int32 (b, "f_sync_auto_reconnect", 1); + bson_finish (b); + + conn = mongo_sync_connect (config.primary_host, config.primary_port, + TRUE); + ok (mongo_sync_cmd_insert (conn, config.ns, b, NULL) == TRUE); + + shutdown (conn->super.fd, SHUT_RDWR); + sleep (1); + + ok (mongo_sync_cmd_insert (conn, config.ns, b, NULL) == FALSE, + "Inserting fails with auto-reconnect turned off, and a broken " + "connection"); + + mongo_sync_conn_set_auto_reconnect (conn, TRUE); + + ok (mongo_sync_cmd_insert (conn, config.ns, b, NULL) == TRUE, + "Inserting works with auto-reconnect turned on, and a broken " + "connection"); + + mongo_sync_conn_set_auto_reconnect (conn, FALSE); + + shutdown (conn->super.fd, SHUT_RDWR); + sleep (1); + + ok (mongo_sync_cmd_insert (conn, config.ns, b, NULL) == FALSE, + "Turning off auto-reconnect works"); + + shutdown (conn->super.fd, SHUT_RDWR); + sleep (1); + + p = mongo_sync_cmd_query (conn, config.ns, 0, 0, 1, b, NULL); + ok (p == NULL, + "Query fails with auto-reconnect turned off"); + + mongo_sync_conn_set_auto_reconnect (conn, TRUE); + p = mongo_sync_cmd_query (conn, config.ns, 0, 0, 1, b, NULL); + ok (p != NULL, + "Query does reconnect with auto-reconnect turned on"); + mongo_wire_packet_free (p); + + mongo_sync_disconnect (conn); +} + +RUN_NET_TEST (6, func_mongo_sync_auto_reconnect); diff --git a/tests/func/mongo/sync/f_sync_auto_reconnect_cache.c b/tests/func/mongo/sync/f_sync_auto_reconnect_cache.c new file mode 100644 index 0000000..d69ea5d --- /dev/null +++ b/tests/func/mongo/sync/f_sync_auto_reconnect_cache.c @@ -0,0 +1,107 @@ +#include "test.h" +#include <mongo.h> + +#include <errno.h> +#include <sys/socket.h> + +#include "libmongo-private.h" + +void +test_func_mongo_sync_auto_reconnect_cache (void) +{ + mongo_sync_conn_recovery_cache *cache; + mongo_sync_connection *conn; + bson *b; + mongo_packet *p; + gchar *primary_addr; + const gchar *error_msg; + + primary_addr = g_strdup_printf ("%s:%d", config.primary_host, config.primary_port); + + b = bson_new (); + bson_append_int32 (b, "f_sync_auto_reconnect", 1); + bson_finish (b); + + cache = mongo_sync_conn_recovery_cache_new (); + + mongo_sync_conn_recovery_cache_seed_add (cache, + config.primary_host, + config.primary_port); + + conn = mongo_sync_connect_recovery_cache (cache, + TRUE); + + ok (mongo_sync_cmd_insert (conn, config.ns, b, NULL) == TRUE); + + shutdown (conn->super.fd, SHUT_RDWR); + sleep (1); + + ok (mongo_sync_cmd_insert (conn, config.ns, b, NULL) == FALSE, + "Inserting fails with auto-reconnect turned off, and a broken " + "connection"); + + error_msg = mongo_sync_conn_get_last_error (conn); + + ok (error_msg != NULL, "We have an error msg when insert fails."); + + mongo_sync_conn_set_auto_reconnect (conn, TRUE); + + ok (mongo_sync_cmd_insert (conn, config.ns, b, NULL) == TRUE, + "Inserting works with auto-reconnect turned on, and a broken " + "connection"); + + error_msg = mongo_sync_conn_get_last_error (conn); + + ok (error_msg == NULL, + "After a succesful insert we shouldn't have an error msg."); + + mongo_sync_conn_set_auto_reconnect (conn, FALSE); + + shutdown (conn->super.fd, SHUT_RDWR); + sleep (1); + + ok (mongo_sync_cmd_insert (conn, config.ns, b, NULL) == FALSE, + "Turning off auto-reconnect works"); + + skip (!config.secondary_host, 7, + "Secondary host not set up"); + + shutdown (conn->super.fd, SHUT_RDWR); + sleep (1); + + p = mongo_sync_cmd_query (conn, config.ns, 0, 0, 1, b, NULL); + ok (p == NULL, + "Query fails with auto-reconnect turned off"); + + error_msg = mongo_sync_conn_get_last_error(conn); + ok (error_msg != NULL, "We have an error msg after a failure query."); + + mongo_sync_conn_set_auto_reconnect (conn, TRUE); + p = mongo_sync_cmd_query (conn, config.ns, 0, 0, 1, b, NULL); + ok (p != NULL, + "Query does reconnect with auto-reconnect turned on"); + + ok (mongo_sync_conn_get_last_error(conn) == NULL, + "We shouldn't have any error messages after a successful operation."); + + mongo_wire_packet_free (p); + + mongo_sync_cmd_is_master (conn); + + ok (conn->rs.hosts != NULL, + "We have hosts in the connection's replica set."); + + ok (cache->rs.hosts == NULL, "Cache is empty."); + + mongo_sync_disconnect (conn); + + ok (cache->rs.hosts != NULL, "Cache is filled by disconnect()"); + + mongo_sync_conn_recovery_cache_free (cache); + + endskip; + + g_free (primary_addr); +} + +RUN_NET_TEST (13, func_mongo_sync_auto_reconnect_cache); diff --git a/tests/func/mongo/sync/f_sync_conn_seed_add.c b/tests/func/mongo/sync/f_sync_conn_seed_add.c new file mode 100644 index 0000000..03bcdd2 --- /dev/null +++ b/tests/func/mongo/sync/f_sync_conn_seed_add.c @@ -0,0 +1,58 @@ +#include "test.h" +#include <mongo.h> + +#include "libmongo-private.h" + +void +test_func_mongo_sync_conn_seed_add (void) +{ + mongo_sync_connection *conn; + GList *l; + + conn = mongo_sync_connect (config.primary_host, config.primary_port, + FALSE); + close (conn->super.fd); + + 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, TRUE); + ok (conn == NULL, + "mongo_sync_reconnect() fails without seeds or discovery"); + + conn = mongo_sync_connect (config.primary_host, config.primary_port, + FALSE); + close (conn->super.fd); + l = conn->rs.hosts; + while (l) + { + g_free (l->data); + l = g_list_delete_link (l, l); + } + conn->rs.hosts = NULL; + + ok (mongo_sync_conn_seed_add (conn, config.primary_host, + config.primary_port), + "mongo_sync_conn_seed_add() works"); + + conn = mongo_sync_reconnect (conn, TRUE); + ok (conn != NULL, + "mongo_sync_reconnect() works when properly seeded"); + + mongo_sync_disconnect (conn); +} + +RUN_NET_TEST (3, func_mongo_sync_conn_seed_add); diff --git a/tests/func/mongo/sync/f_sync_invalid_getlasterror.c b/tests/func/mongo/sync/f_sync_invalid_getlasterror.c new file mode 100644 index 0000000..6af227b --- /dev/null +++ b/tests/func/mongo/sync/f_sync_invalid_getlasterror.c @@ -0,0 +1,27 @@ +#include "test.h" +#include <mongo.h> +#include <errno.h> + +void +test_func_mongo_sync_invalid_getlasterror (void) +{ + mongo_sync_connection *conn; + gchar *error = NULL; + gboolean res; + + conn = mongo_sync_connect (config.primary_host, config.primary_port, + TRUE); + + res = mongo_sync_cmd_get_last_error + (conn, "1234567890123456789012345678901234567890123456789012345678901234567890", + &error); + + ok (res == FALSE, + "Trying to get the last error from an invalid DB results in an error."); + ok (error == NULL, + "When getLastError() fails, error remains NULL"); + + mongo_sync_disconnect (conn); +} + +RUN_NET_TEST (2, func_mongo_sync_invalid_getlasterror); diff --git a/tests/func/mongo/sync/f_sync_max_insert_size.c b/tests/func/mongo/sync/f_sync_max_insert_size.c new file mode 100644 index 0000000..9ea5854 --- /dev/null +++ b/tests/func/mongo/sync/f_sync_max_insert_size.c @@ -0,0 +1,69 @@ +#include "test.h" +#include <mongo.h> + +#include <errno.h> + +#include "libmongo-private.h" + +void +test_func_mongo_sync_max_insert_size (void) +{ + mongo_sync_connection *conn; + const bson *docs[10]; + bson *b1, *b2, *b3; + + b1 = bson_new (); + bson_append_string (b1, "func_mongo_sync_max_insert_size", "works", -1); + + bson_finish (b1); + b2 = bson_new (); + bson_append_int32 (b2, "int32", 1984); + bson_finish (b2); + b3 = bson_new (); + bson_finish (b3); + + conn = mongo_sync_connect (config.primary_host, config.primary_port, + FALSE); + + /* + * cmd_insert_n() + */ + mongo_sync_conn_set_max_insert_size (conn, bson_size (b1) + + bson_size (b3) + 1); + + docs[0] = b1; + docs[1] = b2; + docs[2] = b3; + + ok (mongo_sync_cmd_insert_n (conn, config.ns, 3, docs) == TRUE, + "mongo_sync_cmd_insert_n() works with a small max_insert_size"); + + mongo_sync_conn_set_max_insert_size (conn, 1); + errno = 0; + ok (mongo_sync_cmd_insert_n (conn, config.ns, 3, docs) == FALSE, + "mongo_sync_cmd_insert_n() should fail if any one document is too big"); + cmp_ok (errno, "==", EMSGSIZE, + "errno is set to EMSGSIZE"); + + /* + * cmd_insert() + */ + mongo_sync_conn_set_max_insert_size (conn, bson_size (b1) + + bson_size (b3) + 1); + ok (mongo_sync_cmd_insert (conn, config.ns, b1, b2, b3, NULL) == TRUE, + "mongo_sync_cmd_insert() works with a small max_insert_size"); + + mongo_sync_conn_set_max_insert_size (conn, 1); + errno = 0; + ok (mongo_sync_cmd_insert (conn, config.ns, b1, b2, b3, NULL) == FALSE, + "mongo_sync_cmd_insert() should fail if any one document is too big"); + cmp_ok (errno, "==", EMSGSIZE, + "errno is set to EMSGSIZE"); + + mongo_sync_disconnect (conn); + bson_free (b1); + bson_free (b2); + bson_free (b3); +} + +RUN_NET_TEST (6, func_mongo_sync_max_insert_size); diff --git a/tests/func/mongo/sync/f_sync_oidtest.c b/tests/func/mongo/sync/f_sync_oidtest.c new file mode 100644 index 0000000..2a64692 --- /dev/null +++ b/tests/func/mongo/sync/f_sync_oidtest.c @@ -0,0 +1,44 @@ +#include "test.h" +#include <mongo.h> + +#include <string.h> + +void +test_func_mongo_sync_oidtest (void) +{ + mongo_sync_connection *conn; + bson *boid, *reply = NULL; + bson_cursor *c; + mongo_packet *p; + guint8 *oid; + const guint8 *noid; + + mongo_util_oid_init (0); + + oid = mongo_util_oid_new (1); + boid = bson_new (); + bson_append_oid (boid, "driverOIDTest", oid); + bson_finish (boid); + + conn = mongo_sync_connect (config.primary_host, config.primary_port, + FALSE); + + p = mongo_sync_cmd_custom (conn, config.db, boid); + ok (p != NULL, + "driverOIDTest(OID) custom command works"); + mongo_wire_reply_packet_get_nth_document (p, 1, &reply); + bson_finish (reply); + + c = bson_find (reply, "oid"); + bson_cursor_get_oid (c, &noid); + ok (memcmp (oid, noid, 12) == 0, + "driverOIDTest(OID) returns the same OID"); + bson_cursor_free (c); + + mongo_sync_disconnect (conn); + mongo_wire_packet_free (p); + bson_free (boid); + bson_free (reply); +} + +RUN_NET_TEST (2, func_mongo_sync_oidtest); diff --git a/tests/func/mongo/sync/f_sync_safe_mode.c b/tests/func/mongo/sync/f_sync_safe_mode.c new file mode 100644 index 0000000..e312c2f --- /dev/null +++ b/tests/func/mongo/sync/f_sync_safe_mode.c @@ -0,0 +1,112 @@ +#include "test.h" +#include <mongo.h> + +#include <errno.h> +#include <string.h> + +#include "libmongo-private.h" + +void +test_func_mongo_sync_safe_mode_basics (void) +{ + mongo_sync_connection *conn; + const bson *docs[10]; + bson *b1, *b2, *b3, *b4, *cmd; + mongo_packet *p; + gchar *error; + + mongo_util_oid_init (0); + + b1 = bson_new (); + bson_append_string (b1, "func_mongo_sync_safe_mode", "works", -1); + bson_finish (b1); + + b2 = bson_new (); + bson_append_int32 (b2, "int32", 1984); + bson_finish (b2); + + b3 = test_bson_generate_full (); + b4 = test_bson_generate_full (); + + docs[0] = b1; + docs[1] = b2; + docs[2] = b3; + docs[3] = b4; + + conn = mongo_sync_connect (config.primary_host, config.primary_port, + FALSE); + + /* Test inserts */ + mongo_sync_conn_set_safe_mode (conn, FALSE); + ok (mongo_sync_cmd_insert_n (conn, config.ns, 4, docs) == TRUE, + "mongo_sync_cmd_insert_n() should not fail with safe mode off"); + + mongo_sync_conn_set_safe_mode (conn, TRUE); + ok (mongo_sync_cmd_insert_n (conn, config.ns, 4, docs) == FALSE, + "mongo_sync_cmd_insert_n() should fail with safe mode on"); + + /* Test a custom command */ + cmd = bson_new (); + bson_append_int32 (cmd, "bogusCommand", 1); + bson_finish (cmd); + + mongo_sync_cmd_reset_error (conn, config.db); + mongo_sync_conn_set_safe_mode (conn, FALSE); + p = mongo_sync_cmd_custom (conn, config.db, cmd); + mongo_sync_cmd_get_last_error (conn, config.db, &error); + ok (p == NULL && strcmp (error, "no such cmd: bogusCommand") == 0, + "mongo_sync_cmd_custom() with a bogus command fails with safe-mode off"); + bson_free (cmd); + + cmd = bson_new (); + bson_append_int32 (cmd, "bogusCommand2", 1); + bson_finish (cmd); + mongo_sync_cmd_reset_error (conn, config.db); + mongo_sync_conn_set_safe_mode (conn, TRUE); + p = mongo_sync_cmd_custom (conn, config.db, cmd); + mongo_sync_cmd_get_last_error (conn, config.db, &error); + ok (p == NULL && strcmp (error, "no such cmd: bogusCommand2") == 0, + "mongo_sync_cmd_custom() with a bogus command fails with safe-mode on"); + bson_free (cmd); + + mongo_sync_disconnect (conn); + bson_free (b1); + bson_free (b2); + bson_free (b3); + bson_free (b4); +} + +#define INVALID_NS "1234567890123456789012345678901234567890123456789012345678901234567890.test" + +void +test_func_mongo_sync_safe_mode_invalid_db (void) +{ + mongo_sync_connection *conn; + bson *b; + const bson *docs[1]; + + b = bson_new (); + bson_append_int32 (b, "int32", 1984); + bson_finish (b); + + docs[0] = b; + + conn = mongo_sync_connect (config.primary_host, config.primary_port, + TRUE); + mongo_sync_conn_set_safe_mode (conn, TRUE); + + ok (mongo_sync_cmd_insert_n (conn, INVALID_NS, 1, docs) == FALSE, + "mongo_sync_cmd_insert_n() should fail with safe mode on and an invalid NS"); + + mongo_sync_disconnect (conn); + bson_free (b); +} + +void +test_func_mongo_sync_safe_mode (void) +{ + test_func_mongo_sync_safe_mode_basics (); + test_func_mongo_sync_safe_mode_invalid_db (); +} + +RUN_NET_TEST (5, func_mongo_sync_safe_mode); diff --git a/tests/func/mongo/sync/f_sync_safe_mode_cache.c b/tests/func/mongo/sync/f_sync_safe_mode_cache.c new file mode 100644 index 0000000..082617f --- /dev/null +++ b/tests/func/mongo/sync/f_sync_safe_mode_cache.c @@ -0,0 +1,131 @@ +#include "test.h" +#include <mongo.h> + +#include <errno.h> +#include <string.h> + +#include "libmongo-private.h" + +void +test_func_mongo_sync_safe_mode_basics_cache (void) +{ + mongo_sync_connection *conn; + mongo_sync_conn_recovery_cache *cache; + + const bson *docs[10]; + bson *b1, *b2, *b3, *b4, *cmd; + mongo_packet *p; + gchar *error; + + mongo_util_oid_init (0); + + b1 = bson_new (); + bson_append_string (b1, "func_mongo_sync_safe_mode", "works", -1); + bson_finish (b1); + + b2 = bson_new (); + bson_append_int32 (b2, "int32", 1984); + bson_finish (b2); + + b3 = test_bson_generate_full (); + b4 = test_bson_generate_full (); + + docs[0] = b1; + docs[1] = b2; + docs[2] = b3; + docs[3] = b4; + + cache = mongo_sync_conn_recovery_cache_new (); + + mongo_sync_conn_recovery_cache_seed_add (cache, + config.primary_host, + config.primary_port); + + conn = mongo_sync_connect_recovery_cache (cache, FALSE); + + /* Test inserts */ + mongo_sync_conn_set_safe_mode (conn, FALSE); + ok (mongo_sync_cmd_insert_n (conn, config.ns, 4, docs) == TRUE, + "mongo_sync_cmd_insert_n() should not fail with safe mode off"); + + mongo_sync_conn_set_safe_mode (conn, TRUE); + ok (mongo_sync_cmd_insert_n (conn, config.ns, 4, docs) == FALSE, + "mongo_sync_cmd_insert_n() should fail with safe mode on"); + + /* Test a custom command */ + cmd = bson_new (); + bson_append_int32 (cmd, "bogusCommand", 1); + bson_finish (cmd); + + mongo_sync_cmd_reset_error (conn, config.db); + mongo_sync_conn_set_safe_mode (conn, FALSE); + p = mongo_sync_cmd_custom (conn, config.db, cmd); + mongo_sync_cmd_get_last_error (conn, config.db, &error); + ok (p == NULL && strcmp (error, "no such cmd: bogusCommand") == 0, + "mongo_sync_cmd_custom() with a bogus command fails with safe-mode off"); + bson_free (cmd); + g_free (error); + + cmd = bson_new (); + bson_append_int32 (cmd, "bogusCommand2", 1); + bson_finish (cmd); + mongo_sync_cmd_reset_error (conn, config.db); + mongo_sync_conn_set_safe_mode (conn, TRUE); + p = mongo_sync_cmd_custom (conn, config.db, cmd); + mongo_sync_cmd_get_last_error (conn, config.db, &error); + ok (p == NULL && strcmp (error, "no such cmd: bogusCommand2") == 0, + "mongo_sync_cmd_custom() with a bogus command fails with safe-mode on"); + bson_free (cmd); + g_free (error); + + mongo_sync_disconnect (conn); + mongo_sync_conn_recovery_cache_free (cache); + + bson_free (b1); + bson_free (b2); + bson_free (b3); + bson_free (b4); +} + +#define INVALID_NS "1234567890123456789012345678901234567890123456789012345678901234567890.test" + +void +test_func_mongo_sync_safe_mode_invalid_db_cache (void) +{ + mongo_sync_connection *conn; + mongo_sync_conn_recovery_cache *cache; + bson *b; + const bson *docs[1]; + + b = bson_new (); + bson_append_int32 (b, "int32", 1984); + bson_finish (b); + + docs[0] = b; + + cache = mongo_sync_conn_recovery_cache_new (); + + mongo_sync_conn_recovery_cache_seed_add (cache, + config.primary_host, + config.primary_port); + + conn = mongo_sync_connect_recovery_cache (cache, TRUE); + + mongo_sync_conn_set_safe_mode (conn, TRUE); + + ok (mongo_sync_cmd_insert_n (conn, INVALID_NS, 1, docs) == FALSE, + "mongo_sync_cmd_insert_n() should fail with safe mode on and an invalid NS"); + + mongo_sync_disconnect (conn); + mongo_sync_conn_recovery_cache_free (cache); + bson_free (b); +} + +void +test_func_mongo_sync_safe_mode_cache (void) +{ + test_func_mongo_sync_safe_mode_basics_cache (); + test_func_mongo_sync_safe_mode_invalid_db_cache (); +} + +RUN_NET_TEST (5, func_mongo_sync_safe_mode_cache); diff --git a/tests/func/mongo/sync/f_sync_write_error.c b/tests/func/mongo/sync/f_sync_write_error.c new file mode 100644 index 0000000..b6d4750 --- /dev/null +++ b/tests/func/mongo/sync/f_sync_write_error.c @@ -0,0 +1,52 @@ +#include "test.h" +#include <mongo.h> + +#include <errno.h> +#include <sys/socket.h> + +#include "libmongo-private.h" + +#define INVALID_NS "test.$Uncle$.Dagobert$" + +void +test_func_mongo_sync_write_error (void) +{ + mongo_sync_connection *conn; + bson *b; + const gchar *error_msg; + + b = bson_new (); + bson_append_int32 (b, "f_sync_write_error", 1); + bson_finish (b); + + conn = mongo_sync_connect (config.primary_host, config.primary_port, + TRUE); + + ok (mongo_sync_cmd_insert (conn, config.ns, b, NULL) == TRUE, + "Inserting works with correct namespace when safe mode is off"); + + ok (mongo_sync_cmd_insert (conn, INVALID_NS, b, NULL) == TRUE, + "Inserting works with invalid namespace when safe mode is off"); + + error_msg = mongo_sync_conn_get_last_error (conn); + ok (error_msg == NULL, + "When safe mode is off, there is no error msg, even if ns is invalid."); + + ok (mongo_sync_conn_set_safe_mode (conn, TRUE) == TRUE, + "Setting safe mode works."); + + ok (mongo_sync_cmd_insert (conn, config.ns, b, NULL) == TRUE, + "Inserting works with correct namespace when safe mode is on"); + + ok (mongo_sync_cmd_insert (conn, INVALID_NS, b, NULL) == FALSE, + "Inserting fails with invalid namespace when safe mode is on"); + + error_msg = mongo_sync_conn_get_last_error (conn); + + ok (error_msg != NULL, + "Inserting failed in safe mode, so we should have an error msg"); + + mongo_sync_disconnect (conn); +} + +RUN_NET_TEST (7, func_mongo_sync_write_error); diff --git a/tests/libtap/Makefile.am b/tests/libtap/Makefile.am new file mode 100644 index 0000000..271ade2 --- /dev/null +++ b/tests/libtap/Makefile.am @@ -0,0 +1,4 @@ +check_LTLIBRARIES = libtap.la +libtap_la_SOURCES = tap.c tap.h test.h test.c +libtap_la_CFLAGS = -I$(top_srcdir)/src/ @GLIB_CFLAGS@ +libtap_la_LIBADD = $(top_builddir)/src/libmongo-client.la @GLIB_LIBS@ diff --git a/tests/libtap/tap.c b/tests/libtap/tap.c new file mode 100644 index 0000000..e73ae4a --- /dev/null +++ b/tests/libtap/tap.c @@ -0,0 +1,298 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <glib.h> +#include "tap.h" + +static int expected_tests = NO_PLAN; +static int failed_tests; +static int current_test; +static char *todo_mesg; + +void +plan (int tests) { + expected_tests = tests; + if (tests != NO_PLAN) + printf("1..%d\n", tests); +} + +static char * +vstrdupf (const char *fmt, va_list args) { + char *str; + int size; + va_list args2; + va_copy(args2, args); + if (!fmt) + fmt = ""; + size = g_vsnprintf(NULL, 0, fmt, args2) + 2; + str = malloc(size); + vsprintf(str, fmt, args); + va_end(args2); + return str; +} + +int +vok_at_loc (const char *file, int line, int test, const char *fmt, + va_list args) +{ + char *name = vstrdupf(fmt, args); + printf("%sok %d", test ? "" : "not ", ++current_test); + if (*name) + printf(" - %s", name); + if (todo_mesg) { + printf(" # TODO"); + if (*todo_mesg) + printf(" %s", todo_mesg); + } + printf("\n"); + if (!test) { + if (*name) + diag(" Failed%s test '%s'\n at %s line %d.", + todo_mesg ? " (TODO)" : "", name, file, line); + else + diag(" Failed%s test at %s line %d.", + todo_mesg ? " (TODO)" : "", file, line); + if (!todo_mesg) + failed_tests++; + } + free(name); + return test; +} + +int +ok_at_loc (const char *file, int line, int test, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + vok_at_loc(file, line, test, fmt, args); + va_end(args); + return test; +} + +static int +mystrcmp (const char *a, const char *b) { + return a == b ? 0 : !a ? -1 : !b ? 1 : strcmp(a, b); +} + +#define eq(a, b) (!mystrcmp(a, b)) +#define ne(a, b) (mystrcmp(a, b)) + +int +is_at_loc (const char *file, int line, const char *got, const char *expected, + const char *fmt, ...) +{ + int test = eq(got, expected); + va_list args; + va_start(args, fmt); + vok_at_loc(file, line, test, fmt, args); + va_end(args); + if (!test) { + diag(" got: '%s'", got); + diag(" expected: '%s'", expected); + } + return test; +} + +int +isnt_at_loc (const char *file, int line, const char *got, const char *expected, + const char *fmt, ...) +{ + int test = ne(got, expected); + va_list args; + va_start(args, fmt); + vok_at_loc(file, line, test, fmt, args); + va_end(args); + if (!test) { + diag(" got: '%s'", got); + diag(" expected: anything else"); + } + return test; +} + +int +cmp_ok_at_loc (const char *file, int line, int a, const char *op, int b, + const char *fmt, ...) +{ + int test = eq(op, "||") ? a || b + : eq(op, "&&") ? a && b + : eq(op, "|") ? a | b + : eq(op, "^") ? a ^ b + : eq(op, "&") ? a & b + : eq(op, "==") ? a == b + : eq(op, "!=") ? a != b + : eq(op, "<") ? a < b + : eq(op, ">") ? a > b + : eq(op, "<=") ? a <= b + : eq(op, ">=") ? a >= b + : eq(op, "<<") ? a << b + : eq(op, ">>") ? a >> b + : eq(op, "+") ? a + b + : eq(op, "-") ? a - b + : eq(op, "*") ? a * b + : eq(op, "/") ? a / b + : eq(op, "%") ? a % b + : diag("unrecognized operator '%s'", op); + va_list args; + va_start(args, fmt); + vok_at_loc(file, line, test, fmt, args); + va_end(args); + if (!test) { + diag(" %d", a); + diag(" %s", op); + diag(" %d", b); + } + return test; +} + +static void +vdiag_to_fh (FILE *fh, const char *fmt, va_list args) { + char *mesg, *line; + int i; + if (!fmt) + return; + mesg = vstrdupf(fmt, args); + line = mesg; + for (i = 0; *line; i++) { + char c = mesg[i]; + if (!c || c == '\n') { + mesg[i] = '\0'; + fprintf(fh, "# %s\n", line); + if (!c) break; + mesg[i] = c; + line = &mesg[i+1]; + } + } + free(mesg); + return; +} + +int +diag (const char *fmt, ...) { + va_list args; + va_start(args, fmt); + vdiag_to_fh(stderr, fmt, args); + va_end(args); + return 0; +} + +int +note (const char *fmt, ...) { + va_list args; + va_start(args, fmt); + vdiag_to_fh(stdout, fmt, args); + va_end(args); + return 0; +} + +int +exit_status () { + int retval = 0; + if (expected_tests == NO_PLAN) { + printf("1..%d\n", current_test); + } + else if (current_test != expected_tests) { + diag("Looks like you planned %d test%s but ran %d.", + expected_tests, expected_tests > 1 ? "s" : "", current_test); + retval = 255; + } + if (failed_tests) { + diag("Looks like you failed %d test%s of %d run.", + failed_tests, failed_tests > 1 ? "s" : "", current_test); + if (expected_tests == NO_PLAN) + retval = failed_tests; + else + retval = expected_tests - current_test + failed_tests; + } + return retval; +} + +void +skippy (int n, const char *fmt, ...) { + char *why; + va_list args; + va_start(args, fmt); + why = vstrdupf(fmt, args); + va_end(args); + while (n --> 0) { + printf("ok %d ", ++current_test); + note("skip %s\n", why); + } + free(why); +} + +void +ctodo (int ignore __attribute__((unused)), const char *fmt, ...) { + va_list args; + va_start(args, fmt); + todo_mesg = vstrdupf(fmt, args); + va_end(args); +} + +void +cendtodo () { + free(todo_mesg); + todo_mesg = NULL; +} + +#ifndef _WIN32 +#include <sys/mman.h> +#include <regex.h> + +#ifdef __APPLE__ +#define MAP_ANONYMOUS MAP_ANON +#endif + +#ifndef MAP_ANON +#define MAP_ANON MAP_ANONYMOUS +#endif + +/* Create a shared memory int to keep track of whether a piece of code executed +dies. to be used in the dies_ok and lives_ok macros */ +int +tap_test_died (int status) { + static int *test_died = NULL; + int prev; + if (!test_died) { + test_died = (int *)mmap(0, sizeof (int), PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANON, -1, 0); + *test_died = 0; + } + prev = *test_died; + *test_died = status; + return prev; +} + +int +like_at_loc (int for_match, const char *file, int line, const char *got, + const char *expected, const char *fmt, ...) +{ + int test; + regex_t re; + int err = regcomp(&re, expected, REG_EXTENDED); + if (err) { + char errbuf[256]; + regerror(err, &re, errbuf, sizeof errbuf); + fprintf(stderr, "Unable to compile regex '%s': %s at %s line %d\n", + expected, errbuf, file, line); + exit(255); + } + err = regexec(&re, got, 0, NULL, 0); + regfree(&re); + test = for_match ? !err : err; + va_list args; + va_start(args, fmt); + vok_at_loc(file, line, test, fmt, args); + va_end(args); + if (!test) { + if (for_match) { + diag(" '%s'", got); + diag(" doesn't match: '%s'", expected); + } + else { + diag(" '%s'", got); + diag(" matches: '%s'", expected); + } + } + return test; +} +#endif diff --git a/tests/libtap/tap.h b/tests/libtap/tap.h new file mode 100644 index 0000000..3e841bc --- /dev/null +++ b/tests/libtap/tap.h @@ -0,0 +1,85 @@ +#ifndef __TAP_H__ +#define __TAP_H__ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + +#define NO_PLAN -1 +#define ok(...) ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) +#define pass(...) ok(1, ## __VA_ARGS__) +#define fail(...) ok(0, ## __VA_ARGS__) +#define is(...) is_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) +#define isnt(...) isnt_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) +#define cmp_ok(...) cmp_ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) + +int vok_at_loc (const char *file, int line, int test, const char *fmt, + va_list args); +void plan (int tests); +int ok_at_loc (const char *file, int line, int test, const char *fmt, + ...); +int diag (const char *fmt, ...); +int note (const char *fmt, ...); +int exit_status (void); +void skippy (int n, const char *fmt, ...); +void ctodo (int ignore, const char *fmt, ...); +void cendtodo (void); +int is_at_loc (const char *file, int line, const char *got, + const char *expected, const char *fmt, ...); +int isnt_at_loc (const char *file, int line, const char *got, + const char *expected, const char *fmt, ...); +int cmp_ok_at_loc (const char *file, int line, int a, const char *op, + int b, const char *fmt, ...); + +#ifdef _WIN32 +#define like(...) skippy(1, "like is not implemented on MSWin32") +#define unlike(...) like() +#else +#define like(...) like_at_loc(1, __FILE__, __LINE__, __VA_ARGS__, NULL) +#define unlike(...) like_at_loc(0, __FILE__, __LINE__, __VA_ARGS__, NULL) +int like_at_loc (int for_match, const char *file, int line, + const char *got, const char *expected, + const char *fmt, ...); +#endif + +#define skip(test, ...) do {if (test) {skippy(__VA_ARGS__, NULL); break;} +#define endskip } while (0) + +#define todo(...) ctodo(0, ## __VA_ARGS__, NULL) +#define endtodo cendtodo() + +#define dies_ok(code, ...) dies_ok_common(code, 1, ## __VA_ARGS__) +#define lives_ok(code, ...) dies_ok_common(code, 0, ## __VA_ARGS__) + +#ifdef _WIN32 +#define dies_ok_common(...) \ + skippy(1, "Death detection is not supported on MSWin32") +#else +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +int tap_test_died (int status); +#define dies_ok_common(code, for_death, ...) \ + do { \ + tap_test_died(1); \ + int cpid = fork(); \ + switch (cpid) { \ + case -1: \ + perror("fork error"); \ + exit(EXIT_FAILURE); \ + case 0: /* child */ \ + close(1); close(2); \ + code \ + tap_test_died(0); \ + exit(EXIT_SUCCESS); \ + } \ + if (waitpid(cpid, NULL, 0) < 0) { \ + perror("waitpid error"); \ + exit(EXIT_FAILURE); \ + } \ + int it_died = tap_test_died(0); \ + if (!it_died) {code} \ + ok(for_death ? it_died : !it_died, ## __VA_ARGS__); \ + } while (0) +#endif +#endif diff --git a/tests/libtap/test.c b/tests/libtap/test.c new file mode 100644 index 0000000..979807f --- /dev/null +++ b/tests/libtap/test.c @@ -0,0 +1,183 @@ +#include "test.h" +#include "bson.h" +#include "mongo-utils.h" + +#include <glib.h> +#include <string.h> + +#ifndef HAVE_MSG_NOSIGNAL +#include <signal.h> +#endif + + +func_config_t config; + +bson * +test_bson_generate_full (void) +{ + bson *b, *d, *a, *scope; + guint8 oid[] = "1234567890ab"; + + a = bson_new (); + bson_append_int32 (a, "0", 32); + bson_append_int64 (a, "1", (gint64)-42); + bson_finish (a); + + d = bson_new (); + bson_append_string (d, "name", "sub-document", -1); + bson_append_int32 (d, "answer", 42); + bson_finish (d); + + scope = bson_new (); + bson_append_string (scope, "v", "hello world", -1); + bson_finish (scope); + + b = bson_new (); + bson_append_double (b, "double", 3.14); + bson_append_string (b, "str", "hello world", -1); + bson_append_document (b, "doc", d); + bson_append_array (b, "array", a); + bson_append_binary (b, "binary0", BSON_BINARY_SUBTYPE_GENERIC, + (guint8 *)"foo\0bar", 7); + bson_append_oid (b, "_id", oid); + bson_append_boolean (b, "TRUE", FALSE); + bson_append_utc_datetime (b, "date", 1294860709000); + bson_append_timestamp (b, "ts", 1294860709000); + bson_append_null (b, "null"); + bson_append_regex (b, "foobar", "s/foo.*bar/", "i"); + bson_append_javascript (b, "alert", "alert (\"hello world!\");", -1); + bson_append_symbol (b, "sex", "Marilyn Monroe", -1); + bson_append_javascript_w_scope (b, "print", "alert (v);", -1, scope); + bson_append_int32 (b, "int32", 32); + bson_append_int64 (b, "int64", (gint64)-42); + bson_finish (b); + + bson_free (d); + bson_free (a); + bson_free (scope); + + return b; +} + +mongo_packet * +test_mongo_wire_generate_reply (gboolean valid, gint32 nreturn, + gboolean with_docs) +{ + mongo_reply_packet_header rh; + mongo_packet_header h; + mongo_packet *p; + guint8 *data; + gint data_size = sizeof (mongo_reply_packet_header); + bson *b1 = NULL, *b2 = NULL; + + p = mongo_wire_packet_new (); + + h.opcode = (valid) ? GINT32_TO_LE (1) : GINT32_TO_LE (42); + h.id = GINT32_TO_LE (1984); + h.resp_to = GINT32_TO_LE (42); + if (with_docs) + { + b1 = test_bson_generate_full (); + b2 = test_bson_generate_full (); + data_size += bson_size (b1) + bson_size (b2); + } + h.length = GINT32_TO_LE (sizeof (mongo_packet_header) + data_size); + + mongo_wire_packet_set_header (p, &h); + + data = g_try_malloc (data_size); + + rh.flags = 0; + rh.cursor_id = GINT64_TO_LE ((gint64)12345); + rh.start = 0; + rh.returned = GINT32_TO_LE (nreturn); + + memcpy (data, &rh, sizeof (mongo_reply_packet_header)); + if (with_docs) + { + memcpy (data + sizeof (mongo_reply_packet_header), + bson_data (b1), bson_size (b1)); + memcpy (data + sizeof (mongo_reply_packet_header) + bson_size (b1), + bson_data (b2), bson_size (b2)); + } + + mongo_wire_packet_set_data (p, data, data_size); + g_free (data); + bson_free (b1); + bson_free (b2); + + return p; +} + +mongo_sync_connection * +test_make_fake_sync_conn (gint fd, gboolean slaveok) +{ + mongo_sync_connection *c; + + c = g_try_new0 (mongo_sync_connection, 1); + if (!c) + return NULL; + + c->super.fd = fd; + c->slaveok = slaveok; + c->safe_mode = FALSE; + c->auto_reconnect = FALSE; + c->max_insert_size = MONGO_SYNC_DEFAULT_MAX_INSERT_SIZE; + + return c; +} + +gboolean +test_env_setup (void) +{ + config.primary_host = config.secondary_host = NULL; + config.primary_port = config.secondary_port = 27017; + config.db = g_strdup ("test"); + config.coll = g_strdup ("libmongo"); + + if (getenv ("TEST_DB")) + { + g_free (config.db); + config.db = g_strdup (getenv ("TEST_DB")); + } + if (getenv ("TEST_COLLECTION")) + { + g_free (config.coll); + config.coll = g_strdup (getenv ("TEST_COLLECTION")); + } + config.ns = g_strconcat (config.db, ".", config.coll, NULL); + + config.gfs_prefix = g_strconcat (config.ns, ".", "grid", NULL); + + if (!getenv ("TEST_PRIMARY") || strlen (getenv ("TEST_PRIMARY")) == 0) + return FALSE; + + if (!mongo_util_parse_addr (getenv ("TEST_PRIMARY"), &config.primary_host, + &config.primary_port)) + return FALSE; + + if (getenv ("TEST_SECONDARY") && strlen (getenv ("TEST_SECONDARY")) > 0) + mongo_util_parse_addr (getenv ("TEST_SECONDARY"), &config.secondary_host, + &config.secondary_port); + + return TRUE; +} + +void +test_env_free (void) +{ + g_free (config.primary_host); + g_free (config.secondary_host); + g_free (config.db); + g_free (config.coll); + g_free (config.ns); + g_free (config.gfs_prefix); +} + +void +test_main_setup (void) +{ + #ifndef HAVE_MSG_NOSIGNAL + signal(SIGPIPE, SIG_IGN); + #endif +} diff --git a/tests/libtap/test.h b/tests/libtap/test.h new file mode 100644 index 0000000..1c442f5 --- /dev/null +++ b/tests/libtap/test.h @@ -0,0 +1,84 @@ +#ifndef LIBMONGO_CLIENT_TEST_H +#define LIBMONGO_CLIENT_TEST_H 1 + +#include "tap.h" +#include "bson.h" +#include "mongo-wire.h" +#include "mongo-sync.h" +#include "libmongo-private.h" + +#include <dlfcn.h> + +typedef struct +{ + gchar *primary_host; + gint primary_port; + + gchar *secondary_host; + gint secondary_port; + + gchar *db; + gchar *coll; + gchar *ns; + + gchar *gfs_prefix; +} func_config_t; + +extern func_config_t config; + +#define begin_network_tests(n) \ + do \ + { \ + skip(!test_env_setup (), n, "Environment not set up for network tests") + +#define end_network_tests() \ + endskip; \ + test_env_free(); \ + } while (0) + +#define RUN_TEST(n, t) \ + int \ + main (void) \ + { \ + test_main_setup(); \ + plan (n); \ + test_##t (); \ + return 0; \ + } + +gboolean test_env_setup (void); +void test_env_free (void); +void test_main_setup (void); + +#define RUN_NET_TEST(n, t) \ + int \ + main (void) \ + { \ + test_main_setup(); \ + if (!test_env_setup ()) \ + printf ("1..0 # skip, Environment not set up for network tests"); \ + else \ + { \ + plan (n); \ + test_##t (); \ + } \ + test_env_free (); \ + return 0; \ + } + +bson *test_bson_generate_full (void); +mongo_packet *test_mongo_wire_generate_reply (gboolean valid, + gint32 nreturn, + gboolean with_docs); +mongo_sync_connection *test_make_fake_sync_conn (gint fd, + gboolean slaveok); + +#define SAVE_OLD_FUNC(n) \ + static void *(*func_##n)(); \ + if (!func_##n) \ + func_##n = (void *(*)())dlsym (RTLD_NEXT, #n); + +#define CALL_OLD_FUNC(n, ...) \ + func_##n (__VA_ARGS__) + +#endif diff --git a/tests/perf/bson/p_bson_find.c b/tests/perf/bson/p_bson_find.c new file mode 100644 index 0000000..4e62132 --- /dev/null +++ b/tests/perf/bson/p_bson_find.c @@ -0,0 +1,43 @@ +#include "tap.h" +#include "test.h" + +#include <mongo.h> + +#define MAX_KEYS 10000 + +void +test_p_bson_find (void) +{ + bson *b; + bson_cursor *c; + gint i; + gchar **keys; + gboolean ret = TRUE; + + keys = g_new(gchar *, MAX_KEYS); + + b = bson_new (); + for (i = 0; i < MAX_KEYS; i++) + { + keys[i] = g_strdup_printf ("tmp_key_%d", i); + bson_append_int32 (b, keys[i], i); + } + bson_finish (b); + + for (i = 1; i <= MAX_KEYS; i++) + { + c = bson_find (b, keys[i - 1]); + if (!c) + ret = FALSE; + bson_cursor_free (c); + g_free (keys[i - 1]); + } + + bson_free (b); + g_free (keys); + + ok (ret == TRUE, + "bson_find() performance test ok"); +} + +RUN_TEST (1, p_bson_find); diff --git a/tests/runall b/tests/runall new file mode 100755 index 0000000..e25f8ef --- /dev/null +++ b/tests/runall @@ -0,0 +1,17 @@ +#! /bin/sh +set -e + +fail_counter=0 + +trap '[ $? -eq 0 ] && rm -f current-test.out current-test.err' 0 + +for test in $@; do + ${test} 2>current-test.err >current-test.out + if grep "not ok" current-test.out >/dev/null 2>/dev/null; then + echo "${test} failed:" >&2 + cat current-test.err >&2 + fail_counter=`expr ${fail_counter} + 1` + fi +done + +exit ${fail_counter} diff --git a/tests/test_cleanup.c b/tests/test_cleanup.c new file mode 100644 index 0000000..bef203a --- /dev/null +++ b/tests/test_cleanup.c @@ -0,0 +1,31 @@ +#include "test.h" +#include <mongo.h> + +int +main (void) +{ + mongo_sync_connection *conn; + gchar *c; + + if (!test_env_setup ()) + return 0; + + conn = mongo_sync_connect (config.primary_host, config.primary_port, FALSE); + mongo_sync_cmd_drop (conn, config.db, config.coll); + + c = g_strconcat (config.coll, ".grid.files", NULL); + mongo_sync_cmd_drop (conn, config.db, c); + g_free (c); + + c = g_strconcat (config.coll, ".grid.chunks", NULL); + mongo_sync_cmd_drop (conn, config.db, c); + g_free (c); + + c = g_strconcat (config.coll, ".capped", NULL); + mongo_sync_cmd_drop (conn, config.db, c); + g_free (c); + + test_env_free (); + + return 0; +} diff --git a/tests/tools/coverage-report-entry.pl b/tests/tools/coverage-report-entry.pl new file mode 100644 index 0000000..53ec17b --- /dev/null +++ b/tests/tools/coverage-report-entry.pl @@ -0,0 +1,70 @@ +#!/usr/bin/perl +# +# Copyright (C) 2006 Daniel Berrange +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +print <<EOF; +<html> +<head> +<title>Coverage report for $ARGV[0]</title> +<style type="text/css"> + span.perfect { + background: rgb(0,255,0); + } + span.terrible { + background: rgb(255,0,0); + } +</style> +</head> +<body> +<h1>Coverage report for $ARGV[0]</h1> + +<pre> +EOF + + +while (<>) { + s/&/&/g; + s/</</g; + s/>/>/g; + + if (/^\s*function (\S+) called (\d+) returned \d+% blocks executed \d+%/) { + my $class = $2 > 0 ? "perfect" : "terrible"; + $_ = "<span class=\"$class\" id=\"" . $1 . "\">$_</span>"; + } elsif (/^\s*branch\s+\d+\s+taken\s+(\d+)%\s+.*$/) { + my $class = $1 > 0 ? "perfect" : "terrible"; + $_ = "<span class=\"$class\">$_</span>"; + } elsif (/^\s*branch\s+\d+\s+never executed.*$/) { + my $class = "terrible"; + $_ = "<span class=\"$class\">$_</span>"; + } elsif (/^\s*call\s+\d+\s+never executed.*$/) { + my $class = "terrible"; + $_ = "<span class=\"$class\">$_</span>"; + } elsif (/^\s*call\s+\d+\s+returned\s+(\d+)%.*$/) { + my $class = $1 > 0 ? "perfect" : "terrible"; + $_ = "<span class=\"$class\">$_</span>"; + } + + + print; +} + +print <<EOF; +</pre> +</body> +</html> +EOF diff --git a/tests/tools/coverage-report.pl b/tests/tools/coverage-report.pl new file mode 100644 index 0000000..6ad7abd --- /dev/null +++ b/tests/tools/coverage-report.pl @@ -0,0 +1,125 @@ +#!/usr/bin/perl +# +# Copyright (C) 2006 Daniel Berrange +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +use warnings; +use strict; + +my %coverage = ( functions => {}, files => {} ); + +my %filemap; + +my $type; +my $name; + +my @functions; + +while (<>) { + if (/^Function '(.*)'\s*$/) { + $type = "function"; + $name = $1; + $coverage{$type}->{$name} = {}; + push @functions, $name; + } elsif (/^File '(.*?)'\s*$/) { + $type = "file"; + $name = $1; + $coverage{$type}->{$name} = {}; + + foreach my $func (@functions) { + $coverage{"function"}->{$func}->{file} = $name; + } + @functions = (); + } elsif (/^Lines executed:(.*)%\s*of\s*(\d+)\s*$/) { + $coverage{$type}->{$name}->{lines} = $2; + $coverage{$type}->{$name}->{linesCoverage} = $1; + } elsif (/^Branches executed:(.*)%\s*of\s*(\d+)\s*$/) { + $coverage{$type}->{$name}->{branches} = $2; + $coverage{$type}->{$name}->{branchesCoverage} = $1; + } elsif (/^Taken at least once:(.*)%\s*of\s*(\d+)\s*$/) { + $coverage{$type}->{$name}->{conds} = $2; + $coverage{$type}->{$name}->{condsCoverage} = $1; + } elsif (/^Calls executed:(.*)%\s*of\s*(\d+)\s*$/) { + $coverage{$type}->{$name}->{calls} = $2; + $coverage{$type}->{$name}->{callsCoverage} = $1; + } elsif (/^No branches$/) { + $coverage{$type}->{$name}->{branches} = 0; + $coverage{$type}->{$name}->{branchesCoverage} = "100.00"; + $coverage{$type}->{$name}->{conds} = 0; + $coverage{$type}->{$name}->{condsCoverage} = "100.00"; + } elsif (/^No calls$/) { + $coverage{$type}->{$name}->{calls} = 0; + $coverage{$type}->{$name}->{callsCoverage} = "100.00"; + } elsif (/^\s*(.*):creating '(.*)'\s*$/) { + $filemap{$1} = $2; + } elsif (/^\s*$/) { + # nada + } else { + warn "Shit [$_]\n"; + } +} + +my %summary; +foreach my $type ("function", "file") { + $summary{$type} = {}; + foreach my $m ("lines", "branches", "conds", "calls") { + my $totalGot = 0; + my $totalMiss = 0; + my $count = 0; + foreach my $func (keys %{$coverage{function}}) { + $count++; + my $got = $coverage{function}->{$func}->{$m}; + $totalGot += $got; + my $miss = $got * $coverage{function}->{$func}->{$m ."Coverage"} / 100; + $totalMiss += $miss; + } + $summary{$type}->{$m} = sprintf("%d", $totalGot); + $summary{$type}->{$m . "Coverage"} = sprintf("%.2f", $totalMiss / $totalGot * 100); + } +} + + + +print "<coverage>\n"; + +foreach my $type ("function", "file") { + printf "<%ss>\n", $type; + foreach my $name (sort { $a cmp $b } keys %{$coverage{$type}}) { + my $rec = $coverage{$type}->{$name}; + printf " <entry name=\"%s\" details=\"%s\">\n", $name, ($type eq "file" ? $filemap{$name} : $filemap{$rec->{file}}); + printf " <lines count=\"%s\" coverage=\"%s\"/>\n", $rec->{lines}, $rec->{linesCoverage}; + if (exists $rec->{branches}) { + printf " <branches count=\"%s\" coverage=\"%s\"/>\n", $rec->{branches}, $rec->{branchesCoverage}; + } + if (exists $rec->{conds}) { + printf " <conditions count=\"%s\" coverage=\"%s\"/>\n", $rec->{conds}, $rec->{condsCoverage}; + } + if (exists $rec->{calls}) { + printf " <calls count=\"%s\" coverage=\"%s\"/>\n", $rec->{calls}, $rec->{callsCoverage}; + } + print " </entry>\n"; + } + + printf " <summary>\n"; + printf " <lines count=\"%s\" coverage=\"%s\"/>\n", $summary{$type}->{lines}, $summary{$type}->{linesCoverage}; + printf " <branches count=\"%s\" coverage=\"%s\"/>\n", $summary{$type}->{branches}, $summary{$type}->{branchesCoverage}; + printf " <conditions count=\"%s\" coverage=\"%s\"/>\n", $summary{$type}->{conds}, $summary{$type}->{condsCoverage}; + printf " <calls count=\"%s\" coverage=\"%s\"/>\n", $summary{$type}->{calls}, $summary{$type}->{callsCoverage}; + printf " </summary>\n"; + printf "</%ss>\n", $type; +} + +print "</coverage>\n"; diff --git a/tests/tools/coverage-report.xsl b/tests/tools/coverage-report.xsl new file mode 100644 index 0000000..ca3f57f --- /dev/null +++ b/tests/tools/coverage-report.xsl @@ -0,0 +1,235 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +# +# Copyright (C) 2006 Daniel Berrange +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +--> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + version="1.0"> + + <xsl:output method="html"/> + + <xsl:template match="coverage"> + <html> + <head> + <title>Coverage report</title> + <style type="text/css"> + tbody tr.odd td.label { + border-top: 1px solid rgb(128,128,128); + border-bottom: 1px solid rgb(128,128,128); + } + tbody tr.odd td.label { + background: rgb(200,200,200); + } + + thead, tfoot { + background: rgb(60,60,60); + color: white; + font-weight: bold; + } + + tr td.perfect { + background: rgb(0,255,0); + color: black; + } + tr td.excellant { + background: rgb(140,255,140); + color: black; + } + tr td.good { + background: rgb(160,255,0); + color: black; + } + tr td.poor { + background: rgb(255,160,0); + color: black; + } + tr td.bad { + background: rgb(255,140,140); + color: black; + } + tr td.terrible { + background: rgb(255,0,0); + color: black; + } + </style> + </head> + <body> + <h1>Coverage report</h1> + <xsl:apply-templates/> + </body> + </html> + </xsl:template> + + <xsl:template match="functions"> + <h2>Function coverage</h2> + <xsl:call-template name="content"> + <xsl:with-param name="type" select="'function'"/> + </xsl:call-template> + </xsl:template> + + + <xsl:template match="files"> + <h2>File coverage</h2> + <xsl:call-template name="content"> + <xsl:with-param name="type" select="'file'"/> + </xsl:call-template> + </xsl:template> + + <xsl:template name="content"> + <xsl:param name="type"/> + <table> + <thead> + <tr> + <th>Name</th> + <th>Lines</th> + <th>Branches</th> + <th>Conditions</th> + <th>Calls</th> + </tr> + </thead> + <tbody> + <xsl:for-each select="entry"> + <xsl:call-template name="entry"> + <xsl:with-param name="type" select="$type"/> + <xsl:with-param name="class"> + <xsl:choose> + <xsl:when test="position() mod 2"> + <xsl:text>odd</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>even</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:with-param> + </xsl:call-template> + </xsl:for-each> + </tbody> + <tfoot> + <xsl:for-each select="summary"> + <xsl:call-template name="entry"> + <xsl:with-param name="type" select="'summary'"/> + <xsl:with-param name="class"> + <xsl:choose> + <xsl:when test="position() mod 2"> + <xsl:text>odd</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>even</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:with-param> + </xsl:call-template> + </xsl:for-each> + </tfoot> + </table> + </xsl:template> + + <xsl:template name="entry"> + <xsl:param name="type"/> + <xsl:param name="class"/> + <tr class="{$class}"> + <xsl:choose> + <xsl:when test="$type = 'function'"> + <td class="label"><a href="{@details}.html#{@name}"><xsl:value-of select="@name"/></a></td> + </xsl:when> + <xsl:when test="$type = 'file'"> + <td class="label"><a href="{@details}.html"><xsl:value-of select="@name"/></a></td> + </xsl:when> + <xsl:otherwise> + <td class="label">Summary</td> + </xsl:otherwise> + </xsl:choose> + + <xsl:if test="count(lines)"> + <xsl:apply-templates select="lines"/> + </xsl:if> + <xsl:if test="not(count(lines))"> + <xsl:call-template name="missing"/> + </xsl:if> + + <xsl:if test="count(branches)"> + <xsl:apply-templates select="branches"/> + </xsl:if> + <xsl:if test="not(count(branches))"> + <xsl:call-template name="missing"/> + </xsl:if> + + <xsl:if test="count(conditions)"> + <xsl:apply-templates select="conditions"/> + </xsl:if> + <xsl:if test="not(count(conditions))"> + <xsl:call-template name="missing"/> + </xsl:if> + + <xsl:if test="count(calls)"> + <xsl:apply-templates select="calls"/> + </xsl:if> + <xsl:if test="not(count(calls))"> + <xsl:call-template name="missing"/> + </xsl:if> + + </tr> + </xsl:template> + + <xsl:template match="lines"> + <xsl:call-template name="row"/> + </xsl:template> + + <xsl:template match="branches"> + <xsl:call-template name="row"/> + </xsl:template> + + <xsl:template match="conditions"> + <xsl:call-template name="row"/> + </xsl:template> + + <xsl:template match="calls"> + <xsl:call-template name="row"/> + </xsl:template> + + <xsl:template name="missing"> + <td></td> + </xsl:template> + + <xsl:template name="row"> + <xsl:variable name="quality"> + <xsl:choose> + <xsl:when test="@coverage = 100"> + <xsl:text>perfect</xsl:text> + </xsl:when> + <xsl:when test="@coverage >= 80.0"> + <xsl:text>excellant</xsl:text> + </xsl:when> + <xsl:when test="@coverage >= 60.0"> + <xsl:text>good</xsl:text> + </xsl:when> + <xsl:when test="@coverage >= 40.0"> + <xsl:text>poor</xsl:text> + </xsl:when> + <xsl:when test="@coverage >= 20.0"> + <xsl:text>bad</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>terrible</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <td class="{$quality}"><xsl:value-of select="@coverage"/>% of <xsl:value-of select="@count"/></td> + </xsl:template> + +</xsl:stylesheet> diff --git a/tests/unit/bson/bson_append_array.c b/tests/unit/bson/bson_append_array.c new file mode 100644 index 0000000..040f0ed --- /dev/null +++ b/tests/unit/bson/bson_append_array.c @@ -0,0 +1,65 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_array (void) +{ + bson *b, *e1, *e2; + + e1 = bson_new (); + bson_append_int32 (e1, "0", 1984); + bson_append_string (e1, "1", "hello world", -1); + bson_finish (e1); + + e2 = bson_new (); + bson_append_string (e2, "0", "bar", -1); + ok (bson_append_array (e2, "1", e1), + "bson_append_array() works"); + bson_finish (e2); + bson_free (e1); + + b = bson_new (); + ok (bson_append_array (b, "0", e2), + "bson_append_array() works still"); + bson_finish (b); + bson_free (e2); + + cmp_ok (bson_size (b), "==", 58, "BSON array element size check"); + ok (memcmp (bson_data (b), + "\072\000\000\000\004\060\000\062\000\000\000\002\060\000\004" + "\000\000\000\142\141\162\000\004\061\000\037\000\000\000\020" + "\060\000\300\007\000\000\002\061\000\014\000\000\000\150\145" + "\154\154\157\040\167\157\162\154\144\000\000\000\000", + bson_size (b)) == 0, + "BSON array element contents check"); + + bson_free (b); + + e1 = bson_new (); + bson_append_int32 (e1, "0", 1984); + b = bson_new (); + + ok (bson_append_array (b, "array", e1) == FALSE, + "bson_append_array() with an unfinished array should fail"); + bson_finish (e1); + ok (bson_append_array (b, NULL, e1) == FALSE, + "bson_append_array() with a NULL name should fail"); + ok (bson_append_array (b, "foo", NULL) == FALSE, + "bson_append_array() with a NULL array should fail"); + ok (bson_append_array (NULL, "foo", e1) == FALSE, + "bson_append_array() with a NULL BSON should fail"); + bson_finish (b); + cmp_ok (bson_size (b), "==", 5, + "BSON object should be empty"); + + ok (bson_append_array (b, "array", e1) == FALSE, + "Appending to a finished element should fail"); + + bson_free (e1); + bson_free (b); +} + +RUN_TEST (10, bson_array); diff --git a/tests/unit/bson/bson_append_binary.c b/tests/unit/bson/bson_append_binary.c new file mode 100644 index 0000000..06ea362 --- /dev/null +++ b/tests/unit/bson/bson_append_binary.c @@ -0,0 +1,56 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_binary (void) +{ + bson *b; + + b = bson_new (); + ok (bson_append_binary (b, "binary0", BSON_BINARY_SUBTYPE_GENERIC, + (guint8 *)"foo\0bar", 7), + "bson_append_binary(), type 0 works"); + ok (bson_append_binary (b, "binary2", BSON_BINARY_SUBTYPE_BINARY, + (guint8 *)"\0\0\0\7foo\0bar", 11), + "bson_append_binary(), type 2 works"); + bson_finish (b); + + cmp_ok (bson_size (b), "==", 51, "BSON binary element size check"); + ok (memcmp (bson_data (b), + "\063\000\000\000\005\142\151\156\141\162\171\060\000\007\000" + "\000\000\000\146\157\157\000\142\141\162\005\142\151\156\141" + "\162\171\062\000\013\000\000\000\002\000\000\000\007\146\157" + "\157\000\142\141\162\000", + bson_size (b)) == 0, + "BSON binary element contents check"); + + bson_free (b); + + b = bson_new (); + ok (bson_append_binary (b, NULL, BSON_BINARY_SUBTYPE_GENERIC, + (guint8 *)"foo\0bar", 7) == FALSE, + "bson_append_binary() without a key name should fail"); + ok (bson_append_binary (b, "binary1", BSON_BINARY_SUBTYPE_GENERIC, + NULL, 10) == FALSE, + "bson_append_binary () without binary data should fail"); + ok (bson_append_binary (b, "binary3", BSON_BINARY_SUBTYPE_GENERIC, + (guint8 *)"foo\0bar", -1) == FALSE, + "bson_append_binary () with an invalid length should fail"); + ok (bson_append_binary (NULL, "binary1", BSON_BINARY_SUBTYPE_GENERIC, + (guint8 *)"foo\0bar", 7) == FALSE, + "bson_append_binary () without a BSON object should fail"); + bson_finish (b); + cmp_ok (bson_size (b), "==", 5, + "BSON object should be empty"); + + ok (bson_append_binary (b, "binary", BSON_BINARY_SUBTYPE_GENERIC, + (guint8 *)"foo\0bar", 7) == FALSE, + "Appending to a finished element should fail"); + + bson_free (b); +} + +RUN_TEST (10, bson_binary); diff --git a/tests/unit/bson/bson_append_boolean.c b/tests/unit/bson/bson_append_boolean.c new file mode 100644 index 0000000..03df0a5 --- /dev/null +++ b/tests/unit/bson/bson_append_boolean.c @@ -0,0 +1,43 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_boolean (void) +{ + bson *b; + + b = bson_new (); + ok (bson_append_boolean (b, "FALSE", FALSE), + "bson_append_boolean() works"); + ok (bson_append_boolean (b, "TRUE", TRUE), + "bson_append_boolean() works still"); + bson_finish (b); + + cmp_ok (bson_size (b), "==", 20, "BSON boolean element size check"); + ok (memcmp (bson_data (b), + "\024\000\000\000\010\106\101\114\123\105\000\000\010\124\122" + "\125\105\000\001\000", + bson_size (b)) == 0, + "BSON boolean element contents check"); + + bson_free (b); + + b = bson_new (); + ok (bson_append_boolean (b, NULL, TRUE) == FALSE, + "bson_append_boolean() with a NULL key should fail"); + ok (bson_append_boolean (NULL, "TRUE", TRUE) == FALSE, + "bson_append_boolean() without a BSON object should fail"); + bson_finish (b); + cmp_ok (bson_size (b), "==", 5, + "BSON object should be empty"); + + ok (bson_append_boolean (b, "b", TRUE) == FALSE, + "Appending to a finished element should fail"); + + bson_free (b); +} + +RUN_TEST (8, bson_boolean); diff --git a/tests/unit/bson/bson_append_document.c b/tests/unit/bson/bson_append_document.c new file mode 100644 index 0000000..04d077c --- /dev/null +++ b/tests/unit/bson/bson_append_document.c @@ -0,0 +1,67 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_document (void) +{ + bson *b, *e1, *e2; + + e1 = bson_new (); + bson_append_int32 (e1, "i32", 1984); + bson_append_string (e1, "str", "hello world", -1); + bson_finish (e1); + + e2 = bson_new (); + bson_append_string (e2, "foo", "bar", -1); + ok (bson_append_document (e2, "subd", e1), + "bson_append_document() works"); + bson_finish (e2); + bson_free (e1); + + b = bson_new (); + ok (bson_append_document (b, "doc", e2), + "bson_append_document() works still"); + bson_finish (b); + bson_free (e2); + + cmp_ok (bson_size (b), "==", 69, "BSON document element size check"); + ok (memcmp (bson_data (b), + "\105\000\000\000\003\144\157\143\000\073\000\000\000\002\146" + "\157\157\000\004\000\000\000\142\141\162\000\003\163\165\142" + "\144\000\043\000\000\000\020\151\063\062\000\300\007\000\000" + "\002\163\164\162\000\014\000\000\000\150\145\154\154\157\040" + "\167\157\162\154\144\000\000\000\000", + bson_size (b)) == 0, + "BSON document element contents check"); + + bson_free (b); + + e1 = bson_new (); + bson_append_int32 (e1, "foo", 42); + b = bson_new (); + + ok (bson_append_document (b, "doc", e1) == FALSE, + "bson_append_document() with an unfinished document should fail"); + bson_finish (e1); + ok (bson_append_document (b, NULL, e1) == FALSE, + "bson_append_document() with a NULL key should fail"); + ok (bson_append_document (b, "doc", NULL) == FALSE, + "bson_append_document() with a NULL document should fail"); + ok (bson_append_document (NULL, "doc", e1) == FALSE, + "bson_append_document() without a BSON object should fail"); + bson_finish (b); + + cmp_ok (bson_size (b), "==", 5, + "BSON object should be empty"); + + ok (bson_append_document (b, "doc", e1) == FALSE, + "Appending to a finished element should fail"); + + bson_free (e1); + bson_free (b); +} + +RUN_TEST (10, bson_document); diff --git a/tests/unit/bson/bson_append_double.c b/tests/unit/bson/bson_append_double.c new file mode 100644 index 0000000..de62c15 --- /dev/null +++ b/tests/unit/bson/bson_append_double.c @@ -0,0 +1,41 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_double (void) +{ + bson *b; + double d = 3.14; + + b = bson_new (); + ok (bson_append_double (b, "double", d), "bson_append_double() works"); + bson_finish (b); + + cmp_ok (bson_size (b), "==", 21, "BSON double element size check"); + ok (memcmp (bson_data (b), + "\025\000\000\000\001\144\157\165\142\154\145\000\037\205\353" + "\121\270\036\011\100\000", + bson_size (b)) == 0, + "BSON double element contents check"); + + bson_free (b); + + b = bson_new (); + ok (bson_append_double (b, NULL, d) == FALSE, + "bson_append_double() with a NULL key should fail"); + ok (bson_append_double (NULL, "double", d) == FALSE, + "bson_append_double() without a BSON object should fail"); + bson_finish (b); + cmp_ok (bson_size (b), "==", 5, + "BSON object should be empty"); + + ok (bson_append_double (b, "d", d) == FALSE, + "Appending to a finished element should fail"); + + bson_free (b); +} + +RUN_TEST (7, bson_double); diff --git a/tests/unit/bson/bson_append_int32.c b/tests/unit/bson/bson_append_int32.c new file mode 100644 index 0000000..e2a2867 --- /dev/null +++ b/tests/unit/bson/bson_append_int32.c @@ -0,0 +1,40 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_int32 (void) +{ + bson *b; + gint32 i = 1984; + + b = bson_new (); + ok (bson_append_int32 (b, "i32", i), "bson_append_int32() works"); + bson_finish (b); + + cmp_ok (bson_size (b), "==", 14, "BSON int32 element size check"); + ok (memcmp (bson_data (b), + "\016\000\000\000\020\151\063\062\000\300\007\000\000\000", + bson_size (b)) == 0, + "BSON int32 element contents check"); + + bson_free (b); + + b = bson_new (); + ok (bson_append_int32 (b, NULL, i) == FALSE, + "bson_append_int32() with a NULL key should fail"); + ok (bson_append_int32 (NULL, "i32", i) == FALSE, + "bson_append_int32() without a BSON object should fail"); + bson_finish (b); + cmp_ok (bson_size (b), "==", 5, + "BSON object should be empty"); + + ok (bson_append_int32 (b, "i32", i) == FALSE, + "Appending to a finished element should fail"); + + bson_free (b); +} + +RUN_TEST (7, bson_int32); diff --git a/tests/unit/bson/bson_append_int64.c b/tests/unit/bson/bson_append_int64.c new file mode 100644 index 0000000..22d9691 --- /dev/null +++ b/tests/unit/bson/bson_append_int64.c @@ -0,0 +1,41 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_int64 (void) +{ + bson *b; + gint64 l = 9876543210; + + b = bson_new (); + ok (bson_append_int64 (b, "i64", l), "bson_append_int64() works"); + bson_finish (b); + + cmp_ok (bson_size (b), "==", 18, "BSON int64 element size check"); + ok (memcmp (bson_data (b), + "\022\000\000\000\022\151\066\064\000\352\026\260\114\002\000" + "\000\000\000", + bson_size (b)) == 0, + "BSON int64 element contents check"); + + bson_free (b); + + b = bson_new (); + ok (bson_append_int64 (b, NULL, l) == FALSE, + "bson_append_int64() with a NULL key should fail"); + ok (bson_append_int64 (NULL, "i64", l) == FALSE, + "bson_append_int64() without a BSON object should fail"); + bson_finish (b); + cmp_ok (bson_size (b), "==", 5, + "BSON object should be empty"); + + ok (bson_append_int64 (b, "i64", l) == FALSE, + "Appending to a finished element should fail"); + + bson_free (b); +} + +RUN_TEST (7, bson_int64); diff --git a/tests/unit/bson/bson_append_js_code.c b/tests/unit/bson/bson_append_js_code.c new file mode 100644 index 0000000..4b250b0 --- /dev/null +++ b/tests/unit/bson/bson_append_js_code.c @@ -0,0 +1,66 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_js_code (void) +{ + bson *b; + + /* Test #1: A single JS element, with default size. */ + b = bson_new (); + ok (bson_append_javascript (b, "hello", + "function () { print (\"hello world!\"); }", -1), + "bson_append_javascript() works"); + bson_finish (b); + + cmp_ok (bson_size (b), "==", 56, "BSON javascript element size check"); + ok (memcmp (bson_data (b), + "\070\000\000\000\015\150\145\154\154\157\000\050\000\000\000" + "\146\165\156\143\164\151\157\156\040\050\051\040\173\040\160" + "\162\151\156\164\040\050\042\150\145\154\154\157\040\167\157" + "\162\154\144\041\042\051\073\040\175\000\000", + bson_size (b)) == 0, + "BSON javascript element contents check"); + bson_free (b); + + /* Test #2: A single javascript element, with explicit length. */ + b = bson_new (); + ok (bson_append_javascript (b, "hello", + "print (\"hello world!\"); garbage is gone.", + strlen ("print (\"hello world!\");")), + "bson_append_javascript() with explicit length works"); + bson_finish (b); + + cmp_ok (bson_size (b), "==", 40, "BSON javascript element size check, #2"); + ok (memcmp (bson_data (b), + "\050\000\000\000\015\150\145\154\154\157\000\030\000\000\000" + "\160\162\151\156\164\040\050\042\150\145\154\154\157\040\167" + "\157\162\154\144\041\042\051\073\000\000", + bson_size (b)) == 0, + "BSON javascript element contents check, #2"); + bson_free (b); + + /* Test #3: Negative test, passing an invalid arguments. */ + b = bson_new (); + ok (bson_append_javascript (b, "hello", "print();", -42) == FALSE, + "bson_append_javascript() with an invalid length should fail"); + ok (bson_append_javascript (b, NULL, "print();", -1) == FALSE, + "bson_append_javascript() should fail without a key name"); + ok (bson_append_javascript (b, "hello", NULL, -1) == FALSE, + "bson_append_javascript() should fail without javascript code"); + ok (bson_append_javascript (NULL, "hello", "print();", -1) == FALSE, + "bson_append_javascript() should fail without a BSON object"); + bson_finish (b); + cmp_ok (bson_size (b), "==", 5, + "BSON object should be empty"); + + ok (bson_append_javascript (b, "js", "print();", -1) == FALSE, + "Appending to a finished element should fail"); + + bson_free (b); +} + +RUN_TEST (12, bson_js_code); diff --git a/tests/unit/bson/bson_append_js_code_w_scope.c b/tests/unit/bson/bson_append_js_code_w_scope.c new file mode 100644 index 0000000..09297f3 --- /dev/null +++ b/tests/unit/bson/bson_append_js_code_w_scope.c @@ -0,0 +1,79 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_js_code_w_scope (void) +{ + bson *b, *scope; + + scope = bson_new (); + bson_append_string (scope, "foo", "bar", -1); + bson_finish (scope); + + /* Test #1: A single JS element, with default size. */ + b = bson_new (); + ok (bson_append_javascript_w_scope (b, "f", + "alert ('hello');", -1, + scope), + "bson_append_javascript_w_scope() works"); + bson_finish (b); + + cmp_ok (bson_size (b), "==", 51, "BSON javascript w/ element size check"); + ok (memcmp (bson_data (b), + "\063\000\000\000\017\146\000\053\000\000\000\021\000\000\000" + "\141\154\145\162\164\040\050\047\150\145\154\154\157\047\051" + "\073\000\022\000\000\000\002\146\157\157\000\004\000\000\000" + "\142\141\162\000\000\000", + bson_size (b)) == 0, + "BSON javascript w/ scope element contents check"); + bson_free (b); + + /* Test #2: A single javascript element, with explicit length. */ + b = bson_new (); + ok (bson_append_javascript_w_scope (b, "f", + "alert ('hello'); garbage", + strlen ("alert ('hello');"), + scope), + "bson_append_javascript_w_scope() with explicit length works"); + bson_finish (b); + + cmp_ok (bson_size (b), "==", 51, "BSON javascript w/ element size check"); + ok (memcmp (bson_data (b), + "\063\000\000\000\017\146\000\053\000\000\000\021\000\000\000" + "\141\154\145\162\164\040\050\047\150\145\154\154\157\047\051" + "\073\000\022\000\000\000\002\146\157\157\000\004\000\000\000" + "\142\141\162\000\000\000", + bson_size (b)) == 0, + "BSON javascript w/ scope element contents check"); + bson_free (b); + + /* Test #3: Negative test, passing an invalid arguments. */ + b = bson_new (); + + ok (bson_append_javascript_w_scope (b, "hello", "print();", + -42, scope) == FALSE, + "bson_append_javascript_w_scope() with an invalid length should fail"); + ok (bson_append_javascript_w_scope (b, NULL, "print();", -1, scope) == FALSE, + "bson_append_javascript_w_scope() should fail without a key name"); + ok (bson_append_javascript_w_scope (b, "hello", NULL, -1, scope) == FALSE, + "bson_append_javascript_w_scope() should fail without javascript code"); + ok (bson_append_javascript_w_scope (NULL, "hello", "print();", + -1, scope) == FALSE, + "bson_append_javascript_w_scope() should fail without a BSON object"); + ok (bson_append_javascript_w_scope (b, "hello", "print();", + -1, NULL) == FALSE, + "bson_append_javascript_w_scope() should fail without a scope object"); + bson_finish (b); + cmp_ok (bson_size (b), "==", 5, + "BSON object should be empty"); + + ok (bson_append_javascript_w_scope (b, "js", "print();", -1, scope) == FALSE, + "Appending to a finished element should fail"); + + bson_free (b); +} + +RUN_TEST (13, bson_js_code_w_scope); diff --git a/tests/unit/bson/bson_append_null.c b/tests/unit/bson/bson_append_null.c new file mode 100644 index 0000000..294ea50 --- /dev/null +++ b/tests/unit/bson/bson_append_null.c @@ -0,0 +1,40 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_null (void) +{ + bson *b; + + b = bson_new (); + ok (bson_append_null (b, "null"), + "bson_append_null() works"); + bson_finish (b); + + cmp_ok (bson_size (b), "==", 11, "BSON NULL element size check"); + ok (memcmp (bson_data (b), + "\013\000\000\000\012\156\165\154\154\000\000", + bson_size (b)) == 0, + "BSON NULL element contents check"); + + bson_free (b); + + b = bson_new (); + ok (bson_append_null (b, NULL) == FALSE, + "bson_append_null() should fail without a key name"); + ok (bson_append_null (NULL, "null") == FALSE, + "bson_append_null() should fail without a BSON object"); + bson_finish (b); + cmp_ok (bson_size (b), "==", 5, + "BSON object should be empty"); + + ok (bson_append_null (b, "null") == FALSE, + "Appending to a finished element should fail"); + + bson_free (b); +} + +RUN_TEST (7, bson_null); diff --git a/tests/unit/bson/bson_append_oid.c b/tests/unit/bson/bson_append_oid.c new file mode 100644 index 0000000..2db75a3 --- /dev/null +++ b/tests/unit/bson/bson_append_oid.c @@ -0,0 +1,43 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_oid (void) +{ + bson *b; + guint8 oid[] = "1234567890ab"; + + b = bson_new (); + ok (bson_append_oid (b, "_id", oid), "bson_append_oid() works"); + bson_finish (b); + + cmp_ok (bson_size (b), "==", 22, "BSON OID element size check"); + ok (memcmp (bson_data (b), + "\026\000\000\000\007\137\151\144\000\061\062\063\064\065\066" + "\067\070\071\060\141\142\000", + bson_size (b)) == 0, + "BSON OID element contents check"); + + bson_free (b); + + b = bson_new (); + ok (bson_append_oid (b, "_id", NULL) == FALSE, + "bson_append_oid() should fail without an OID"); + ok (bson_append_oid (b, NULL, oid) == FALSE, + "bson_append_oid() should fail without a key name"); + ok (bson_append_oid (NULL, "_id", oid) == FALSE, + "bson_append_oid() should fail without a BSON object"); + bson_finish (b); + cmp_ok (bson_size (b), "==", 5, + "BSON object should be empty"); + + ok (bson_append_oid (b, "_id", oid) == FALSE, + "Appending to a finished element should fail"); + + bson_free (b); +} + +RUN_TEST (8, bson_oid); diff --git a/tests/unit/bson/bson_append_regexp.c b/tests/unit/bson/bson_append_regexp.c new file mode 100644 index 0000000..172cd2a --- /dev/null +++ b/tests/unit/bson/bson_append_regexp.c @@ -0,0 +1,45 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_regex (void) +{ + bson *b; + + b = bson_new (); + ok (bson_append_regex (b, "regex", "foo.*bar", "i"), + "bson_append_regex() works"); + bson_finish (b); + + cmp_ok (bson_size (b), "==", 23, "BSON regex element size check"); + ok (memcmp (bson_data (b), + "\027\000\000\000\013\162\145\147\145\170\000\146\157\157\056" + "\052\142\141\162\000\151\000\000", + bson_size (b)) == 0, + "BSON regex element contents check"); + + bson_free (b); + + b = bson_new (); + ok (bson_append_regex (b, "regex", "foo.*bar", NULL) == FALSE, + "bson_append_regex() without options should fail"); + ok (bson_append_regex (b, "regex", NULL, "i") == FALSE, + "bson_append_regex() without a regex should fail"); + ok (bson_append_regex (b, NULL, "foo.*bar", "i") == FALSE, + "bson_append_regex() should fail without a key name"); + ok (bson_append_regex (NULL, "regex", "foo.*bar", "i") == FALSE, + "bson_append_regex() should fail without a BSON object"); + bson_finish (b); + cmp_ok (bson_size (b), "==", 5, + "BSON object should be empty"); + + ok (bson_append_regex (b, "regex", "foo.*bar", "i") == FALSE, + "Appending to a finished element should fail"); + + bson_free (b); +} + +RUN_TEST (9, bson_regex); diff --git a/tests/unit/bson/bson_append_string.c b/tests/unit/bson/bson_append_string.c new file mode 100644 index 0000000..e6a73a7 --- /dev/null +++ b/tests/unit/bson/bson_append_string.c @@ -0,0 +1,61 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_string (void) +{ + bson *b; + + /* Test #1: A single string element, with default size. */ + b = bson_new (); + ok (bson_append_string (b, "hello", "world", -1), + "bson_append_string() works"); + bson_finish (b); + cmp_ok (bson_size (b), "==", 22, "BSON string element size check"); + ok (memcmp (bson_data (b), + "\026\000\000\000\002\150\145\154\154\157\000\006\000\000\000" + "\167\157\162\154\144\000\000", + bson_size (b)) == 0, + "BSON string element contents check"); + bson_free (b); + + /* Test #2: A single string element, with explicit length. */ + b = bson_new (); + ok (bson_append_string (b, "goodbye", + "cruel world, this garbage is gone.", + strlen ("cruel world")), + "bson_append_string() with explicit length works"); + bson_finish (b); + + cmp_ok (bson_size (b), "==", 30, "BSON string element size check, #2"); + ok (memcmp (bson_data (b), + "\036\000\000\000\002\147\157\157\144\142\171\145\000\014\000" + "\000\000\143\162\165\145\154\040\167\157\162\154\144\000\000", + bson_size (b)) == 0, + "BSON string element contents check, #2"); + bson_free (b); + + /* Test #3: Negative test, passing invalid arguments. */ + b = bson_new (); + ok (bson_append_string (b, "hello", "world", -42) == FALSE, + "bson_append_string() should fail with invalid length"); + ok (bson_append_string (b, "hello", NULL, -1) == FALSE, + "bson_append_string() should fail without a string"); + ok (bson_append_string (b, NULL, "world", -1) == FALSE, + "bson_append_string() should fail without a key name"); + ok (bson_append_string (NULL, "hello", "world", -1) == FALSE, + "bson_append_string() should fail without a BSON object"); + bson_finish (b); + cmp_ok (bson_size (b), "==", 5, + "BSON object should be empty"); + + ok (bson_append_string (b, "hello", "world", -1) == FALSE, + "Appending to a finished element should fail"); + + bson_free (b); +} + +RUN_TEST (12, bson_string); diff --git a/tests/unit/bson/bson_append_symbol.c b/tests/unit/bson/bson_append_symbol.c new file mode 100644 index 0000000..6c16301 --- /dev/null +++ b/tests/unit/bson/bson_append_symbol.c @@ -0,0 +1,61 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_symbol (void) +{ + bson *b; + + /* Test #1: A single symbol element, with default size. */ + b = bson_new (); + ok (bson_append_symbol (b, "hello", "world", -1), + "bson_append_symbol() works"); + bson_finish (b); + cmp_ok (bson_size (b), "==", 22, "BSON symbol element size check"); + ok (memcmp (bson_data (b), + "\026\000\000\000\016\150\145\154\154\157\000\006\000\000\000" + "\167\157\162\154\144\000\000", + bson_size (b)) == 0, + "BSON symbol element contents check"); + bson_free (b); + + /* Test #2: A single symbol element, with explicit length. */ + b = bson_new (); + ok (bson_append_symbol (b, "goodbye", + "cruel world, this garbage is gone.", + strlen ("cruel world")), + "bson_append_symbol() with explicit length works"); + bson_finish (b); + + cmp_ok (bson_size (b), "==", 30, "BSON symbol element size check, #2"); + ok (memcmp (bson_data (b), + "\036\000\000\000\016\147\157\157\144\142\171\145\000\014\000" + "\000\000\143\162\165\145\154\040\167\157\162\154\144\000\000", + bson_size (b)) == 0, + "BSON symbol element contents check, #2"); + bson_free (b); + + /* Test #3: Negative test, passing invalid arguments. */ + b = bson_new (); + ok (bson_append_symbol (b, "hello", "world", -42) == FALSE, + "bson_append_symbol() should fail with invalid length"); + ok (bson_append_symbol (b, "hello", NULL, -1) == FALSE, + "bson_append_symbol() should fail without a string"); + ok (bson_append_symbol (b, NULL, "world", -1) == FALSE, + "bson_append_symbol() should fail without a key name"); + ok (bson_append_symbol (NULL, "hello", "world", -1) == FALSE, + "bson_append_symbol() should fail without a BSON object"); + bson_finish (b); + cmp_ok (bson_size (b), "==", 5, + "BSON object should be empty"); + + ok (bson_append_symbol (b, "hello", "world", -1) == FALSE, + "Appending to a finished element should fail"); + + bson_free (b); +} + +RUN_TEST (12, bson_symbol); diff --git a/tests/unit/bson/bson_append_timestamp.c b/tests/unit/bson/bson_append_timestamp.c new file mode 100644 index 0000000..4864ef4 --- /dev/null +++ b/tests/unit/bson/bson_append_timestamp.c @@ -0,0 +1,41 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_timestamp (void) +{ + bson *b; + gint64 l = 9876543210; + + b = bson_new (); + ok (bson_append_timestamp (b, "ts", l), "bson_append_timestamp() works"); + bson_finish (b); + + cmp_ok (bson_size (b), "==", 17, "BSON timestamp element size check"); + ok (memcmp (bson_data (b), + "\021\000\000\000\021\164\163\000\352\026\260\114\002\000\000" + "\000\000", + bson_size (b)) == 0, + "BSON timestamp element contents check"); + + bson_free (b); + + b = bson_new (); + ok (bson_append_timestamp (b, NULL, l) == FALSE, + "bson_append_timestamp() with a NULL key should fail"); + ok (bson_append_timestamp (NULL, "ts", l) == FALSE, + "bson_append_timestamp() without a BSON object should fail"); + bson_finish (b); + cmp_ok (bson_size (b), "==", 5, + "BSON object should be empty"); + + ok (bson_append_timestamp (b, "ts", l) == FALSE, + "Appending to a finished element should fail"); + + bson_free (b); +} + +RUN_TEST (7, bson_timestamp); diff --git a/tests/unit/bson/bson_append_utc_datetime.c b/tests/unit/bson/bson_append_utc_datetime.c new file mode 100644 index 0000000..b2e38fb --- /dev/null +++ b/tests/unit/bson/bson_append_utc_datetime.c @@ -0,0 +1,41 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_utc_datetime (void) +{ + bson *b; + + b = bson_new (); + ok (bson_append_utc_datetime (b, "date", 1294860709000), + "bson_append_utc_datetime() works"); + bson_finish (b); + + cmp_ok (bson_size (b), "==", 19, "BSON UTC datetime element size check"); + ok (memcmp (bson_data (b), + "\023\000\000\000\011\144\141\164\145\000\210\154\266\173\055" + "\001\000\000\000", + bson_size (b)) == 0, + "BSON UTC datetime element contents check"); + + bson_free (b); + + b = bson_new (); + ok (bson_append_utc_datetime (b, NULL, 1294860709000) == FALSE, + "bson_append_utc_datetime() with a NULL key should fail"); + ok (bson_append_utc_datetime (NULL, "date", 1294860709000) == FALSE, + "bson_append_utc_datetime() without a BSON object should fail"); + bson_finish (b); + cmp_ok (bson_size (b), "==", 5, + "BSON object should be empty"); + + ok (bson_append_utc_datetime (b, "date", 1294860709000) == FALSE, + "Appending to a finished element should fail"); + + bson_free (b); +} + +RUN_TEST (7, bson_utc_datetime); diff --git a/tests/unit/bson/bson_build.c b/tests/unit/bson/bson_build.c new file mode 100644 index 0000000..29693db --- /dev/null +++ b/tests/unit/bson/bson_build.c @@ -0,0 +1,70 @@ +#include "bson.h" +#include "tap.h" +#include "test.h" + +#include <string.h> +#include <glib.h> + +void +test_bson_build (void) +{ + bson *b, *o, *d, *a, *scope; + guint8 oid[] = "1234567890ab"; + + a = bson_build (BSON_TYPE_INT32, "0", 32, + BSON_TYPE_INT64, "1", (gint64)-42, + BSON_TYPE_NONE); + bson_finish (a); + d = bson_build (BSON_TYPE_STRING, "name", "sub-document", -1, + BSON_TYPE_INT32, "answer", 42, + BSON_TYPE_NONE); + bson_finish (d); + + scope = bson_build (BSON_TYPE_STRING, "v", "hello world", -1, + BSON_TYPE_NONE); + bson_finish (scope); + + b = bson_build (BSON_TYPE_DOUBLE, "double", 3.14, + BSON_TYPE_STRING, "str", "hello world", -1, + BSON_TYPE_DOCUMENT, "doc", d, + BSON_TYPE_ARRAY, "array", a, + BSON_TYPE_BINARY, "binary0", BSON_BINARY_SUBTYPE_GENERIC, + (guint8 *)"foo\0bar", 7, + BSON_TYPE_OID, "_id", oid, + BSON_TYPE_BOOLEAN, "TRUE", FALSE, + BSON_TYPE_UTC_DATETIME, "date", 1294860709000, + BSON_TYPE_TIMESTAMP, "ts", 1294860709000, + BSON_TYPE_NULL, "null", + BSON_TYPE_REGEXP, "foobar", "s/foo.*bar/", "i", + BSON_TYPE_JS_CODE, "alert", "alert (\"hello world!\");", -1, + BSON_TYPE_SYMBOL, "sex", "Marilyn Monroe", -1, + BSON_TYPE_JS_CODE_W_SCOPE, "print", "alert (v);", -1, scope, + BSON_TYPE_INT32, "int32", 32, + BSON_TYPE_INT64, "int64", (gint64)-42, + BSON_TYPE_NONE); + bson_finish (b); + bson_free (d); + bson_free (a); + bson_free (scope); + + o = test_bson_generate_full (); + + cmp_ok (bson_size (b), "==", bson_size (o), + "bson_build() and hand crafted BSON object sizes match"); + ok (memcmp (bson_data (b), bson_data (o), bson_size (b)) == 0, + "bson_build() and hand crafted BSON objects match"); + + bson_free (b); + bson_free (o); + + b = bson_build (BSON_TYPE_UNDEFINED, BSON_TYPE_NONE); + ok (b == NULL, + "bson_build() should fail with an unsupported element type"); + b = bson_build (BSON_TYPE_STRING, "str", "hello", -1, + BSON_TYPE_UNDEFINED, + BSON_TYPE_NONE); + ok (b == NULL, + "bson_build() should fail with an unsupported element type"); +} + +RUN_TEST (4, bson_build); diff --git a/tests/unit/bson/bson_build_full.c b/tests/unit/bson/bson_build_full.c new file mode 100644 index 0000000..08f2e45 --- /dev/null +++ b/tests/unit/bson/bson_build_full.c @@ -0,0 +1,71 @@ +#include "bson.h" +#include "tap.h" +#include "test.h" + +#include <string.h> +#include <glib.h> + +#include <stdio.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> + +void +test_bson_build_full (void) +{ + bson *b, *o; + + b = bson_build_full (BSON_TYPE_DOUBLE, "double", FALSE, 3.14, + BSON_TYPE_STRING, "str", FALSE, "hello world", -1, + BSON_TYPE_DOCUMENT, "doc", TRUE, + bson_build (BSON_TYPE_STRING, "name", "sub-document", -1, + BSON_TYPE_INT32, "answer", 42, + BSON_TYPE_NONE), + BSON_TYPE_ARRAY, "array", TRUE, + bson_build (BSON_TYPE_INT32, "0", 32, + BSON_TYPE_INT64, "1", (gint64)-42, + BSON_TYPE_NONE), + BSON_TYPE_BINARY, "binary0", FALSE, BSON_BINARY_SUBTYPE_GENERIC, + "foo\0bar", 7, + BSON_TYPE_OID, "_id", FALSE, "1234567890ab", + BSON_TYPE_BOOLEAN, "TRUE", FALSE, FALSE, + BSON_TYPE_UTC_DATETIME, "date", FALSE, 1294860709000, + BSON_TYPE_TIMESTAMP, "ts", FALSE, 1294860709000, + BSON_TYPE_NULL, "null", FALSE, + BSON_TYPE_REGEXP, "foobar", FALSE, "s/foo.*bar/", "i", + BSON_TYPE_JS_CODE, "alert", FALSE, "alert (\"hello world!\");", -1, + BSON_TYPE_SYMBOL, "sex", FALSE, "Marilyn Monroe", -1, + BSON_TYPE_JS_CODE_W_SCOPE, "print", TRUE, "alert (v);", -1, + bson_build (BSON_TYPE_STRING, "v", "hello world", -1, + BSON_TYPE_NONE), + BSON_TYPE_INT32, "int32", FALSE, 32, + BSON_TYPE_INT64, "int64", FALSE, (gint64)-42, + BSON_TYPE_NONE); + bson_finish (b); + + o = test_bson_generate_full (); + + cmp_ok (bson_size (b), "==", bson_size (o), + "bson_build_full() and hand crafted BSON object sizes match"); + + ok (memcmp (bson_data (b), bson_data (o), bson_size (b)) == 0, + "bson_build_full() and hand crafted BSON objects match"); + + bson_free (b); + bson_free (o); + + b = bson_build_full (BSON_TYPE_UNDEFINED, "undef", FALSE, + BSON_TYPE_NONE); + ok (b == NULL, + "bson_build_full() should fail with an unsupported element type"); + b = bson_build_full (BSON_TYPE_STRING, "str", FALSE, "hello", -1, + BSON_TYPE_UNDEFINED, "undef", FALSE, + BSON_TYPE_NONE); + ok (b == NULL, + "bson_build_full() should fail with an unsupported element type"); + +} + +RUN_TEST (4, bson_build_full); diff --git a/tests/unit/bson/bson_cursor_find.c b/tests/unit/bson/bson_cursor_find.c new file mode 100644 index 0000000..db1afd5 --- /dev/null +++ b/tests/unit/bson/bson_cursor_find.c @@ -0,0 +1,39 @@ +#include "test.h" +#include "mongo.h" + +#include <string.h> + +void +test_bson_cursor_find (void) +{ + bson *b; + bson_cursor *c; + + b = test_bson_generate_full (); + c = bson_find (b, "TRUE"); + + ok (bson_cursor_find (c, NULL) == FALSE, + "bson_cursor_find() should fail with a NULL key"); + ok (bson_cursor_find (NULL, "int32") == FALSE, + "bson_cursor_find() should fail with a NULL cursor"); + + ok (bson_cursor_find (c, "sex") == TRUE, + "bson_cursor_find() works"); + + ok (bson_cursor_find (c, "str") == TRUE, + "bson_cursor_find() should wrap over if neccessary"); + + ok (bson_cursor_find (c, "-invalid-key-") == FALSE, + "bson_cursor_find() should fail when the key is not found"); + + ok (bson_cursor_find (c, "int64") == TRUE, + "bson_cursor_find() works, even after a previous failure"); + + ok (bson_cursor_find (c, "int6") == FALSE, + "bson_cursor_find() does not match prefixes"); + + bson_cursor_free (c); + bson_free (b); +} + +RUN_TEST (7, bson_cursor_find); diff --git a/tests/unit/bson/bson_cursor_find_next.c b/tests/unit/bson/bson_cursor_find_next.c new file mode 100644 index 0000000..96d7f0e --- /dev/null +++ b/tests/unit/bson/bson_cursor_find_next.c @@ -0,0 +1,33 @@ +#include "test.h" +#include "mongo.h" + +#include <string.h> + +void +test_bson_cursor_find_next (void) +{ + bson *b; + bson_cursor *c; + + b = test_bson_generate_full (); + c = bson_find (b, "TRUE"); + + ok (bson_cursor_find_next (c, NULL) == FALSE, + "bson_cursor_find_next() should fail with a NULL key"); + ok (bson_cursor_find_next (NULL, "int32") == FALSE, + "bson_cursor_find_next() should fail with a NULL cursor"); + + ok (bson_cursor_find_next (c, "sex") == TRUE, + "bson_cursor_find_next() works"); + + ok (bson_cursor_find_next (c, "str") == FALSE, + "bson_cursor_find_next() should fail when the key is not found"); + + ok (bson_cursor_find_next (c, "int64") == TRUE, + "bson_cursor_find_next() works, even after a previous failure"); + + bson_cursor_free (c); + bson_free (b); +} + +RUN_TEST (5, bson_cursor_find_next); diff --git a/tests/unit/bson/bson_cursor_get_array.c b/tests/unit/bson/bson_cursor_get_array.c new file mode 100644 index 0000000..becdc5d --- /dev/null +++ b/tests/unit/bson/bson_cursor_get_array.c @@ -0,0 +1,44 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_cursor_get_array (void) +{ + bson *b, *a = NULL; + bson_cursor *c; + + ok (bson_cursor_get_array (NULL, &a) == FALSE, + "bson_cursor_get_array() with a NULL cursor fails"); + + b = test_bson_generate_full (); + c = bson_cursor_new (b); + + ok (bson_cursor_get_array (c, NULL) == FALSE, + "bson_cursor_get_array() with a NULL destination fails"); + ok (bson_cursor_get_array (c, &a) == FALSE, + "bson_cursor_get_array() at the initial position fails"); + ok (a == NULL, + "destination remains unchanged after failed cursor operations"); + bson_cursor_free (c); + + c = bson_find (b, "array"); + ok (bson_cursor_get_array (c, &a), + "bson_cursor_get_array() works"); + cmp_ok (bson_size (a), ">", 0, + "the returned document is finished"); + bson_free (a); + + bson_cursor_next (c); + + ok (bson_cursor_get_array (c, &a) == FALSE, + "bson_cursor_get_array() fails if the cursor points to " + "non-array data"); + + bson_cursor_free (c); + bson_free (b); +} + +RUN_TEST (7, bson_cursor_get_array); diff --git a/tests/unit/bson/bson_cursor_get_binary.c b/tests/unit/bson/bson_cursor_get_binary.c new file mode 100644 index 0000000..3ec0dc3 --- /dev/null +++ b/tests/unit/bson/bson_cursor_get_binary.c @@ -0,0 +1,60 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_cursor_get_binary (void) +{ + bson *b; + bson_cursor *c; + const guint8 *d = (guint8 *)"deadbeef"; + bson_binary_subtype t = 0xff; + gint32 s = -1; + + ok (bson_cursor_get_binary (NULL, &t, &d, &s) == FALSE, + "bson_cursor_get_binary() with a NULL cursor fails"); + + b = test_bson_generate_full (); + c = bson_cursor_new (b); + + ok (bson_cursor_get_binary (c, NULL, NULL, NULL) == FALSE, + "bson_cursor_get_binary() with NULL destinations fails"); + ok (bson_cursor_get_binary (c, NULL, &d, &s) == FALSE, + "bson_cursor_get_binary() with a NULL subtype destination fails"); + ok (bson_cursor_get_binary (c, &t, NULL, &s) == FALSE, + "bson_cursor_get_binary() with a NULL binary destination fails"); + ok (bson_cursor_get_binary (c, &t, &d, NULL) == FALSE, + "bson_cursor_get_binary() with a NULL size destination fails"); + ok (bson_cursor_get_binary (c, &t, &d, &s) == FALSE, + "bson_cursor_get_binary() at the initial position fails"); + ok (memcmp (d, "deadbeef", sizeof ("deadbeef")) == 0, + "binary destination remains unchanged after failed cursor operations"); + cmp_ok (t, "==", 0xff, + "subtype destination remains unchanged after failed cursor " + "operations"); + cmp_ok (s, "==", -1, + "size destination remains unchanged after failed cursor operations"); + bson_cursor_free (c); + + c = bson_find (b, "binary0"); + ok (bson_cursor_get_binary (c, &t, &d, &s), + "bson_cursor_get_binary() works"); + cmp_ok (s, "==", 7, + "bson_cursor_get_binary() returns the correct result"); + ok (memcmp (d, "foo\0bar", s) == 0, + "bson_cursor_get_binary() returns the correct result"); + cmp_ok (t, "==", BSON_BINARY_SUBTYPE_GENERIC, + "bson_cursor_get_binary() returns the correct result"); + + bson_cursor_next (c); + ok (bson_cursor_get_binary (c, &t, &d, &s) == FALSE, + "bson_cursor_get_binary() should fail when the cursor points to " + "non-binary data"); + + bson_cursor_free (c); + bson_free (b); +} + +RUN_TEST (14, bson_cursor_get_binary); diff --git a/tests/unit/bson/bson_cursor_get_boolean.c b/tests/unit/bson/bson_cursor_get_boolean.c new file mode 100644 index 0000000..079d2b2 --- /dev/null +++ b/tests/unit/bson/bson_cursor_get_boolean.c @@ -0,0 +1,43 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_cursor_get_boolean (void) +{ + bson *b; + bson_cursor *c; + gboolean d = TRUE; + + ok (bson_cursor_get_boolean (NULL, &d) == FALSE, + "bson_cursor_get_boolean() with a NULL cursor fails"); + + b = test_bson_generate_full (); + c = bson_cursor_new (b); + + ok (bson_cursor_get_boolean (c, NULL) == FALSE, + "bson_cursor_get_boolean() with a NULL destination fails"); + ok (bson_cursor_get_boolean (c, &d) == FALSE, + "bson_cursor_get_boolean() at the initial position fails"); + cmp_ok (d, "==", TRUE, + "destination remains unchanged after failed cursor operations"); + bson_cursor_free (c); + + c = bson_find (b, "TRUE"); + ok (bson_cursor_get_boolean (c, &d), + "bson_cursor_get_boolean() works"); + cmp_ok (d, "==", FALSE, + "bson_cursor_get_boolean() returns the correct result"); + + bson_cursor_next (c); + ok (bson_cursor_get_boolean (c, &d) == FALSE, + "bson_cursor_get_boolean() should fail when the cursor points to " + "non-double data"); + + bson_cursor_free (c); + bson_free (b); +} + +RUN_TEST (7, bson_cursor_get_boolean); diff --git a/tests/unit/bson/bson_cursor_get_document.c b/tests/unit/bson/bson_cursor_get_document.c new file mode 100644 index 0000000..107ecf5 --- /dev/null +++ b/tests/unit/bson/bson_cursor_get_document.c @@ -0,0 +1,43 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_cursor_get_document (void) +{ + bson *b, *d = NULL; + bson_cursor *c; + + ok (bson_cursor_get_document (NULL, &d) == FALSE, + "bson_cursor_get_document() with a NULL cursor fails"); + + b = test_bson_generate_full (); + c = bson_cursor_new (b); + + ok (bson_cursor_get_document (c, NULL) == FALSE, + "bson_cursor_get_document() with a NULL destination fails"); + ok (bson_cursor_get_document (c, &d) == FALSE, + "bson_cursor_get_document() at the initial position fails"); + ok (d == NULL, + "destination remains unchanged after failed cursor operations"); + bson_cursor_free (c); + + c = bson_find (b, "doc"); + ok (bson_cursor_get_document (c, &d), + "bson_cursor_get_document() works"); + cmp_ok (bson_size (d), ">", 0, + "the returned document is finished"); + bson_free (d); + + bson_cursor_next (c); + ok (bson_cursor_get_document (c, &d) == FALSE, + "bson_cursor_get_document() fails if the cursor points to " + "non-document data"); + + bson_cursor_free (c); + bson_free (b); +} + +RUN_TEST (7, bson_cursor_get_document); diff --git a/tests/unit/bson/bson_cursor_get_double.c b/tests/unit/bson/bson_cursor_get_double.c new file mode 100644 index 0000000..7b5cdff --- /dev/null +++ b/tests/unit/bson/bson_cursor_get_double.c @@ -0,0 +1,43 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_cursor_get_double (void) +{ + bson *b; + bson_cursor *c; + gdouble d = 12.34; + + ok (bson_cursor_get_double (NULL, &d) == FALSE, + "bson_cursor_get_double() with a NULL cursor fails"); + + b = test_bson_generate_full (); + c = bson_cursor_new (b); + + ok (bson_cursor_get_double (c, NULL) == FALSE, + "bson_cursor_get_double() with a NULL destination fails"); + ok (bson_cursor_get_double (c, &d) == FALSE, + "bson_cursor_get_double() at the initial position fails"); + ok (d == 12.34, + "destination remains unchanged after failed cursor operations"); + bson_cursor_free (c); + + c = bson_find (b, "double"); + ok (bson_cursor_get_double (c, &d), + "bson_cursor_get_double() works"); + ok (d == 3.14, + "bson_cursor_get_double() returns the correct result"); + + bson_cursor_next (c); + ok (bson_cursor_get_double (c, &d) == FALSE, + "bson_cursor_get_double() should fail when the cursor points to " + "non-double data"); + + bson_cursor_free (c); + bson_free (b); +} + +RUN_TEST (7, bson_cursor_get_double); diff --git a/tests/unit/bson/bson_cursor_get_int32.c b/tests/unit/bson/bson_cursor_get_int32.c new file mode 100644 index 0000000..caea604 --- /dev/null +++ b/tests/unit/bson/bson_cursor_get_int32.c @@ -0,0 +1,43 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_cursor_get_int32 (void) +{ + bson *b; + bson_cursor *c; + gint d = 12345; + + ok (bson_cursor_get_int32 (NULL, &d) == FALSE, + "bson_cursor_get_int32() with a NULL cursor fails"); + + b = test_bson_generate_full (); + c = bson_cursor_new (b); + + ok (bson_cursor_get_int32 (c, NULL) == FALSE, + "bson_cursor_get_int32() with a NULL destination fails"); + ok (bson_cursor_get_int32 (c, &d) == FALSE, + "bson_cursor_get_int32() at the initial position fails"); + cmp_ok (d, "==", 12345, + "destination remains unchanged after failed cursor operations"); + bson_cursor_free (c); + + c = bson_find (b, "int32"); + ok (bson_cursor_get_int32 (c, &d), + "bson_cursor_get_int32() works"); + cmp_ok (d, "==", 32, + "bson_cursor_get_int32() returns the correct result"); + + bson_cursor_next (c); + ok (bson_cursor_get_int32 (c, &d) == FALSE, + "bson_cursor_get_int32() should fail when the cursor points to " + "non-int32 data"); + + bson_cursor_free (c); + bson_free (b); +} + +RUN_TEST (7, bson_cursor_get_int32); diff --git a/tests/unit/bson/bson_cursor_get_int64.c b/tests/unit/bson/bson_cursor_get_int64.c new file mode 100644 index 0000000..d1c80f5 --- /dev/null +++ b/tests/unit/bson/bson_cursor_get_int64.c @@ -0,0 +1,45 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_cursor_get_int64 (void) +{ + bson *b; + bson_cursor *c; + gint64 d = (gint64)987654; + + ok (bson_cursor_get_int64 (NULL, &d) == FALSE, + "bson_cursor_get_int64() with a NULL cursor fails"); + + b = test_bson_generate_full (); + c = bson_cursor_new (b); + + ok (bson_cursor_get_int64 (c, NULL) == FALSE, + "bson_cursor_get_int64() with a NULL destination fails"); + ok (bson_cursor_get_int64 (c, &d) == FALSE, + "bson_cursor_get_int64() at the initial position fails"); + cmp_ok (d, "==", 987654, + "destination remains unchanged after failed cursor operations"); + bson_cursor_free (c); + + c = bson_find (b, "int64"); + ok (bson_cursor_get_int64 (c, &d), + "bson_cursor_get_int64() works"); + cmp_ok (d, "==", (gint64)-42, + "bson_cursor_get_int64() returns the correct result"); + + bson_cursor_free (c); + + c = bson_find (b, "double"); + ok (bson_cursor_get_int64 (c, &d) == FALSE, + "bson_cursor_get_int64() should fail when the cursor points to " + "non-int64 data"); + + bson_cursor_free (c); + bson_free (b); +} + +RUN_TEST (7, bson_cursor_get_int64); diff --git a/tests/unit/bson/bson_cursor_get_javascript.c b/tests/unit/bson/bson_cursor_get_javascript.c new file mode 100644 index 0000000..4231cbd --- /dev/null +++ b/tests/unit/bson/bson_cursor_get_javascript.c @@ -0,0 +1,43 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_cursor_get_javascript (void) +{ + bson *b; + bson_cursor *c; + const gchar *s = "deadbeef"; + + ok (bson_cursor_get_javascript (NULL, &s) == FALSE, + "bson_cursor_get_javascript() with a NULL cursor fails"); + + b = test_bson_generate_full (); + c = bson_cursor_new (b); + + ok (bson_cursor_get_javascript (c, NULL) == FALSE, + "bson_cursor_get_javascript() with a NULL destination fails"); + ok (bson_cursor_get_javascript (c, &s) == FALSE, + "bson_cursor_get_javascript() at the initial position fails"); + is (s, "deadbeef", + "destination remains unchanged after failed cursor operations"); + bson_cursor_free (c); + + c = bson_find (b, "alert"); + ok (bson_cursor_get_javascript (c, &s), + "bson_cursor_get_javascript() works"); + is (s, "alert (\"hello world!\");", + "bson_cursor_get_javascript() returns the correct result"); + + bson_cursor_next (c); + ok (bson_cursor_get_javascript (c, &s) == FALSE, + "bson_cursor_get_javascript() should fail when the cursor points to " + "non-javascript data"); + + bson_cursor_free (c); + bson_free (b); +} + +RUN_TEST (7, bson_cursor_get_javascript); diff --git a/tests/unit/bson/bson_cursor_get_javascript_w_scope.c b/tests/unit/bson/bson_cursor_get_javascript_w_scope.c new file mode 100644 index 0000000..2e0b9ca --- /dev/null +++ b/tests/unit/bson/bson_cursor_get_javascript_w_scope.c @@ -0,0 +1,57 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_cursor_get_javascript_w_scope (void) +{ + bson *b, *scope = NULL, *valid; + bson_cursor *c; + const gchar *s = "deadbeef"; + + ok (bson_cursor_get_javascript_w_scope (NULL, &s, &scope) == FALSE, + "bson_cursor_get_javascript_w_scope() with a NULL cursor fails"); + + b = test_bson_generate_full (); + c = bson_cursor_new (b); + + ok (bson_cursor_get_javascript_w_scope (c, NULL, &scope) == FALSE, + "bson_cursor_get_javascript_w_scope() with a NULL js destination fails"); + ok (bson_cursor_get_javascript_w_scope (c, &s, NULL) == FALSE, + "bson_cursor_get_javascript_w_scope() with a NULL scope destinatin fails"); + ok (bson_cursor_get_javascript_w_scope (c, &s, &scope) == FALSE, + "bson_cursor_get_javascript_w_scope() at the initial position fails"); + is (s, "deadbeef", + "destination remains unchanged after failed cursor operations"); + bson_cursor_free (c); + + c = bson_find (b, "print"); + ok (bson_cursor_get_javascript_w_scope (c, &s, &scope), + "bson_cursor_get_javascript_w_scope() works"); + is (s, "alert (v);", + "bson_cursor_get_javascript_w_scope() returns the correct result"); + + valid = bson_new (); + bson_append_string (valid, "v", "hello world", -1); + bson_finish (valid); + + cmp_ok (bson_size (scope), "==", bson_size (valid), + "The returned scope's length is correct"); + ok (memcmp (bson_data (scope), bson_data (valid), + bson_size (scope)) == 0, + "The returned scope is correct"); + bson_free (valid); + + bson_cursor_next (c); + ok (bson_cursor_get_javascript_w_scope (c, &s, &scope) == FALSE, + "bson_cursor_get_javascript_w_scope() should fail when the cursor " + "points to non-javascript data"); + + bson_cursor_free (c); + bson_free (b); + bson_free (scope); +} + +RUN_TEST (10, bson_cursor_get_javascript_w_scope); diff --git a/tests/unit/bson/bson_cursor_get_oid.c b/tests/unit/bson/bson_cursor_get_oid.c new file mode 100644 index 0000000..5c2d77b --- /dev/null +++ b/tests/unit/bson/bson_cursor_get_oid.c @@ -0,0 +1,43 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_cursor_get_oid (void) +{ + bson *b; + bson_cursor *c; + const gchar *s = "abababababab"; + + ok (bson_cursor_get_oid (NULL, (const guint8 **)&s) == FALSE, + "bson_cursor_get_oid() with a NULL cursor fails"); + + b = test_bson_generate_full (); + c = bson_cursor_new (b); + + ok (bson_cursor_get_oid (c, NULL) == FALSE, + "bson_cursor_get_oid() with a NULL destination fails"); + ok (bson_cursor_get_oid (c, (const guint8 **)&s) == FALSE, + "bson_cursor_get_oid() at the initial position fails"); + ok (memcmp (s, "abababababab", 12) == 0, + "destination remains unchanged after failed cursor operations"); + bson_cursor_free (c); + + c = bson_find (b, "_id"); + ok (bson_cursor_get_oid (c, (const guint8 **)&s), + "bson_cursor_get_oid() works"); + ok (memcmp (s, "1234567890ab", 12) == 0, + "bson_cursor_get_oid() returns the correct result"); + + bson_cursor_next (c); + ok (bson_cursor_get_oid (c, (const guint8 **)&s) == FALSE, + "bson_cursor_get_oid() should fail when the cursor points to " + "non-oid data"); + + bson_cursor_free (c); + bson_free (b); +} + +RUN_TEST (7, bson_cursor_get_oid); diff --git a/tests/unit/bson/bson_cursor_get_regex.c b/tests/unit/bson/bson_cursor_get_regex.c new file mode 100644 index 0000000..59edefd --- /dev/null +++ b/tests/unit/bson/bson_cursor_get_regex.c @@ -0,0 +1,52 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_cursor_get_regex (void) +{ + bson *b; + bson_cursor *c; + const gchar *r = "deadbeef"; + const gchar *o = "g"; + + ok (bson_cursor_get_regex (NULL, &r, &o) == FALSE, + "bson_cursor_get_regex() with a NULL cursor fails"); + + b = test_bson_generate_full (); + c = bson_cursor_new (b); + + ok (bson_cursor_get_regex (c, NULL, NULL) == FALSE, + "bson_cursor_get_regex() with NULL destinations fails"); + ok (bson_cursor_get_regex (c, &r, NULL) == FALSE, + "bson_cursor_get_regex() with a NULL option destination fails"); + ok (bson_cursor_get_regex (c, NULL, &o) == FALSE, + "bson_cursor_get_regex() with a NULL regex destination fails"); + ok (bson_cursor_get_regex (c, &r, &o) == FALSE, + "bson_cursor_get_regex() at the initial position fails"); + is (r, "deadbeef", + "regex destination remains unchanged after failed cursor operations"); + is (o, "g", + "options destination remains unchanged after failed cursor operations"); + bson_cursor_free (c); + + c = bson_find (b, "foobar"); + ok (bson_cursor_get_regex (c, &r, &o), + "bson_cursor_get_regex() works"); + is (r, "s/foo.*bar/", + "bson_cursor_get_regex() returns the correct result"); + is (o, "i", + "bson_cursor_get_regex() returns the correct result"); + + bson_cursor_next (c); + ok (bson_cursor_get_regex (c, &r, &o) == FALSE, + "bson_cursor_get_regex() should fail when the cursor points to " + "non-regex data"); + + bson_cursor_free (c); + bson_free (b); +} + +RUN_TEST (11, bson_cursor_get_regex); diff --git a/tests/unit/bson/bson_cursor_get_string.c b/tests/unit/bson/bson_cursor_get_string.c new file mode 100644 index 0000000..18662bb --- /dev/null +++ b/tests/unit/bson/bson_cursor_get_string.c @@ -0,0 +1,43 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_cursor_get_string (void) +{ + bson *b; + bson_cursor *c; + const gchar *s = "deadbeef"; + + ok (bson_cursor_get_string (NULL, &s) == FALSE, + "bson_cursor_get_string() with a NULL cursor fails"); + + b = test_bson_generate_full (); + c = bson_cursor_new (b); + + ok (bson_cursor_get_string (c, NULL) == FALSE, + "bson_cursor_get_string() with a NULL destination fails"); + ok (bson_cursor_get_string (c, &s) == FALSE, + "bson_cursor_get_string() at the initial position fails"); + is (s, "deadbeef", + "destination remains unchanged after failed cursor operations"); + bson_cursor_free (c); + + c = bson_find (b, "str"); + ok (bson_cursor_get_string (c, &s), + "bson_cursor_get_string() works"); + is (s, "hello world", + "bson_cursor_get_string() returns the correct result"); + + bson_cursor_next (c); + ok (bson_cursor_get_string (c, &s) == FALSE, + "bson_cursor_get_string() should fail when the cursor points to " + "non-string data"); + + bson_cursor_free (c); + bson_free (b); +} + +RUN_TEST (7, bson_cursor_get_string); diff --git a/tests/unit/bson/bson_cursor_get_symbol.c b/tests/unit/bson/bson_cursor_get_symbol.c new file mode 100644 index 0000000..785e71b --- /dev/null +++ b/tests/unit/bson/bson_cursor_get_symbol.c @@ -0,0 +1,43 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_cursor_get_symbol (void) +{ + bson *b; + bson_cursor *c; + const gchar *s = "deadbeef"; + + ok (bson_cursor_get_symbol (NULL, &s) == FALSE, + "bson_cursor_get_symbol() with a NULL cursor fails"); + + b = test_bson_generate_full (); + c = bson_cursor_new (b); + + ok (bson_cursor_get_symbol (c, NULL) == FALSE, + "bson_cursor_get_symbol() with a NULL destination fails"); + ok (bson_cursor_get_symbol (c, &s) == FALSE, + "bson_cursor_get_symbol() at the initial position fails"); + is (s, "deadbeef", + "destination remains unchanged after failed cursor operations"); + bson_cursor_free (c); + + c = bson_find (b, "sex"); + ok (bson_cursor_get_symbol (c, &s), + "bson_cursor_get_symbol() works"); + is (s, "Marilyn Monroe", + "bson_cursor_get_symbol() returns the correct result"); + + bson_cursor_next (c); + ok (bson_cursor_get_symbol (c, &s) == FALSE, + "bson_cursor_get_symbol() should fail when the cursor points to " + "non-symbol data"); + + bson_cursor_free (c); + bson_free (b); +} + +RUN_TEST (7, bson_cursor_get_symbol); diff --git a/tests/unit/bson/bson_cursor_get_timestamp.c b/tests/unit/bson/bson_cursor_get_timestamp.c new file mode 100644 index 0000000..3bfc86c --- /dev/null +++ b/tests/unit/bson/bson_cursor_get_timestamp.c @@ -0,0 +1,43 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_cursor_get_timestamp (void) +{ + bson *b; + bson_cursor *c; + gint64 d = (gint64)987654; + + ok (bson_cursor_get_timestamp (NULL, &d) == FALSE, + "bson_cursor_get_timestamp() with a NULL cursor fails"); + + b = test_bson_generate_full (); + c = bson_cursor_new (b); + + ok (bson_cursor_get_timestamp (c, NULL) == FALSE, + "bson_cursor_get_timestamp() with a NULL destination fails"); + ok (bson_cursor_get_timestamp (c, &d) == FALSE, + "bson_cursor_get_timestamp() at the initial position fails"); + cmp_ok (d, "==", 987654, + "destination remains unchanged after failed cursor operations"); + bson_cursor_free (c); + + c = bson_find (b, "ts"); + ok (bson_cursor_get_timestamp (c, &d), + "bson_cursor_get_timestamp() works"); + ok (d == 1294860709000, + "bson_cursor_get_timestamp() returns the correct result"); + + bson_cursor_next (c); + ok (bson_cursor_get_timestamp (c, &d) == FALSE, + "bson_cursor_get_timestamp() should fail when the cursor points to " + "non-timestamp data"); + + bson_cursor_free (c); + bson_free (b); +} + +RUN_TEST (7, bson_cursor_get_timestamp); diff --git a/tests/unit/bson/bson_cursor_get_utc_datetime.c b/tests/unit/bson/bson_cursor_get_utc_datetime.c new file mode 100644 index 0000000..70e1332 --- /dev/null +++ b/tests/unit/bson/bson_cursor_get_utc_datetime.c @@ -0,0 +1,43 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_cursor_get_utc_datetime (void) +{ + bson *b; + bson_cursor *c; + gint64 d = (gint64)987654; + + ok (bson_cursor_get_utc_datetime (NULL, &d) == FALSE, + "bson_cursor_get_utc_datetime() with a NULL cursor fails"); + + b = test_bson_generate_full (); + c = bson_cursor_new (b); + + ok (bson_cursor_get_utc_datetime (c, NULL) == FALSE, + "bson_cursor_get_utc_datetime() with a NULL destination fails"); + ok (bson_cursor_get_utc_datetime (c, &d) == FALSE, + "bson_cursor_get_utc_datetime() at the initial position fails"); + cmp_ok (d, "==", 987654, + "destination remains unchanged after failed cursor operations"); + bson_cursor_free (c); + + c = bson_find (b, "date"); + ok (bson_cursor_get_utc_datetime (c, &d), + "bson_cursor_get_utc_datetime() works"); + ok (d == 1294860709000, + "bson_cursor_get_utc_datetime() returns the correct result"); + + bson_cursor_next (c); + ok (bson_cursor_get_utc_datetime (c, &d) == FALSE, + "bson_cursor_get_utc_datetime() should fail when the cursor points to " + "non-datetime data"); + + bson_cursor_free (c); + bson_free (b); +} + +RUN_TEST (7, bson_cursor_get_utc_datetime); diff --git a/tests/unit/bson/bson_cursor_key.c b/tests/unit/bson/bson_cursor_key.c new file mode 100644 index 0000000..7db98b6 --- /dev/null +++ b/tests/unit/bson/bson_cursor_key.c @@ -0,0 +1,30 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_cursor_key (void) +{ + bson *b; + bson_cursor *c; + + is (bson_cursor_key (NULL), NULL, + "bson_cursor_key(NULL) should fail"); + + b = test_bson_generate_full (); + c = bson_cursor_new (b); + + is (bson_cursor_key (c), NULL, + "bson_cursor_key() should fail at the initial position"); + bson_cursor_next (c); + + is (bson_cursor_key (c), "double", + "bson_cursor_key() works"); + + bson_cursor_free (c); + bson_free (b); +} + +RUN_TEST (3, bson_cursor_key); diff --git a/tests/unit/bson/bson_cursor_new.c b/tests/unit/bson/bson_cursor_new.c new file mode 100644 index 0000000..7bcb32b --- /dev/null +++ b/tests/unit/bson/bson_cursor_new.c @@ -0,0 +1,28 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_cursor_new (void) +{ + bson *b; + bson_cursor *c; + + ok (bson_cursor_new (NULL) == NULL, + "bson_cursor_new(NULL) should fail"); + + b = bson_new (); + ok (bson_cursor_new (b) == NULL, + "bson_cursor_new() should fail with an unfinished BSON object"); + bson_free (b); + + b = test_bson_generate_full (); + ok ((c = bson_cursor_new (b)) != NULL, + "bson_cursor_new() works"); + bson_cursor_free (c); + bson_free (b); +} + +RUN_TEST (3, bson_cursor_new); diff --git a/tests/unit/bson/bson_cursor_next.c b/tests/unit/bson/bson_cursor_next.c new file mode 100644 index 0000000..a2fc137 --- /dev/null +++ b/tests/unit/bson/bson_cursor_next.c @@ -0,0 +1,42 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_cursor_next (void) +{ + bson *b; + bson_cursor *c; + + ok (bson_cursor_next (NULL) == FALSE, + "bson_cursor_next (NULL) should fail"); + + b = bson_new (); + bson_finish (b); + c = bson_cursor_new (b); + + ok (bson_cursor_next (c) == FALSE, + "bson_cursor_next() should fail with an empty document"); + + bson_cursor_free (c); + bson_free (b); + + b = test_bson_generate_full (); + c = bson_cursor_new (b); + ok (bson_cursor_next (c), + "initial bson_cursor_next() works"); + ok (bson_cursor_next (c), + "subsequent bson_cursor_next() works too"); + + while (bson_cursor_next (c)) ; + + ok (bson_cursor_next (c) == FALSE, + "bson_cursor_next() fails after the end of the BSON object"); + + bson_cursor_free (c); + bson_free (b); +} + +RUN_TEST (5, bson_cursor_next); diff --git a/tests/unit/bson/bson_cursor_type.c b/tests/unit/bson/bson_cursor_type.c new file mode 100644 index 0000000..86be005 --- /dev/null +++ b/tests/unit/bson/bson_cursor_type.c @@ -0,0 +1,30 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_cursor_type (void) +{ + bson *b; + bson_cursor *c; + + cmp_ok (bson_cursor_type (NULL), "==", BSON_TYPE_NONE, + "bson_cursor_type(NULL) should fail"); + + b = test_bson_generate_full (); + c = bson_cursor_new (b); + + cmp_ok (bson_cursor_type (c), "==", BSON_TYPE_NONE, + "bson_cursor_type() should fail at the beginning of the BSON " + "object"); + bson_cursor_next (c); + cmp_ok (bson_cursor_type (c), "==", BSON_TYPE_DOUBLE, + "bson_cursor_type() works"); + + bson_cursor_free (c); + bson_free (b); +} + +RUN_TEST (3, bson_cursor_type); diff --git a/tests/unit/bson/bson_cursor_type_as_string.c b/tests/unit/bson/bson_cursor_type_as_string.c new file mode 100644 index 0000000..8ee6fea --- /dev/null +++ b/tests/unit/bson/bson_cursor_type_as_string.c @@ -0,0 +1,31 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_cursor_type_as_string (void) +{ + bson *b; + bson_cursor *c; + + is (bson_cursor_type_as_string (NULL), NULL, + "bson_cursor_type_as_string(NULL) should fail"); + + b = test_bson_generate_full (); + c = bson_cursor_new (b); + + is (bson_cursor_type_as_string (c), NULL, + "bson_cursor_type_as_string() should fail at the initial position"); + bson_cursor_next (c); + + is (bson_cursor_type_as_string (c), + bson_type_as_string (bson_cursor_type (c)), + "bson_cursor_type_as_string() works"); + + bson_cursor_free (c); + bson_free (b); +} + +RUN_TEST (3, bson_cursor_type_as_string); diff --git a/tests/unit/bson/bson_empty.c b/tests/unit/bson/bson_empty.c new file mode 100644 index 0000000..69d840a --- /dev/null +++ b/tests/unit/bson/bson_empty.c @@ -0,0 +1,22 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_empty (void) +{ + bson *b; + + b = bson_new (); + bson_finish (b); + + cmp_ok (bson_size (b), "==", 5, "Empty BSON size check"); + ok (memcmp (bson_data (b), "\005\000\000\000\000", bson_size (b)) == 0, + "Empty BSON contents check"); + + bson_free (b); +} + +RUN_TEST (2, bson_empty) diff --git a/tests/unit/bson/bson_find.c b/tests/unit/bson/bson_find.c new file mode 100644 index 0000000..54e8767 --- /dev/null +++ b/tests/unit/bson/bson_find.c @@ -0,0 +1,34 @@ +#include "tap.h" +#include "test.h" +#include "bson.h" + +#include <string.h> + +void +test_bson_find (void) +{ + bson *b; + bson_cursor *c; + + ok (bson_find (NULL, NULL) == NULL, + "bson_find() with NULL parameters should fail"); + ok (bson_find (NULL, "key") == NULL, + "bson_find() with a NULL BSON object should fail"); + b = bson_new (); + ok (bson_find (b, "key") == NULL, + "bson_find() with an unfinished BSON object should fail"); + bson_free (b); + + b = test_bson_generate_full (); + ok (bson_find (b, NULL) == FALSE, + "bson_find() with a NULL key should fail"); + ok (bson_find (b, "__invalid__") == FALSE, + "bson_find() with a non-existent key should fail"); + ok ((c = bson_find (b, "alert")) != NULL, + "bson_find() works"); + + bson_cursor_free (c); + bson_free (b); +} + +RUN_TEST (6, bson_find); diff --git a/tests/unit/bson/bson_new.c b/tests/unit/bson/bson_new.c new file mode 100644 index 0000000..3149027 --- /dev/null +++ b/tests/unit/bson/bson_new.c @@ -0,0 +1,28 @@ +#include "bson.h" +#include "test.h" +#include "tap.h" + +#include <string.h> + +void +test_bson_new (void) +{ + bson *b; + + ok ((b = bson_new ()) != NULL, "bson_new() works"); + ok (bson_data (b) == NULL, + "bson_data() with an unfished object should fail"); + ok (bson_size (b) == -1, + "bson_size() with an unfinished object should fail"); + ok (bson_finish (b), "bson_finish() works"); + ok (bson_finish (b), + "bson_finish() works on an already finished object too"); + bson_free (b); + + ok (bson_size (NULL) == -1, "bson_size(NULL) works correctly"); + ok (bson_data (NULL) == NULL, "bson_data(NULL) works correctly"); + ok (bson_finish (NULL) == FALSE, "bson_finish(NULL) works correctly"); + bson_free (NULL); +} + +RUN_TEST (8, bson_new); diff --git a/tests/unit/bson/bson_new_from_data.c b/tests/unit/bson/bson_new_from_data.c new file mode 100644 index 0000000..740cb6e --- /dev/null +++ b/tests/unit/bson/bson_new_from_data.c @@ -0,0 +1,46 @@ +#include "bson.h" +#include "test.h" +#include "tap.h" + +#include <string.h> + +void +test_bson_new_from_data (void) +{ + bson *orig, *new; + + orig = test_bson_generate_full (); + + ok (bson_new_from_data (NULL, 0) == NULL, + "bson_new_from_data (NULL, 0) fails"); + ok (bson_new_from_data (NULL, bson_size (orig)) == NULL, + "bson_new_from_data (NULL, size) fails"); + ok (bson_new_from_data (bson_data (orig), 0) == NULL, + "bson_new_from_data (orig, 0) fails"); + ok (bson_new_from_data (bson_data (orig), -1) == NULL, + "bson_new_from_data (orig, -1) fails"); + ok (bson_new_from_data (NULL, -1) == NULL, + "bson_new_from_data (NULL, -1) fails"); + + ok ((new = bson_new_from_data (bson_data (orig), + bson_size (orig) - 1)) != NULL, + "bson_new_from_data() works"); + cmp_ok (bson_size (new), "==", -1, + "Copied object is unfinished"); + bson_finish (new); + + ok (orig != new, "Copied BSON object is not the same as the original"); + + cmp_ok (bson_size (orig), "==", bson_size (new), + "Copied (& finished) object has the same size as the original"); + ok (bson_data (orig) != bson_data (new), + "The copied data is not the same as the original"); + ok (memcmp (bson_data (orig), bson_data (new), + bson_size (orig)) == 0, + "The copied data is identical to the original"); + + bson_free (orig); + bson_free (new); +} + +RUN_TEST (11, bson_new_from_data); diff --git a/tests/unit/bson/bson_reset.c b/tests/unit/bson/bson_reset.c new file mode 100644 index 0000000..23f2ce6 --- /dev/null +++ b/tests/unit/bson/bson_reset.c @@ -0,0 +1,27 @@ +#include "bson.h" +#include "test.h" +#include "tap.h" + +void +test_bson_reset (void) +{ + bson *b; + + b = test_bson_generate_full (); + + cmp_ok (bson_size (b), "!=", -1, + "bson_size() != -1 on a non-empty document"); + ok (bson_reset (b), "bson_reset() works"); + cmp_ok (bson_size (b), "==", -1, + "bson_size() on a reseted object returns an error"); + bson_finish (b); + cmp_ok (bson_size (b), "==", 5, + "bson_size() on a reseted & finished object matches the " + "size of an empty document"); + bson_free (b); + + ok (bson_reset (NULL) == FALSE, + "bson_reset(NULL) should fail"); +} + +RUN_TEST (5, bson_reset); diff --git a/tests/unit/bson/bson_type_as_string.c b/tests/unit/bson/bson_type_as_string.c new file mode 100644 index 0000000..35e8210 --- /dev/null +++ b/tests/unit/bson/bson_type_as_string.c @@ -0,0 +1,40 @@ +#include "bson.h" +#include "test.h" +#include "tap.h" + +#include <string.h> + +#define CHECK_TYPE(t) \ + is (bson_type_as_string (t), #t, \ + "bson_type_as_string(%s) works", #t) + +void +test_bson_type_as_string (void) +{ + CHECK_TYPE (BSON_TYPE_NONE); + CHECK_TYPE (BSON_TYPE_DOUBLE); + CHECK_TYPE (BSON_TYPE_STRING); + CHECK_TYPE (BSON_TYPE_DOCUMENT); + CHECK_TYPE (BSON_TYPE_ARRAY); + CHECK_TYPE (BSON_TYPE_BINARY); + CHECK_TYPE (BSON_TYPE_UNDEFINED); + CHECK_TYPE (BSON_TYPE_OID); + CHECK_TYPE (BSON_TYPE_BOOLEAN); + CHECK_TYPE (BSON_TYPE_UTC_DATETIME); + CHECK_TYPE (BSON_TYPE_NULL); + CHECK_TYPE (BSON_TYPE_REGEXP); + CHECK_TYPE (BSON_TYPE_DBPOINTER); + CHECK_TYPE (BSON_TYPE_JS_CODE); + CHECK_TYPE (BSON_TYPE_SYMBOL); + CHECK_TYPE (BSON_TYPE_JS_CODE_W_SCOPE); + CHECK_TYPE (BSON_TYPE_INT32); + CHECK_TYPE (BSON_TYPE_TIMESTAMP); + CHECK_TYPE (BSON_TYPE_INT64); + CHECK_TYPE (BSON_TYPE_MIN); + CHECK_TYPE (BSON_TYPE_MAX); + + ok (bson_type_as_string (42) == NULL, + "bson_type_as_string() returns NULL on invalid type."); +} + +RUN_TEST (22, bson_type_as_string); diff --git a/tests/unit/bson/bson_validate_key.c b/tests/unit/bson/bson_validate_key.c new file mode 100644 index 0000000..126b1fd --- /dev/null +++ b/tests/unit/bson/bson_validate_key.c @@ -0,0 +1,36 @@ +#include "tap.h" +#include "test.h" + +#include <errno.h> +#include <bson.h> +#include <string.h> + +void +test_bson_validate_key (void) +{ + gboolean valid; + + valid = bson_validate_key (NULL, FALSE, FALSE); + ok (valid == FALSE && errno == EINVAL, + "bson_validate_key() sets errno when the key is NULL"); + + valid = bson_validate_key ("$foo.bar", FALSE, FALSE); + ok (valid == TRUE, + "bson_validate_key() returns success if both checks are off"); + + valid = bson_validate_key ("$foo.bar", FALSE, TRUE); + ok (valid == FALSE, + "bson_validate_key() returns failiure if the key starts with a $"); + valid = bson_validate_key ("foo.bar$", FALSE, TRUE); + ok (valid == TRUE, + "bson_validate_key() returns success if the key does not start with a $"); + + valid = bson_validate_key ("foo.bar", TRUE, TRUE); + ok (valid == FALSE, + "bson_validate_key() returns failiure if the key contains a dot"); + valid = bson_validate_key ("foobar", TRUE, TRUE); + ok (valid == TRUE, + "bson_validate_key() returns success if the key does not contain a dot"); +} + +RUN_TEST (6, bson_validate_key) 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); |