varnishtest "Test timestamps"

# We can't test the value of a timestamp, but this should fail
# if we can't set the header at all.
# We also test that `now` remains unchanged during a vcl sub

server s1 {
	rxreq
	txresp

	rxreq
	txresp

	rxreq
	expect req.method == PIPE
	expect req.http.req-time != <undef>
	expect req.http.bereq-time != <undef>
	txresp
} -start

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

	sub recv_sub {
		set req.http.now-recv_sub = now;
	}
	sub vcl_recv {
		if (req.restarts == 0) {
			set req.http.req-time = req.time;
		} else if (req.http.req-time != "" + req.time) {
			return (fail);
		}
		set req.http.now-recv = now;
		vtc.sleep(1s);
		call recv_sub;
		if (req.http.now-recv != req.http.now-recv_sub) {
			return (fail);
		}
	}
	sub vcl_pipe {
		set bereq.http.req-time = req.time;
		set bereq.http.bereq-time = bereq.time;
	}
	sub vcl_synth {
		set resp.http.now-synth = now;
		if (req.http.req-time != "" + req.time) {
			return (fail);
		}
		set req.http.req-time = req.time;
		set resp.http.resp-time = resp.time;
	}

	sub vcl_deliver {
		if (req.http.req-time != "" + req.time) {
			return (fail);
		}
		set resp.http.resp-time = resp.time;
		set resp.http.obj-time = obj.time;
		set resp.http.now-deliver = now;
		if (req.http.now-recv == req.http.now-deliver) {
			return (fail);
		}

		vtc.sleep(1s);
		if (req.restarts == 0) {
			return (restart);
		}
		return (synth(200));
	}

	sub bf_sub {
		set bereq.http.now-bf_sub = now;
	}
	sub vcl_backend_fetch {
		if (bereq.retries == 0) {
			set bereq.http.bereq-time = bereq.time;
		} else if (bereq.http.bereq-time != "" + bereq.time) {
			# bereq.time is identical for all retries
			return (fail);
		}
		if (bereq.time <= std.time(bereq.http.req-time)) {
			return (fail);
		}
		set bereq.http.now-bf = now;
		vtc.sleep(1s);
		call bf_sub;
		# now remains constant during built-in vcl sub
		if (bereq.http.now-bf != bereq.http.now-bf_sub) {
			return (fail);
		}
	}
	sub br_sub {
		set beresp.http.now-br_sub = now;
	}
	sub vcl_backend_response {
		if (bereq.http.bereq-time != "" + bereq.time) {
			return (fail);
		}
		set beresp.http.beresp-time = beresp.time;
		set beresp.http.now-br = now;
		vtc.sleep(1s);
		call br_sub;
		if (beresp.http.now-br != beresp.http.now-br_sub) {
			return (fail);
		}
		if (bereq.http.now-bf == beresp.http.now-br) {
			return (fail);
		}
		if (bereq.retries == 0) {
			return (retry);
		}
	}
	sub vcl_backend_error {
		call vcl_backend_response;
	}
} -start

client c1 {
	txreq
	rxresp
	expect resp.status == 200
	expect resp.http.now-synth ~ "^..., .. ... .... ..:..:.. GMT"

	txreq -method PIPE
	rxresp
} -run
