diff options
Diffstat (limited to 'src/cmd/go/internal/vcweb/vcstest/vcstest_test.go')
-rw-r--r-- | src/cmd/go/internal/vcweb/vcstest/vcstest_test.go | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/src/cmd/go/internal/vcweb/vcstest/vcstest_test.go b/src/cmd/go/internal/vcweb/vcstest/vcstest_test.go new file mode 100644 index 0000000..4a6d600 --- /dev/null +++ b/src/cmd/go/internal/vcweb/vcstest/vcstest_test.go @@ -0,0 +1,170 @@ +// Copyright 2022 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. + +package vcstest_test + +import ( + "cmd/go/internal/vcweb" + "errors" + "flag" + "fmt" + "io" + "io/fs" + "log" + "net" + "net/http" + "net/http/httptest" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + "time" +) + +var ( + dir = flag.String("dir", "../../../testdata/vcstest", "directory containing scripts to serve") + host = flag.String("host", "localhost", "hostname on which to serve HTTP") + port = flag.Int("port", -1, "port on which to serve HTTP; if nonnegative, skips running tests") +) + +func TestMain(m *testing.M) { + flag.Parse() + + if *port >= 0 { + err := serveStandalone(*host, *port) + if err != nil { + log.Fatal(err) + } + os.Exit(0) + } + + m.Run() +} + +// serveStandalone serves the vcweb testdata in a standalone HTTP server. +func serveStandalone(host string, port int) (err error) { + scriptDir, err := filepath.Abs(*dir) + if err != nil { + return err + } + work, err := os.MkdirTemp("", "vcweb") + if err != nil { + return err + } + defer func() { + if rmErr := os.RemoveAll(work); err == nil { + err = rmErr + } + }() + + log.Printf("running scripts in %s", work) + + v, err := vcweb.NewServer(scriptDir, work, log.Default()) + if err != nil { + return err + } + + l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", host, port)) + if err != nil { + return err + } + log.Printf("serving on http://%s:%d/", host, l.Addr().(*net.TCPAddr).Port) + + return http.Serve(l, v) +} + +// TestScripts verifies that the VCS setup scripts in cmd/go/testdata/vcstest +// run successfully. +func TestScripts(t *testing.T) { + scriptDir, err := filepath.Abs(*dir) + if err != nil { + t.Fatal(err) + } + s, err := vcweb.NewServer(scriptDir, t.TempDir(), log.Default()) + if err != nil { + t.Fatal(err) + } + srv := httptest.NewServer(s) + + // To check for data races in the handler, run the root handler to produce an + // overview of the script status at an arbitrary point during the test. + // (We ignore the output because the expected failure mode is a friendly stack + // dump from the race detector.) + t.Run("overview", func(t *testing.T) { + t.Parallel() + + time.Sleep(1 * time.Millisecond) // Give the other handlers time to race. + + resp, err := http.Get(srv.URL) + if err == nil { + io.Copy(io.Discard, resp.Body) + resp.Body.Close() + } else { + t.Error(err) + } + }) + + t.Cleanup(func() { + // The subtests spawned by WalkDir run in parallel. When they complete, this + // Cleanup callback will run. At that point we fetch the root URL (which + // contains a status page), both to test that the root handler runs without + // crashing and to display a nice summary of the server's view of the test + // coverage. + resp, err := http.Get(srv.URL) + if err == nil { + var body []byte + body, err = io.ReadAll(resp.Body) + if err == nil && testing.Verbose() { + t.Logf("GET %s:\n%s", srv.URL, body) + } + resp.Body.Close() + } + if err != nil { + t.Error(err) + } + + srv.Close() + }) + + err = filepath.WalkDir(scriptDir, func(path string, d fs.DirEntry, err error) error { + if err != nil || d.IsDir() { + return err + } + + rel, err := filepath.Rel(scriptDir, path) + if err != nil { + return err + } + if rel == "README" { + return nil + } + + t.Run(filepath.ToSlash(rel), func(t *testing.T) { + t.Parallel() + + buf := new(strings.Builder) + logger := log.New(buf, "", log.LstdFlags) + // Load the script but don't try to serve the results: + // different VCS tools have different handler protocols, + // and the tests that actually use these repos will ensure + // that they are served correctly as a side effect anyway. + err := s.HandleScript(rel, logger, func(http.Handler) {}) + if buf.Len() > 0 { + t.Log(buf) + } + if err != nil { + if notInstalled := (vcweb.ServerNotInstalledError{}); errors.As(err, ¬Installed) || errors.Is(err, exec.ErrNotFound) { + t.Skip(err) + } + t.Error(err) + } + }) + return nil + }) + + if err != nil { + t.Error(err) + } +} |