varnishtest "shard director reconfiguration in init"

server s1 {
} -start

server s2 {
} -start

server s3 {
	rxreq
	txresp -body "xiuFi3Pe"
} -start

varnish v1 -vcl+backend {
	import std;
	import directors;

	sub vcl_init {
		new vd = directors.shard();
		new vd2 = directors.shard();
		vd.debug(3);

		std.log("-- invalid replicas");
		if (!vd.reconfigure(replicas=0)) {
			# continue intentionally
			std.log("reconfigure failed");
		}

		std.log("-- no changes - no debug output");
		if (!vd.reconfigure(replicas=25)) {
			# continue intentionally
			std.log("reconfigure failed");
		}

		std.log("-- no backends");
		if (!vd.clear()) {
			return(fail("clear failed"));
		}
		if (!vd.reconfigure(replicas=25)) {
			# continue intentionally
			std.log("reconfigure failed");
		}

		std.log("-- one backend");
		if (!vd.add_backend(s1)) {
			return(fail("add s1 failed"));
		}
		if (!vd.reconfigure(replicas=1)) {
			return(fail("reconfigure failed"));
		}

		std.log("-- no change - no output");
		if (!vd.reconfigure(replicas=1)) {
			return(fail("reconfigure failed"));
		}

		std.log("-- change, clear, no backends");
		# change, then clear
		vd.add_backend(s1);
		vd.add_backend(s2);
		vd.clear();
		vd.add_backend(s1);
		vd.add_backend(s2);
		vd.clear();
		if (!vd.reconfigure()) {
			# continue intentionally
			std.log("reconfigure failed");
		}

		std.log("-- duplicate add");
		vd.clear();
		vd.add_backend(s1);
		vd.add_backend(s2);
		vd.add_backend(s1);
		if (!vd.reconfigure(replicas=1)) {
			return(fail("reconfigure failed"));
		}

		std.log("-- duplicate add with idents");
		vd.clear();
		vd.add_backend(s1);
		vd.add_backend(s1, ident="s1_1");
		vd.add_backend(s1, ident="s1_2");
		vd.add_backend(s2);
		vd.add_backend(s2, ident="s1");
		vd.add_backend(s2, ident="s1_1");
		vd.add_backend(s2, ident="s1_2");
		if (!vd.reconfigure(replicas=1)) {
			return(fail("reconfigure failed"));
		}

		std.log("-- remove s1_2 specifically");
		vd.remove_backend(ident="s1_2");
		if (!vd.reconfigure(replicas=1)) {
			return(fail("reconfigure failed"));
		}

		std.log("-- remove all instances of s1");
		vd.remove_backend(s1);
		if (!vd.reconfigure(replicas=1)) {
			return(fail("reconfigure failed"));
		}

		std.log("-- re-add some - no 2nd director");
		vd.clear();
		vd.add_backend(s3, "1");
		vd.add_backend(s3, "2");
		vd.add_backend(s3, "3");
		vd2.clear();
		vd2.add_backend(s3, "4");
		vd.add_backend(s3, "4");
		vd.add_backend(s3, "5");
		vd.add_backend(s3, "6");
		vd.add_backend(s3, "7");
		vd.add_backend(s3, "8");
		vd.add_backend(s3, "9");
		if (!vd.reconfigure(replicas=1)) {
			return(fail("reconfigure failed"));
		}

		std.log("-- remove second-last");
		vd.remove_backend(ident="8");
		if (!vd.reconfigure(replicas=1)) {
			return(fail("reconfigure failed"));
		}

		std.log("-- remove last");
		vd.remove_backend(ident="9");
		if (!vd.reconfigure(replicas=1)) {
			return(fail("reconfigure failed"));
		}

		vd.set_warmup(1);
		vd.set_warmup(-0.001);

		std.log("-- END");

		## gcov - semantic testing via the client request & .list
		# expand
		vd.add_backend(s1, "0x00");
		vd.add_backend(s1, "0x01");
		vd.add_backend(s1, "0x02");
		vd.add_backend(s1, "0x03");
		vd.add_backend(s1, "0x04");
		vd.add_backend(s1, "0x05");
		vd.add_backend(s1, "0x06");
		vd.add_backend(s1, "0x07");
		vd.add_backend(s1, "0x08");
		vd.add_backend(s1, "0x09");
		vd.add_backend(s1, "0x0a");
		vd.add_backend(s1, "0x0b");
		vd.add_backend(s1, "0x0c");
		vd.add_backend(s1, "0x0d");
		vd.add_backend(s1, "0x0e");
		vd.add_backend(s1, "0x0f");
		if (!vd.reconfigure(replicas=1)) {
			return(fail("reconfigure failed"));
		}
		vd.remove_backend(s1, "0x00");
		vd.remove_backend(s1, "0x01");
		vd.remove_backend(s1, "0x02");
		vd.remove_backend(s1, "0x03");
		vd.remove_backend(s1, "0x04");
		vd.remove_backend(s1, "0x05");
		vd.remove_backend(s1, "0x06");
		vd.remove_backend(s1, "0x07");
		vd.remove_backend(s1, "0x08");
		vd.remove_backend(s1, "0x09");
		vd.remove_backend(s1, "0x0a");
		vd.remove_backend(s1, "0x0b");
		vd.remove_backend(s1, "0x0c");
		vd.remove_backend(s1, "0x0d");
		vd.remove_backend(s1, "0x0e");
		vd.remove_backend(s1, "0x0f");
		if (!vd.reconfigure(replicas=1)) {
			return(fail("reconfigure failed"));
		}
		vd.set_warmup(0.5);


		# hole handling
		vd.remove_backend(s3, "4");
		vd.remove_backend(s3, "5");
		vd.add_backend(s1, "4");
		vd.add_backend(s2, "5");
		vd.remove_backend(s1, "5");
		vd.remove_backend(s1, "4");
		vd.add_backend(s3, "4a");
		vd.add_backend(s3, "5a");
		vd.set_warmup(0);
		# implicit .reconfigure() - checked via backend.list
	}

	sub vcl_recv {
		set req.backend_hint = vd.backend();
		return(pass);
	}

} -start

logexpect l1 -v v1 -g raw -d 1 {
	expect 0 0    CLI     {^Rd vcl.load}

	expect 0 0    VCL_Log {^-- invalid replicas$}
	expect 0 0    Error   {^vmod_directors: shard vd: .reconfigure.. invalid replicas argument 0}
	expect 0 0    VCL_Log {^reconfigure failed}

	expect 0 0    VCL_Log {^-- no changes - no debug output$}

	expect 0 0    VCL_Log {^-- no backends$}
	expect 0 0    Error   {^vmod_directors: shard vd: .reconfigure.. no backends}
	expect 0 0    VCL_Log {^reconfigure failed}

	expect 0 0    VCL_Log {^-- one backend$}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = f08ad325, host =  0}

	expect 0 0    VCL_Log {^-- no change - no output$}

	expect 0 0    VCL_Log {^-- change, clear, no backends$}
	expect 0 0    Error   {^vmod_directors: shard vd: .reconfigure.. no backends}
	expect 0 0    VCL_Log {^reconfigure failed}

	expect 0 0    VCL_Log {^-- duplicate add$}
	expect 0 0    Notice  {^vmod_directors: shard vd: backend s1 already exists - skipping$}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = 6e040182, host =  1}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = f08ad325, host =  0}

	expect 0 0    VCL_Log {^-- duplicate add with idents$}
	expect 0 0    Notice  {^vmod_directors: shard vd: backend s1 already exists - skipping}
	expect 0 0    Notice  {^vmod_directors: shard vd: backend s1/s1_1 already exists - skipping}
	expect 0 0    Notice  {^vmod_directors: shard vd: backend s1/s1_2 already exists - skipping}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = 6e040182, host =  3}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = 732c7bbe, host =  2}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = bae80b0b, host =  1}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = f08ad325, host =  0}

	expect 0 0    VCL_Log {^-- remove s1_2 specifically$}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = 6e040182, host =  2}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = bae80b0b, host =  1}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = f08ad325, host =  0}

	expect 0 0    VCL_Log {^-- remove all instances of s1$}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = 6e040182, host =  0}

	expect 0 0    VCL_Log {^-- re-add some - no 2nd director$}
	expect 0 0    Debug   {^vmod_directors: shard:.*point =  3d1fe97, host =  3}
	expect 0 0    Debug   {^vmod_directors: shard:.*point =  a25a43b, host =  6}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = 2b20d9a2, host =  1}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = 6337e62c, host =  8}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = c9803f17, host =  5}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = d51dafe6, host =  0}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = eb74a7d5, host =  4}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = f493ce58, host =  2}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = fc1a5162, host =  7}

	expect 0 0    VCL_Log {^-- remove second-last$}
	expect 0 0    Debug   {^vmod_directors: shard:.*point =  3d1fe97, host =  3}
	expect 0 0    Debug   {^vmod_directors: shard:.*point =  a25a43b, host =  6}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = 2b20d9a2, host =  1}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = 6337e62c, host =  7}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = c9803f17, host =  5}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = d51dafe6, host =  0}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = eb74a7d5, host =  4}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = f493ce58, host =  2}

	expect 0 0    VCL_Log {^-- remove last$}
	expect 0 0    Debug   {^vmod_directors: shard:.*point =  3d1fe97, host =  3}
	expect 0 0    Debug   {^vmod_directors: shard:.*point =  a25a43b, host =  6}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = 2b20d9a2, host =  1}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = c9803f17, host =  5}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = d51dafe6, host =  0}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = eb74a7d5, host =  4}
	expect 0 0    Debug   {^vmod_directors: shard:.*point = f493ce58, host =  2}
	expect 0 0    Notice  {^\Qvmod_directors: shard vd: .set_warmup(1.000000) ignored\E$}
	expect 0 0    Notice  {^\Qvmod_directors: shard vd: .set_warmup(-0.001000) ignored\E$}

	expect 0 0    VCL_Log {^-- END$}
} -start

client c1 {
	txreq
	rxresp
	expect resp.body == "xiuFi3Pe"
} -run

logexpect l1 -wait

varnish v1 -cliexpect {(?s)Ident.*s3 +1 +h.*s3 +2 +h.*s3 +4a +h.*s3 +5a +h.*s3 +6 +h.*s3 +7 +h} "backend.list -p"
