summaryrefslogtreecommitdiff
path: root/tests/tap/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/tap/process.c')
-rw-r--r--tests/tap/process.c125
1 files changed, 101 insertions, 24 deletions
diff --git a/tests/tap/process.c b/tests/tap/process.c
index 16154c7..8ed4cfd 100644
--- a/tests/tap/process.c
+++ b/tests/tap/process.c
@@ -1,18 +1,37 @@
/*
* Utility functions for tests that use subprocesses.
*
- * Provides utility functions for subprocess manipulation. Currently, only
- * one utility function is provided: is_function_output, which runs a function
- * in a subprocess and checks its output and exit status against expected
- * values.
+ * Provides utility functions for subprocess manipulation. Specifically,
+ * provides a function, run_setup, which runs a command and bails if it fails,
+ * using its error message as the bail output, and is_function_output, which
+ * runs a function in a subprocess and checks its output and exit status
+ * against expected values.
*
- * Copyright 2009, 2010 Board of Trustees, Leland Stanford Jr. University
- * Copyright (c) 2004, 2005, 2006
- * by Internet Systems Consortium, Inc. ("ISC")
- * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
- * 2002, 2003 by The Internet Software Consortium and Rich Salz
+ * The canonical version of this file is maintained in the rra-c-util package,
+ * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
*
- * See LICENSE for licensing terms.
+ * Written by Russ Allbery <rra@stanford.edu>
+ * Copyright 2002, 2004, 2005 Russ Allbery <rra@stanford.edu>
+ * Copyright 2009, 2010, 2011
+ * The Board of Trustees of the Leland Stanford Junior University
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
*/
#include <config.h>
@@ -22,26 +41,24 @@
#include <tests/tap/basic.h>
#include <tests/tap/process.h>
-#include <util/xmalloc.h>
+#include <tests/tap/string.h>
/*
* Given a function, an expected exit status, and expected output, runs that
* function in a subprocess, capturing stdout and stderr via a pipe, and
- * compare the combination of stdout and stderr with the expected output and
- * the exit status with the expected status. Expects the function to always
- * exit (not die from a signal).
+ * returns the function output in newly allocated memory. Also captures the
+ * process exit status.
*/
-void
-is_function_output(test_function_type function, int status, const char *output,
- const char *format, ...)
+static void
+run_child_function(test_function_type function, void *data, int *status,
+ char **output)
{
int fds[2];
pid_t child;
- char *buf, *msg;
+ char *buf;
ssize_t count, ret, buflen;
int rval;
- va_list args;
/* Flush stdout before we start to avoid odd forking issues. */
fflush(stdout);
@@ -61,7 +78,7 @@ is_function_output(test_function_type function, int status, const char *output,
_exit(255);
/* Now, run the function and exit successfully if it returns. */
- (*function)();
+ (*function)(data);
fflush(stdout);
_exit(0);
} else {
@@ -71,7 +88,7 @@ is_function_output(test_function_type function, int status, const char *output,
*/
close(fds[1]);
buflen = BUFSIZ;
- buf = xmalloc(buflen);
+ buf = bmalloc(buflen);
count = 0;
do {
ret = read(fds[0], buf + count, buflen - count - 1);
@@ -79,18 +96,41 @@ is_function_output(test_function_type function, int status, const char *output,
count += ret;
if (count >= buflen - 1) {
buflen += BUFSIZ;
- buf = xrealloc(buf, buflen);
+ buf = brealloc(buf, buflen);
}
} while (ret > 0);
buf[count < 0 ? 0 : count] = '\0';
if (waitpid(child, &rval, 0) == (pid_t) -1)
sysbail("waitpid failed");
+ close(fds[0]);
}
+ /* Store the output and return. */
+ *status = rval;
+ *output = buf;
+}
+
+
+/*
+ * Given a function, data to pass to that function, an expected exit status,
+ * and expected output, runs that function in a subprocess, capturing stdout
+ * and stderr via a pipe, and compare the combination of stdout and stderr
+ * with the expected output and the exit status with the expected status.
+ * Expects the function to always exit (not die from a signal).
+ */
+void
+is_function_output(test_function_type function, void *data, int status,
+ const char *output, const char *format, ...)
+{
+ char *buf, *msg;
+ int rval;
+ va_list args;
+
+ run_child_function(function, data, &rval, &buf);
+
/* Now, check the results against what we expected. */
va_start(args, format);
- if (xvasprintf(&msg, format, args) < 0)
- bail("cannot format test description");
+ bvasprintf(&msg, format, args);
va_end(args);
ok(WIFEXITED(rval), "%s (exited)", msg);
is_int(status, WEXITSTATUS(rval), "%s (status)", msg);
@@ -98,3 +138,40 @@ is_function_output(test_function_type function, int status, const char *output,
free(buf);
free(msg);
}
+
+
+/*
+ * A helper function for run_setup. This is a function to run an external
+ * command, suitable for passing into run_child_function. The expected
+ * argument must be an argv array, with argv[0] being the command to run.
+ */
+static void
+exec_command(void *data)
+{
+ char *const *argv = data;
+
+ execvp(argv[0], argv);
+}
+
+
+/*
+ * Given a command expressed as an argv struct, with argv[0] the name or path
+ * to the command, run that command. If it exits with a non-zero status, use
+ * the part of its output up to the first newline as the error message when
+ * calling bail.
+ */
+void
+run_setup(const char *const argv[])
+{
+ char *output, *p;
+ int status;
+
+ run_child_function(exec_command, (void *) argv, &status, &output);
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ p = strchr(output, '\n');
+ if (p != NULL)
+ *p = '\0';
+ bail("%s", output);
+ }
+ free(output);
+}