Parallel tests

Jim Meyering jim at meyering.net
Wed Oct 6 08:04:40 UTC 2010


Jim Meyering wrote:
> Jeff Darcy wrote:
>> I looked into this a bit after it came up on IRC.  The reason it's
>> failing is that the two mongod instances are using the same port.
>> They're also using the same directory, which I think is *a* problem but
>> not *the* problem.  In any case, here's a diff (on top of my
>> replication-test patch) which shows how to make things behave.
>>
>> diff --git a/t/replication b/t/replication
>> index 7f311e7..5299a71 100644
>> --- a/t/replication
>> +++ b/t/replication
>> @@ -3,11 +3,11 @@
>>
>>  . "${srcdir=.}/init.sh"; path_prepend_ ..
>>
>> -mkdir mongod fs_upstream fs_downstream || framework_failure_ mkdir failed
>> +mkdir mongod2 fs_upstream fs_downstream || framework_failure_ mkdir failed
>
> Changing this directory name is not needed, since init.sh ensures that
> each test is run in a uniquely-named temporary directory.
>
>> -mongod --pidfilepath mongod/pid --dbpath mongod > mongod.log 2>&1 &
>> +mongod --port 27018 --dbpath mongod2 > mongod.log 2>&1 &
>
> Perfect.  That solves the problem.
> Please factor out that new port number, say m_port=27018
> Otherwise, it's too easy to accidentally change only one or two of the 3 uses.
>
> Thanks!

Actually, if it's ok with you,
I'll go ahead and push three of your patches,
since I've already made the adjustments, while reviewing
and testing them.

The above, adjusted as suggested, as well as these two prereqs:

    $ git shortlog -3
    Jeff Darcy (3):
          Add rep_count control operation on API root.
          Add replication tests.
          tests: run 2nd test's mongod on a different port for parallel make check

>From aed80dde305ddbf98f089989124ffb109f440281 Mon Sep 17 00:00:00 2001
From: Jeff Darcy <jdarcy at redhat.com>
Date: Tue, 5 Oct 2010 13:06:27 -0400
Subject: [PATCH 1/3] Add rep_count control operation on API root.

---
 proxy.c |   11 +++++++++
 proxy.h |    1 +
 rest.c  |   72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 84 insertions(+), 0 deletions(-)

diff --git a/proxy.c b/proxy.c
index cdcea5f..73d67d7 100644
--- a/proxy.c
+++ b/proxy.c
@@ -102,6 +102,7 @@ static repl_item	*queue_tail	= NULL;
 static pthread_mutex_t	 queue_lock;
 static sem_t		 queue_sema;
 static json_t		*config		= NULL;
+static int		 rep_count	= 0;

 static int
 validate_server (unsigned int i)
@@ -800,6 +801,8 @@ repl_worker (void *notused ATTRIBUTE_UNUSED)
 		}
 		free(item->path);
 		free(item);
+		/* No atomic dec without test?  Lame. */
+		(void)g_atomic_int_dec_and_test(&rep_count);
 	}
 }

@@ -911,6 +914,7 @@ replicate (const char *url, size_t size, const char *policy)
 		}
 		queue_tail = item;
 		pthread_mutex_unlock(&queue_lock);
+		g_atomic_int_inc(&rep_count);
 		sem_post(&queue_sema);
 	}

@@ -952,6 +956,7 @@ replicate_namespace_action (const char *name, repl_t action)
 		}
 		queue_tail = item;
 		pthread_mutex_unlock(&queue_lock);
+		g_atomic_int_inc(&rep_count);
 		sem_post(&queue_sema);
 	}
 }
@@ -1067,3 +1072,9 @@ follow_link (char *object, char *key)

 	return "no_such_object";
 }
+
+int
+get_rep_count (void)
+{
+	return g_atomic_int_get(&rep_count);
+}
diff --git a/proxy.h b/proxy.h
index f44e884..22efcd0 100644
--- a/proxy.h
+++ b/proxy.h
@@ -40,5 +40,6 @@ int	 get_provider		(int i, provider_t *out);
 void	 update_provider	(const char *provider,
 				 const char *username, const char *password);
 char	*get_provider_value	(int i, const char *fname);
+int	 get_rep_count		(void);

 #endif
diff --git a/rest.c b/rest.c
index f501674..17dad68 100644
--- a/rest.c
+++ b/rest.c
@@ -1132,6 +1132,76 @@ create_bucket (char *name)
 }

 static int
+control_api_root (void *cctx, struct MHD_Connection *conn, const char *url,
+		  const char *method, const char *version, const char *data,
+		  size_t *data_size, void **rctx)
+{
+	struct MHD_Response	*resp;
+	my_state		*ms	= *rctx;
+	int			 rc;
+	char			*op;
+	char			 buf[80];
+	int			 len;
+
+	(void)cctx;
+	(void)method;
+	(void)version;
+
+	DPRINTF("ROOT POST (%s, %zu)\n",url,*data_size);
+
+	if (ms->state == MS_NEW) {
+		ms->state = MS_NORMAL;
+		ms->url = (char *)url;
+		ms->dict = g_hash_table_new_full(
+			g_str_hash,g_str_equal,free,free);
+		ms->cleanup |= CLEANUP_DICT;
+		ms->post = MHD_create_post_processor(conn,4096,
+			post_iterator,ms->dict);
+		ms->cleanup |= CLEANUP_POST;
+		return MHD_YES;
+	}
+
+	if (*data_size) {
+		MHD_post_process(ms->post,data,*data_size);
+		*data_size = 0;
+		return MHD_YES;
+	}
+
+	rc = MHD_HTTP_BAD_REQUEST;
+
+	op = g_hash_table_lookup(ms->dict,"op");
+	if (op) {
+		if (!strcmp(op,"rep_status")) {
+			len = snprintf(buf,sizeof(buf),"%d requests\n",
+				get_rep_count());
+			rc = MHD_HTTP_OK;
+		}
+		else {
+			len = snprintf(buf,sizeof(buf),"unknown op");
+		}
+	}
+	else {
+		len = snprintf(buf,sizeof(buf),"missing op");
+	}
+
+	if (len >= (int)sizeof(buf)) {
+		len = 0;
+		rc = MHD_HTTP_INTERNAL_SERVER_ERROR;
+	}
+
+	/* NB The last arg tells MHD to copy the arg and free it later. */
+	resp = MHD_create_response_from_data(len,buf,MHD_NO,MHD_YES);
+	if (!resp) {
+		return MHD_NO;
+	}
+	MHD_queue_response(conn,rc,resp);
+	MHD_destroy_response(resp);
+
+	free_ms(ms);
+	return MHD_YES;
+}
+
+static int
 proxy_bucket_post (void *cctx, struct MHD_Connection *conn, const char *url,
 		   const char *method, const char *version, const char *data,
 		   size_t *data_size, void **rctx)
@@ -1512,6 +1582,8 @@ proxy_create_bucket (void *cctx, struct MHD_Connection *conn, const char *url,
 static const rule my_rules[] = {
 	{ /* get bucket list */
 	  "GET",	URL_ROOT,	proxy_api_root  	},
+	{ /* perform a control operation on the API root */
+	  "POST",	URL_ROOT,	control_api_root	},
 	{ /* get object list */
 	  "GET",	URL_BUCKET,	proxy_list_objs		},
 	{ /* create bucket */
--
1.7.3.1.45.g9855b


>From a4f70dea04986b2f66e59695a3b39659c0b56425 Mon Sep 17 00:00:00 2001
From: Jeff Darcy <jdarcy at redhat.com>
Date: Tue, 5 Oct 2010 13:07:12 -0400
Subject: [PATCH 2/3] Add replication tests.

---
 t/Makefile.am |    2 +-
 t/replication |  100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 101 insertions(+), 1 deletions(-)
 create mode 100644 t/replication

diff --git a/t/Makefile.am b/t/Makefile.am
index f68e661..2f58326 100644
--- a/t/Makefile.am
+++ b/t/Makefile.am
@@ -15,7 +15,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.

 TESTS =						\
-  basic
+  basic replication

 EXTRA_DIST =					\
   $(TESTS)					\
diff --git a/t/replication b/t/replication
new file mode 100644
index 0000000..7f311e7
--- /dev/null
+++ b/t/replication
@@ -0,0 +1,100 @@
+#!/bin/sh
+# Test replication functionality.
+
+. "${srcdir=.}/init.sh"; path_prepend_ ..
+
+mkdir mongod fs_upstream fs_downstream || framework_failure_ mkdir failed
+
+# FIXME: start this only if there's not a working one already running, or
+# probably better, start this one unconditionally and make iwhd use it.
+mongod --pidfilepath mongod/pid --dbpath mongod > mongod.log 2>&1 &
+mongo_pid=$!
+cleanup_() { kill $mongo_pid; sleep 3; }
+
+# Wait for up to 3 seconds for mongod to begin listening.
+wait_for .1 30 'mongo < /dev/null' \
+  || framework_failure_ mongod failed to start
+
+cat > iwhd_u.cfg << EOF
+[
+	{ "name":"upstream",   "type":"fs",   "path":"fs_upstream" },
+	{ "name":"downstream", "type":"http", "host":"localhost", "port": 9093,
+	  "color": "blue" }
+]
+EOF
+
+port=9092
+iwhd -v -p $port -c iwhd_u.cfg &
+iwhd_pid=$!
+wait_for .1 30 "curl http://localhost:$port" \
+	|| framework_failure_ "iwhd upstream"
+cleanup_() { kill $mongo_pid $iwhd_pid; sleep 3; }
+
+cat > iwhd_d.cfg << EOF
+[
+	{"name": "downstream", "type": "fs", "path": "fs_downstream" }
+]
+EOF
+
+d_port=9093
+iwhd -v -p $d_port -c iwhd_d.cfg &
+iwhd_d_pid=$!
+wait_for .1 30 "curl http://localhost:$d_port" \
+	|| framework_failure_ "iwhd downstream"
+cleanup_() { kill $mongo_pid $iwhd_pid $iwhd_d_pid; sleep 3; }
+
+api=http://localhost:$port
+wait_for_repl() {
+	curl -d op=rep_status $api > repl.out || return 1
+	test "$(cat repl.out)" = "0 requests" || return 1
+	return 0
+}
+bkt=$api/rbucket
+
+# Create a bucket to work in.
+curl -X PUT $bkt || fail=1
+# Make sure it exists at both ends (i.e. create was replicated).
+wait_for .1 50 "wait_for_repl $api" || fail_ "replication seems stuck"
+test -d fs_upstream/rbucket || fail=1
+test -d fs_downstream/rbucket || fail=1
+
+# Add a file, make sure it's *not* replicated (default policy).
+echo foo | curl -T - $bkt/file2 || fail=1
+wait_for .1 50 "wait_for_repl $api" || fail_ "replication seems stuck"
+test -f fs_upstream/rbucket/file2 || fail=1
+test -f fs_downstream/rbucket/file2 && fail=1
+
+# Set the replication policy to always replicate.
+echo -n 1 | curl -T - $bkt/_default/_policy || fail=1
+
+# Add a file, make sure it *is* replicated.
+echo foo | curl -T - $bkt/file3 || fail=1
+wait_for .1 50 "wait_for_repl $api" || fail_ "replication seems stuck"
+test -f fs_upstream/rbucket/file3 || fail=1
+test -f fs_downstream/rbucket/file3 || fail=1
+
+# Make sure we can do selective replication based on object/site attributes.
+echo -n '$color==#color' | curl -T - $bkt/_default/_policy || fail=1
+
+# Positive test.
+# NB this file is also used by the delete test below
+echo -n blue | curl -T - $bkt/file4/color || fail=1
+echo -n foo | curl -T - $bkt/file4 || fail=1
+wait_for .1 50 "wait_for_repl $api" || fail_ "replication seems stuck"
+test -f fs_downstream/rbucket/file4 || fail=1
+
+# Negative test.
+echo -n red | curl -T - $bkt/file5/color || fail=1
+echo -n foo | curl -T - $bkt/file5 || fail=1
+wait_for .1 50 "wait_for_repl $api" || fail_ "replication seems stuck"
+test -f fs_downstream/rbucket/file5 && fail=1
+
+# Test replication of deletes.
+curl -X DELETE $bkt/file4 || fail=2
+wait_for .1 50 "wait_for_repl $api" || fail_ "replication seems stuck"
+test -f fs_upstream/rbucket/file4 && fail=1
+test -f fs_downstream/rbucket/file4 && fail=1
+
+# TBD: add op=check result checks
+
+Exit $fail
--
1.7.3.1.45.g9855b


>From 1132a7be47951bf99e0bb5eba149f6d42c415074 Mon Sep 17 00:00:00 2001
From: Jeff Darcy <jdarcy at redhat.com>
Date: Wed, 6 Oct 2010 09:59:12 +0200
Subject: [PATCH 3/3] tests: run 2nd test's mongod on a different port for parallel make check

With the addition of this second mongod-running test script,
"make -j2 check" would often fail.
* t/replication: Each test script must run mongod on a different
port so that all may be run in parallel.
---
 t/replication |    8 +++++---
 1 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/t/replication b/t/replication
index 7f311e7..8259a5c 100644
--- a/t/replication
+++ b/t/replication
@@ -5,9 +5,11 @@

 mkdir mongod fs_upstream fs_downstream || framework_failure_ mkdir failed

+m_port=27018
+
 # FIXME: start this only if there's not a working one already running, or
 # probably better, start this one unconditionally and make iwhd use it.
-mongod --pidfilepath mongod/pid --dbpath mongod > mongod.log 2>&1 &
+mongod --port $m_port --pidfilepath mongod/pid --dbpath mongod > mongod.log 2>&1 &
 mongo_pid=$!
 cleanup_() { kill $mongo_pid; sleep 3; }

@@ -24,7 +26,7 @@ cat > iwhd_u.cfg << EOF
 EOF

 port=9092
-iwhd -v -p $port -c iwhd_u.cfg &
+iwhd -v -p $port -c iwhd_u.cfg -d localhost:$m_port &
 iwhd_pid=$!
 wait_for .1 30 "curl http://localhost:$port" \
 	|| framework_failure_ "iwhd upstream"
@@ -37,7 +39,7 @@ cat > iwhd_d.cfg << EOF
 EOF

 d_port=9093
-iwhd -v -p $d_port -c iwhd_d.cfg &
+iwhd -v -p $d_port -c iwhd_d.cfg -d localhost:$m_port &
 iwhd_d_pid=$!
 wait_for .1 30 "curl http://localhost:$d_port" \
 	|| framework_failure_ "iwhd downstream"
--
1.7.3.1.45.g9855b


More information about the iwhd-devel mailing list