webtest

package module
v0.0.0-...-911ffeb Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 30, 2023 License: BSD-3-Clause Imports: 13 Imported by: 0

README

webtest

Go Reference

This package contains a testing DSL extracted from the website code that powers go.dev.

That package is internal. This copy has been slightly cleaned up and tagged for public consumption. It is distributed under the same license.

(The idea for this comes from https://github.com/rogpeppe/go-internal.)

This fork of https://github.com/cespare/webtest expands on the original webtest package in the following ways:

  • Support for PUT, PATCH and DELETE HTTP methods (in addition to GET, HEAD and POST)
  • Support for the reqcookie verb to set a cookie on the request
  • Support for the cookie and rawcookie verbs to assert a cookie's value on the HTTP response
  • Support for end-to-end testing, serving the handler with an HTTP server and executing requests with a client
  • Better test coverage

Documentation

Overview

Package webtest implements script-based testing for web servers.

The scripts, described below, are run against http.Handler implementations.

The test function TestHandler takes a *testing.T and a glob pattern, which must match at least one file. It creates a subtest of the top-level test for each script. Within each per-script subtest, it creates a per-case subtest for each case in the script, making it easy to run selected cases.

The function CheckHandler is similar but does not require a *testing.T, making it suitable for use in other contexts. It runs the entire script and returns a multiline error summarizing any problems.

The function CheckHandlerE2E is the same as CheckHandler except that it serves the handler with an HTTP server and makes a real HTTP request using the provided client, allowing assertions on responses obtained in an end-to-end fashion.

Scripts

A script is a text file containing a sequence of cases, separated by blank lines. Lines beginning with # characters are ignored as comments. A case is a sequence of lines describing a request, along with checks to be applied to the response. For example, here is a trivial script:

GET /
body contains Go is an open source programming language

This script has a single case. The first line describes the request. The second line describes a single check to be applied to the response. In this case, the request is a GET of the URL /, and the response body must contain the text “Go is an open source programming language”.

Requests

Each case begins with a line starting with GET, HEAD, POST, PATCH, PUT or DELETE. The argument (the remainder of the line) is the URL to be used in the request. Following this line, the request can be further customized using lines of the form

<verb> [<key>] <text>

where the verb and key are single space-separated words and the text is arbitrary text to the end of the line, or multiline text (described below). Whether there is a key depends on the <verb>.

The possible values for <verb> are as follows.

The verb “hint” specifies text to be printed if the test case fails, as a hint about what might be wrong.

The verb “reqheader” takes the header name as the <key> and sets a header value for the request:

GET /x.png
reqheader If-None-Match "97efa32"

The verb “reqcookie” takes the cookie name as the <key> and sets a cookie value for the request:

GET /index.html
reqcookie user_id 123

The verbs “postbody”, “postquery”, and “posttype” customize a POST, PATCH, PUT or DELETE request.

For example:

POST /api
posttype application/json
postbody {"go": true}

This describes a POST request with a posted Content-Type of “application/json” and a body “{"go": true}”.

The “postquery” verb specifies a post body in the form of a sequence of key-value pairs, query-encoded and concatenated automatically as a convenience. Using “postquery” also sets the default posted Content-Type to “application/x-www-form-urlencoded”.

For example:

POST /api
postquery
	x=hello world
	y=Go & You

This stanza sends a request with post body “x=hello+world&y=Go+%26+You”. (The multiline syntax is described in detail below.)

Checks

By default, a stanza like the ones above checks only that the request succeeds in returning a response with HTTP status code 200 (OK). Additional checks are specified by more lines of the form

<value> [<key>] <op> <text>

In the example above, <value> is “body”, there is no <key>, <op> is “contains”, and <text> is “Go is an open source programming language”. Whether there is a <key> depends on the <value>; “body” does not have one.

The possible values for <value> are:

body - the full response body
code - the HTTP status code
cookie <key> - the value of the cookie in the Set-Cookie response header
header <key> - the value in the header line with the given key
rawcookie <key> - the raw encoding of the cookie identified by <key> in the Set-Cookie response header
redirect - the target of a redirect, as found in the Location header
trimbody - the response body, trimmed

If a case contains no check of “code”, then it defaults to checking that the HTTP status code is 200, as described above, with one exception: if the case contains a check of “redirect”, then the code is required to be a 30x code.

The “trimbody” value is the body with all runs of spaces and tabs reduced to single spaces, leading and trailing spaces removed on each line, and blank lines removed.

The "rawcookie" value includes the cookie name and all the following properties of the cookie as per the HTTP spec, so for example the value could be:

ssn=secretid; path=/; secure; HttpOnly; SameSite=Lax

The possible operators for <op> are:

== - the value must be equal to the text
!= - the value must not be equal to the text
~  - the value must match the text interprted as a regular expression
!~ - the value must not match the text interprted as a regular expression
contains  - the value must contain the text as a substring
!contains - the value must not contain the text as a substring

For example:

GET /change/75944e2e3a63
hint no change redirect - hg to git mapping not registered?
code == 302
redirect contains bdb10cf
body contains bdb10cf
body !contains UA-

GET /pkg/net/http/httptrace/
body ~ Got1xxResponse.*// Go 1\.11
body ~ GotFirstResponseByte func\(\)\s*$

Multiline Texts

The <text> in a request or check line can take a multiline form, by omitting it from the original line and then specifying the text as one or more following lines, each indented by a single tab. The text is taken to be the sequence of indented lines, including the final newline, but with the leading tab removed from each.

The “postquery” example above showed the multiline syntax. Another common use is for multiline “body” checks. For example:

GET /hello
body ==
	<!DOCTYPE html>
	hello, world

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CheckHandler

func CheckHandler(fsys fs.FS, glob string, h http.Handler) error

CheckHandler runs the test script files in fsys matched by glob against the handler h. If any errors are encountered, CheckHandler returns an error listing the problems.

func CheckHandlerE2E

func CheckHandlerE2E(fsys fs.FS, glob string, h http.Handler, client Doer) error

CheckHandlerE2E is like CheckHandler, but the handler is served by a test server and the request is executed by an HTTP client. If client is nil, http.DefaultClient is used.

func HandlerWithCheck

func HandlerWithCheck(h http.Handler, path string, fsys fs.FS, glob string) http.Handler

HandlerWithCheck returns an http.Handler that responds to each request by running the test script files mached by glob against the handler h. If the tests pass, the returned http.Handler responds with status code 200. If they fail, it prints the details and responds with status code 503 (service unavailable).

func TestHandler

func TestHandler(t *testing.T, glob string, h http.Handler)

TestHandler runs the test script files matched by glob against the handler h.

Types

type Doer

type Doer interface {
	Do(req *http.Request) (*http.Response, error)
}

Doer defines the Do method required to execute an HTTP request. The net/http.Client type satisfies that interface.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL