Test VCL Using Varnishtest

Varnish developers know varnishtest, it’s yet another executable that ships with Varnish. When compiling Varnish and VMODs, there is typically a set of varnishtests you can run to ensure that everything is working correctly. And without a doubt it is useful to be able to validate that 1 + 1 = 2, as this allows IT Admins to be able to get just a few minutes of sleep each night.

What not everyone knows is it is possible to use varnishtest against your own VCL and create a test driven deployment lifecycle. Image that before you deploy new VCL to github, all of your VTCs must pass. Now, there is cause for celebration. The key to doing this is being able to run the CLI within the varnish block to load VCL from a separate file. Allow me to illustrate with an example:


    vcl 4.1;

    backend default {
        .host = "";
        .port = "8000";

    sub vcl_deliver {
        set resp.http.X-Message = "hello world";


varnishtest “basic varnishtest that loads VCL from a seperate file”

    server s1 -listen " 8000" {
        expect req.url == "/"
        txresp -status 200 -reason "OK"
    } -start

    varnish v1 -cli "vcl.load v1 ${pwd}/default.vcl" -start

    client c1 {
        txreq -url "/"
        expect resp.status == 200
        expect resp.reason == "OK"
        expect resp.http.X-Message == "hello world"
    } -run

When we run this, the result is something like this:

top TEST text.vtc passed (2.115)

Note that in order for this test to pass, post 8000 on must be available and not already bound to by another process. The port may not be free if you are running the test on the same server that your origin server is running on. If this is the case, the test will fail, and you will see this in the output:

---- s1 Server listen address ( 8000) cannot be resolved: bind(2)

Okay, so we are able to run tests on a VCL file that is outside of the varnishtest. If you still are not convinced, we can purposefully change the VCL or the test so that it now fails:


vcl 4.1;

    backend default {
        .host = "";
        .port = "8000";

    sub vcl_deliver {
        set resp.http.X-Message = "not hello world";

Now when I run varnishtest test.vtc, I get a large output, including this line:

---- c1 EXPECT resp.http.X-Message (not hello world) == "hello world" failed

And finally this:

top TEST text.vtc FAILED (2.015) exit=2

Wallah, we are now ready to run these tests before deploying VCL, and have some sense that we aren’t completely breaking the site. Being an engineer has never been so easy.

If you are getting really into varnishtest, here are some tricks to help you along the way. Of course, check out man vtc and this documentation on VTCs. In addition, you can search through the log list of VTCs that ship with the varnish cache project in Github with a query such at this: repo:varnishcache/varnish-cache path:*.vtc logexpect. In this case you will see lots of examples of VTCs with a logexpect statement, which can really help if you have never used one before.





Leave a Reply

Your email address will not be published. Required fields are marked *