[master] a33b931 List commands in a single tbl-include file. Move misc commands to separate source file.

Poul-Henning Kamp phk at FreeBSD.org
Tue Mar 27 09:13:08 UTC 2018


commit a33b931e6ddd9b6fa74782560b7334636a23749f
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Tue Mar 27 09:11:23 2018 +0000

    List commands in a single tbl-include file.
    Move misc commands to separate source file.

diff --git a/bin/varnishtest/Makefile.am b/bin/varnishtest/Makefile.am
index 974aaf9..efbac2a 100644
--- a/bin/varnishtest/Makefile.am
+++ b/bin/varnishtest/Makefile.am
@@ -27,22 +27,24 @@ bin_PROGRAMS =	varnishtest
 varnishtest_SOURCES = \
 		hpack.h \
 		programs.h \
+		cmds.h \
 		vmods.h \
-		vtc.c \
 		vtc.h \
+		vtc.c \
 		vtc_barrier.c \
 		vtc_client.c \
-		vtc_http.c \
-		vtc_http.h \
-		vtc_log.c \
-		vtc_http2.c \
 		vtc_h2_dectbl.h \
 		vtc_h2_enctbl.h \
 		vtc_h2_hpack.c \
 		vtc_h2_priv.h \
 		vtc_h2_stattbl.h \
 		vtc_h2_tbl.c \
+		vtc_http.c \
+		vtc_http.h \
+		vtc_http2.c \
+		vtc_log.c \
 		vtc_logexp.c \
+		vtc_misc.c \
 		vtc_main.c \
 		vtc_process.c \
 		vtc_proxy.c \
diff --git a/bin/varnishtest/cmds.h b/bin/varnishtest/cmds.h
new file mode 100644
index 0000000..58c2e7b
--- /dev/null
+++ b/bin/varnishtest/cmds.h
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2018 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*lint -save -e525 -e539 */
+
+CMD(barrier)
+CMD(client)
+CMD(delay)
+CMD(err_shell)
+CMD(feature)
+//CMD(haproxy)
+CMD(logexpect)
+CMD(process)
+CMD(server)
+CMD(setenv)
+CMD(shell)
+CMD(varnish)
+CMD(varnishtest)
+#undef CMD
+
+/*lint -restore */
diff --git a/bin/varnishtest/flint.lnt b/bin/varnishtest/flint.lnt
index 1dc2716..25eace2 100644
--- a/bin/varnishtest/flint.lnt
+++ b/bin/varnishtest/flint.lnt
@@ -35,6 +35,7 @@
 
 -e788	// enum value not used in defaulted switch
 
+-efile(451, cmds.h)
 -efile(451, vmods.h)
 -efile(451, programs.h)
 -efile(451, vtc_h2_stattbl.h)
diff --git a/bin/varnishtest/vtc.c b/bin/varnishtest/vtc.c
index 8d7f764..76f1e7a 100644
--- a/bin/varnishtest/vtc.c
+++ b/bin/varnishtest/vtc.c
@@ -31,10 +31,6 @@
 #include <sys/wait.h>
 
 #include <ctype.h>
-#include <errno.h>
-#include <grp.h>
-#include <math.h>
-#include <pwd.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -44,8 +40,6 @@
 #include "vtc.h"
 
 #include "vav.h"
-#include "vnum.h"
-#include "vre.h"
 #include "vtim.h"
 
 #ifdef HAVE_SYS_PERSONALITY_H
@@ -57,8 +51,8 @@
 volatile sig_atomic_t	vtc_error;	/* Error encountered */
 int			vtc_stop;	/* Stops current test without error */
 pthread_t		vtc_thread;
+int			ign_unknown_macro = 0;
 static struct vtclog	*vltop;
-static int		ign_unknown_macro = 0;
 
 /**********************************************************************
  * Macro facility
@@ -426,436 +420,13 @@ reset_cmds(const struct cmds *cmd)
 		cmd->cmd(NULL, NULL, NULL, NULL);
 }
 
-/* SECTION: varnishtest varnishtest
- *
- * This should be the first command in your vtc as it will identify the test
- * case with a short yet descriptive sentence. It takes exactly one argument, a
- * string, eg::
- *
- *         varnishtest "Check that varnishtest is actually a valid command"
- *
- * It will also print that string in the log.
- */
-
-static void
-cmd_varnishtest(CMD_ARGS)
-{
-
-	(void)priv;
-	(void)cmd;
-	(void)vl;
-
-	if (av == NULL)
-		return;
-	AZ(strcmp(av[0], "varnishtest"));
-
-	vtc_log(vl, 1, "TEST %s", av[1]);
-	AZ(av[2]);
-}
-
-/* SECTION: shell shell
- *
- * Pass the string given as argument to a shell. If you have multiple
- * commands to run, you can use curly barces to describe a multi-lines
- * script, eg::
- *
- *         shell {
- *                 echo begin
- *                 cat /etc/fstab
- *                 echo end
- *         }
- *
- * By default a zero exit code is expected, otherwise the vtc will fail.
- *
- * Notice that the commandstring is prefixed with "exec 2>&1;" to join
- * stderr and stdout back to the varnishtest process.
- *
- * Optional arguments:
- *
- * \-err
- *	Expect non-zero exit code.
- *
- * \-exit N
- *	Expect exit code N instead of zero.
- *
- * \-expect STRING
- *	Expect string to be found in stdout+err.
- *
- * \-match REGEXP
- *	Expect regexp to match the stdout+err output.
- */
-/* SECTION: client-server.spec.shell shell
- *
- * Same as for the top-level shell.
- */
-
-static void
-cmd_shell_engine(struct vtclog *vl, int ok, const char *cmd,
-    const char *expect, const char *re)
-{
-	struct vsb *vsb;
-	FILE *fp;
-	vre_t *vre = NULL;
-	const char *errptr;
-	int r, c;
-	int err;
-
-	AN(vl);
-	AN(cmd);
-	vsb = VSB_new_auto();
-	AN(vsb);
-	if (re != NULL) {
-		vre = VRE_compile(re, 0, &errptr, &err);
-		if (vre == NULL)
-			vtc_fatal(vl, "shell_match invalid regexp (\"%s\")",
-			    re);
-	}
-	VSB_printf(vsb, "exec 2>&1 ; %s", cmd);
-	AZ(VSB_finish(vsb));
-	vtc_dump(vl, 4, "shell_cmd", VSB_data(vsb), -1);
-	fp = popen(VSB_data(vsb), "r");
-	if (fp == NULL)
-		vtc_fatal(vl, "popen fails: %s", strerror(errno));
-	VSB_clear(vsb);
-	do {
-		c = getc(fp);
-		if (c != EOF)
-			VSB_putc(vsb, c);
-	} while (c != EOF);
-	r = pclose(fp);
-	AZ(VSB_finish(vsb));
-	vtc_dump(vl, 4, "shell_out", VSB_data(vsb), VSB_len(vsb));
-	vtc_log(vl, 4, "shell_status = 0x%04x", WEXITSTATUS(r));
-	if (WIFSIGNALED(r))
-		vtc_log(vl, 4, "shell_signal = %d", WTERMSIG(r));
-
-	if (ok < 0 && !WEXITSTATUS(r) && !WIFSIGNALED(r))
-		vtc_fatal(vl, "shell did not fail as expected");
-	else if (ok >= 0 && WEXITSTATUS(r) != ok)
-		vtc_fatal(vl, "shell_exit not as expected: "
-		    "got 0x%04x wanted 0x%04x", WEXITSTATUS(r), ok);
-
-	if (expect != NULL) {
-		if (strstr(VSB_data(vsb), expect) == NULL)
-			vtc_fatal(vl,
-			    "shell_expect not found: (\"%s\")", expect);
-		else
-			vtc_log(vl, 4, "shell_expect found");
-	} else if (vre != NULL) {
-		if (VRE_exec(vre, VSB_data(vsb), VSB_len(vsb), 0, 0,
-		    NULL, 0, NULL) < 1)
-			vtc_fatal(vl,
-			    "shell_match failed: (\"%s\")", re);
-		else
-			vtc_log(vl, 4, "shell_match succeeded");
-		VRE_free(&vre);
-	}
-	VSB_destroy(&vsb);
-}
-
-
-void
-cmd_shell(CMD_ARGS)
-{
-	const char *expect = NULL;
-	const char *re = NULL;
-	int n;
-	int ok = 0;
-
-	(void)priv;
-	(void)cmd;
-
-	if (av == NULL)
-		return;
-	for (n = 1; av[n] != NULL; n++) {
-		if (!strcmp(av[n], "-err")) {
-			ok = -1;
-		} else if (!strcmp(av[n], "-exit")) {
-			n += 1;
-			ok = atoi(av[n]);
-		} else if (!strcmp(av[n], "-expect")) {
-			if (re != NULL)
-				vtc_fatal(vl,
-				    "Cannot use -expect with -match");
-			n += 1;
-			expect = av[n];
-		} else if (!strcmp(av[n], "-match")) {
-			if (expect != NULL)
-				vtc_fatal(vl,
-				    "Cannot use -match with -expect");
-			n += 1;
-			re = av[n];
-		} else {
-			break;
-		}
-	}
-	AN(av[n]);
-	cmd_shell_engine(vl, ok, av[n], expect, re);
-}
-
-/* SECTION: err_shell err_shell
- *
- * This is very similar to the the ``shell`` command, except it takes a first
- * string as argument before the command::
- *
- *         err_shell "foo" "echo foo"
- *
- * err_shell expect the shell command to fail AND stdout to match the string,
- * failing the test case otherwise.
- */
-
-static void
-cmd_err_shell(CMD_ARGS)
-{
-	(void)priv;
-	(void)cmd;
-
-	if (av == NULL)
-		return;
-	AN(av[1]);
-	AN(av[2]);
-	AZ(av[3]);
-	vtc_log(vl, 1,
-	    "NOTICE: err_shell is deprecated, use 'shell -err -expect'");
-	cmd_shell_engine(vl, -1, av[2], av[1], NULL);
-}
-
-/* SECTION: setenv setenv
- *
- * Set or change an environment variable::
- *
- *         setenv FOO "bar baz"
- *
- * The above will set the environment variable $FOO to the value
- * provided. There is also an ``-ifunset`` argument which will only
- * set the value if the the environment variable does not already
- * exist::
- *
- *        setenv -ifunset FOO quux
- */
-static void
-cmd_setenv(CMD_ARGS)
-{
-	int r;
-	int force;
-
-	(void)priv;
-	(void)cmd;
-
-	if (av == NULL)
-		return;
-	AN(av[1]);
-	AN(av[2]);
-
-	force = 1;
-	if (strcmp("-ifunset", av[1]) == 0) {
-		force = 0;
-		av++;
-		AN(av[2]);
-	}
-	if (av[3] != NULL)
-		vtc_fatal(vl, "CMD setenv: Unexpected argument '%s'", av[3]);
-	r = setenv(av[1], av[2], force);
-	if (r != 0)
-		vtc_log(vl, 0, "CMD setenv %s=\"%s\" failed: %s",
-		    av[1], av[2], strerror(errno));
-}
-
-/* SECTION: delay delay
- *
- * Sleep for the number of seconds specified in the argument. The number
- * can include a fractional part, e.g. 1.5.
- */
-/* SECTION: stream.spec.delay delay
- *
- * Same as for the top-level delay.
- */
-void
-cmd_delay(CMD_ARGS)
-{
-	double f;
-
-	(void)priv;
-	(void)cmd;
-	if (av == NULL)
-		return;
-	AN(av[1]);
-	AZ(av[2]);
-	f = VNUM(av[1]);
-	if (isnan(f))
-		vtc_fatal(vl, "Syntax error in number (%s)", av[1]);
-	vtc_log(vl, 3, "delaying %g second(s)", f);
-	VTIM_sleep(f);
-}
-
-/* SECTION: feature feature
- *
- * Test that the required feature(s) for a test are available, and skip
- * the test otherwise; or change the interpretation of the test, as
- * documented below. feature takes any number of arguments from this list:
- *
- * SO_RCVTIMEO_WORKS
- *        The SO_RCVTIMEO socket option is working
- * 64bit
- *        The environment is 64 bits
- * !OSX
- *        The environment is not OSX
- * dns
- *        DNS lookups are working
- * topbuild
- *        varnishtest has been started with '-i'
- * root
- *        varnishtest has been invoked by the root user
- * user_varnish
- *        The varnish user is present
- * user_vcache
- *        The vcache user is present
- * group_varnish
- *        The varnish group is present
- * cmd <command-line>
- *        A command line that should execute with a zero exit status
- * ignore_unknown_macro
- *        Do not fail the test if a string of the form ${...} is not
- *        recognized as a macro.
- * term
- *        Support for ADM3A terminal
- *
- * persistent_storage
- *        Varnish was built with the deprecated persistent storage.
- *
- * Be careful with ignore_unknown_macro, because it may cause a test with a
- * misspelled macro to fail silently. You should only need it if you must
- * run a test with strings of the form "${...}".
- */
-
-#if WITH_PERSISTENT_STORAGE
-static const unsigned with_persistent_storage = 1;
-#else
-static const unsigned with_persistent_storage = 0;
-#endif
-
-static int
-test_term(struct vtclog *vl)
-{
-	FILE *p;
-	int a, b;
-
-	p = popen("tput -T ansi.sys clear 2>&1", "r");
-	if (p == NULL)
-		return (0);
-	a = fgetc(p);
-	b = fgetc(p);
-	if (a == 0x1b && b == '[')
-		return (1);
-	vtc_log(vl, 3, "No 'ansi.sys' terminfo entry.");
-	return (0);
-}
-
-static void
-cmd_feature(CMD_ARGS)
-{
-	int r;
-	int good;
-
-	(void)priv;
-	(void)cmd;
-
-	if (av == NULL)
-		return;
-
-#define FEATURE(nm, tst)				\
-	do {						\
-		if (!strcmp(*av, nm)) {			\
-			if (tst) {			\
-				good = 1;		\
-			} else {			\
-				vtc_stop = 2;		\
-			}				\
-		}					\
-	} while (0)
-
-	for (av++; *av != NULL; av++) {
-		good = 0;
-		if (!strcmp(*av, "SO_RCVTIMEO_WORKS")) {
-#ifdef SO_RCVTIMEO_WORKS
-			good = 1;
-#else
-			vtc_stop = 2;
-#endif
-		}
-
-		if (!strcmp(*av, "!OSX")) {
-#if !defined(__APPLE__) || !defined(__MACH__)
-			good = 1;
-#else
-			vtc_stop = 2;
-#endif
-		}
-		FEATURE("pcre_jit", VRE_has_jit);
-		FEATURE("64bit", sizeof(void*) == 8);
-		FEATURE("dns", feature_dns);
-		FEATURE("topbuild", iflg);
-		FEATURE("root", !geteuid());
-		FEATURE("user_varnish", getpwnam("varnish") != NULL);
-		FEATURE("user_vcache", getpwnam("vcache") != NULL);
-		FEATURE("group_varnish", getgrnam("varnish") != NULL);
-		FEATURE("term", test_term(vl));
-		FEATURE("persistent_storage", with_persistent_storage);
-
-		if (!strcmp(*av, "disable_aslr")) {
-			good = 1;
-#ifdef HAVE_SYS_PERSONALITY_H
-			r = personality(0xffffffff);
-			r = personality(r | ADDR_NO_RANDOMIZE);
-			if (r < 0) {
-				good = 0;
-				vtc_stop = 2;
-			}
-#endif
-		} else if (!strcmp(*av, "cmd")) {
-			av++;
-			if (*av == NULL)
-				vtc_fatal(vl, "Missing the command-line");
-			r = system(*av);
-			if (WEXITSTATUS(r) == 0)
-				good = 1;
-			else
-				vtc_stop = 2;
-		} else if (!strcmp(*av, "ignore_unknown_macro")) {
-			ign_unknown_macro = 1;
-			good = 1;
-		}
-		if (good)
-			continue;
-
-		if (!vtc_stop)
-			vtc_fatal(vl, "FAIL test, unknown feature: %s", *av);
-		else
-			vtc_log(vl, 1,
-			    "SKIPPING test, lacking feature: %s", *av);
-		return;
-	}
-}
-
 /**********************************************************************
  * Execute a file
  */
 
 static const struct cmds cmds[] = {
 #define CMD(n) { #n, cmd_##n },
-	CMD(server)
-	CMD(client)
-	CMD(varnish)
-	CMD(delay)
-	CMD(varnishtest)
-	CMD(shell)
-	CMD(err_shell)
-	CMD(barrier)
-	CMD(feature)
-	CMD(logexpect)
-	CMD(process)
-	CMD(setenv)
-#undef CMD
+#include "cmds.h"
 	{ NULL, NULL }
 };
 
diff --git a/bin/varnishtest/vtc.h b/bin/varnishtest/vtc.h
index 8f0d130..387181c 100644
--- a/bin/varnishtest/vtc.h
+++ b/bin/varnishtest/vtc.h
@@ -69,16 +69,8 @@ void parse_string(const char *spec, const struct cmds *cmd, void *priv,
     struct vtclog *vl);
 int fail_out(void);
 
-#define CMD(n) cmd_f cmd_##n
-CMD(delay);
-CMD(server);
-CMD(client);
-CMD(varnish);
-CMD(barrier);
-CMD(logexpect);
-CMD(process);
-CMD(shell);
-#undef CMD
+#define CMD(n) cmd_f cmd_##n;
+#include "cmds.h"
 
 extern volatile sig_atomic_t vtc_error; /* Error, bail out */
 extern int vtc_stop;		/* Abandon current test, no error */
@@ -90,6 +82,7 @@ extern struct vsb *params_vsb;
 extern int leave_temp;
 extern int vtc_witness;
 extern int feature_dns;
+extern int ign_unknown_macro;
 
 void init_server(void);
 
diff --git a/bin/varnishtest/vtc_misc.c b/bin/varnishtest/vtc_misc.c
new file mode 100644
index 0000000..30f404e
--- /dev/null
+++ b/bin/varnishtest/vtc_misc.c
@@ -0,0 +1,458 @@
+/*-
+ * Copyright (c) 2008-2011 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <grp.h>
+#include <math.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "vtc.h"
+
+#include "vnum.h"
+#include "vre.h"
+#include "vtim.h"
+
+/* SECTION: varnishtest varnishtest
+ *
+ * This should be the first command in your vtc as it will identify the test
+ * case with a short yet descriptive sentence. It takes exactly one argument, a
+ * string, eg::
+ *
+ *         varnishtest "Check that varnishtest is actually a valid command"
+ *
+ * It will also print that string in the log.
+ */
+
+void v_matchproto_(cmd_f)
+cmd_varnishtest(CMD_ARGS)
+{
+
+	(void)priv;
+	(void)cmd;
+	(void)vl;
+
+	if (av == NULL)
+		return;
+	AZ(strcmp(av[0], "varnishtest"));
+
+	vtc_log(vl, 1, "TEST %s", av[1]);
+	AZ(av[2]);
+}
+
+/* SECTION: shell shell
+ *
+ * Pass the string given as argument to a shell. If you have multiple
+ * commands to run, you can use curly barces to describe a multi-lines
+ * script, eg::
+ *
+ *         shell {
+ *                 echo begin
+ *                 cat /etc/fstab
+ *                 echo end
+ *         }
+ *
+ * By default a zero exit code is expected, otherwise the vtc will fail.
+ *
+ * Notice that the commandstring is prefixed with "exec 2>&1;" to join
+ * stderr and stdout back to the varnishtest process.
+ *
+ * Optional arguments:
+ *
+ * \-err
+ *	Expect non-zero exit code.
+ *
+ * \-exit N
+ *	Expect exit code N instead of zero.
+ *
+ * \-expect STRING
+ *	Expect string to be found in stdout+err.
+ *
+ * \-match REGEXP
+ *	Expect regexp to match the stdout+err output.
+ */
+/* SECTION: client-server.spec.shell shell
+ *
+ * Same as for the top-level shell.
+ */
+
+static void
+cmd_shell_engine(struct vtclog *vl, int ok, const char *cmd,
+    const char *expect, const char *re)
+{
+	struct vsb *vsb;
+	FILE *fp;
+	vre_t *vre = NULL;
+	const char *errptr;
+	int r, c;
+	int err;
+
+	AN(vl);
+	AN(cmd);
+	vsb = VSB_new_auto();
+	AN(vsb);
+	if (re != NULL) {
+		vre = VRE_compile(re, 0, &errptr, &err);
+		if (vre == NULL)
+			vtc_fatal(vl, "shell_match invalid regexp (\"%s\")",
+			    re);
+	}
+	VSB_printf(vsb, "exec 2>&1 ; %s", cmd);
+	AZ(VSB_finish(vsb));
+	vtc_dump(vl, 4, "shell_cmd", VSB_data(vsb), -1);
+	fp = popen(VSB_data(vsb), "r");
+	if (fp == NULL)
+		vtc_fatal(vl, "popen fails: %s", strerror(errno));
+	VSB_clear(vsb);
+	do {
+		c = getc(fp);
+		if (c != EOF)
+			VSB_putc(vsb, c);
+	} while (c != EOF);
+	r = pclose(fp);
+	AZ(VSB_finish(vsb));
+	vtc_dump(vl, 4, "shell_out", VSB_data(vsb), VSB_len(vsb));
+	vtc_log(vl, 4, "shell_status = 0x%04x", WEXITSTATUS(r));
+	if (WIFSIGNALED(r))
+		vtc_log(vl, 4, "shell_signal = %d", WTERMSIG(r));
+
+	if (ok < 0 && !WEXITSTATUS(r) && !WIFSIGNALED(r))
+		vtc_fatal(vl, "shell did not fail as expected");
+	else if (ok >= 0 && WEXITSTATUS(r) != ok)
+		vtc_fatal(vl, "shell_exit not as expected: "
+		    "got 0x%04x wanted 0x%04x", WEXITSTATUS(r), ok);
+
+	if (expect != NULL) {
+		if (strstr(VSB_data(vsb), expect) == NULL)
+			vtc_fatal(vl,
+			    "shell_expect not found: (\"%s\")", expect);
+		else
+			vtc_log(vl, 4, "shell_expect found");
+	} else if (vre != NULL) {
+		if (VRE_exec(vre, VSB_data(vsb), VSB_len(vsb), 0, 0,
+		    NULL, 0, NULL) < 1)
+			vtc_fatal(vl,
+			    "shell_match failed: (\"%s\")", re);
+		else
+			vtc_log(vl, 4, "shell_match succeeded");
+		VRE_free(&vre);
+	}
+	VSB_destroy(&vsb);
+}
+
+
+void
+cmd_shell(CMD_ARGS)
+{
+	const char *expect = NULL;
+	const char *re = NULL;
+	int n;
+	int ok = 0;
+
+	(void)priv;
+	(void)cmd;
+
+	if (av == NULL)
+		return;
+	for (n = 1; av[n] != NULL; n++) {
+		if (!strcmp(av[n], "-err")) {
+			ok = -1;
+		} else if (!strcmp(av[n], "-exit")) {
+			n += 1;
+			ok = atoi(av[n]);
+		} else if (!strcmp(av[n], "-expect")) {
+			if (re != NULL)
+				vtc_fatal(vl,
+				    "Cannot use -expect with -match");
+			n += 1;
+			expect = av[n];
+		} else if (!strcmp(av[n], "-match")) {
+			if (expect != NULL)
+				vtc_fatal(vl,
+				    "Cannot use -match with -expect");
+			n += 1;
+			re = av[n];
+		} else {
+			break;
+		}
+	}
+	AN(av[n]);
+	cmd_shell_engine(vl, ok, av[n], expect, re);
+}
+
+/* SECTION: err_shell err_shell
+ *
+ * This is very similar to the the ``shell`` command, except it takes a first
+ * string as argument before the command::
+ *
+ *         err_shell "foo" "echo foo"
+ *
+ * err_shell expect the shell command to fail AND stdout to match the string,
+ * failing the test case otherwise.
+ */
+
+void v_matchproto_(cmd_f)
+cmd_err_shell(CMD_ARGS)
+{
+	(void)priv;
+	(void)cmd;
+
+	if (av == NULL)
+		return;
+	AN(av[1]);
+	AN(av[2]);
+	AZ(av[3]);
+	vtc_log(vl, 1,
+	    "NOTICE: err_shell is deprecated, use 'shell -err -expect'");
+	cmd_shell_engine(vl, -1, av[2], av[1], NULL);
+}
+
+/* SECTION: setenv setenv
+ *
+ * Set or change an environment variable::
+ *
+ *         setenv FOO "bar baz"
+ *
+ * The above will set the environment variable $FOO to the value
+ * provided. There is also an ``-ifunset`` argument which will only
+ * set the value if the the environment variable does not already
+ * exist::
+ *
+ *        setenv -ifunset FOO quux
+ */
+
+void v_matchproto_(cmd_f)
+cmd_setenv(CMD_ARGS)
+{
+	int r;
+	int force;
+
+	(void)priv;
+	(void)cmd;
+
+	if (av == NULL)
+		return;
+	AN(av[1]);
+	AN(av[2]);
+
+	force = 1;
+	if (strcmp("-ifunset", av[1]) == 0) {
+		force = 0;
+		av++;
+		AN(av[2]);
+	}
+	if (av[3] != NULL)
+		vtc_fatal(vl, "CMD setenv: Unexpected argument '%s'", av[3]);
+	r = setenv(av[1], av[2], force);
+	if (r != 0)
+		vtc_log(vl, 0, "CMD setenv %s=\"%s\" failed: %s",
+		    av[1], av[2], strerror(errno));
+}
+
+/* SECTION: delay delay
+ *
+ * Sleep for the number of seconds specified in the argument. The number
+ * can include a fractional part, e.g. 1.5.
+ */
+/* SECTION: stream.spec.delay delay
+ *
+ * Same as for the top-level delay.
+ */
+void
+cmd_delay(CMD_ARGS)
+{
+	double f;
+
+	(void)priv;
+	(void)cmd;
+	if (av == NULL)
+		return;
+	AN(av[1]);
+	AZ(av[2]);
+	f = VNUM(av[1]);
+	if (isnan(f))
+		vtc_fatal(vl, "Syntax error in number (%s)", av[1]);
+	vtc_log(vl, 3, "delaying %g second(s)", f);
+	VTIM_sleep(f);
+}
+
+/* SECTION: feature feature
+ *
+ * Test that the required feature(s) for a test are available, and skip
+ * the test otherwise; or change the interpretation of the test, as
+ * documented below. feature takes any number of arguments from this list:
+ *
+ * SO_RCVTIMEO_WORKS
+ *        The SO_RCVTIMEO socket option is working
+ * 64bit
+ *        The environment is 64 bits
+ * !OSX
+ *        The environment is not OSX
+ * dns
+ *        DNS lookups are working
+ * topbuild
+ *        varnishtest has been started with '-i'
+ * root
+ *        varnishtest has been invoked by the root user
+ * user_varnish
+ *        The varnish user is present
+ * user_vcache
+ *        The vcache user is present
+ * group_varnish
+ *        The varnish group is present
+ * cmd <command-line>
+ *        A command line that should execute with a zero exit status
+ * ignore_unknown_macro
+ *        Do not fail the test if a string of the form ${...} is not
+ *        recognized as a macro.
+ * term
+ *        Support for ADM3A terminal
+ *
+ * persistent_storage
+ *        Varnish was built with the deprecated persistent storage.
+ *
+ * Be careful with ignore_unknown_macro, because it may cause a test with a
+ * misspelled macro to fail silently. You should only need it if you must
+ * run a test with strings of the form "${...}".
+ */
+
+#if WITH_PERSISTENT_STORAGE
+static const unsigned with_persistent_storage = 1;
+#else
+static const unsigned with_persistent_storage = 0;
+#endif
+
+static int
+test_term(struct vtclog *vl)
+{
+	FILE *p;
+	int a, b;
+
+	p = popen("tput -T ansi.sys clear 2>&1", "r");
+	if (p == NULL)
+		return (0);
+	a = fgetc(p);
+	b = fgetc(p);
+	if (a == 0x1b && b == '[')
+		return (1);
+	vtc_log(vl, 3, "No 'ansi.sys' terminfo entry.");
+	return (0);
+}
+
+void v_matchproto_(cmd_f)
+cmd_feature(CMD_ARGS)
+{
+	int r;
+	int good;
+
+	(void)priv;
+	(void)cmd;
+
+	if (av == NULL)
+		return;
+
+#define FEATURE(nm, tst)				\
+	do {						\
+		if (!strcmp(*av, nm)) {			\
+			if (tst) {			\
+				good = 1;		\
+			} else {			\
+				vtc_stop = 2;		\
+			}				\
+		}					\
+	} while (0)
+
+	for (av++; *av != NULL; av++) {
+		good = 0;
+		if (!strcmp(*av, "SO_RCVTIMEO_WORKS")) {
+#ifdef SO_RCVTIMEO_WORKS
+			good = 1;
+#else
+			vtc_stop = 2;
+#endif
+		}
+
+		if (!strcmp(*av, "!OSX")) {
+#if !defined(__APPLE__) || !defined(__MACH__)
+			good = 1;
+#else
+			vtc_stop = 2;
+#endif
+		}
+		FEATURE("pcre_jit", VRE_has_jit);
+		FEATURE("64bit", sizeof(void*) == 8);
+		FEATURE("dns", feature_dns);
+		FEATURE("topbuild", iflg);
+		FEATURE("root", !geteuid());
+		FEATURE("user_varnish", getpwnam("varnish") != NULL);
+		FEATURE("user_vcache", getpwnam("vcache") != NULL);
+		FEATURE("group_varnish", getgrnam("varnish") != NULL);
+		FEATURE("term", test_term(vl));
+		FEATURE("persistent_storage", with_persistent_storage);
+
+		if (!strcmp(*av, "disable_aslr")) {
+			good = 1;
+#ifdef HAVE_SYS_PERSONALITY_H
+			r = personality(0xffffffff);
+			r = personality(r | ADDR_NO_RANDOMIZE);
+			if (r < 0) {
+				good = 0;
+				vtc_stop = 2;
+			}
+#endif
+		} else if (!strcmp(*av, "cmd")) {
+			av++;
+			if (*av == NULL)
+				vtc_fatal(vl, "Missing the command-line");
+			r = system(*av);
+			if (WEXITSTATUS(r) == 0)
+				good = 1;
+			else
+				vtc_stop = 2;
+		} else if (!strcmp(*av, "ignore_unknown_macro")) {
+			ign_unknown_macro = 1;
+			good = 1;
+		}
+		if (good)
+			continue;
+
+		if (!vtc_stop)
+			vtc_fatal(vl, "FAIL test, unknown feature: %s", *av);
+		else
+			vtc_log(vl, 1,
+			    "SKIPPING test, lacking feature: %s", *av);
+		return;
+	}
+}


More information about the varnish-commit mailing list