summaryrefslogtreecommitdiff
path: root/testapp.c
diff options
context:
space:
mode:
authorTrond Norbye <Trond.Norbye@sun.com>2009-08-13 14:23:05 +0200
committerDustin Sallings <dustin@spy.net>2009-08-13 11:21:09 -0700
commite337faf6520deabec4cd2b0beabf82793ff8fbf1 (patch)
treec27c7c3efcbad84b4efabf52ae542a9f79ae59d4 /testapp.c
parenteb18f0a0a7f137068dbe639ac630acae02edd655 (diff)
downloadmemcached-e337faf6520deabec4cd2b0beabf82793ff8fbf1.tar.gz
Allow memcached to bind to an ephemeral port
To ease testing you can pass -p -1 to memcached and it will create and bind to an ephemeral port. If you set the environment variable MEMCACHED_PORT_FILENAME to a filename memcached will write the port numbers to the file in the following format: TCP INET6: 5555 TCP INET: 5555 UDP INET6: 6666 UDP INET: 6666 testapp can now just tell the server to start and don't try to locate a random port for it to use, but instead read the file and connect on the port.
Diffstat (limited to 'testapp.c')
-rw-r--r--testapp.c111
1 files changed, 95 insertions, 16 deletions
diff --git a/testapp.c b/testapp.c
index c0013ac..5dbd3cb 100644
--- a/testapp.c
+++ b/testapp.c
@@ -9,6 +9,7 @@
#include <inttypes.h>
#include <stdbool.h>
#include <unistd.h>
+#include <netinet/in.h>
#include "config.h"
#include "cache.h"
@@ -230,30 +231,108 @@ static enum test_return test_safe_strtol(void) {
return TEST_PASS;
}
-static enum test_return test_issue_44(void) {
- char pidfile[80];
- char buffer[256];
- sprintf(pidfile, "/tmp/memcached.%d", getpid());
- sprintf(buffer, "./memcached-debug -p 0 -P %s -d", pidfile);
- assert(system(buffer) == 0);
- sleep(1);
- FILE *fp = fopen(pidfile, "r");
- assert(fp);
- assert(fgets(buffer, sizeof(buffer), fp));
+/**
+ * Function to start the server and let it listen on a random port
+ *
+ * @param port_out where to store the TCP port number the server is
+ * listening on
+ * @param daemon set to true if you want to run the memcached server
+ * as a daemon process
+ * @return the pid of the memcached server
+ */
+static pid_t start_server(in_port_t *port_out, bool daemon) {
+ char environment[80];
+ snprintf(environment, sizeof(environment),
+ "MEMCACHED_PORT_FILENAME=/tmp/ports.%u", getpid());
+ char *filename= environment + strlen("MEMCACHED_PORT_FILENAME=");
+ char pid_file[80];
+ snprintf(pid_file, sizeof(pid_file), "/tmp/pid.%u", getpid());
+
+ remove(filename);
+ remove(pid_file);
+
+ pid_t pid = fork();
+ assert(pid != -1);
+
+ if (pid == 0) {
+ /* Child */
+ char *argv[10];
+ int arg = 0;
+ putenv(environment);
+ argv[arg++] = "./memcached-debug";
+ argv[arg++] = "-p";
+ argv[arg++] = "-1";
+ argv[arg++] = "-U";
+ argv[arg++] = "0";
+ if (daemon) {
+ argv[arg++] = "-d";
+ argv[arg++] = "-P";
+ argv[arg++] = pid_file;
+ }
+ argv[arg++] = NULL;
+ assert(execv("./memcached-debug", argv) != -1);
+ }
+
+ /* Yeah just let us "busy-wait" for the file to be created ;-) */
+ while (access(filename, F_OK) == -1) {
+ usleep(10);
+ }
+
+ FILE *fp = fopen(filename, "r");
+ if (fp == NULL) {
+ fprintf(stderr, "Failed to open the file containing port numbers: %s\n",
+ strerror(errno));
+ assert(false);
+ }
+
+ *port_out = (in_port_t)-1;
+ char buffer[80];
+ while ((fgets(buffer, sizeof(buffer), fp)) != NULL) {
+ if (strncmp(buffer, "TCP INET: ", 10) == 0) {
+ int32_t val;
+ assert(safe_strtol(buffer + 10, &val));
+ *port_out = (in_port_t)val;
+ }
+ }
fclose(fp);
- pid_t pid = atol(buffer);
- assert(kill(pid, 0) == 0);
+ assert(remove(filename) == 0);
+
+ if (daemon) {
+ /* loop and wait for the pid file.. There is a potential race
+ * condition that the server just created the file but isn't
+ * finished writing the content, but I'll take the chance....
+ */
+ while (access(pid_file, F_OK) == -1) {
+ usleep(10);
+ }
+
+ fp = fopen(pid_file, "r");
+ if (fp == NULL) {
+ fprintf(stderr, "Failed to open pid file: %s\n",
+ strerror(errno));
+ assert(false);
+ }
+ assert(fgets(buffer, sizeof(buffer), fp) != NULL);
+ fclose(fp);
+
+ int32_t val;
+ assert(safe_strtol(buffer, &val));
+ pid = (pid_t)val;
+ }
+
+ return pid;
+}
+
+static enum test_return test_issue_44(void) {
+ in_port_t port;
+ pid_t pid = start_server(&port, true);
assert(kill(pid, SIGHUP) == 0);
sleep(1);
- assert(kill(pid, 0) == 0);
assert(kill(pid, SIGTERM) == 0);
- assert(remove(pidfile) == 0);
return TEST_PASS;
}
-
-
typedef enum test_return (*TEST_FUNC)(void);
struct testcase {
const char *description;