blob: 84e83a5a72e0958a3472380767adff9a3d02080f [file] [log] [blame]
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Regression tests to run against a production instance of godoc.
package main_test
import (
"bytes"
"flag"
"io"
"io/ioutil"
"net/http"
"net/url"
"regexp"
"strings"
"testing"
)
var host = flag.String("regtest.host", "", "host to run regression test against")
func TestLiveServer(t *testing.T) {
*host = strings.TrimSuffix(*host, "/")
if *host == "" {
t.Skip("regtest.host flag missing.")
}
substringTests := []struct {
Message string
Path string
Substring string
Regexp string
NoAnalytics bool // expect the response to not contain GA.
PostBody string
StatusCode int // if 0, expect 2xx status code.
}{
{
Path: "/doc/",
Substring: "an introduction to using modules in a simple project",
},
{
Path: "/conduct",
Substring: "Project Stewards",
},
{
Path: "/doc/faq",
Substring: "What is the purpose of the project",
},
{
Path: "/pkg/",
Substring: "Package tar",
},
{
Path: "/pkg/os/",
Substring: "func Open",
},
{
Path: "/pkg/net/http/",
Substring: `title="Added in Go 1.11"`,
Message: "version information not present - failed InitVersionInfo?",
},
{
Path: "/robots.txt",
Substring: "Disallow: /search",
Message: "robots not present - not deployed from Dockerfile?",
NoAnalytics: true,
},
{
Path: "/change/75944e2e3a63",
Substring: "bdb10cf",
Message: "no change redirect - hg to git mapping not registered?",
NoAnalytics: true,
StatusCode: 302,
},
{
Path: "/dl/",
Substring: `href="/dl/go1.11.windows-amd64.msi"`,
Message: "missing data on dl page - misconfiguration of datastore?",
},
{
Path: "/dl/?mode=json",
Substring: ".windows-amd64.msi",
NoAnalytics: true,
},
{
Message: "broken shortlinks - misconfiguration of datastore or memcache?",
Path: "/s/go2design",
Regexp: "proposal.*Found",
NoAnalytics: true,
StatusCode: 302,
},
{
Message: "incorrect search result - broken index?",
Path: "/search?q=IsDir",
Substring: "src/os/types.go",
},
{
Path: "/compile",
PostBody: "body=" + url.QueryEscape("package main; func main() { print(6*7); }"),
Regexp: `^{"compile_errors":"","output":"42"}$`,
NoAnalytics: true,
},
{
Path: "/compile",
PostBody: "body=" + url.QueryEscape("//empty"),
Substring: "expected 'package', found 'EOF'",
NoAnalytics: true,
},
{
Path: "/compile",
PostBody: "version=2&body=package+main%3Bimport+(%22fmt%22%3B%22time%22)%3Bfunc+main()%7Bfmt.Print(%22A%22)%3Btime.Sleep(time.Second)%3Bfmt.Print(%22B%22)%7D",
Regexp: `^{"Errors":"","Events":\[{"Message":"A","Kind":"stdout","Delay":0},{"Message":"B","Kind":"stdout","Delay":1000000000}\]}$`,
NoAnalytics: true,
},
{
Path: "/share",
PostBody: "package main",
Substring: "", // just check it is a 2xx.
NoAnalytics: true,
},
{
Path: "/x/net",
Substring: `<meta name="go-import" content="golang.org/x/net git https://go.googlesource.com/net">`,
NoAnalytics: true,
},
{
Message: "release history page has an entry for Go 1.14.2",
Path: "/doc/devel/release.html",
Regexp: `go1\.14\.2\s+\(released 2020/04/08\)\s+includes\s+fixes to cgo, the go command, the runtime,`,
},
{
Message: "Go project page has an entry for Go 1.14",
Path: "/project/",
Substring: `<li><a href="/doc/go1.14">Go 1.14</a> <small>(February 2020)</small></li>`,
},
{
Message: "Go project subpath does not exist",
Path: "/project/notexist",
StatusCode: http.StatusNotFound,
},
}
for _, tc := range substringTests {
t.Run(tc.Path, func(t *testing.T) {
method := "GET"
var reqBody io.Reader
if tc.PostBody != "" {
method = "POST"
reqBody = strings.NewReader(tc.PostBody)
}
req, err := http.NewRequest(method, *host+tc.Path, reqBody)
if err != nil {
t.Fatalf("NewRequest: %v", err)
}
if reqBody != nil {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
resp, err := http.DefaultTransport.RoundTrip(req)
if err != nil {
t.Fatalf("RoundTrip: %v", err)
}
if tc.StatusCode == 0 {
if resp.StatusCode > 299 {
t.Errorf("Non-OK status code: %v", resp.StatusCode)
}
} else if tc.StatusCode != resp.StatusCode {
t.Errorf("StatusCode; got %v, want %v", resp.StatusCode, tc.StatusCode)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatalf("ReadAll: %v", err)
}
const googleAnalyticsID = "UA-11222381-2" // golang.org analytics ID
if !tc.NoAnalytics && !bytes.Contains(body, []byte(googleAnalyticsID)) {
t.Errorf("want response to contain analytics tracking ID")
}
if tc.Substring != "" {
tc.Regexp = regexp.QuoteMeta(tc.Substring)
}
re := regexp.MustCompile(tc.Regexp)
if !re.Match(body) {
t.Log("------ actual output -------")
t.Log(string(body))
t.Log("----------------------------")
if tc.Message != "" {
t.Log(tc.Message)
}
t.Fatalf("wanted response to match %s", tc.Regexp)
}
})
}
}