Commit 0a2c6dad authored by Dridi Boukelmoune's avatar Dridi Boukelmoune

vtc: varnish vNAME -expect PATTERN OP PATTERN

Make it possible to compare VSCs, to create a synchronization point
based on internal events (especially with custom VSCs).

For example:

    # block until baz catches up
    varnish v1 -expect FOO.bar == FOO.baz

This is still subject to roughly 5s before timing out.
parent 2a0de6d8
varnishtest "The cache_hit_grace counter" varnishtest "The cache_hit_grace counter"
server s1 { server s1 {
# normal fetch
rxreq rxreq
expect req.url == "/1" expect req.url == "/1"
expect req.http.bgfetch == false
txresp -hdr "Age: 1" -hdr "Cache-Control: max-age=2" -body "1" txresp -hdr "Age: 1" -hdr "Cache-Control: max-age=2" -body "1"
# background fetch:
rxreq rxreq
expect req.url == "/1" expect req.url == "/1"
expect req.http.bgfetch == true
txresp -body "2" txresp -body "2"
# normal fetch
rxreq rxreq
expect req.url == "/2" expect req.url == "/2"
expect req.http.bgfetch == false
txresp txresp
} -start } -start
varnish v1 -vcl+backend { } -start varnish v1 -vcl+backend {
sub vcl_backend_fetch {
set bereq.http.bgfetch = bereq.is_bgfetch;
}
} -start
client c1 { client c1 {
txreq -url "/1" txreq -url "/1"
...@@ -35,6 +39,8 @@ client c2 { ...@@ -35,6 +39,8 @@ client c2 {
expect resp.body == "1" expect resp.body == "1"
} -run } -run
varnish v1 -expect cache_hit >= cache_hit_grace
delay 2 delay 2
client c3 { client c3 {
...@@ -45,6 +51,8 @@ client c3 { ...@@ -45,6 +51,8 @@ client c3 {
expect resp.body == "2" expect resp.body == "2"
} -run } -run
varnish v1 -expect cache_hit >= cache_hit_grace
# Check that counters are correct: # Check that counters are correct:
varnish v1 -expect cache_hit == 2 varnish v1 -expect cache_hit == 2
......
...@@ -44,4 +44,5 @@ client c1 { ...@@ -44,4 +44,5 @@ client c1 {
delay 1 delay 1
varnish v1 -expect s_fetch > s_bgfetch
varnish v1 -expect n_objectcore == 1 varnish v1 -expect n_objectcore == 1
...@@ -910,12 +910,29 @@ varnish_vsc(const struct varnish *v, const char *arg) ...@@ -910,12 +910,29 @@ varnish_vsc(const struct varnish *v, const char *arg)
* Check statistics * Check statistics
*/ */
struct stat_arg {
const char *pattern;
uintmax_t val;
unsigned good;
};
struct stat_priv { struct stat_priv {
char target_pattern[256]; struct stat_arg lhs;
uintmax_t val; struct stat_arg rhs;
const struct varnish *v;
}; };
static int
stat_match(const char *pattern, const char *name)
{
if (strchr(pattern, '.') == NULL) {
if (fnmatch("MAIN.*", name, 0))
return (FNM_NOMATCH);
name += 5;
}
return (fnmatch(pattern, name, 0));
}
static int static int
do_expect_cb(void *priv, const struct VSC_point * const pt) do_expect_cb(void *priv, const struct VSC_point * const pt)
{ {
...@@ -924,13 +941,24 @@ do_expect_cb(void *priv, const struct VSC_point * const pt) ...@@ -924,13 +941,24 @@ do_expect_cb(void *priv, const struct VSC_point * const pt)
if (pt == NULL) if (pt == NULL)
return (0); return (0);
if (fnmatch(sp->target_pattern, pt->name, 0)) if (!sp->lhs.good && stat_match(sp->lhs.pattern, pt->name) == 0) {
return (0); AZ(strcmp(pt->ctype, "uint64_t"));
AN(pt->ptr);
sp->lhs.val = *pt->ptr;
sp->lhs.good = 1;
}
AZ(strcmp(pt->ctype, "uint64_t")); if (sp->rhs.pattern == NULL) {
AN(pt->ptr); sp->rhs.good = 1;
sp->val = *pt->ptr; } else if (!sp->rhs.good &&
return (1); stat_match(sp->rhs.pattern, pt->name) == 0) {
AZ(strcmp(pt->ctype, "uint64_t"));
AN(pt->ptr);
sp->rhs.val = *pt->ptr;
sp->rhs.good = 1;
}
return (sp->lhs.good && sp->rhs.good);
} }
/********************************************************************** /**********************************************************************
...@@ -939,55 +967,49 @@ do_expect_cb(void *priv, const struct VSC_point * const pt) ...@@ -939,55 +967,49 @@ do_expect_cb(void *priv, const struct VSC_point * const pt)
static void static void
varnish_expect(const struct varnish *v, char * const *av) varnish_expect(const struct varnish *v, char * const *av)
{ {
uint64_t ref;
int good;
char *r;
char *p;
int i, not = 0;
struct stat_priv sp; struct stat_priv sp;
int good, i, not;
r = av[0]; uintmax_t u;
if (r[0] == '!') { char *l, *p;
not = 1;
r++; ZERO_OBJ(&sp, sizeof sp);
l = av[0];
not = (*l == '!');
if (not) {
l++;
AZ(av[1]); AZ(av[1]);
} else { } else {
AN(av[1]); AN(av[1]);
AN(av[2]); AN(av[2]);
} u = strtoumax(av[2], &p, 0);
p = strrchr(r, '.'); if (u != UINTMAX_MAX && *p == '\0')
if (p == NULL) { sp.rhs.val = u;
bprintf(sp.target_pattern, "MAIN.%s", r); else
} else { sp.rhs.pattern = av[2];
bprintf(sp.target_pattern, "%s", r);
} }
sp.val = 0; sp.lhs.pattern = l;
sp.v = v;
ref = 0;
good = 0;
for (i = 0; i < 50; i++, (void)usleep(100000)) { for (i = 0; i < 50; i++, (void)usleep(100000)) {
(void)VSM_Status(v->vsm_vsc); (void)VSM_Status(v->vsm_vsc);
sp.lhs.good = sp.rhs.good = 0;
good = VSC_Iter(v->vsc, v->vsm_vsc, do_expect_cb, &sp); good = VSC_Iter(v->vsc, v->vsm_vsc, do_expect_cb, &sp);
if (!good) { if (!good)
good = -2; good = -2;
if (good < 0)
continue; continue;
}
if (not) if (not)
vtc_fatal(v->vl, "Found (not expected): %s", av[0]+1); vtc_fatal(v->vl, "Found (not expected): %s", l);
good = 0; good = -1;
ref = strtoumax(av[2], &p, 0); if (!strcmp(av[1], "==")) good = (sp.lhs.val == sp.rhs.val);
if (ref == UINTMAX_MAX || *p) if (!strcmp(av[1], "!=")) good = (sp.lhs.val != sp.rhs.val);
vtc_fatal(v->vl, "Syntax error in number (%s)", av[2]); if (!strcmp(av[1], ">" )) good = (sp.lhs.val > sp.rhs.val);
if (!strcmp(av[1], "==")) { if (sp.val == ref) good = 1; } if (!strcmp(av[1], "<" )) good = (sp.lhs.val < sp.rhs.val);
else if (!strcmp(av[1], "!=")) { if (sp.val != ref) good = 1; } if (!strcmp(av[1], ">=")) good = (sp.lhs.val >= sp.rhs.val);
else if (!strcmp(av[1], ">")) { if (sp.val > ref) good = 1; } if (!strcmp(av[1], "<=")) good = (sp.lhs.val <= sp.rhs.val);
else if (!strcmp(av[1], "<")) { if (sp.val < ref) good = 1; } if (good == -1)
else if (!strcmp(av[1], ">=")) { if (sp.val >= ref) good = 1; }
else if (!strcmp(av[1], "<=")) { if (sp.val <= ref) good = 1; }
else
vtc_fatal(v->vl, "comparison %s unknown", av[1]); vtc_fatal(v->vl, "comparison %s unknown", av[1]);
if (good) if (good)
break; break;
...@@ -997,19 +1019,19 @@ varnish_expect(const struct varnish *v, char * const *av) ...@@ -997,19 +1019,19 @@ varnish_expect(const struct varnish *v, char * const *av)
} }
if (good == -2) { if (good == -2) {
if (not) { if (not) {
vtc_log(v->vl, 2, "not found (as expected): %s", vtc_log(v->vl, 2, "not found (as expected): %s", l);
av[0] + 1);
return; return;
} }
vtc_fatal(v->vl, "stats field %s unknown", av[0]); vtc_fatal(v->vl, "stats field %s unknown",
sp.lhs.good ? sp.rhs.pattern : sp.lhs.pattern);
} }
if (good == 1) { if (good == 1) {
vtc_log(v->vl, 2, "as expected: %s (%ju) %s %s", vtc_log(v->vl, 2, "as expected: %s (%ju) %s %s (%ju)",
av[0], sp.val, av[1], av[2]); av[0], sp.lhs.val, av[1], av[2], sp.rhs.val);
} else { } else {
vtc_fatal(v->vl, "Not true: %s (%ju) %s %s (%ju)", vtc_fatal(v->vl, "Not true: %s (%ju) %s %s (%ju)",
av[0], (uintmax_t)sp.val, av[1], av[2], (uintmax_t)ref); av[0], sp.lhs.val, av[1], av[2], sp.rhs.val);
} }
} }
...@@ -1091,11 +1113,14 @@ varnish_expect(const struct varnish *v, char * const *av) ...@@ -1091,11 +1113,14 @@ varnish_expect(const struct varnish *v, char * const *av)
* Once Varnish is stopped, clean everything after it. This is only used * Once Varnish is stopped, clean everything after it. This is only used
* in very few tests and you should never need it. * in very few tests and you should never need it.
* *
* \-expectexit NUMBER
* Expect varnishd to exit(3) with this value
*
* Once Varnish is started, you can talk to it (as you would through * Once Varnish is started, you can talk to it (as you would through
* ``varnishadm``) with these additional switches:: * ``varnishadm``) with these additional switches::
* *
* varnish vNAME [-cli STRING] [-cliok STRING] [-clierr STRING] * varnish vNAME [-cli STRING] [-cliok STRING] [-clierr STRING]
* [-clijson STRING] [-expect STRING OP NUMBER] * [-clijson STRING]
* *
* \-cli STRING|-cliok STRING|-clierr STATUS STRING|-cliexpect REGEXP STRING * \-cli STRING|-cliok STRING|-clierr STATUS STRING|-cliexpect REGEXP STRING
* All four of these will send STRING to the CLI, the only difference * All four of these will send STRING to the CLI, the only difference
...@@ -1107,14 +1132,22 @@ varnish_expect(const struct varnish *v, char * const *av) ...@@ -1107,14 +1132,22 @@ varnish_expect(const struct varnish *v, char * const *av)
* Send STRING to the CLI, expect success (CLIS_OK/200) and check * Send STRING to the CLI, expect success (CLIS_OK/200) and check
* that the response is parsable JSON. * that the response is parsable JSON.
* *
* \-expect PATTERN OP NUMBER * It is also possible to interact with its shared memory (as you would
* through tools like ``varnishstat``) with additional switches:
*
* \-expect \!PATTERN|PATTERN OP NUMBER|PATTERN OP PATTERN
* Look into the VSM and make sure the first VSC counter identified by * Look into the VSM and make sure the first VSC counter identified by
* PATTERN has a correct value. OP can be ==, >, >=, <, <=. For * PATTERN has a correct value. OP can be ==, >, >=, <, <=. For
* example:: * example::
* *
* varnish v1 -expect SM?.s1.g_space > 1000000 * varnish v1 -expect SM?.s1.g_space > 1000000
* \-expectexit NUMBER * varnish v1 -expect cache_hit >= cache_hit_grace
* Expect varnishd to exit(3) with this value *
* In the \! form the test fails if a counter matches PATTERN.
*
* The ``MAIN.`` namespace can be omitted from PATTERN.
*
* The test takes up to 5 seconds before timing out.
* *
* \-vsc PATTERN * \-vsc PATTERN
* Dump VSC counters matching PATTERN. * Dump VSC counters matching PATTERN.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment