varnish-cache/bin/varnishtest/vtc.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
31
#include <sys/wait.h>
32
33
#include <ctype.h>
34
#include <stdarg.h>
35
#include <stdio.h>
36
#include <stdlib.h>
37
#include <string.h>
38
#include <unistd.h>
39
40
#include "vtc.h"
41
42
#include "vav.h"
43
#include "vrnd.h"
44
#include "vtim.h"
45
46
#define         MAX_TOKENS              200
47
48
volatile sig_atomic_t   vtc_error;      /* Error encountered */
49
int                     vtc_stop;       /* Stops current test without error */
50
pthread_t               vtc_thread;
51
int                     ign_unknown_macro = 0;
52
static struct vtclog    *vltop;
53
54
static pthread_mutex_t  vtc_vrnd_mtx;
55
56
static void
57 16472
vtc_vrnd_lock(void)
58
{
59 16472
        AZ(pthread_mutex_lock(&vtc_vrnd_mtx));
60 16472
}
61
62
static void
63 16472
vtc_vrnd_unlock(void)
64
{
65 16472
        AZ(pthread_mutex_unlock(&vtc_vrnd_mtx));
66 16472
}
67
68
/**********************************************************************
69
 * Macro facility
70
 */
71
72
struct macro {
73
        unsigned                magic;
74
#define MACRO_MAGIC             0x803423e3
75
        VTAILQ_ENTRY(macro)     list;
76
        char                    *name;
77
        char                    *val;
78
};
79
80
static VTAILQ_HEAD(,macro) macro_list = VTAILQ_HEAD_INITIALIZER(macro_list);
81
82
/**********************************************************************/
83
84
static struct macro *
85 46360
macro_def_int(const char *name, const char *fmt, va_list ap)
86
{
87
        struct macro *m;
88
        char buf[256];
89
90 388892
        VTAILQ_FOREACH(m, &macro_list, list)
91 343624
                if (!strcmp(name, m->name))
92 1092
                        break;
93 46360
        if (m == NULL) {
94 45268
                ALLOC_OBJ(m, MACRO_MAGIC);
95 45268
                AN(m);
96 45268
                REPLACE(m->name, name);
97 45268
                AN(m->name);
98 45268
                VTAILQ_INSERT_TAIL(&macro_list, m, list);
99
        }
100 46360
        AN(m);
101 46360
        vbprintf(buf, fmt, ap);
102 46360
        REPLACE(m->val, buf);
103 46360
        AN(m->val);
104 46360
        return (m);
105
}
106
107
108
/**********************************************************************
109
 * This is for defining macros before we fork the child process which
110
 * runs the test-case.
111
 */
112
113
void
114 14856
extmacro_def(const char *name, const char *fmt, ...)
115
{
116
        va_list ap;
117
118 14856
        va_start(ap, fmt);
119 14856
        (void)macro_def_int(name, fmt, ap);
120 14856
        va_end(ap);
121 14856
}
122
123
/**********************************************************************
124
 * Below this point is run inside the testing child-process.
125
 */
126
127
static pthread_mutex_t          macro_mtx;
128
129
static void
130 3052
init_macro(void)
131
{
132
        struct macro *m;
133
134
        /* Dump the extmacros for completeness */
135 18292
        VTAILQ_FOREACH(m, &macro_list, list)
136 15240
                vtc_log(vltop, 4, "extmacro def %s=%s", m->name, m->val);
137
138 3052
        AZ(pthread_mutex_init(&macro_mtx, NULL));
139 3052
}
140
141
void
142 31504
macro_def(struct vtclog *vl, const char *instance, const char *name,
143
    const char *fmt, ...)
144
{
145
        char buf1[256];
146
        struct macro *m;
147
        va_list ap;
148
149 31504
        AN(fmt);
150
151 31504
        if (instance != NULL) {
152 25400
                bprintf(buf1, "%s_%s", instance, name);
153 25400
                name = buf1;
154
        }
155
156 31504
        AZ(pthread_mutex_lock(&macro_mtx));
157 31504
        va_start(ap, fmt);
158 31504
        m = macro_def_int(name, fmt, ap);
159 31504
        va_end(ap);
160 31504
        vtc_log(vl, 4, "macro def %s=%s", name, m->val);
161 31504
        AZ(pthread_mutex_unlock(&macro_mtx));
162 31504
}
163
164
void
165 10422
macro_undef(struct vtclog *vl, const char *instance, const char *name)
166
{
167
        char buf1[256];
168
        struct macro *m;
169
170 10422
        if (instance != NULL) {
171 10422
                bprintf(buf1, "%s_%s", instance, name);
172 10422
                name = buf1;
173
        }
174
175 10422
        AZ(pthread_mutex_lock(&macro_mtx));
176 88118
        VTAILQ_FOREACH(m, &macro_list, list)
177 87968
                if (!strcmp(name, m->name))
178 10272
                        break;
179 10422
        if (m != NULL) {
180 10272
                if (!vtc_stop)
181 328
                        vtc_log(vl, 4, "macro undef %s", name);
182 10272
                VTAILQ_REMOVE(&macro_list, m, list);
183 10272
                free(m->name);
184 10272
                free(m->val);
185 10272
                FREE_OBJ(m);
186
        }
187 10422
        AZ(pthread_mutex_unlock(&macro_mtx));
188 10422
}
189
190
char *
191 26812
macro_get(const char *b, const char *e)
192
{
193
        struct macro *m;
194
        int l;
195 26812
        char *retval = NULL;
196
197 26812
        AN(b);
198 26812
        if (e == NULL)
199 11512
                e = strchr(b, '\0');
200 26812
        AN(e);
201 26812
        l = e - b;
202
203 26812
        if (l == 4 && !memcmp(b, "date", l)) {
204 12
                double t = VTIM_real();
205 12
                retval = malloc(64);
206 12
                AN(retval);
207 12
                VTIM_format(t, retval);
208 12
                return (retval);
209
        }
210
211 26800
        AZ(pthread_mutex_lock(&macro_mtx));
212 152152
        VTAILQ_FOREACH(m, &macro_list, list) {
213 152064
                CHECK_OBJ_NOTNULL(m, MACRO_MAGIC);
214 152064
                if (!strncmp(b, m->name, l) && m->name[l] == '\0')
215 26712
                        break;
216
        }
217 26800
        if (m != NULL)
218 26712
                retval = strdup(m->val);
219 26800
        AZ(pthread_mutex_unlock(&macro_mtx));
220 26800
        return (retval);
221
}
222
223
struct vsb *
224 3848
macro_expandf(struct vtclog *vl, const char *fmt, ...)
225
{
226
        va_list ap;
227
        struct vsb *vsb1, *vsb2;
228
229 3848
        vsb1 = VSB_new_auto();
230 3848
        AN(vsb1);
231 3848
        va_start(ap, fmt);
232 3848
        VSB_vprintf(vsb1, fmt, ap);
233 3848
        va_end(ap);
234 3848
        AZ(VSB_finish(vsb1));
235 3848
        vsb2 = macro_expand(vl, VSB_data(vsb1));
236 3848
        VSB_destroy(&vsb1);
237 3848
        return (vsb2);
238
}
239
240
struct vsb *
241 14656
macro_expand(struct vtclog *vl, const char *text)
242
{
243
        struct vsb *vsb;
244
        const char *p, *q;
245
        char *m;
246
247 14656
        vsb = VSB_new_auto();
248 14656
        AN(vsb);
249 44612
        while (*text != '\0') {
250 24656
                p = strstr(text, "${");
251 24656
                if (p == NULL) {
252 9356
                        VSB_cat(vsb, text);
253 9356
                        break;
254
                }
255 15300
                VSB_bcat(vsb, text, p - text);
256 15300
                q = strchr(p, '}');
257 15300
                if (q == NULL) {
258 0
                        VSB_cat(vsb, text);
259 0
                        break;
260
                }
261 15300
                assert(p[0] == '$');
262 15300
                assert(p[1] == '{');
263 15300
                assert(q[0] == '}');
264 15300
                p += 2;
265 15300
                m = macro_get(p, q);
266 15300
                if (m == NULL) {
267 88
                        if (!ign_unknown_macro) {
268 0
                                VSB_destroy(&vsb);
269 0
                                vtc_fatal(vl, "Macro ${%.*s} not found",
270 0
                                          (int)(q - p), p);
271
                                NEEDLESS(return (NULL));
272
                        }
273 88
                        VSB_printf(vsb, "${%.*s}", (int)(q - p), p);
274
                } else {
275 15212
                        VSB_printf(vsb, "%s", m);
276 15212
                        free(m);
277
                }
278 15300
                text = q + 1;
279
        }
280 14656
        AZ(VSB_finish(vsb));
281 14656
        return (vsb);
282
}
283
284
/**********************************************************************
285
 * Parse a string
286
 *
287
 * We make a copy of the string and deliberately leak it, so that all
288
 * the cmd functions we call don't have to strdup(3) all over the place.
289
 *
290
 * Static checkers like Coverity may bitch about this, but we don't care.
291
 */
292
293
static const struct cmds global_cmds[] = {
294
#define CMD_GLOBAL(n) { #n, cmd_##n },
295
#include "cmds.h"
296
        { NULL, NULL }
297
};
298
299
300
void
301 18648
parse_string(const char *spec, const struct cmds *cmd, void *priv,
302
    struct vtclog *vl)
303
{
304
        char *token_s[MAX_TOKENS], *token_e[MAX_TOKENS];
305
        struct vsb *token_exp[MAX_TOKENS];
306
        char *e, *p, *q, *f, *buf;
307
        int nest_brace;
308
        int tn;
309
        const struct cmds *cp;
310
311 18648
        AN(spec);
312 18648
        buf = strdup(spec);
313 18648
        AN(buf);
314 18648
        e = strchr(buf, '\0');
315 18648
        AN(e);
316 249302
        for (p = buf; p < e; p++) {
317 230831
                if (vtc_error || vtc_stop)
318
                        break;
319
                /* Start of line */
320 230790
                if (isspace(*p))
321 124072
                        continue;
322 106723
                if (*p == '\n')
323 0
                        continue;
324
325 106723
                if (*p == '#') {
326 5868
                        for (; *p != '\0' && *p != '\n'; p++)
327
                                ;
328 5868
                        if (*p == '\0')
329 0
                                break;
330 5868
                        continue;
331
                }
332
333 100855
                q = strchr(p, '\n');
334 100855
                if (q == NULL)
335 947
                        q = strchr(p, '\0');
336 100855
                if (q - p > 60)
337 5072
                        vtc_log(vl, 2, "=== %.60s...", p);
338
                else
339 95783
                        vtc_log(vl, 2, "=== %.*s", (int)(q - p), p);
340
341
                /* First content on line, collect tokens */
342 100838
                tn = 0;
343 100838
                f = p;
344 769124
                while (p < e) {
345 667334
                        assert(tn < MAX_TOKENS);
346 667342
                        assert(p < e);
347 667342
                        if (*p == '\n') { /* End on NL */
348 99904
                                break;
349
                        }
350 567438
                        if (isspace(*p)) { /* Inter-token whitespace */
351 238689
                                p++;
352 238689
                                continue;
353
                        }
354 328760
                        if (*p == '\\' && p[1] == '\n') { /* line-cont */
355 3000
                                p += 2;
356 3000
                                continue;
357
                        }
358 325760
                        if (*p == '"') { /* quotes */
359 33704
                                token_s[tn] = ++p;
360 33704
                                q = p;
361 778959
                                for (; *p != '\0'; p++) {
362 778959
                                        assert(p < e);
363 778959
                                        if (*p == '"')
364 33704
                                                break;
365 745255
                                        if (*p == '\\') {
366 9692
                                                p += VAV_BackSlash(p, q) - 1;
367 9692
                                                q++;
368
                                        } else {
369 735563
                                                if (*p == '\n')
370 0
                                                        vtc_fatal(vl,
371
                                "Unterminated quoted string in line: %*.*s",
372 0
                                (int)(p - f), (int)(p - f), f);
373 735563
                                                assert(*p != '\n');
374 735563
                                                *q++ = *p;
375
                                        }
376
                                }
377 33704
                                token_e[tn++] = q;
378 33704
                                p++;
379 292056
                        } else if (*p == '{') { /* Braces */
380 21114
                                nest_brace = 0;
381 21114
                                token_s[tn] = p + 1;
382 3275658
                                for (; p < e; p++) {
383 3275658
                                        if (*p == '{')
384 37646
                                                nest_brace++;
385 3238012
                                        else if (*p == '}') {
386 37646
                                                if (--nest_brace == 0)
387 21114
                                                        break;
388
                                        }
389
                                }
390 21114
                                assert(*p == '}');
391 21114
                                token_e[tn++] = p++;
392
                        } else { /* other tokens */
393 270942
                                token_s[tn] = p;
394 1781077
                                for (; p < e && !isspace(*p); p++)
395 1510135
                                        continue;
396 270941
                                token_e[tn++] = p;
397
                        }
398
                }
399
400 100856
                assert(p <= e);
401 100856
                assert(tn < MAX_TOKENS);
402 100856
                token_s[tn] = NULL;
403 426613
                for (tn = 0; token_s[tn] != NULL; tn++) {
404 325756
                        token_exp[tn] = NULL;
405 325756
                        AN(token_e[tn]);        /*lint !e771 */
406 325757
                        *token_e[tn] = '\0';    /*lint !e771 */
407 325757
                        if (NULL != strstr(token_s[tn], "${")) {
408 2684
                                token_exp[tn] = macro_expand(vl, token_s[tn]);
409 2684
                                if (vtc_error)
410 0
                                        return;
411 2684
                                token_s[tn] = VSB_data(token_exp[tn]);
412 2684
                                token_e[tn] = strchr(token_s[tn], '\0');
413
                        }
414
                }
415
416 1800115
                for (cp = cmd; cp->name != NULL; cp++)
417 1795475
                        if (!strcmp(token_s[0], cp->name))
418 96217
                                break;
419
420 100857
                if (cp->name == NULL) {
421 8832
                        for (cp = global_cmds; cp->name != NULL; cp++)
422 8832
                                if (!strcmp(token_s[0], cp->name))
423 4596
                                        break;
424
                }
425
426 100857
                if (cp->name == NULL)
427 0
                        vtc_fatal(vl, "Unknown command: \"%s\"", token_s[0]);
428
429 100857
                assert(cp->cmd != NULL);
430 100857
                cp->cmd(token_s, priv, cmd, vl);
431
        }
432
}
433
434
/**********************************************************************
435
 * Reset commands (between tests)
436
 */
437
438
static void
439 3052
reset_cmds(const struct cmds *cmd)
440
{
441
442 39676
        for (; cmd->name != NULL; cmd++)
443 36624
                cmd->cmd(NULL, NULL, NULL, NULL);
444 3052
}
445
446
/**********************************************************************
447
 * Execute a file
448
 */
449
450
static const struct cmds cmds[] = {
451
#define CMD_TOP(n) { #n, cmd_##n },
452
#include "cmds.h"
453
        { NULL, NULL }
454
};
455
456
static const char *tfn;
457
458
int
459 3052
fail_out(void)
460
{
461
        unsigned old_err;
462
        static int once = 0;
463
464 3052
        if (once++) {
465 0
                vtc_log(vltop, 1, "failure during reset");
466 0
                return(vtc_error);
467
        }
468 3052
        old_err = vtc_error;
469 3052
        if (!vtc_stop)
470 3016
                vtc_stop = 1;
471 3052
        vtc_log(vltop, 1, "RESETTING after %s", tfn);
472 3052
        reset_cmds(cmds);
473 3052
        vtc_error |= old_err;
474
475 3052
        if (vtc_error)
476 8
                vtc_log(vltop, 1, "TEST %s FAILED", tfn);
477
        else
478 3044
                vtc_log(vltop, 1, "TEST %s completed", tfn);
479
480 3052
        if (vtc_stop > 1)
481 36
                return (1);
482 3016
        return (vtc_error);
483
}
484
485
int
486 3052
exec_file(const char *fn, const char *script, const char *tmpdir,
487
    char *logbuf, unsigned loglen)
488
{
489
        FILE *f;
490
        struct vsb *vsb;
491
        const char *p;
492
        char *q;
493
494 3052
        (void)signal(SIGPIPE, SIG_IGN);
495
496 3052
        AZ(pthread_mutex_init(&vtc_vrnd_mtx, NULL));
497 3052
        VRND_Lock = vtc_vrnd_lock;
498 3052
        VRND_Unlock = vtc_vrnd_unlock;
499 3052
        VRND_SeedAll();
500
501 3052
        tfn = fn;
502 3052
        vtc_loginit(logbuf, loglen);
503 3052
        vltop = vtc_logopen("top");
504 3052
        AN(vltop);
505
506 3052
        init_macro();
507 3052
        init_server();
508 3052
        init_syslog();
509
510 3052
        vsb = VSB_new_auto();
511 3052
        AN(vsb);
512 3052
        if (*fn != '/') {
513 3052
                q = macro_get("pwd", NULL);
514 3052
                AN(q);
515 3052
                VSB_cat(vsb, q);
516 3052
                free(q);
517
        }
518 3052
        p = strrchr(fn, '/');
519 3052
        if (p != NULL) {
520 3024
                VSB_putc(vsb, '/');
521 3024
                VSB_bcat(vsb, fn, p - fn);
522
        }
523 3052
        if (VSB_len(vsb) == 0)
524 0
                VSB_putc(vsb, '/');
525 3052
        AZ(VSB_finish(vsb));
526 3052
        macro_def(vltop, NULL, "testdir", "%s", VSB_data(vsb));
527 3052
        VSB_destroy(&vsb);
528
529
        /* Move into our tmpdir */
530 3052
        AZ(chdir(tmpdir));
531 3052
        macro_def(vltop, NULL, "tmpdir", "%s", tmpdir);
532
533
        /* Drop file to tell what was going on here */
534 3052
        f = fopen("INFO", "w");
535 3052
        AN(f);
536 3052
        fprintf(f, "Test case: %s\n", fn);
537 3052
        AZ(fclose(f));
538
539 3052
        vtc_stop = 0;
540 3052
        vtc_log(vltop, 1, "TEST %s starting", fn);
541
542 3052
        vtc_thread = pthread_self();
543 3052
        parse_string(script, cmds, NULL, vltop);
544 3044
        return(fail_out());
545
}