| | varnish-cache/bin/varnishtest/vtest2/src/vtc_main.c |
| 0 |
|
/*- |
| 1 |
|
* Copyright (c) 2008-2011 Varnish Software AS |
| 2 |
|
* All rights reserved. |
| 3 |
|
* |
| 4 |
|
* Author: Poul-Henning Kamp <phk@phk.freebsd.dk> |
| 5 |
|
* |
| 6 |
|
* SPDX-License-Identifier: BSD-2-Clause |
| 7 |
|
* |
| 8 |
|
* Redistribution and use in source and binary forms, with or without |
| 9 |
|
* modification, are permitted provided that the following conditions |
| 10 |
|
* are met: |
| 11 |
|
* 1. Redistributions of source code must retain the above copyright |
| 12 |
|
* notice, this list of conditions and the following disclaimer. |
| 13 |
|
* 2. Redistributions in binary form must reproduce the above copyright |
| 14 |
|
* notice, this list of conditions and the following disclaimer in the |
| 15 |
|
* documentation and/or other materials provided with the distribution. |
| 16 |
|
* |
| 17 |
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| 18 |
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 19 |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 20 |
|
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE |
| 21 |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 22 |
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 23 |
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 24 |
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 25 |
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 26 |
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 27 |
|
* SUCH DAMAGE. |
| 28 |
|
*/ |
| 29 |
|
|
| 30 |
|
#include "config.h" |
| 31 |
|
|
| 32 |
|
#include <sys/mman.h> |
| 33 |
|
#include <sys/socket.h> |
| 34 |
|
#include <sys/stat.h> |
| 35 |
|
#include <sys/wait.h> |
| 36 |
|
|
| 37 |
|
#include <ctype.h> |
| 38 |
|
#include <dirent.h> |
| 39 |
|
#include <poll.h> |
| 40 |
|
#include <stdio.h> |
| 41 |
|
#include <stdlib.h> |
| 42 |
|
#include <string.h> |
| 43 |
|
#include <unistd.h> |
| 44 |
|
|
| 45 |
|
#include "vtc.h" |
| 46 |
|
|
| 47 |
|
#include "vev.h" |
| 48 |
|
#include "vfil.h" |
| 49 |
|
#include "vnum.h" |
| 50 |
|
#include "vrnd.h" |
| 51 |
|
#include "vsa.h" |
| 52 |
|
#include "vss.h" |
| 53 |
|
#include "vsub.h" |
| 54 |
|
#include "vtcp.h" |
| 55 |
|
#include "vtim.h" |
| 56 |
|
#include "vct.h" |
| 57 |
|
|
| 58 |
|
static const char *argv0; |
| 59 |
|
|
| 60 |
|
struct buf { |
| 61 |
|
unsigned magic; |
| 62 |
|
#define BUF_MAGIC 0x39d1258a |
| 63 |
|
VTAILQ_ENTRY(buf) list; |
| 64 |
|
char *buf; |
| 65 |
|
struct vsb *diag; |
| 66 |
|
size_t bufsiz; |
| 67 |
|
}; |
| 68 |
|
|
| 69 |
|
static VTAILQ_HEAD(, buf) free_bufs = VTAILQ_HEAD_INITIALIZER(free_bufs); |
| 70 |
|
|
| 71 |
|
struct vtc_tst { |
| 72 |
|
unsigned magic; |
| 73 |
|
#define TST_MAGIC 0x618d8b88 |
| 74 |
|
VTAILQ_ENTRY(vtc_tst) list; |
| 75 |
|
const char *filename; |
| 76 |
|
char *script; |
| 77 |
|
unsigned ntodo; |
| 78 |
|
unsigned nwait; |
| 79 |
|
}; |
| 80 |
|
|
| 81 |
|
struct vtc_job { |
| 82 |
|
unsigned magic; |
| 83 |
|
#define JOB_MAGIC 0x1b5fc419 |
| 84 |
|
struct vtc_tst *tst; |
| 85 |
|
pid_t child; |
| 86 |
|
struct vev *ev; |
| 87 |
|
struct vev *evt; |
| 88 |
|
struct buf *bp; |
| 89 |
|
char *tmpdir; |
| 90 |
|
double t0; |
| 91 |
|
int killed; |
| 92 |
|
}; |
| 93 |
|
|
| 94 |
|
|
| 95 |
|
int iflg = 0; |
| 96 |
|
vtim_dur vtc_maxdur = 60; |
| 97 |
|
static unsigned vtc_bufsiz = 1024 * 1024; |
| 98 |
|
|
| 99 |
|
static VTAILQ_HEAD(, vtc_tst) tst_head = VTAILQ_HEAD_INITIALIZER(tst_head); |
| 100 |
|
static struct vev_root *vb; |
| 101 |
|
static int njob = 0; |
| 102 |
|
static int npar = 1; /* Number of parallel tests */ |
| 103 |
|
static int vtc_continue; /* Continue on error */ |
| 104 |
|
static int vtc_verbosity = 1; /* Verbosity Level */ |
| 105 |
|
static int vtc_good; |
| 106 |
|
static int vtc_fail; |
| 107 |
|
static int vtc_skip; |
| 108 |
|
static char *tmppath; |
| 109 |
|
static char *cwd = NULL; |
| 110 |
|
char *vmod_path = NULL; |
| 111 |
|
struct vsb *params_vsb = NULL; |
| 112 |
|
int leave_temp; |
| 113 |
|
static struct vsb *cbvsb; |
| 114 |
|
static int bad_backend_fd; |
| 115 |
|
|
| 116 |
|
static int cleaner_fd = -1; |
| 117 |
|
static pid_t cleaner_pid; |
| 118 |
|
const char *default_listen_addr; |
| 119 |
|
|
| 120 |
|
static struct buf * |
| 121 |
41080 |
get_buf(void) |
| 122 |
|
{ |
| 123 |
|
struct buf *bp; |
| 124 |
|
|
| 125 |
41080 |
bp = VTAILQ_FIRST(&free_bufs); |
| 126 |
41080 |
CHECK_OBJ_ORNULL(bp, BUF_MAGIC); |
| 127 |
41080 |
if (bp != NULL) { |
| 128 |
760 |
VTAILQ_REMOVE(&free_bufs, bp, list); |
| 129 |
760 |
VSB_clear(bp->diag); |
| 130 |
760 |
} else { |
| 131 |
40320 |
ALLOC_OBJ(bp, BUF_MAGIC); |
| 132 |
40320 |
AN(bp); |
| 133 |
40320 |
bp->bufsiz = vtc_bufsiz; |
| 134 |
40320 |
bp->buf = mmap(NULL, bp->bufsiz, PROT_READ|PROT_WRITE, |
| 135 |
|
MAP_ANON | MAP_SHARED, -1, 0); |
| 136 |
40320 |
assert(bp->buf != MAP_FAILED); |
| 137 |
40320 |
bp->diag = VSB_new_auto(); |
| 138 |
40320 |
AN(bp->diag); |
| 139 |
|
} |
| 140 |
41080 |
memset(bp->buf, 0, bp->bufsiz); |
| 141 |
41080 |
return (bp); |
| 142 |
|
} |
| 143 |
|
|
| 144 |
|
static void |
| 145 |
41080 |
rel_buf(struct buf **bp) |
| 146 |
|
{ |
| 147 |
41080 |
CHECK_OBJ_NOTNULL(*bp, BUF_MAGIC); |
| 148 |
|
|
| 149 |
41080 |
VTAILQ_INSERT_HEAD(&free_bufs, (*bp), list); |
| 150 |
41080 |
*bp = NULL; |
| 151 |
41080 |
} |
| 152 |
|
|
| 153 |
|
/********************************************************************** |
| 154 |
|
* Parse a -D option argument into a name/val pair, and insert |
| 155 |
|
* into extmacro list |
| 156 |
|
*/ |
| 157 |
|
|
| 158 |
|
static int |
| 159 |
40 |
parse_D_opt(char *arg) |
| 160 |
|
{ |
| 161 |
|
char *p, *q; |
| 162 |
|
|
| 163 |
40 |
p = arg; |
| 164 |
40 |
q = strchr(p, '='); |
| 165 |
40 |
if (!q) |
| 166 |
0 |
return (0); |
| 167 |
40 |
*q++ = '\0'; |
| 168 |
40 |
extmacro_def(p, NULL, "%s", q); |
| 169 |
|
|
| 170 |
40 |
return (1); |
| 171 |
40 |
} |
| 172 |
|
|
| 173 |
|
/********************************************************************** |
| 174 |
|
* Print usage |
| 175 |
|
*/ |
| 176 |
|
|
| 177 |
|
static void v_noreturn_ |
| 178 |
120 |
usage(void) |
| 179 |
|
{ |
| 180 |
120 |
fprintf(stderr, "usage: %s [options] file ...\n", argv0); |
| 181 |
|
#define FMT " %-28s # %s\n" |
| 182 |
120 |
fprintf(stderr, FMT, "-b size", |
| 183 |
|
"Set internal buffer size (default: 1M)"); |
| 184 |
120 |
fprintf(stderr, FMT, "-C", "Use cleaner subprocess"); |
| 185 |
120 |
fprintf(stderr, FMT, "-D name=val", "Define macro"); |
| 186 |
120 |
fprintf(stderr, FMT, "-i", "Find varnish binaries in build tree"); |
| 187 |
120 |
fprintf(stderr, FMT, "-j jobs", "Run this many tests in parallel"); |
| 188 |
120 |
fprintf(stderr, FMT, "-k", "Continue on test failure"); |
| 189 |
120 |
fprintf(stderr, FMT, "-L", "Always leave temporary vtc.*"); |
| 190 |
120 |
fprintf(stderr, FMT, "-l", "Leave temporary vtc.* if test fails"); |
| 191 |
120 |
fprintf(stderr, FMT, "-n iterations", "Run tests this many times"); |
| 192 |
120 |
fprintf(stderr, FMT, "-p name=val", "Pass a varnishd parameter"); |
| 193 |
120 |
fprintf(stderr, FMT, "-q", "Quiet mode: report only failures"); |
| 194 |
120 |
fprintf(stderr, FMT, "-t duration", "Time tests out after this long"); |
| 195 |
120 |
fprintf(stderr, FMT, "-v", "Verbose mode: always report test log"); |
| 196 |
120 |
exit(1); |
| 197 |
|
} |
| 198 |
|
|
| 199 |
|
/********************************************************************** |
| 200 |
|
* When running many tests, cleaning the tmpdir with "rm -rf" becomes |
| 201 |
|
* chore which limits our performance. |
| 202 |
|
* When the number of tests are above 100, we spawn a child-process |
| 203 |
|
* to do that for us. |
| 204 |
|
*/ |
| 205 |
|
|
| 206 |
|
static void |
| 207 |
41080 |
cleaner_do(const char *dirname) |
| 208 |
|
{ |
| 209 |
|
char buf[BUFSIZ]; |
| 210 |
|
|
| 211 |
41080 |
AZ(memcmp(dirname, tmppath, strlen(tmppath))); |
| 212 |
41080 |
if (cleaner_pid > 0) { |
| 213 |
960 |
bprintf(buf, "%s\n", dirname); |
| 214 |
960 |
assert(write(cleaner_fd, buf, strlen(buf)) == strlen(buf)); |
| 215 |
960 |
return; |
| 216 |
|
} |
| 217 |
40120 |
bprintf(buf, "exec /bin/rm -rf %s\n", dirname); |
| 218 |
40120 |
AZ(system(buf)); |
| 219 |
41080 |
} |
| 220 |
|
|
| 221 |
|
static void |
| 222 |
80 |
cleaner_setup(void) |
| 223 |
|
{ |
| 224 |
|
int p[2], st; |
| 225 |
|
char buf[BUFSIZ]; |
| 226 |
|
char *q; |
| 227 |
|
pid_t pp; |
| 228 |
|
|
| 229 |
80 |
AZ(pipe(p)); |
| 230 |
80 |
assert(p[0] > STDERR_FILENO); |
| 231 |
80 |
assert(p[1] > STDERR_FILENO); |
| 232 |
80 |
cleaner_pid = fork(); |
| 233 |
80 |
assert(cleaner_pid >= 0); |
| 234 |
160 |
if (cleaner_pid == 0) { |
| 235 |
80 |
closefd(&p[1]); |
| 236 |
80 |
(void)!nice(1); /* Not important */ |
| 237 |
80 |
setbuf(stdin, NULL); |
| 238 |
80 |
AZ(dup2(p[0], STDIN_FILENO)); |
| 239 |
1040 |
while (fgets(buf, sizeof buf, stdin)) { |
| 240 |
960 |
AZ(memcmp(buf, tmppath, strlen(tmppath))); |
| 241 |
960 |
q = buf + strlen(buf); |
| 242 |
960 |
assert(q > buf); |
| 243 |
960 |
assert(q[-1] == '\n'); |
| 244 |
960 |
q[-1] = '\0'; |
| 245 |
|
|
| 246 |
|
/* Dont expend a shell on running /bin/rm */ |
| 247 |
960 |
pp = fork(); |
| 248 |
960 |
assert(pp >= 0); |
| 249 |
1920 |
if (pp == 0) |
| 250 |
960 |
exit(execlp( |
| 251 |
960 |
"rm", "rm", "-rf", buf, (char*)0)); |
| 252 |
960 |
assert(waitpid(pp, &st, 0) == pp); |
| 253 |
960 |
AZ(st); |
| 254 |
|
} |
| 255 |
80 |
exit(0); |
| 256 |
|
} |
| 257 |
80 |
closefd(&p[0]); |
| 258 |
80 |
cleaner_fd = p[1]; |
| 259 |
80 |
} |
| 260 |
|
|
| 261 |
|
static void |
| 262 |
41080 |
cleaner_neuter(void) |
| 263 |
|
{ |
| 264 |
41080 |
if (cleaner_pid > 0) |
| 265 |
960 |
closefd(&cleaner_fd); |
| 266 |
41080 |
} |
| 267 |
|
|
| 268 |
|
static void |
| 269 |
40200 |
cleaner_finish(void) |
| 270 |
|
{ |
| 271 |
|
int st; |
| 272 |
|
|
| 273 |
40200 |
if (cleaner_pid > 0) { |
| 274 |
80 |
closefd(&cleaner_fd); |
| 275 |
80 |
assert(waitpid(cleaner_pid, &st, 0) == cleaner_pid); |
| 276 |
80 |
AZ(st); |
| 277 |
80 |
} |
| 278 |
40200 |
} |
| 279 |
|
|
| 280 |
|
/********************************************************************** |
| 281 |
|
* CallBack |
| 282 |
|
*/ |
| 283 |
|
|
| 284 |
|
static int |
| 285 |
41402 |
tst_cb(const struct vev *ve, int what) |
| 286 |
|
{ |
| 287 |
|
struct vtc_job *jp; |
| 288 |
|
char buf[BUFSIZ]; |
| 289 |
|
int ecode; |
| 290 |
|
int i, stx; |
| 291 |
|
pid_t px; |
| 292 |
|
double t; |
| 293 |
|
FILE *f; |
| 294 |
|
char *p; |
| 295 |
|
|
| 296 |
41402 |
CAST_OBJ_NOTNULL(jp, ve->priv, JOB_MAGIC); |
| 297 |
41402 |
CHECK_OBJ_NOTNULL(jp->tst, TST_MAGIC); |
| 298 |
|
|
| 299 |
|
// printf("CB %p %s %d\n", ve, jp->tst->filename, what); |
| 300 |
41402 |
if (what == 0) { |
| 301 |
0 |
jp->killed = 1; |
| 302 |
0 |
AZ(kill(-jp->child, SIGKILL)); /* XXX: Timeout */ |
| 303 |
0 |
} else { |
| 304 |
41402 |
assert(what & (VEV__RD | VEV__HUP)); |
| 305 |
|
} |
| 306 |
|
|
| 307 |
41402 |
*buf = '\0'; |
| 308 |
41402 |
i = read(ve->fd, buf, sizeof buf); |
| 309 |
41402 |
if (i > 0) |
| 310 |
322 |
VSB_bcat(jp->bp->diag, buf, i); |
| 311 |
41402 |
if (i == 0) { |
| 312 |
|
|
| 313 |
41080 |
njob--; |
| 314 |
41080 |
px = wait4(jp->child, &stx, 0, NULL); |
| 315 |
41080 |
assert(px == jp->child); |
| 316 |
41080 |
t = VTIM_mono() - jp->t0; |
| 317 |
41080 |
AZ(close(ve->fd)); |
| 318 |
|
|
| 319 |
41080 |
ecode = WTERMSIG(stx); |
| 320 |
41080 |
if (ecode == 0) |
| 321 |
41080 |
ecode = WEXITSTATUS(stx); |
| 322 |
|
|
| 323 |
41080 |
AZ(VSB_finish(jp->bp->diag)); |
| 324 |
|
|
| 325 |
41080 |
VSB_clear(cbvsb); |
| 326 |
41080 |
VSB_cat(cbvsb, jp->bp->buf); |
| 327 |
41080 |
p = strchr(jp->bp->buf, '\0'); |
| 328 |
41080 |
if (p > jp->bp->buf && p[-1] != '\n') |
| 329 |
0 |
VSB_putc(cbvsb, '\n'); |
| 330 |
82160 |
VSB_quote_pfx(cbvsb, "* diag 0.0 ", |
| 331 |
41080 |
VSB_data(jp->bp->diag), -1, VSB_QUOTE_NONL); |
| 332 |
41080 |
AZ(VSB_finish(cbvsb)); |
| 333 |
41080 |
rel_buf(&jp->bp); |
| 334 |
|
|
| 335 |
41080 |
if ((ecode > 1 && vtc_verbosity) || vtc_verbosity > 1) |
| 336 |
40480 |
printf("%s", VSB_data(cbvsb)); |
| 337 |
|
|
| 338 |
41080 |
if (!ecode) |
| 339 |
40436 |
vtc_good++; |
| 340 |
644 |
else if (ecode == 1) |
| 341 |
604 |
vtc_skip++; |
| 342 |
|
else |
| 343 |
40 |
vtc_fail++; |
| 344 |
|
|
| 345 |
41080 |
if (leave_temp == 0 || (leave_temp == 1 && ecode <= 1)) { |
| 346 |
41080 |
cleaner_do(jp->tmpdir); |
| 347 |
41080 |
} else { |
| 348 |
0 |
bprintf(buf, "%s/LOG", jp->tmpdir); |
| 349 |
0 |
f = fopen(buf, "w"); |
| 350 |
0 |
AN(f); |
| 351 |
0 |
(void)fprintf(f, "%s\n", VSB_data(cbvsb)); |
| 352 |
0 |
AZ(fclose(f)); |
| 353 |
|
} |
| 354 |
41080 |
free(jp->tmpdir); |
| 355 |
|
|
| 356 |
41080 |
if (jp->killed) |
| 357 |
0 |
printf("# top TEST %s TIMED OUT (kill -9)\n", |
| 358 |
0 |
jp->tst->filename); |
| 359 |
41080 |
if (ecode > 1) { |
| 360 |
40 |
printf("# top TEST %s FAILED (%.3f)", |
| 361 |
40 |
jp->tst->filename, t); |
| 362 |
40 |
if (WIFSIGNALED(stx)) |
| 363 |
0 |
printf(" signal=%d\n", WTERMSIG(stx)); |
| 364 |
40 |
else if (WIFEXITED(stx)) |
| 365 |
40 |
printf(" exit=%d\n", WEXITSTATUS(stx)); |
| 366 |
40 |
if (!vtc_continue) { |
| 367 |
|
/* XXX kill -9 other jobs ? */ |
| 368 |
40 |
exit(2); |
| 369 |
|
} |
| 370 |
41040 |
} else if (vtc_verbosity) { |
| 371 |
41000 |
printf("# top TEST %s %s (%.3f)\n", |
| 372 |
41000 |
jp->tst->filename, |
| 373 |
41000 |
ecode ? "skipped" : "passed", t); |
| 374 |
41000 |
} |
| 375 |
41040 |
if (jp->evt != NULL) { |
| 376 |
41040 |
VEV_Stop(vb, jp->evt); |
| 377 |
41040 |
free(jp->evt); |
| 378 |
41040 |
} |
| 379 |
41400 |
jp->tst->nwait--; |
| 380 |
41400 |
if (jp->tst->nwait == 0) { |
| 381 |
40680 |
free(jp->tst->script); |
| 382 |
40680 |
FREE_OBJ(jp->tst); |
| 383 |
40680 |
} |
| 384 |
41040 |
FREE_OBJ(jp); |
| 385 |
41040 |
return (1); |
| 386 |
|
} |
| 387 |
322 |
return (0); |
| 388 |
41362 |
} |
| 389 |
|
|
| 390 |
|
/********************************************************************** |
| 391 |
|
* Start Test |
| 392 |
|
*/ |
| 393 |
|
|
| 394 |
|
static void |
| 395 |
41080 |
start_test(void) |
| 396 |
|
{ |
| 397 |
|
struct vtc_tst *tp; |
| 398 |
|
int p[2], retval; |
| 399 |
|
struct vtc_job *jp; |
| 400 |
|
char tmpdir[PATH_MAX]; |
| 401 |
|
char default_n[PATH_MAX]; |
| 402 |
|
|
| 403 |
41080 |
ALLOC_OBJ(jp, JOB_MAGIC); |
| 404 |
41080 |
AN(jp); |
| 405 |
|
|
| 406 |
41080 |
jp->bp = get_buf(); |
| 407 |
|
|
| 408 |
41080 |
bprintf(tmpdir, "%s/vtc.%d.%08x", tmppath, (int)getpid(), |
| 409 |
|
(unsigned)random()); |
| 410 |
41080 |
AZ(mkdir(tmpdir, 0755)); |
| 411 |
|
|
| 412 |
41080 |
bprintf(default_n, "%s/default_n", tmpdir); |
| 413 |
|
|
| 414 |
41080 |
AZ(setenv("VARNISH_DEFAULT_N", default_n, 1)); |
| 415 |
|
|
| 416 |
41080 |
tp = VTAILQ_FIRST(&tst_head); |
| 417 |
41080 |
CHECK_OBJ_NOTNULL(tp, TST_MAGIC); |
| 418 |
41080 |
AN(tp->ntodo); |
| 419 |
41080 |
tp->ntodo--; |
| 420 |
41080 |
VTAILQ_REMOVE(&tst_head, tp, list); |
| 421 |
41080 |
if (tp->ntodo > 0) |
| 422 |
360 |
VTAILQ_INSERT_TAIL(&tst_head, tp, list); |
| 423 |
|
|
| 424 |
41080 |
jp->tst = tp; |
| 425 |
41080 |
REPLACE(jp->tmpdir, tmpdir); |
| 426 |
|
|
| 427 |
41080 |
AZ(pipe(p)); |
| 428 |
41080 |
assert(p[0] > STDERR_FILENO); |
| 429 |
41080 |
assert(p[1] > STDERR_FILENO); |
| 430 |
41080 |
jp->t0 = VTIM_mono(); |
| 431 |
41080 |
jp->child = fork(); |
| 432 |
41080 |
assert(jp->child >= 0); |
| 433 |
82160 |
if (jp->child == 0) { |
| 434 |
41080 |
cleaner_neuter(); // Too dangerous to have around |
| 435 |
41080 |
AZ(setpgid(getpid(), 0)); |
| 436 |
41080 |
VFIL_null_fd(STDIN_FILENO); |
| 437 |
41080 |
assert(dup2(p[1], STDOUT_FILENO) == STDOUT_FILENO); |
| 438 |
41080 |
assert(dup2(p[1], STDERR_FILENO) == STDERR_FILENO); |
| 439 |
41080 |
VSUB_closefrom(STDERR_FILENO + 1); |
| 440 |
82160 |
retval = exec_file(jp->tst->filename, jp->tst->script, |
| 441 |
41080 |
jp->tmpdir, jp->bp->buf, jp->bp->bufsiz); |
| 442 |
41080 |
exit(retval); |
| 443 |
|
} |
| 444 |
41080 |
closefd(&p[1]); |
| 445 |
|
|
| 446 |
41080 |
jp->ev = VEV_Alloc(); |
| 447 |
41080 |
AN(jp->ev); |
| 448 |
41080 |
jp->ev->fd_flags = VEV__RD | VEV__HUP | VEV__ERR; |
| 449 |
41080 |
jp->ev->fd = p[0]; |
| 450 |
41080 |
jp->ev->priv = jp; |
| 451 |
41080 |
jp->ev->callback = tst_cb; |
| 452 |
41080 |
AZ(VEV_Start(vb, jp->ev)); |
| 453 |
|
|
| 454 |
41080 |
jp->evt = VEV_Alloc(); |
| 455 |
41080 |
AN(jp->evt); |
| 456 |
41080 |
jp->evt->fd = -1; |
| 457 |
41080 |
jp->evt->timeout = vtc_maxdur; |
| 458 |
41080 |
jp->evt->priv = jp; |
| 459 |
41080 |
jp->evt->callback = tst_cb; |
| 460 |
41080 |
AZ(VEV_Start(vb, jp->evt)); |
| 461 |
41080 |
} |
| 462 |
|
|
| 463 |
|
/********************************************************************** |
| 464 |
|
* i-mode = "we're inside a src-tree" |
| 465 |
|
* |
| 466 |
|
* Find the abs path to top of source dir from Makefile, if that |
| 467 |
|
* fails, fall back on "../../" |
| 468 |
|
* |
| 469 |
|
* Set PATH to all programs build directories |
| 470 |
|
* Set vmod_path to all vmods build directories |
| 471 |
|
* |
| 472 |
|
*/ |
| 473 |
|
|
| 474 |
|
static char * |
| 475 |
79920 |
top_dir(const char *makefile, const char *top_var) |
| 476 |
|
{ |
| 477 |
|
const char *b, *e; |
| 478 |
|
char *var; |
| 479 |
|
|
| 480 |
79920 |
AN(makefile); |
| 481 |
79920 |
AN(top_var); |
| 482 |
79920 |
assert(*top_var == '\n'); |
| 483 |
|
|
| 484 |
79920 |
b = strstr(makefile, top_var); |
| 485 |
79920 |
top_var++; |
| 486 |
|
|
| 487 |
79920 |
if (b == NULL) { |
| 488 |
0 |
fprintf(stderr, "could not find '%s' in Makefile\n", top_var); |
| 489 |
0 |
return (NULL); |
| 490 |
|
} |
| 491 |
|
|
| 492 |
79920 |
e = strchr(b + 1, '\n'); |
| 493 |
79920 |
if (e == NULL) { |
| 494 |
0 |
fprintf(stderr, "No NL after '%s' in Makefile\n", top_var); |
| 495 |
0 |
return (NULL); |
| 496 |
|
} |
| 497 |
|
|
| 498 |
79920 |
b = memchr(b, '/', e - b); |
| 499 |
79920 |
if (b == NULL) { |
| 500 |
0 |
fprintf(stderr, "No '/' after '%s' in Makefile\n", top_var); |
| 501 |
0 |
return (NULL); |
| 502 |
|
} |
| 503 |
79920 |
var = strndup(b, e - b); |
| 504 |
79920 |
AN(var); |
| 505 |
79920 |
return (var); |
| 506 |
79920 |
} |
| 507 |
|
|
| 508 |
|
static void |
| 509 |
119880 |
build_path(const char *topdir, const char *subdir, |
| 510 |
|
const char *pfx, const char *sfx, struct vsb *vsb) |
| 511 |
|
{ |
| 512 |
|
char buf[PATH_MAX]; |
| 513 |
|
DIR *dir; |
| 514 |
|
struct dirent *de; |
| 515 |
|
struct stat st; |
| 516 |
119880 |
const char *topsep = "", *sep = ""; |
| 517 |
|
|
| 518 |
119880 |
if (*subdir != '\0') |
| 519 |
79920 |
topsep = "/"; |
| 520 |
119880 |
bprintf(buf, "%s%s%s/", topdir, topsep, subdir); |
| 521 |
119880 |
dir = opendir(buf); |
| 522 |
119880 |
XXXAN(dir); |
| 523 |
519480 |
while (1) { |
| 524 |
9310800 |
de = readdir(dir); |
| 525 |
9310800 |
if (de == NULL) |
| 526 |
119880 |
break; |
| 527 |
9190920 |
if (strncmp(de->d_name, pfx, strlen(pfx))) |
| 528 |
8791320 |
continue; |
| 529 |
399600 |
bprintf(buf, "%s%s%s/%s", topdir, topsep, subdir, de->d_name); |
| 530 |
399600 |
if (!stat(buf, &st) && S_ISDIR(st.st_mode)) { |
| 531 |
399600 |
VSB_cat(vsb, sep); |
| 532 |
399600 |
VSB_cat(vsb, buf); |
| 533 |
399600 |
VSB_cat(vsb, sfx); |
| 534 |
399600 |
sep = ":"; |
| 535 |
399600 |
} |
| 536 |
|
} |
| 537 |
119880 |
AZ(closedir(dir)); |
| 538 |
119880 |
} |
| 539 |
|
|
| 540 |
|
static void |
| 541 |
39960 |
i_mode(void) |
| 542 |
|
{ |
| 543 |
|
struct vsb *vsb; |
| 544 |
|
char *p, *topbuild, *topsrc; |
| 545 |
|
|
| 546 |
|
/* |
| 547 |
|
* This code has a rather intimate knowledge of auto* generated |
| 548 |
|
* makefiles. |
| 549 |
|
*/ |
| 550 |
|
|
| 551 |
39960 |
vsb = VSB_new_auto(); |
| 552 |
39960 |
AN(vsb); |
| 553 |
|
|
| 554 |
39960 |
p = VFIL_readfile(NULL, "Makefile", NULL); |
| 555 |
39960 |
if (p == NULL) { |
| 556 |
0 |
fprintf(stderr, "No Makefile to search for -i flag.\n"); |
| 557 |
0 |
exit(2); |
| 558 |
|
} |
| 559 |
|
|
| 560 |
39960 |
topbuild = top_dir(p, "\nabs_top_builddir"); |
| 561 |
39960 |
topsrc = top_dir(p, "\nabs_top_srcdir"); |
| 562 |
39960 |
free(p); |
| 563 |
39960 |
if (topbuild == NULL || topsrc == NULL) { |
| 564 |
0 |
free(topbuild); |
| 565 |
0 |
free(topsrc); |
| 566 |
0 |
exit(2); |
| 567 |
|
} |
| 568 |
39960 |
extmacro_def("topbuild", NULL, "%s", topbuild); |
| 569 |
39960 |
extmacro_def("topsrc", NULL, "%s", topsrc); |
| 570 |
|
|
| 571 |
|
/* |
| 572 |
|
* Build $PATH which can find all programs in the build tree |
| 573 |
|
*/ |
| 574 |
39960 |
VSB_clear(vsb); |
| 575 |
39960 |
VSB_cat(vsb, "PATH="); |
| 576 |
39960 |
build_path(topbuild, "bin", "varnish", "", vsb); |
| 577 |
|
#ifdef WITH_CONTRIB |
| 578 |
39960 |
VSB_putc(vsb, ':'); |
| 579 |
39960 |
build_path(topsrc, "", "contrib", "", vsb); |
| 580 |
|
#endif |
| 581 |
39960 |
VSB_printf(vsb, ":%s", getenv("PATH")); |
| 582 |
39960 |
AZ(VSB_finish(vsb)); |
| 583 |
39960 |
AZ(putenv(strdup(VSB_data(vsb)))); |
| 584 |
|
|
| 585 |
|
/* |
| 586 |
|
* Build vmod_path which can find all VMODs in the build tree |
| 587 |
|
*/ |
| 588 |
|
|
| 589 |
39960 |
VSB_clear(vsb); |
| 590 |
39960 |
build_path(topbuild, "vmod", ".libs", "", vsb); |
| 591 |
39960 |
AZ(VSB_finish(vsb)); |
| 592 |
39960 |
vmod_path = strdup(VSB_data(vsb)); |
| 593 |
39960 |
AN(vmod_path); |
| 594 |
|
|
| 595 |
39960 |
free(topbuild); |
| 596 |
39960 |
free(topsrc); |
| 597 |
39960 |
VSB_destroy(&vsb); |
| 598 |
|
|
| 599 |
|
/* |
| 600 |
|
* strict jemalloc checking |
| 601 |
|
*/ |
| 602 |
39960 |
AZ(putenv(strdup("MALLOC_CONF=abort:true,junk:true"))); |
| 603 |
39960 |
} |
| 604 |
|
|
| 605 |
|
/********************************************************************** |
| 606 |
|
* Figure out what IP related magic |
| 607 |
|
*/ |
| 608 |
|
|
| 609 |
|
static void |
| 610 |
40240 |
ip_magic(void) |
| 611 |
|
{ |
| 612 |
|
const struct suckaddr *sa; |
| 613 |
|
char abuf[VTCP_ADDRBUFSIZE]; |
| 614 |
|
char pbuf[VTCP_PORTBUFSIZE]; |
| 615 |
|
char *s; |
| 616 |
|
|
| 617 |
|
/* |
| 618 |
|
* In FreeBSD jails localhost/127.0.0.1 becomes the jails IP# |
| 619 |
|
* XXX: IPv6-only hosts would have similar issue, but it is not |
| 620 |
|
* XXX: obvious how to cope. Ideally "127.0.0.1" would be |
| 621 |
|
* XXX: "localhost", but that doesn't work out of the box. |
| 622 |
|
* XXX: Things like "prefer_ipv6" parameter complicates things. |
| 623 |
|
*/ |
| 624 |
40240 |
sa = VSS_ResolveOne(NULL, "127.0.0.1", "0", 0, SOCK_STREAM, 0); |
| 625 |
40240 |
AN(sa); |
| 626 |
40240 |
bad_backend_fd = VTCP_bind(sa, NULL); |
| 627 |
40240 |
if (bad_backend_fd < 0) { |
| 628 |
0 |
VSA_free(&sa); |
| 629 |
0 |
sa = VSS_ResolveFirst(NULL, "localhost", "0", 0, SOCK_STREAM, 0); |
| 630 |
0 |
AN(sa); |
| 631 |
0 |
bad_backend_fd = VTCP_bind(sa, NULL); |
| 632 |
0 |
} |
| 633 |
40240 |
assert(bad_backend_fd >= 0); |
| 634 |
40240 |
VTCP_myname(bad_backend_fd, abuf, sizeof abuf, pbuf, sizeof(pbuf)); |
| 635 |
40240 |
extmacro_def("localhost", NULL, "%s", abuf); |
| 636 |
40240 |
s = strdup(abuf); |
| 637 |
40240 |
AN(s); |
| 638 |
|
|
| 639 |
|
#if defined (__APPLE__) |
| 640 |
|
/* |
| 641 |
|
* In macOS a bound socket that is not listening will timeout |
| 642 |
|
* instead of refusing the connection so close it and hope |
| 643 |
|
* for the best. |
| 644 |
|
*/ |
| 645 |
|
VTCP_close(&bad_backend_fd); |
| 646 |
|
#endif |
| 647 |
|
|
| 648 |
|
/* Expose a backend that is forever down. */ |
| 649 |
40240 |
if (VSA_Get_Proto(sa) == AF_INET) |
| 650 |
40240 |
extmacro_def("bad_backend", NULL, "%s:%s", abuf, pbuf); |
| 651 |
|
else |
| 652 |
0 |
extmacro_def("bad_backend", NULL, "[%s]:%s", abuf, pbuf); |
| 653 |
|
|
| 654 |
|
/* our default bind/listen address */ |
| 655 |
40240 |
if (VSA_Get_Proto(sa) == AF_INET) |
| 656 |
40240 |
bprintf(abuf, "%s:0", s); |
| 657 |
|
else |
| 658 |
0 |
bprintf(abuf, "[%s]:0", s); |
| 659 |
40240 |
free(s); |
| 660 |
|
|
| 661 |
40240 |
extmacro_def("listen_addr", NULL, "%s", abuf); |
| 662 |
40240 |
default_listen_addr = strdup(abuf); |
| 663 |
40240 |
AN(default_listen_addr); |
| 664 |
40240 |
VSA_free(&sa); |
| 665 |
|
|
| 666 |
|
/* |
| 667 |
|
* We need an IP number which will not respond, ever, and that is a |
| 668 |
|
* lot harder than it sounds. This IP# is from RFC5737 and a |
| 669 |
|
* C-class broadcast at that. |
| 670 |
|
* If tests involving ${bad_ip} fails and you run linux, you should |
| 671 |
|
* check your /proc/sys/net/ipv4/ip_nonlocal_bind setting. |
| 672 |
|
*/ |
| 673 |
|
|
| 674 |
40240 |
extmacro_def("bad_ip", NULL, "%s", "192.0.2.255"); |
| 675 |
40240 |
} |
| 676 |
|
|
| 677 |
|
/********************************************************************** |
| 678 |
|
* Macros |
| 679 |
|
*/ |
| 680 |
|
|
| 681 |
|
static char * v_matchproto_(macro_f) |
| 682 |
87534 |
macro_func_date(int argc, char *const *argv, const char **err) |
| 683 |
|
{ |
| 684 |
|
double t; |
| 685 |
|
char *s; |
| 686 |
|
|
| 687 |
87534 |
assert(argc >= 2); |
| 688 |
87534 |
AN(argv); |
| 689 |
87534 |
AN(err); |
| 690 |
|
|
| 691 |
87534 |
if (argc > 2) { |
| 692 |
0 |
*err = "macro does not take arguments"; |
| 693 |
0 |
return (NULL); |
| 694 |
|
} |
| 695 |
|
|
| 696 |
87534 |
t = VTIM_real(); |
| 697 |
87534 |
s = malloc(VTIM_FORMAT_SIZE); |
| 698 |
87534 |
AN(s); |
| 699 |
87534 |
VTIM_format(t, s); |
| 700 |
87534 |
return (s); |
| 701 |
87534 |
} |
| 702 |
|
|
| 703 |
|
static char * |
| 704 |
1560 |
macro_func_string_repeat(int argc, char *const *argv, const char **err) |
| 705 |
|
{ |
| 706 |
|
struct vsb vsb[1]; |
| 707 |
|
const char *p; |
| 708 |
|
char *res; |
| 709 |
|
size_t l; |
| 710 |
|
int i; |
| 711 |
|
|
| 712 |
1560 |
if (argc != 4) { |
| 713 |
0 |
*err = "repeat takes 2 arguments"; |
| 714 |
0 |
return (NULL); |
| 715 |
|
} |
| 716 |
|
|
| 717 |
1560 |
p = argv[2]; |
| 718 |
1560 |
i = SF_Parse_Integer(&p, err); |
| 719 |
|
|
| 720 |
1560 |
if (*err != NULL) |
| 721 |
0 |
return (NULL); |
| 722 |
|
|
| 723 |
1560 |
if (*p != '\0' || i < 0) { |
| 724 |
0 |
*err = "invalid number of repetitions"; |
| 725 |
0 |
return (NULL); |
| 726 |
|
} |
| 727 |
|
|
| 728 |
1560 |
l = (strlen(argv[3]) * i) + 1; |
| 729 |
1560 |
res = malloc(l); |
| 730 |
1560 |
AN(res); |
| 731 |
1560 |
AN(VSB_init(vsb, res, l)); |
| 732 |
1301160 |
while (i > 0) { |
| 733 |
1299600 |
AZ(VSB_cat(vsb, argv[3])); |
| 734 |
1299600 |
i--; |
| 735 |
|
} |
| 736 |
1560 |
AZ(VSB_finish(vsb)); |
| 737 |
1560 |
VSB_fini(vsb); |
| 738 |
1560 |
return (res); |
| 739 |
1560 |
} |
| 740 |
|
|
| 741 |
|
static char * |
| 742 |
1560 |
macro_func_string(int argc, char *const *argv, const char **err) |
| 743 |
|
{ |
| 744 |
|
|
| 745 |
1560 |
assert(argc >= 2); |
| 746 |
1560 |
AN(argv); |
| 747 |
1560 |
AN(err); |
| 748 |
|
|
| 749 |
1560 |
if (argc == 2) { |
| 750 |
0 |
*err = "missing action"; |
| 751 |
0 |
return (NULL); |
| 752 |
|
} |
| 753 |
|
|
| 754 |
1560 |
if (!strcmp(argv[2], "repeat")) |
| 755 |
1560 |
return (macro_func_string_repeat(argc - 1, argv + 1, err)); |
| 756 |
|
|
| 757 |
0 |
*err = "unknown action"; |
| 758 |
0 |
return (NULL); |
| 759 |
1560 |
} |
| 760 |
|
|
| 761 |
|
/********************************************************************** |
| 762 |
|
* Main |
| 763 |
|
*/ |
| 764 |
|
|
| 765 |
|
static int |
| 766 |
40840 |
read_file(const char *fn, int ntest) |
| 767 |
|
{ |
| 768 |
|
struct vtc_tst *tp; |
| 769 |
|
char *p, *q; |
| 770 |
|
|
| 771 |
40840 |
p = VFIL_readfile(NULL, fn, NULL); |
| 772 |
40840 |
if (p == NULL) { |
| 773 |
80 |
fprintf(stderr, "Cannot stat file \"%s\": %s\n", |
| 774 |
40 |
fn, strerror(errno)); |
| 775 |
40 |
return (2); |
| 776 |
|
} |
| 777 |
40880 |
for (q = p ;q != NULL && *q != '\0'; q++) { |
| 778 |
40880 |
if (vct_islws(*q)) |
| 779 |
80 |
continue; |
| 780 |
40800 |
if (*q != '#') |
| 781 |
40800 |
break; |
| 782 |
0 |
q = strchr(q, '\n'); |
| 783 |
0 |
if (q == NULL) |
| 784 |
0 |
break; |
| 785 |
0 |
} |
| 786 |
|
|
| 787 |
40800 |
if (q == NULL || *q == '\0') { |
| 788 |
0 |
fprintf(stderr, "File \"%s\" has no content.\n", fn); |
| 789 |
0 |
free(p); |
| 790 |
0 |
return (2); |
| 791 |
|
} |
| 792 |
|
|
| 793 |
43120 |
if ((strncmp(q, "varnishtest", 11) || !isspace(q[11])) && |
| 794 |
2320 |
(strncmp(q, "vtest", 5) || !isspace(q[5]))) { |
| 795 |
160 |
fprintf(stderr, |
| 796 |
|
"File \"%s\" doesn't start with" |
| 797 |
80 |
" 'vtest' or 'varnishtest'\n", fn); |
| 798 |
80 |
free(p); |
| 799 |
80 |
vtc_skip++; |
| 800 |
80 |
return (2); |
| 801 |
|
} |
| 802 |
40720 |
ALLOC_OBJ(tp, TST_MAGIC); |
| 803 |
40720 |
AN(tp); |
| 804 |
40720 |
tp->filename = fn; |
| 805 |
40720 |
tp->script = p; |
| 806 |
40720 |
tp->ntodo = ntest; |
| 807 |
40720 |
tp->nwait = ntest; |
| 808 |
40720 |
VTAILQ_INSERT_TAIL(&tst_head, tp, list); |
| 809 |
40720 |
return (0); |
| 810 |
40840 |
} |
| 811 |
|
|
| 812 |
|
/********************************************************************** |
| 813 |
|
* Main |
| 814 |
|
*/ |
| 815 |
|
|
| 816 |
|
int |
| 817 |
40440 |
main(int argc, char * const *argv) |
| 818 |
|
{ |
| 819 |
|
int ch, i; |
| 820 |
40440 |
int ntest = 1; /* Run tests this many times */ |
| 821 |
40440 |
int nstart = 0; |
| 822 |
40440 |
int use_cleaner = 0; |
| 823 |
|
uintmax_t bufsiz; |
| 824 |
|
const char *p; |
| 825 |
|
char buf[PATH_MAX]; |
| 826 |
|
|
| 827 |
40440 |
argv0 = strrchr(argv[0], '/'); |
| 828 |
40440 |
if (argv0 == NULL) |
| 829 |
0 |
argv0 = argv[0]; |
| 830 |
|
else |
| 831 |
40440 |
argv0++; |
| 832 |
|
|
| 833 |
40440 |
if (getenv("TMPDIR") != NULL) |
| 834 |
40400 |
tmppath = strdup(getenv("TMPDIR")); |
| 835 |
|
else |
| 836 |
40 |
tmppath = strdup("/tmp"); |
| 837 |
|
|
| 838 |
|
#ifdef PACKAGE_VERSION |
| 839 |
40440 |
extmacro_def("pkg_version", NULL, PACKAGE_VERSION); |
| 840 |
|
#endif |
| 841 |
|
#ifdef PACKAGE_BRANCH |
| 842 |
40440 |
extmacro_def("pkg_branch", NULL, PACKAGE_BRANCH); |
| 843 |
|
#endif |
| 844 |
|
|
| 845 |
40440 |
cwd = getcwd(buf, sizeof buf); |
| 846 |
40440 |
extmacro_def("pwd", NULL, "%s", cwd); |
| 847 |
|
|
| 848 |
40440 |
extmacro_def("date", macro_func_date, NULL); |
| 849 |
40440 |
extmacro_def("string", macro_func_string, NULL); |
| 850 |
|
|
| 851 |
40440 |
vmod_path = NULL; |
| 852 |
|
|
| 853 |
40440 |
params_vsb = VSB_new_auto(); |
| 854 |
40440 |
AN(params_vsb); |
| 855 |
40440 |
p = getenv("VTEST_DURATION"); |
| 856 |
40440 |
if (p == NULL) |
| 857 |
40400 |
p = getenv("VARNISHTEST_DURATION"); |
| 858 |
80760 |
if (p != NULL) |
| 859 |
40 |
vtc_maxdur = atoi(p); |
| 860 |
|
|
| 861 |
40440 |
VRND_SeedAll(); |
| 862 |
40440 |
cbvsb = VSB_new_auto(); |
| 863 |
40440 |
AN(cbvsb); |
| 864 |
40440 |
setbuf(stdout, NULL); |
| 865 |
40440 |
setbuf(stderr, NULL); |
| 866 |
121400 |
while ((ch = getopt(argc, argv, "b:CD:hij:kLln:p:qt:vW")) != -1) { |
| 867 |
81040 |
switch (ch) { |
| 868 |
|
case 'b': |
| 869 |
80 |
if (VNUM_2bytes(optarg, &bufsiz, 0)) { |
| 870 |
0 |
fprintf(stderr, "Cannot parse b opt '%s'\n", |
| 871 |
0 |
optarg); |
| 872 |
0 |
exit(2); |
| 873 |
|
} |
| 874 |
80 |
if (bufsiz > UINT_MAX) { |
| 875 |
0 |
fprintf(stderr, "Invalid b opt '%s'\n", |
| 876 |
0 |
optarg); |
| 877 |
0 |
exit(2); |
| 878 |
|
} |
| 879 |
80 |
vtc_bufsiz = (unsigned)bufsiz; |
| 880 |
80 |
break; |
| 881 |
|
case 'C': |
| 882 |
120 |
use_cleaner = !use_cleaner; |
| 883 |
120 |
break; |
| 884 |
|
case 'D': |
| 885 |
40 |
if (!parse_D_opt(optarg)) { |
| 886 |
0 |
fprintf(stderr, "Cannot parse D opt '%s'\n", |
| 887 |
0 |
optarg); |
| 888 |
0 |
exit(2); |
| 889 |
|
} |
| 890 |
40 |
break; |
| 891 |
|
case 'i': |
| 892 |
39960 |
iflg = 1; |
| 893 |
39960 |
break; |
| 894 |
|
case 'j': |
| 895 |
80 |
npar = strtoul(optarg, NULL, 0); |
| 896 |
80 |
break; |
| 897 |
|
case 'L': |
| 898 |
80 |
leave_temp = 2; |
| 899 |
80 |
break; |
| 900 |
|
case 'l': |
| 901 |
120 |
leave_temp = 1; |
| 902 |
120 |
break; |
| 903 |
|
case 'k': |
| 904 |
40 |
vtc_continue = !vtc_continue; |
| 905 |
40 |
break; |
| 906 |
|
case 'n': |
| 907 |
80 |
ntest = strtoul(optarg, NULL, 0); |
| 908 |
80 |
break; |
| 909 |
|
case 'p': |
| 910 |
40 |
VSB_cat(params_vsb, " -p "); |
| 911 |
40 |
VSB_quote(params_vsb, optarg, -1, 0); |
| 912 |
40 |
break; |
| 913 |
|
case 'q': |
| 914 |
40 |
if (vtc_verbosity > 0) |
| 915 |
40 |
vtc_verbosity--; |
| 916 |
40 |
break; |
| 917 |
|
case 't': |
| 918 |
40 |
vtc_maxdur = strtoul(optarg, NULL, 0); |
| 919 |
40 |
break; |
| 920 |
|
case 'v': |
| 921 |
40240 |
if (vtc_verbosity < 2) |
| 922 |
40240 |
vtc_verbosity++; |
| 923 |
40240 |
break; |
| 924 |
|
default: |
| 925 |
80 |
usage(); |
| 926 |
|
} |
| 927 |
|
} |
| 928 |
40360 |
argc -= optind; |
| 929 |
40360 |
argv += optind; |
| 930 |
|
|
| 931 |
40360 |
if (argc < 1) |
| 932 |
40 |
usage(); |
| 933 |
|
|
| 934 |
81080 |
for (; argc > 0; argc--, argv++) { |
| 935 |
40840 |
if (!read_file(*argv, ntest)) |
| 936 |
40720 |
continue; |
| 937 |
120 |
if (!vtc_continue) |
| 938 |
80 |
exit(2); |
| 939 |
40 |
} |
| 940 |
|
|
| 941 |
40240 |
AZ(VSB_finish(params_vsb)); |
| 942 |
|
|
| 943 |
40240 |
ip_magic(); |
| 944 |
|
|
| 945 |
40240 |
if (iflg) |
| 946 |
39960 |
i_mode(); |
| 947 |
|
|
| 948 |
79840 |
vb = VEV_New(); |
| 949 |
|
|
| 950 |
79840 |
if (use_cleaner) |
| 951 |
80 |
cleaner_setup(); |
| 952 |
|
|
| 953 |
40240 |
i = 0; |
| 954 |
162680 |
while (!VTAILQ_EMPTY(&tst_head) || i) { |
| 955 |
122440 |
if (!VTAILQ_EMPTY(&tst_head) && njob < npar) { |
| 956 |
41080 |
start_test(); |
| 957 |
41080 |
njob++; |
| 958 |
|
/* Stagger ramp-up */ |
| 959 |
41080 |
if (nstart++ < npar) |
| 960 |
40320 |
(void)usleep(random() % 100000L); |
| 961 |
41080 |
i = 1; |
| 962 |
41080 |
continue; |
| 963 |
|
} |
| 964 |
81360 |
i = VEV_Once(vb); |
| 965 |
|
} |
| 966 |
40200 |
cleaner_finish(); |
| 967 |
40200 |
(void)close(bad_backend_fd); |
| 968 |
40200 |
if (vtc_continue) |
| 969 |
80 |
fprintf(stderr, |
| 970 |
|
"%d tests failed, %d tests skipped, %d tests passed\n", |
| 971 |
40 |
vtc_fail, vtc_skip, vtc_good); |
| 972 |
40200 |
if (vtc_fail) |
| 973 |
0 |
return (1); |
| 974 |
40200 |
if (vtc_skip && !vtc_good) |
| 975 |
644 |
return (77); |
| 976 |
39556 |
return (0); |
| 977 |
40200 |
} |