vtest "Test vmod usage and test vmods (debug & vtc)"

server s1 {
	rxreq
	expect req.http.encrypted == "ROT52"
	txresp -hdr "foo: bAr" -hdr "bar: fOo" -bodylen 4
} -start

vinyl v1 -vcl+backend {
	import std;
	import debug;
	import vtc;
	import debug;		// again
	import debug as dbg;
	import debug as dbg;	// again

	sub vcl_init {
		new objx = dbg.obj();
		objx.obj();
		dbg.vsc_new();
		std.log("inside vcl_init");
	}

	sub vcl_synth {
		set req.http.overwrite = "the workspace " +
		    "to ensure we notice any unfinished privs";
	}

	sub priv_task {
		debug.test_priv_task_get();
		debug.test_priv_task("foo");
	}

	sub vcl_recv {
		if (req.url == "/priv-task-no-mem") {
			vtc.workspace_alloc(client, -4);
			call priv_task;
			return (fail);
		}
		if (req.url == "/fail") {
			debug.test_priv_task("foo");
			return (fail);
		}
		debug.rot52(req);
		debug.vsc_count();
	}

	sub vcl_deliver {
		set resp.http.who = debug.author(mithrandir);
		set resp.http.really = debug.author();
		set resp.http.when = objx.date();
		set resp.http.what = vtc.typesize("dfijlopsz");
		set resp.http.not = vtc.typesize("*");
		debug.test_priv_call();
		debug.test_priv_vcl();
		objx.test_priv_call();
		objx.test_priv_vcl();
		std.syslog(8 + 7, "Somebody runs vinyltest");
		debug.rot52(resp);
	}
} -start

vinyl v1 -expect DEBUG.count == 0

client c1 {
	txreq -url "/bar"
	rxresp
	expect resp.status == 200
	expect resp.bodylen == "4"
	expect resp.http.who == "Tollef"
	expect resp.http.really == "Poul-Henning"
	expect resp.http.when == "Thu, 01 Jan 1970 00:00:21 GMT"
	expect resp.http.encrypted == "ROT52"
	expect resp.http.what >= 16
	expect resp.http.not == -1
	txreq -url "/fail"
	rxresp
	expect resp.status == 503
} -run

vinyl v1 -vsl_catchup

client c1 {
	txreq -url "/priv-task-no-mem"
	rxresp
	expect resp.status == 503
} -run

vinyl v1 -vsl_catchup

vinyl v1 -expect DEBUG.count == 1

logexpect l1 -v v1 -g raw -d 1 {
	expect * 0    CLI		{^Rd vcl.load}
	expect 0 0    VCL_Log		{^inside vcl_init}
	expect 0 0    Debug		{VCL_EVENT_WARM}

	expect * 1001 VCL_call		{^DELIVER}
	expect 0 =    RespHeader	{^who: Tollef}
	expect 0 =    RespHeader	{^really: Poul-Henning}
	expect 0 =    RespHeader	{^when: Thu, 01 Jan 1970 00:00:21 GMT}
	expect 0 =    RespHeader	{^what: [1-9][0-9]}
	expect 0 =    RespHeader	{^not: -1}
	expect 0 =    RespHeader	{^Encrypted: ROT52}
	expect 0 =    VCL_return	{^deliver}
} -run

vinyl v1 -errvcl {Wrong enum value.  Expected one of:} {
	import debug;
	sub vcl_deliver {
		set resp.http.who = debug.author(ENUM);
	}
}

vinyl v1 -errvcl {Wrong enum value.  Expected one of:} {
	import debug;
	sub vcl_deliver {
		set resp.http.who = debug.author(slink);
	}
}

vinyl v1 -errvcl {Expression has type STRING, expected REAL} {
	import std;
	sub vcl_deliver {
		set resp.http.who = std.random("foo", "bar");
	}
}

vinyl v1 -errvcl {Symbol not found: 'obj'} {
	import debug;
	sub vcl_hit {
		debug.rot52(obj);
	}
}

vinyl v1 -errvcl {Symbol not found: 'obj'} {
	import debug;
	sub vcl_deliver {
		debug.rot52(obj);
	}
}

vinyl v1 -errvcl {rot13: VFP already registered (per-vcl)} {
	import debug;
	backend none none;
	sub vcl_init {
		debug.rot104();
	}
}

vinyl v1 -errvcl {Failed from VCL} {
	import debug;
	import directors;
	backend default { .host = "${localhost}"; }
	sub vcl_init {
		return (fail);
		# uninitialized objects coverage
		new xyz = debug.obj();
		new fb = directors.fallback();
		new hsh = directors.hash();
		new rnd = directors.random();
		new rr = directors.round_robin();
		new shd = directors.shard();
		new shp = directors.shard_param();
	}
}

vinyl v1 -errvcl {Failed initialization} {
	import debug;
	backend none none;
	sub vcl_init {
		new fails = debug.obj("fail");
	}
}

shell {
	cat >${tmpdir}/f1 <<-EOF
	vcl 4.1;
	import debug;
	backend none none;
	sub vcl_init {
		new fails = debug.obj("fail");
	}
	EOF
}

vinyl v1 -clierr 300 "vcl.load f1 ${tmpdir}/f1"

shell -exit 1 -expect {failing as requested} {
	vinyladm -t 10 -n ${tmpdir}/v1 vcl.load f1 ${tmpdir}/f1
}

vinyl v1 -cliok "param.set vcc_feature +allow_inline_c"
vinyl v1 -vcl {
	import vtc;

	backend be none;

	C{
		struct zc {
			size_t	z;
			char	c;
		};
		struct ic {
			int	i;
			char	c;
		};
		struct sc {
			short	s;
			char	c;
		};
		struct cc {
			char	c1;
			char	c2;
		};
		struct czc {
			char	c1;
			size_t	z;
			char	c2;
		};
		struct cic {
			char	c1;
			int	i;
			char	c2;
		};
		struct csc {
			char	c1;
			short	s;
			char	c2;
		};
		struct uzp { /* same as vrt_blob */
			unsigned	u;
			size_t		z;
			void		*p;
		};

		#define SETHDR(type)					\
			VRT_SetHdr(					\
			    ctx,					\
			    &VGC_HDR_RESP_ ## type ## _2d_sizeof,	\
			    VRT_INT_string(ctx, sizeof(struct type)),	\
			    0						\
			)
	}C

	sub vcl_recv {
		return (synth(200));
	}

	sub vcl_synth {
		C{ SETHDR(zc); }C
		set resp.http.zc-typesize = vtc.typesize("zc");
		set resp.http.zc-match =
		    (resp.http.zc-sizeof == resp.http.zc-typesize);

		C{ SETHDR(ic); }C
		set resp.http.ic-typesize = vtc.typesize("ic");
		set resp.http.ic-match =
		    (resp.http.ic-sizeof == resp.http.ic-typesize);

		C{ SETHDR(sc); }C
		set resp.http.sc-typesize = vtc.typesize("sc");
		set resp.http.sc-match =
		    (resp.http.sc-sizeof == resp.http.sc-typesize);

		C{ SETHDR(cc); }C
		set resp.http.cc-typesize = vtc.typesize("cc");
		set resp.http.cc-match =
		    (resp.http.cc-sizeof == resp.http.cc-typesize);

		C{ SETHDR(czc); }C
		set resp.http.czc-typesize = vtc.typesize("czc");
		set resp.http.czc-match =
		    (resp.http.czc-sizeof == resp.http.czc-typesize);

		C{ SETHDR(cic); }C
		set resp.http.cic-typesize = vtc.typesize("cic");
		set resp.http.cic-match =
		    (resp.http.cic-sizeof == resp.http.cic-typesize);

		C{ SETHDR(csc); }C
		set resp.http.csc-typesize = vtc.typesize("csc");
		set resp.http.csc-match =
		    (resp.http.csc-sizeof == resp.http.csc-typesize);

		C{ SETHDR(uzp); }C
		set resp.http.uzp-typesize = vtc.typesize("uzp");
		set resp.http.uzp-match =
		    (resp.http.uzp-sizeof == resp.http.uzp-typesize);
	}
}

client c1 {
	txreq
	rxresp

	expect resp.http.zc-match == true
	expect resp.http.ic-match == true
	expect resp.http.sc-match == true
	expect resp.http.cc-match == true

	expect resp.http.czc-match == true
	expect resp.http.cic-match == true
	expect resp.http.csc-match == true
	expect resp.http.uzp-match == true
} -run

vinyl v1 -vsl_catchup

vinyl v1 -vcl+backend { }

vinyl v1 -cliok "debug.vmod"
vinyl v1 -cliok "vcl.list"

vinyl v1 -expect vmods == 3

vinyl v1 -cliok "vcl.discard vcl[1-9] vcl10"
vinyl v1 -cliok "vcl.list"
vinyl v1 -cliok "debug.vmod"

delay .5

vinyl v1 -expect vmods == 0

vinyl v1 -errvcl {Symbol 'std' type (vmod) cannot be used in expression.} {
	import std;

	sub vcl_recv {
		if (std == 2) {
		}
	}
}

vinyl v1 -cliok "debug.vmod"
vinyl v1 -cliok "vcl.list"
vinyl v1 -expect vmods == 0
