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