VTC

Varnish Test Case Syntax

Manual section:

7

OVERVIEW

This document describes the syntax used by Varnish Test Cases files (.vtc). A vtc file describe a scenario with different scripted HTTP-talking entities, and generally one or more Varnish instances to test.

PARSING

A vtc file will be read word after word, with very little tokenization, meaning a syntax error won’t be detected until the test actually reach the relevant action in the test.

A parsing error will most of the time result in an assert being triggered. If this happens, please refer yourself to the related source file and line number. However, this guide should help you avoid the most common mistakes.

Words and strings

The parser splits words by detecting whitespace characters and a string is a word, or a series of words on the same line enclosed by double-quotes (”…”), or, for multi-line strings, enclosed in curly brackets ({…}).

Comments

The leading whitespaces of lines are ignored. Empty lines (or ones consisting only of whitespaces) are ignored too, as are the lines starting with “#” that are comments.

Lines and commands

Test files take at most one command per line, with the first word of the line being the command and the following ones being its arguments. To continue over to a new line without breaking the argument string, you can escape the newline character (\n) with a backslash (\).

MACROS

When a string is processed, macro expansion is performed. Macros are in the form ${<name>[,<args>...]}, they have a name followed by an optional comma- or space-separated list of arguments. Leading and trailing spaces are ignored.

The macros ${foo,bar,baz} and ${ foo bar baz } are equivalent. If an argument contains a space or a comma, arguments can be quoted. For example the macro ${foo,"bar,baz"} gives one argument bar,baz to the macro called foo.

Unless documented otherwise, all macros are simple macros that don’t take arguments.

Built-in macros

${bad_backend}

A socket address that will reliably never accept connections.

${bad_ip}

An unlikely IPv4 address.

${date}

The current date and time formatted for HTTP.

${listen_addr}

The default listen address various components use, by default a random port on localhost.

${localhost}

The first IP address that resolves to “localhost”.

${pwd}

The working directory from which varnishtest was executed.

${string,<action>[,<args>...]}

The string macro is the entry point for text generation, it takes a specialized action with each its own set of arguments.

${string,repeat,<uint>,<str>}

Repeat uint times the string str.

${testdir}

The directory containing the VTC script of the ongoing test case execution.

${tmpdir}

The dedicated working directory for the ongoing test case execution, which happens to also be the current working directory. Useful when an absolute path to the working directory is needed.

${topbuild}

Only present when the -i option is used, to work on Varnish itself instead of a regular installation.

SYNTAX

barrier

NOTE: This command is available everywhere commands are given.

Barriers allows you to synchronize different threads to make sure events occur in the right order. It’s even possible to use them in VCL.

First, it’s necessary to declare the barrier:

barrier bNAME TYPE NUMBER [-cyclic]

With the arguments being:

bNAME

this is the name of the barrier, used to identify it when you’ll create sync points. It must start with ‘b’.

TYPE

it can be “cond” (mutex) or “sock” (socket) and sets internal behavior. If you don’t need VCL synchronization, use cond.

NUMBER

number of sync point needed to go through the barrier.

-cyclic

if present, the barrier will reset itself and be ready for another round once gotten through.

Then, to add a sync point:

barrier bNAME sync

This will block the parent thread until the number of sync points for bNAME reaches the NUMBER given in the barrier declaration.

If you wish to synchronize the VCL, you need to declare a “sock” barrier. This will emit a macro definition named “bNAME_sock” that you can use in VCL (after importing the vtc vmod):

vtc.barrier_sync("${bNAME_sock}");

This function returns 0 if everything went well and is the equivalent of barrier bNAME sync at the VTC top-level.

client/server

Client and server threads are fake HTTP entities used to test your Varnish and VCL. They take any number of arguments, and the one that are not recognized, assuming they don’t start with ‘-’, are treated as specifications, laying out the actions to undertake:

client cNAME [...]
server sNAME [...]

Clients and server are identified by a string that’s the first argument, clients’ names start with ‘c’ and servers’ names start with ‘s’.

As the client and server commands share a good deal of arguments and specification actions, they are grouped in this single section, specific items will be explicitly marked as such.

Arguments
-start

Start the thread in background, processing the last given specification.

-wait

Block until the thread finishes.

-run (client only)

Equivalent to “-start -wait”.

-repeat NUMBER

Instead of processing the specification only once, do it NUMBER times.

-keepalive

For repeat, do not open new connections but rather run all iterations in the same connection

-break (server only)

Stop the server.

-listen STRING (server only)

Dictate the listening socket for the server. STRING is of the form “IP PORT”, or “/PATH/TO/SOCKET” for a Unix domain socket. In the latter case, the path must begin with ‘/’, and the server must be able to create it.

-connect STRING (client only)

Indicate the server to connect to. STRING is also of the form “IP PORT”, or “/PATH/TO/SOCKET”. As with “server -listen”, a Unix domain socket is recognized when STRING begins with a ‘/’.

-dispatch (server only, s0 only)

Normally, to keep things simple, server threads only handle one connection at a time, but the -dispatch switch allows to accept any number of connection and handle them following the given spec.

However, -dispatch is only allowed for the server name “s0”.

-proxy1 STRING (client only)

Use the PROXY protocol version 1 for this connection. STRING is of the form “CLIENTIP:PORT SERVERIP:PORT”.

-proxy2 STRING (client only)

Use the PROXY protocol version 2 for this connection. STRING is of the form “CLIENTIP:PORT SERVERIP:PORT”.

Macros and automatic behaviour

To make things easier in the general case, clients will connect by default to a Varnish server called v1. To connect to a different Varnish server, use ‘-connect ${vNAME_sock}’.

The -vcl+backend switch of the varnish command will add all the declared servers as backends. Be careful though, servers will by default listen to the 127.0.0.1 IP and will pick a random port, and publish 3 macros: sNAME_addr, sNAME_port and sNAME_sock, but only once they are started. For ‘varnish -vcl+backend’ to create the vcl with the correct values, the server must be started first.

Specification

It’s a string, either double-quoted “like this”, but most of the time enclosed in curly brackets, allowing multilining. Write a command per line in it, empty line are ignored, and long line can be wrapped by using a backslash. For example:

client c1 {
    txreq -url /foo \
          -hdr "bar: baz"

    rxresp
} -run
accept (server only)

Close the current connection, if any, and accept a new one. Note that this new connection is HTTP/1.x.

chunked STRING

Send STRING as chunked encoding.

chunkedlen NUMBER

Do as chunked except that the string will be generated for you, with a length of NUMBER characters.

close (server only)

Close the connection. Note that if operating in HTTP/2 mode no extra (GOAWAY) frame is sent, it’s simply a TCP close.

expect STRING1 OP STRING2

Test if “STRING1 OP STRING2” is true, and if not, fails the test. OP can be ==, <, <=, >, >= when STRING1 and STRING2 represent numbers in which case it’s an order operator. If STRING1 and STRING2 are meant as strings OP is a matching operator, either == (exact match) or ~ (regex match).

varnishtest will first try to resolve STRING1 and STRING2 by looking if they have special meanings, in which case, the resolved value is use for the test. Note that this value can be a string representing a number, allowing for tests such as:

expect req.http.x-num > 2

Here’s the list of recognized strings, most should be obvious as they either match VCL logic, or the txreq/txresp options:

  • remote.ip

  • remote.port

  • remote.path

  • req.method

  • req.url

  • req.proto

  • resp.proto

  • resp.status

  • resp.reason

  • resp.chunklen

  • req.bodylen

  • req.body

  • resp.bodylen

  • resp.body

  • req.http.NAME

  • resp.http.NAME

expect_close

Reads from the connection, expecting nothing to read but an EOF.

fatal|non_fatal

Control whether a failure of this entity should stop the test.

gunzip

Gunzip the body in place.

recv NUMBER

Read NUMBER bytes from the connection.

rxchunk

Receive an HTTP chunk.

rxpri (server only)

Receive a preface. If valid set the server to HTTP/2, abort otherwise.

rxreq (server only)

Receive and parse a request’s headers and body.

rxreqbody (server only)

Receive a request’s body.

rxreqhdrs (server only)

Receive and parse a request’s headers (but not the body).

rxresp [-no_obj] (client only)

Receive and parse a response’s headers and body. If -no_obj is present, only get the headers.

rxrespbody (client only)

Receive (part of) a response’s body.

-max : max length of this receive, 0 for all

rxresphdrs (client only)

Receive and parse a response’s headers.

send STRING

Push STRING on the connection.

send_n NUMBER STRING

Write STRING on the socket NUMBER times.

send_urgent STRING

Send string as TCP OOB urgent data. You will never need this.

sendhex STRING

Send bytes as described by STRING. STRING should consist of hex pairs possibly separated by whitespace or newlines. For example: “0F EE a5 3df2”.

settings -dectbl INT

Force internal HTTP/2 settings to certain values. Currently only support setting the decoding table size.

shell

Same as for the top-level shell.

stream

HTTP/2 introduces the concept of streams, and these come with their own specification, and as it’s quite big, have been moved to their own chapter.

timeout NUMBER

Set the TCP timeout for this entity.

txpri (client only)

Send an HTTP/2 preface (“PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n”) and set client to HTTP/2.

txreq|txresp […]

Send a minimal request or response, but overload it if necessary.

txreq is client-specific and txresp is server-specific.

The only thing different between a request and a response, apart from who can send them is that the first line (request line vs status line), so all the options are prety much the same.

-method STRING (txreq only)

What method to use (default: “GET”).

-req STRING (txreq only)

Alias for -method.

-url STRING (txreq only)

What location to use (default “/”).

-proto STRING

What protocol use in the status line. (default: “HTTP/1.1”).

-status NUMBER (txresp only)

What status code to return (default 200).

-reason STRING (txresp only)

What message to put in the status line (default: “OK”).

-noserver (txresp only)

Don’t include a Server header with the id of the server.

-nouseragent (txreq only)

Don’t include a User-Agent header with the id of the client.

These three switches can appear in any order but must come before the following ones.

-nohost

Don’t include a Host header in the request. Also Implied by the addition of a Host header with -hdr.

-nolen

Don’t include a Content-Length header. Also implied by the addition of a Content-Length or Transfer-Encoding header with -hdr.

-nodate

Don’t include a Date header in the response. Also implied by the addition of a Date header with -hdr.

-hdr STRING

Add STRING as a header, it must follow this format: “name: value”. It can be called multiple times.

-hdrlen STRING NUMBER

Add STRING as a header with NUMBER bytes of content.

You can then use the arguments related to the body:

-body STRING

Input STRING as body.

-bodyfrom FILE

Same as -body but content is read from FILE.

-bodylen NUMBER

Generate and input a body that is NUMBER bytes-long.

-gziplevel NUMBER

Set the gzip level (call it before any of the other gzip switches).

-gzipresidual NUMBER

Add extra gzip bits. You should never need it.

-gzipbody STRING

Gzip STRING and send it as body.

-gziplen NUMBER

Combine -bodylen and -gzipbody: generate a string of length NUMBER, gzip it and send as body.

write_body STRING

Write the body of a request or a response to a file. By using the shell command, higher-level checks on the body can be performed (eg. XML, JSON, …) provided that such checks can be delegated to an external program.

delay

NOTE: This command is available everywhere commands are given.

Sleep for the number of seconds specified in the argument. The number can include a fractional part, e.g. 1.5.

feature

Test that the required feature(s) for a test are available, and skip the test otherwise; or change the interpretation of the test, as documented below. feature takes any number of arguments from this list:

64bit

The environment is 64 bits

ipv4

127.0.0.1 works

ipv6

[::1] works

dns

DNS lookups are working

topbuild

The test has been started with ‘-i’

root

The test has been invoked by the root user

user_varnish

The varnish user is present

user_vcache

The vcache user is present

group_varnish

The varnish group is present

cmd <command-line>

A command line that should execute with a zero exit status

ignore_unknown_macro

Do not fail the test if a string of the form ${…} is not recognized as a macro.

persistent_storage

Varnish was built with the deprecated persistent storage.

coverage

Varnish was built with code coverage enabled.

asan

Varnish was built with the address sanitizer.

msan

Varnish was built with the memory sanitizer.

tsan

Varnish was built with the thread sanitizer.

ubsan

Varnish was built with the undefined behavior sanitizer.

sanitizer

Varnish was built with a sanitizer.

workspace_emulator

Varnish was built with its workspace emulator.

abstract_uds

Creation of an abstract unix domain socket succeeded.

disable_aslr

ASLR can be disabled.

A feature name can be prefixed with an exclamation mark (!) to skip a test if the feature is present.

Be careful with ignore_unknown_macro, because it may cause a test with a misspelled macro to fail silently. You should only need it if you must run a test with strings of the form “${…}”.

filewrite

Write strings to file

filewrite [-a] /somefile “Hello” “ “ “Worldn”

The -a flag opens the file in append mode.

haproxy

Define and interact with haproxy instances.

To define a haproxy server, you’ll use this syntax:

haproxy hNAME -conf-OK CONFIG
haproxy hNAME -conf-BAD ERROR CONFIG
haproxy hNAME [-D] [-W] [-arg STRING] [-conf[+vcl] STRING]

The first haproxy hNAME invocation will start the haproxy master process in the background, waiting for the -start switch to actually start the child.

Arguments:

hNAME

Identify the HAProxy server with a string, it must starts with ‘h’.

-conf-OK CONFIG
Run haproxy in ‘-c’ mode to check config is OK

stdout/stderr should contain ‘Configuration file is valid’ The exit code should be 0.

-conf-BAD ERROR CONFIG
Run haproxy in ‘-c’ mode to check config is BAD.

“ERROR” should be part of the diagnostics on stdout/stderr. The exit code should be 1.

-D

Run HAproxy in daemon mode. If not given ‘-d’ mode used.

-W

Enable HAproxy in Worker mode.

-S

Enable HAproxy Master CLI in Worker mode

-arg STRING

Pass an argument to haproxy, for example “-h simple_list”.

-cli STRING

Specify the spec to be run by the command line interface (CLI).

-mcli STRING

Specify the spec to be run by the command line interface (CLI) of the Master process.

-conf STRING

Specify the configuration to be loaded by this HAProxy instance.

-conf+backend STRING
Specify the configuration to be loaded by this HAProxy instance,

all server instances will be automatically appended

-start

Start this HAProxy instance.

-wait

Stop this HAProxy instance.

-expectexit NUMBER

Expect haproxy to exit(3) with this value

haproxy CLI Specification
expect OP STRING

Regex match the CLI reception buffer with STRING if OP is ~ or, on the contraty, if OP is !~ check that there is no regex match.

send STRING

Push STRING on the CLI connection. STRING will be terminated by an end of line character (n).

include

Executes a vtc fragment:

include FILE [...]

Open a file and execute it as a VTC fragment. This command is available everywhere commands are given.

logexpect

Reads the VSL and looks for records matching a given specification. It will process records trying to match the first pattern, and when done, will continue processing, trying to match the following pattern. If a pattern isn’t matched, the test will fail.

logexpect threads are declared this way:

logexpect lNAME -v <id> [-g <grouping>] [-d 0|1] [-q query] \
        [vsl arguments] {
                expect <skip> <vxid> <tag> <regex>
                expect <skip> <vxid> <tag> <regex>
                fail add <vxid> <tag> <regex>
                fail clear
                abort
                ...
        } [-start|-wait|-run]

And once declared, you can start them, or wait on them:

logexpect lNAME <-start|-wait>

With:

lNAME

Name the logexpect thread, it must start with ‘l’.

-v id

Specify the varnish instance to use (most of the time, id=v1).

-g <session|request|vxid|raw

Decide how records are grouped, see -g in man varnishlog for more information.

-d <0|1>

Start processing log records at the head of the log instead of the tail.

-q query

Filter records using a query expression, see man vsl-query for more information. Multiple -q options are not supported.

-m

Also emit log records for misses (only for debugging)

-err

Invert the meaning of success. Usually called once to expect the logexpect to fail

-start

Start the logexpect thread in the background.

-wait

Wait for the logexpect thread to finish

-run

Equivalent to “-start -wait”.

VSL arguments (similar to the varnishlog options):

-C

Use caseless regex

-i <taglist>

Include tags

-I <[taglist:]regex>

Include by regex

-T <seconds>

Transaction end timeout

expect specification:

skip: [uint|*|?]

Max number of record to skip

vxid: [uint|*|=]

vxid to match

tag: [tagname|*|=]

Tag to match against

regex:

regular expression to match against (optional)

For skip, vxid and tag, ‘*’ matches anything, ‘=’ expects the value of the previous matched record. The ‘?’ marker is equivalent to zero, expecting a match on the next record. The difference is that ‘?’ can be used when the order of individual consecutive logs is not deterministic. In other words, lines from a block of alternatives marked by ‘?’ can be matched in any order, but all need to match eventually.

fail specification:

add: Add to the fail list

Arguments are equivalent to expect, except for skip missing

clear: Clear the fail list

Any number of fail specifications can be active during execution of a logexpect. All active fail specifications are matched against every log line and, if any match, the logexpect fails immediately.

For a logexpect to end successfully, there must be no specs on the fail list, so logexpects should always end with

expect <skip> <vxid> <tag> <termination-condition> fail clear

abort specification:

abort(3) varnishtest, intended to help debugging of the VSL client library itself.

loop

loop NUMBER STRING

Process STRING as a specification, NUMBER times.

This works inside all specification strings

process

Run a process with stdin+stdout on a pseudo-terminal and stderr on a pipe.

Output from the pseudo-terminal is copied verbatim to ${pNAME_out}, and the -log/-dump/-hexdump flags will also put it in the vtc-log.

The pseudo-terminal is not in ECHO mode, but if the programs run set it to ECHO mode (“stty sane”) any input sent to the process will also appear in this stream because of the ECHO.

Output from the stderr-pipe is copied verbatim to ${pNAME_err}, and is always included in the vtc_log.

process pNAME SPEC [-allow-core] [-expect-exit N] [-expect-signal N]

[-dump] [-hexdump] [-log] [-run] [-close] [-kill SIGNAL] [-start] [-stop] [-wait] [-write STRING] [-writeln STRING] [-writehex HEXSTRING] [-need-bytes [+]NUMBER] [-screen-dump] [-winsz LINES COLUMNSS] [-ansi-response] [-expect-cursor LINE COLUMN] [-expect-text LINE COLUMN TEXT] [-match-text LINE COLUMN REGEXP]

pNAME

Name of the process. It must start with ‘p’.

SPEC

The command(s) to run in this process.

-hexdump

Log output with vtc_hexdump(). Must be before -start/-run.

-dump

Log output with vtc_dump(). Must be before -start/-run.

-log

Log output with VLU/vtc_log(). Must be before -start/-run.

-start

Start the process.

-expect-exit N

Expect exit status N

-expect-signal N

Expect signal in exit status N

-allow-core

Core dump in exit status is OK

-wait

Wait for the process to finish.

-run

Shorthand for -start -wait.

In most cases, if you just want to start a process and wait for it to finish, you can use the shell command instead. The following commands are equivalent:

shell "do --something"

process p1 "do --something" -run

However, you may use the the process variant to conveniently collect the standard input and output without dealing with shell redirections yourself. The shell command can also expect an expression from either output, consider using it if you only need to match one.

-key KEYSYM

Send emulated key-press. KEYSYM can be one of (NPAGE, PPAGE, HOME, END)

-kill SIGNAL

Send a signal to the process. The argument can be either the string “TERM”, “INT”, or “KILL” for SIGTERM, SIGINT or SIGKILL signals, respectively, or a hyphen (-) followed by the signal number.

If you need to use other signal names, you can use the kill(1) command directly:

shell "kill -USR1 ${pNAME_pid}"

Note that SIGHUP usage is discouraged in test cases.

-stop

Shorthand for -kill TERM.

-close

Alias for “-kill HUP”

-winsz LINES COLUMNS

Change the terminal window size to LIN lines and COL columns.

-write STRING

Write a string to the process’ stdin.

-writeln STRING

Same as -write followed by a newline (\n).

-writehex HEXSTRING

Same as -write but interpreted as hexadecimal bytes.

-need-bytes [+]NUMBER

Wait until at least NUMBER bytes have been received in total. If ‘+’ is prefixed, NUMBER new bytes must be received.

-ansi-response

Respond to terminal respond-back sequences

-expect-cursor LINE COLUMN

Expect cursors location

-expect-text LINE COLUMNS TEXT

Wait for TEXT to appear at LIN,COL on the virtual screen. Lines and columns are numbered 1…N LIN==0 means “on any line” COL==0 means “anywhere on the line”

-match-text LINE COLUMN REGEXP

Wait for the PAT regular expression to match the text at LIN,COL on the virtual screen. Lines and columns are numbered 1…N LIN==0 means “on any line” COL==0 means “anywhere on the line”

-screen-dump

Dump the virtual screen into vtc_log

setenv

Set or change an environment variable:

setenv FOO "bar baz"

The above will set the environment variable $FOO to the value provided. There is also an -ifunset argument which will only set the value if the the environment variable does not already exist:

setenv -ifunset FOO quux

shell

NOTE: This command is available everywhere commands are given.

Pass the string given as argument to a shell. If you have multiple commands to run, you can use curly brackets to describe a multi-lines script, eg:

shell {
        echo begin
        cat /etc/fstab
        echo end
}

By default a zero exit code is expected, otherwise the vtc will fail.

Notice that the commandstring is prefixed with “exec 2>&1;” to combine stderr and stdout back to the test process.

Optional arguments:

-err

Expect non-zero exit code.

-exit N

Expect exit code N instead of zero.

-expect STRING

Expect string to be found in stdout+err.

-match REGEXP

Expect regexp to match the stdout+err output.

stream

(note: this section is at the top-level for easier navigation, but it’s part of the client/server specification)

Streams map roughly to a request in HTTP/2, a request is sent on stream N, the response too, then the stream is discarded. The main exception is the first stream, 0, that serves as coordinator.

Stream syntax follow the client/server one:

stream ID [SPEC] [ACTION]

ID is the HTTP/2 stream number, while SPEC describes what will be done in that stream. If ID has the value next, the actual stream number is computed based on the last one.

Note that, when parsing a stream action, if the entity isn’t operating in HTTP/2 mode, these spec is ran before:

txpri/rxpri # client/server
stream 0 {
    txsettings
    rxsettings
    txsettings -ack
    rxsettings
    expect settings.ack == true
} -run

And HTTP/2 mode is then activated before parsing the specification.

Actions
-start

Run the specification in a thread, giving back control immediately.

-wait

Wait for the started thread to finish running the spec.

-run

equivalent to calling -start then -wait.

Specification

The specification of a stream follows the exact same rules as one for a client or a server.

txreq, txresp, txcont, txpush

These four commands are about sending headers. txreq and txresp will send HEADER frames; txcont will send CONTINUATION frames; txpush PUSH frames. The only difference between txreq and txresp are the default headers set by each of them.

-noadd

Do not add default headers. Useful to avoid duplicates when sending default headers using -hdr, -idxHdr and -litIdxHdr.

-status INT (txresp)

Set the :status pseudo-header.

-url STRING (txreq, txpush)

Set the :path pseudo-header.

-method STRING (txreq, txpush)

Set the :method pseudo-header.

-req STRING (txreq, txpush)

Alias for -method.

-scheme STRING (txreq, txpush)

Set the :scheme pseudo-header.

-hdr STRING1 STRING2

Insert a header, STRING1 being the name, and STRING2 the value.

-idxHdr INT

Insert an indexed header, using INT as index.

-litIdxHdr inc|not|never INT huf|plain STRING

Insert an literal, indexed header. The first argument specify if the header should be added to the table, shouldn’t, or mustn’t be compressed if/when retransmitted.

INT is the index of the header name to use.

The third argument informs about the Huffman encoding: yes (huf) or no (plain).

The last term is the literal value of the header.

-litHdr inc|not|never huf|plain STRING1 huf|plain STRING2

Insert a literal header, with the same first argument as -litIdxHdr.

The second and third terms tell what the name of the header is and if it should be Huffman-encoded, while the last two do the same regarding the value.

-body STRING (txreq, txresp)

Specify a body, effectively putting STRING into a DATA frame after the HEADER frame is sent.

-bodyfrom FILE (txreq, txresp)

Same as -body but content is read from FILE.

-bodylen INT (txreq, txresp)

Do the same thing as -body but generate a string of INT length for you.

-gzipbody STRING (txreq, txresp)

Gzip STRING and send it as body.

-gziplen NUMBER (txreq, txresp)

Combine -bodylen and -gzipbody: generate a string of length NUMBER, gzip it and send as body.

-nostrend (txreq, txresp)

Don’t set the END_STREAM flag automatically, making the peer expect a body after the headers.

-nohdrend

Don’t set the END_HEADERS flag automatically, making the peer expect more HEADER frames.

-dep INT (txreq, txresp)

Tell the peer that this content depends on the stream with the INT id.

-ex (txreq, txresp)

Make the dependency exclusive (-dep is still needed).

-weight (txreq, txresp)

Set the weight for the dependency.

-promised INT (txpush)

The id of the promised stream.

-pad STRING / -padlen INT (txreq, txresp, txpush)

Add string as padding to the frame, either the one you provided with -pad, or one that is generated for you, of length INT is -padlen case.

txdata

By default, data frames are empty. The receiving end will know the whole body has been delivered thanks to the END_STREAM flag set in the last DATA frame, and txdata automatically set it.

-data STRING

Data to be embedded into the frame.

-datalen INT

Generate and INT-bytes long string to be sent in the frame.

-pad STRING / -padlen INT

Add string as padding to the frame, either the one you provided with -pad, or one that is generated for you, of length INT is -padlen case.

-nostrend

Don’t set the END_STREAM flag, allowing to send more data on this stream.

rxreq, rxresp

These are two convenience functions to receive headers and body of an incoming request or response. The only difference is that rxreq can only be by a server, and rxresp by a client.

rxhdrs

rxhdrs will expect one HEADER frame, then, depending on the arguments, zero or more CONTINUATION frame.

-all

Keep waiting for CONTINUATION frames until END_HEADERS flag is seen.

-some INT

Retrieve INT - 1 CONTINUATION frames after the HEADER frame.

rxpush

This works like rxhdrs, expecting a PUSH frame and then zero or more CONTINUATION frames.

-all

Keep waiting for CONTINUATION frames until END_HEADERS flag is seen.

-some INT

Retrieve INT - 1 CONTINUATION frames after the PUSH frame.

rxdata

Receiving data is done using the rxdata keywords and will retrieve one DATA frame, if you wish to receive more, you can use these two convenience arguments:

-all

keep waiting for DATA frame until one sets the END_STREAM flag

-some INT

retrieve INT DATA frames.

Receive a frame, any frame.

sendhex

Push bytes directly on the wire. sendhex takes exactly one argument: a string describing the bytes, in hex notation, with possible whitespaces between them. Here’s an example:

sendhex "00 00 08 00 0900       8d"
rxgoaway

Receive a GOAWAY frame.

txgoaway

Possible options include:

-err STRING|INT

set the error code to explain the termination. The second argument can be a integer or the string version of the error code as found in rfc7540#7.

-laststream INT

the id of the “highest-numbered stream identifier for which the sender of the GOAWAY frame might have taken some action on or might yet take action on”.

-debug

specify the debug data, if any to append to the frame.

gunzip

Same as the gunzip command for HTTP/1.

rxping

Receive a PING frame.

txping

Send PING frame.

-data STRING

specify the payload of the frame, with STRING being an 8-char string.

-ack

set the ACK flag.

rxprio

Receive a PRIORITY frame.

txprio

Send a PRIORITY frame

-stream INT

indicate the id of the stream the sender stream depends on.

-ex

the dependency should be made exclusive (only this streams depends on the parent stream).

-weight INT

an 8-bits integer is used to balance priority between streams depending on the same streams.

rxrst

Receive a RST_STREAM frame.

txrst

Send a RST_STREAM frame. By default, txrst will send a 0 error code (NO_ERROR).

-err STRING|INT

Sets the error code to be sent. The argument can be an integer or a string describing the error, such as NO_ERROR, or CANCEL (see rfc7540#11.4 for more strings).

rxsettings

Receive a SETTINGS frame.

txsettings

SETTINGS frames must be acknowledge, arguments are as follow (most of them are from rfc7540#6.5.2):

-hdrtbl INT

headers table size

-push BOOL

whether push frames are accepted or not

-maxstreams INT

maximum concurrent streams allowed

-winsize INT

sender’s initial window size

-framesize INT

largest frame size authorized

-hdrsize INT

maximum size of the header list authorized

-ack

set the ack bit

rxwinup

Receive a WINDOW_UPDATE frame.

txwinup

Transmit a WINDOW_UPDATE frame, increasing the amount of credit of the connection (from stream 0) or of the stream (any other stream).

-size INT

give INT credits to the peer.

write_body STRING

Same as the write_body command for HTTP/1.

expect

expect in stream works as it does in client or server, except that the elements compared will be different.

Most of these elements will be frame specific, meaning that the last frame received on that stream must of the correct type.

Here the list of keywords you can look at.

GOAWAY specific
goaway.err

The error code (as integer) of the GOAWAY frame.

goaway.laststream

Last-Stream-ID

goaway.debug

Debug data, if any.

PING specific
ping.data

The 8-bytes string of the PING frame payload.

ping.ack (PING)

“true” if the ACK flag was set, “false” otherwise.

PRIORITY specific
prio.stream

The stream ID announced.

prio.exclusive

“true” if the priority is exclusive, else “false”.

prio.weight

The dependency weight.

PUSH_PROMISE specific
push.id

The id of the promised stream.

RESET_STREAM specific
rst.err

The error code (as integer) of the RESET_STREAM frame.

SETTINGS specific
settings.ack

“true” if the ACK flag was set, else “”false.

settings.push

“true” if the push settings was set to yes, “false” if set to no, and <undef> if not present.

settings.hdrtbl

Value of HEADER_TABLE_SIZE if set, <undef> otherwise.

settings.maxstreams

Value of MAX_CONCURRENT_STREAMS if set, <undef> otherwise.

settings.winsize

Value of INITIAL_WINDOW_SIZE if set, <undef> otherwise.

setting.framesize

Value of MAX_FRAME_SIZE if set, <undef> otherwise.

settings.hdrsize

Value of MAX_HEADER_LIST_SIZE if set, <undef> otherwise.

WINDOW_UPDATE specific
winup.size

The size of the upgrade given by the WINDOW_UPDATE frame.

Generic frame
frame.data

Payload of the last frame

frame.type

Type of the frame, as integer.

frame.size

Size of the frame.

frame.stream

Stream of the frame (correspond to the one you are executing this from, obviously).

frame.padding (for DATA, HEADERS, PUSH_PROMISE frames)

Number of padded bytes.

Request and response

Note: it’s possible to inspect a request or response while it is still being construct (in-between two frames for example).

req.bodylen / resp.bodylen

Length in bytes of the request/response so far.

req.body / resp.body

Body of the request/response so far.

req.http.STRING / resp.http.STRING

Value of the header STRING in the request/response.

req.status / resp.status

:status pseudo-header’s value.

req.url / resp.url

:path pseudo-header’s value.

req.method / resp.method

:method pseudo-header’s value.

req.authority / resp.authority

:method pseudo-header’s value.

req.scheme / resp.scheme

:method pseudo-header’s value.

Stream
stream.window

The current local window size of the stream, or, if on stream 0, of the connection.

stream.peer_window

The current peer window size of the stream, or, if on stream 0, of the connection.

stream.weight

Weight of the stream

stream.dependency

Id of the stream this one depends on.

Index tables
tbl.dec.size / tbl.enc.size

Size (bytes) of the decoding/encoding table.

tbl.dec.size / tbl.enc.maxsize

Maximum size (bytes) of the decoding/encoding table.

tbl.dec.length / tbl.enc.length

Number of headers in decoding/encoding table.

tbl.dec[INT].key / tbl.enc[INT].key

Name of the header at index INT of the decoding/encoding table.

tbl.dec[INT].value / tbl.enc[INT].value

Value of the header at index INT of the decoding/encoding table.

syslog

Define and interact with syslog instances (for use with haproxy)

To define a syslog server, you’ll use this syntax:

syslog SNAME

Arguments:

SNAME

Identify the syslog server with a string which must start with ‘S’.

-level STRING

Set the default syslog priority level used by any subsequent “recv” command. Any syslog dgram with a different level will be skipped by “recv” command. This default level value may be superseded by “recv” command if supplied as first argument: “recv <level>”.

-start

Start the syslog server thread in the background.

-repeat
Instead of processing the specification only once, do it

NUMBER times.

-bind

Bind the syslog socket to a local address.

-wait

Wait for that thread to terminate.

-stop

Stop the syslog server thread.

tunnel

The goal of a tunnel is to help control the data transfer between two parties, for example to trigger socket timeouts in the middle of protocol frames, without the need to change how both parties are implemented.

A tunnel accepts a connection and then connects on behalf of the source to the desired destination. Once both connections are established the tunnel will transfer bytes unchanged between the source and destination. Transfer can be interrupted, usually with the help of synchronization methods like barriers. Once the transfer is paused, it is possible to let a specific amount of bytes move in either direction.

Arguments
-start

Start the tunnel in background, processing the last given specification.

-start+pause

Start the tunnel, but already paused.

-wait

Block until the thread finishes.

-listen STRING

Dictate the listening socket for the server. STRING is of the form “IP PORT”, or “HOST PORT”.

Listens by defaults to a local random port.

-connect STRING

Indicate the server to connect to. STRING is also of the form “IP PORT”, or “HOST PORT”.

Connects by default to a varnish instance called v1.

Specification

The specification contains a list of tunnel commands that can be combined with barriers and delays. For example:

tunnel t1 {
    barrier b1 sync
    pause
    delay 1
    send 42
    barrier b2 sync
    resume
} -start

If one end of the tunnel is closed before the end of the specification the test case will fail. A specification that ends in a paused state will implicitely resume the tunnel.

pause

Wait for in-flight bytes to be transferred and pause the tunnel.

The tunnel must be running.

recv NUMBER

Wait until NUMBER bytes are transferred from destination to source.

The tunnel must be paused, it remains paused afterwards.

resume

Resume the transfer of bytes in both directions.

The tunnel must be paused.

send NUMBER

Wait until NUMBER bytes are transferred from source to destination.

The tunnel must be paused, it remains paused afterwards.

varnish

Define and interact with varnish instances.

To define a Varnish server, you’ll use this syntax:

varnish vNAME [-arg STRING] [-vcl STRING] [-vcl+backend STRING]
        [-errvcl STRING STRING] [-jail STRING] [-proto PROXY]

The first varnish vNAME invocation will start the varnishd master process in the background, waiting for the -start switch to actually start the child.

Types used in the description below:

PATTERN

is a ‘glob’ style pattern (ie: fnmatch(3)) as used in shell filename expansion.

Arguments:

vNAME

Identify the Varnish server with a string, it must starts with ‘v’.

-arg STRING

Pass an argument to varnishd, for example “-h simple_list”.

If the ${varnishd_args_prepend} or ${varnishd_args_append} macros are defined, they are expanded and inserted before / appended to the varnishd command line as constructed by varnishtest, before the command line itself is expanded. This enables tweaks to the varnishd command line without editing test cases. This macros can be defined using the -D option for varnishtest.

-vcl STRING

Specify the VCL to load on this Varnish instance. You’ll probably want to use multi-lines strings for this ({…}).

-vcl+backend STRING

Do the exact same thing as -vcl, but adds the definition block of known backends (ie. already defined).

-errvcl STRING1 STRING2

Load STRING2 as VCL, expecting it to fail, and Varnish to send an error string matching STRING1

-jail STRING

Look at man varnishd (-j) for more information.

-proto PROXY

Have Varnish use the proxy protocol. Note that PROXY here is the actual string.

You can decide to start the Varnish instance and/or wait for several events:

varnish vNAME [-start] [-wait] [-wait-running] [-wait-stopped]
-start

Start the child process.

Once successfully started, the following macros are available for the default listen address: ${vNAME_addr}, ${vNAME_port} and ${vNAME_sock}. Additional macros are available, including the listen address name for each address vNAME listens to, like for example: ${vNAME_a0_addr}.

-stop

Stop the child process.

-syntax

Set the VCL syntax level for this command (default: 4.1)

-wait

Wait for that instance to terminate.

-wait-running

Wait for the Varnish child process to be started.

-wait-stopped

Wait for the Varnish child process to stop.

-cleanup

Once Varnish is stopped, clean everything after it. This is only used in very few tests and you should never need it.

-expectexit NUMBER

Expect varnishd to exit(3) with this value

Once Varnish is started, you can talk to it (as you would through varnishadm) with these additional switches:

varnish vNAME [-cli STRING] [-cliok STRING] [-clierr STRING]
              [-clijson STRING]
-cli STRING|-cliok STRING|-clierr STATUS STRING|-cliexpect REGEXP STRING

All four of these will send STRING to the CLI, the only difference is what they expect the result to be. -cli doesn’t expect anything, -cliok expects 200, -clierr expects STATUS, and -cliexpect expects the REGEXP to match the returned response.

-clijson STRING

Send STRING to the CLI, expect success (CLIS_OK/200) and check that the response is parsable JSON.

It is also possible to interact with its shared memory (as you would through tools like varnishstat) with additional switches:

-expect !PATTERN|PATTERN OP NUMBER|PATTERN OP PATTERN

Look into the VSM and make sure the first VSC counter identified by PATTERN has a correct value. OP can be ==, >, >=, <, <=. For example:

varnish v1 -expect SM?.s1.g_space > 1000000
varnish v1 -expect cache_hit >= cache_hit_grace

In the ! form the test fails if a counter matches PATTERN.

The MAIN. namespace can be omitted from PATTERN.

The test takes up to 5 seconds before timing out.

-vsc PATTERN

Dump VSC counters matching PATTERN.

-vsl_catchup

Wait until the logging thread has idled to make sure that all the generated log is flushed

varnishtest

Alternate name for ‘vtest’, see above.

vtest

This should be the first command in your vtc as it will identify the test case with a short yet descriptive sentence. It takes exactly one argument, a string, eg:

vtest "Check that vtest is actually a valid command"

It will also print that string in the log.

HISTORY

This document has been written by Guillaume Quintard.

SEE ALSO