| // Copyright 2023 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 proxytest | |
| import ( | |
| "fmt" | |
| "path/filepath" | |
| "strings" | |
| "testing" | |
| "golang.org/x/mod/modfile" | |
| "golang.org/x/pkgsite-metrics/internal/proxy" | |
| "golang.org/x/pkgsite-metrics/internal/testing/testhelper" | |
| "golang.org/x/tools/txtar" | |
| ) | |
| // SetupTestClient creates a fake module proxy for testing using the given test | |
| // version information. | |
| // | |
| // It returns a function for tearing down the proxy after the test is completed | |
| // and a Client for interacting with the test proxy. | |
| func SetupTestClient(t *testing.T, modules []*Module) (*proxy.Client, func()) { | |
| t.Helper() | |
| s := NewServer(modules) | |
| client, serverClose, err := NewClientForServer(s) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| return client, serverClose | |
| } | |
| // NewClientForServer starts serving proxyMux locally. It returns a client to the | |
| // server and a function to shut down the server. | |
| func NewClientForServer(s *Server) (*proxy.Client, func(), error) { | |
| // override client.httpClient to skip TLS verification | |
| httpClient, prox, serverClose := testhelper.SetupTestClientAndServer(s.mux) | |
| client, err := proxy.New(prox.URL) | |
| if err != nil { | |
| return nil, nil, err | |
| } | |
| client.HTTPClient = httpClient | |
| return client, serverClose, nil | |
| } | |
| // LoadTestModules reads the modules in the given directory. Each file in that | |
| // directory with a .txtar extension should be named "path@version" and should | |
| // be in txtar format (golang.org/x/tools/txtar). The path part of the filename | |
| // will be preceded by "example.com/" and colons will be replaced by slashes to | |
| // form a full module path. The file contents are used verbatim except that some | |
| // variables beginning with "$" are substituted with predefined strings. | |
| // | |
| // LoadTestModules panics if there is an error reading any of the files. | |
| func LoadTestModules(dir string) []*Module { | |
| files, err := filepath.Glob(filepath.Join(dir, "*.txtar")) | |
| if err != nil { | |
| panic(err) | |
| } | |
| var ms []*Module | |
| for _, f := range files { | |
| m, err := readTxtarModule(f) | |
| if err != nil { | |
| panic(err) | |
| } | |
| ms = append(ms, m) | |
| } | |
| return ms | |
| } | |
| var testModuleReplacer = strings.NewReplacer( | |
| "$MITLicense", testhelper.MITLicense, | |
| "$BSD0License", testhelper.BSD0License, | |
| ) | |
| func readTxtarModule(filename string) (*Module, error) { | |
| modver := strings.TrimSuffix(filepath.Base(filename), filepath.Ext(filename)) | |
| i := strings.IndexRune(modver, '@') | |
| if i < 0 { | |
| return nil, fmt.Errorf("%s: filename missing '@'", modver) | |
| } | |
| modulePath, version := "example.com/"+modver[:i], modver[i+1:] | |
| modulePath = strings.ReplaceAll(modulePath, ":", "/") | |
| if modulePath == "" || version == "" { | |
| return nil, fmt.Errorf("%s: empty module path or version", filename) | |
| } | |
| m := &Module{ | |
| ModulePath: modulePath, | |
| Version: version, | |
| Files: map[string]string{}, | |
| } | |
| ar, err := txtar.ParseFile(filename) | |
| if err != nil { | |
| return nil, err | |
| } | |
| for _, f := range ar.Files { | |
| if f.Name == "go.mod" { | |
| // Overwrite the pregenerated module path if one is specified in | |
| // the go.mod file. | |
| m.ModulePath = modfile.ModulePath(f.Data) | |
| } | |
| m.Files[f.Name] = strings.TrimSpace(testModuleReplacer.Replace(string(f.Data))) | |
| } | |
| return m, nil | |
| } | |
| // FindModule returns the module in mods with the given path and version, or nil | |
| // if there isn't one. An empty version argument matches any version. | |
| func FindModule(mods []*Module, path, version string) *Module { | |
| for _, m := range mods { | |
| if m.ModulePath == path && (version == "" || m.Version == version) { | |
| return m | |
| } | |
| } | |
| return nil | |
| } |