varnishtest "shard director/int reconfiguration outside init"

server s1 {
	rxreq
	txresp -body "ech3Ooj"
} -start

server s2 {
} -start

server s3 {
	rxreq
	txresp -body "xiuFi3Pe"
	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);
	}

	sub vcl_recv {
		if (req.http.change == "apply") {
			# test implicit reconfigure at the end of task
			vd.clear();
			vd.add_backend(s1);
			set req.backend_hint = vd.backend();
			return (pass);
		}
		if (req.http.change == "test") {
			set req.backend_hint = vd.backend();
			return (pass);
		}
		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"));
		}

		std.log("-- END");
		set req.backend_hint = vd.backend();
		return(pass);
	}

} -start

# this is identical to v01100.vtc, but split into two logexps

logexpect l1 -v v1 -g raw -d 1 {
	expect * 1001    VCL_Log {^-- invalid replicas$}
	expect 0 1001    Error   {^vmod_directors: shard vd: .reconfigure.. invalid replicas argument 0}
	expect 0 1001    VCL_Log {^reconfigure failed}

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

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

	expect 0 1001    VCL_Log {^-- one backend$}

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

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

	expect 0 1001    VCL_Log {^-- duplicate add$}
	expect 0 1001    Notice  {^vmod_directors: shard vd: backend s1 already exists - skipping$}
	expect 0 1001    VCL_Log {^-- duplicate add with idents$}
	expect 0 1001    Notice  {^vmod_directors: shard vd: backend s1 already exists - skipping}
	expect 0 1001    Notice  {^vmod_directors: shard vd: backend s1/s1_1 already exists - skipping}
	expect 0 1001    Notice  {^vmod_directors: shard vd: backend s1/s1_2 already exists - skipping}
	expect 0 1001    VCL_Log {^-- remove s1_2 specifically$}
	expect 0 1001    VCL_Log {^-- remove all instances of s1$}
	expect 0 1001    VCL_Log {^-- re-add some - no 2nd director$}
	expect 0 1001    VCL_Log {^-- remove second-last$}
	expect 0 1001    VCL_Log {^-- remove last$}
	expect 0 1001    VCL_Log {^-- END$}
}

logexpect l2 -v v1 -g raw -d 1 {
	expect *    0    Debug   {^vmod_directors: shard:.*point = f08ad325, host =  0}
	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    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    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    Debug   {^vmod_directors: shard:.*point = 6e040182, host =  0}
	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    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    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}
}

logexpect l1 -start
logexpect l2 -start

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

	# director not yet changed for this task
	txreq -hdr "change: apply"
	rxresp
	expect resp.body == "xiuFi3Pe"

	# change active
	txreq -hdr "change: test"
	rxresp
	expect resp.body == "ech3Ooj"
} -run

logexpect l1 -wait
logexpect l2 -wait
