internal/datasource: consolidate
Merge ProxyDataSource and LocalDataSource into a single type,
DataSource.
Combine and simplify tests.
For golang/go#47780
Change-Id: I3510fee3a3d786705a2306a6233b352e5af40076
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/344952
Trust: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Julie Qiu <julie@golang.org>
diff --git a/cmd/frontend/main.go b/cmd/frontend/main.go
index 2fbd6a7..429a90c 100644
--- a/cmd/frontend/main.go
+++ b/cmd/frontend/main.go
@@ -20,6 +20,7 @@
"golang.org/x/pkgsite/internal/config"
"golang.org/x/pkgsite/internal/datasource"
"golang.org/x/pkgsite/internal/dcensus"
+ "golang.org/x/pkgsite/internal/fetch"
"golang.org/x/pkgsite/internal/frontend"
"golang.org/x/pkgsite/internal/log"
"golang.org/x/pkgsite/internal/middleware"
@@ -76,13 +77,13 @@
}
if *directProxy {
- var pds *datasource.ProxyDataSource
- if *bypassLicenseCheck {
- pds = datasource.NewBypassingLicenseCheck(proxyClient)
- } else {
- pds = datasource.NewProxy(proxyClient)
- }
- dsg = func(context.Context) internal.DataSource { return pds }
+ ds := datasource.Options{
+ Getters: []fetch.ModuleGetter{fetch.NewProxyModuleGetter(proxyClient)},
+ ProxyClientForLatest: proxyClient,
+ BypassLicenseCheck: *bypassLicenseCheck,
+ SourceClient: source.NewClient(1 * time.Minute),
+ }.New()
+ dsg = func(context.Context) internal.DataSource { return ds }
} else {
db, err := cmdconfig.OpenDB(ctx, cfg, *bypassLicenseCheck)
if err != nil {
diff --git a/cmd/pkgsite/main.go b/cmd/pkgsite/main.go
index 184523b..4e6fab8 100644
--- a/cmd/pkgsite/main.go
+++ b/cmd/pkgsite/main.go
@@ -68,7 +68,11 @@
func newServer(ctx context.Context, paths []string, gopathMode bool) (*frontend.Server, error) {
getters := buildGetters(ctx, paths, gopathMode)
- lds := datasource.NewLocal(getters, source.NewClient(time.Second))
+ lds := datasource.Options{
+ Getters: getters,
+ SourceClient: source.NewClient(time.Second),
+ BypassLicenseCheck: true,
+ }.New()
server, err := frontend.NewServer(frontend.ServerConfig{
DataSourceGetter: func(context.Context) internal.DataSource { return lds },
StaticPath: template.TrustedSourceFromFlag(flag.Lookup("static").Value),
diff --git a/internal/datasource/datasource.go b/internal/datasource/datasource.go
index 34e684a..3d88459 100644
--- a/internal/datasource/datasource.go
+++ b/internal/datasource/datasource.go
@@ -26,29 +26,38 @@
"golang.org/x/pkgsite/internal/version"
)
-// dataSource implements the internal.DataSource interface, by trying a list of
+// DataSource implements the internal.DataSource interface, by trying a list of
// fetch.ModuleGetters to fetch modules and caching the results.
-type dataSource struct {
- getters []fetch.ModuleGetter
- sourceClient *source.Client
- bypassLicenseCheck bool
- cache *lru.Cache
- prox *proxy.Client // used for latest-version info only
-
+type DataSource struct {
+ opts Options
+ cache *lru.Cache
}
-func newDataSource(getters []fetch.ModuleGetter, sc *source.Client, bypassLicenseCheck bool, prox *proxy.Client) *dataSource {
+// Options are parameters for creating a new DataSource.
+type Options struct {
+ // List of getters to try, in order.
+ Getters []fetch.ModuleGetter
+ // If set, this will be used for latest-version information. To fetch modules from the proxy,
+ // include a ProxyModuleGetter in Getters.
+ ProxyClientForLatest *proxy.Client
+ SourceClient *source.Client
+ BypassLicenseCheck bool
+}
+
+// New creates a new DataSource from the options.
+func (o Options) New() *DataSource {
cache, err := lru.New(maxCachedModules)
if err != nil {
- // Can only happen if size is bad.
+ // Can only happen if size is bad, and we control it.
panic(err)
}
- return &dataSource{
- getters: getters,
- sourceClient: sc,
- bypassLicenseCheck: bypassLicenseCheck,
- cache: cache,
- prox: prox,
+ opts := o
+ // Copy getters slice so caller doesn't modify us.
+ opts.Getters = make([]fetch.ModuleGetter, len(opts.Getters))
+ copy(opts.Getters, o.Getters)
+ return &DataSource{
+ opts: opts,
+ cache: cache,
}
}
@@ -61,7 +70,7 @@
const maxCachedModules = 100
// cacheGet returns information from the cache if it is present, and (nil, nil) otherwise.
-func (ds *dataSource) cacheGet(path, version string) (*internal.Module, error) {
+func (ds *DataSource) cacheGet(path, version string) (*internal.Module, error) {
// Look for an exact match first, then use LocalVersion, as for a
// directory-based or GOPATH-mode module.
for _, v := range []string{version, fetch.LocalVersion} {
@@ -74,13 +83,13 @@
}
// cachePut puts information into the cache.
-func (ds *dataSource) cachePut(path, version string, m *internal.Module, err error) {
+func (ds *DataSource) cachePut(path, version string, m *internal.Module, err error) {
ds.cache.Add(internal.Modver{Path: path, Version: version}, cacheEntry{m, err})
}
// getModule gets the module at the given path and version. It first checks the
// cache, and if it isn't there it then tries to fetch it.
-func (ds *dataSource) getModule(ctx context.Context, modulePath, version string) (_ *internal.Module, err error) {
+func (ds *DataSource) getModule(ctx context.Context, modulePath, version string) (_ *internal.Module, err error) {
defer derrors.Wrap(&err, "getModule(%q, %q)", modulePath, version)
mod, err := ds.cacheGet(modulePath, version)
@@ -92,10 +101,10 @@
// module. At worst some work will be duplicated, but if that turns out to
// be a problem we could use golang.org/x/sync/singleflight.
m, err := ds.fetch(ctx, modulePath, version)
- if m != nil && ds.prox != nil {
+ if m != nil && ds.opts.ProxyClientForLatest != nil {
// Use the go.mod file at the raw latest version to fill in deprecation
// and retraction information.
- lmv, err2 := fetch.LatestModuleVersions(ctx, modulePath, ds.prox, nil)
+ lmv, err2 := fetch.LatestModuleVersions(ctx, modulePath, ds.opts.ProxyClientForLatest, nil)
if err2 != nil {
err = err2
} else {
@@ -112,18 +121,18 @@
// fetch fetches a module using the configured ModuleGetters.
// It tries each getter in turn until it finds one that has the module.
-func (ds *dataSource) fetch(ctx context.Context, modulePath, version string) (_ *internal.Module, err error) {
+func (ds *DataSource) fetch(ctx context.Context, modulePath, version string) (_ *internal.Module, err error) {
log.Infof(ctx, "DataSource: fetching %s@%s", modulePath, version)
start := time.Now()
defer func() {
log.Infof(ctx, "DataSource: fetched %s@%s in %s with error %v", modulePath, version, time.Since(start), err)
}()
- for _, g := range ds.getters {
- fr := fetch.FetchModule(ctx, modulePath, version, g, ds.sourceClient)
+ for _, g := range ds.opts.Getters {
+ fr := fetch.FetchModule(ctx, modulePath, version, g, ds.opts.SourceClient)
defer fr.Defer()
if fr.Error == nil {
m := fr.Module
- if ds.bypassLicenseCheck {
+ if ds.opts.BypassLicenseCheck {
m.IsRedistributable = true
for _, unit := range m.Units {
unit.IsRedistributable = true
@@ -142,7 +151,7 @@
// findModule finds the module with longest module path containing the given
// package path. It returns an error if no module is found.
-func (ds *dataSource) findModule(ctx context.Context, pkgPath, modulePath, version string) (_ *internal.Module, err error) {
+func (ds *DataSource) findModule(ctx context.Context, pkgPath, modulePath, version string) (_ *internal.Module, err error) {
defer derrors.Wrap(&err, "findModule(%q, %q, %q)", pkgPath, modulePath, version)
if modulePath != internal.UnknownModulePath {
@@ -162,7 +171,7 @@
}
// GetUnitMeta returns information about a path.
-func (ds *dataSource) GetUnitMeta(ctx context.Context, path, requestedModulePath, requestedVersion string) (_ *internal.UnitMeta, err error) {
+func (ds *DataSource) GetUnitMeta(ctx context.Context, path, requestedModulePath, requestedVersion string) (_ *internal.UnitMeta, err error) {
defer derrors.Wrap(&err, "GetUnitMeta(%q, %q, %q)", path, requestedModulePath, requestedVersion)
module, err := ds.findModule(ctx, path, requestedModulePath, requestedVersion)
@@ -182,7 +191,7 @@
// GetUnit returns information about a unit. Both the module path and package
// path must be known.
-func (ds *dataSource) GetUnit(ctx context.Context, um *internal.UnitMeta, fields internal.FieldSet, bc internal.BuildContext) (_ *internal.Unit, err error) {
+func (ds *DataSource) GetUnit(ctx context.Context, um *internal.UnitMeta, fields internal.FieldSet, bc internal.BuildContext) (_ *internal.Unit, err error) {
defer derrors.Wrap(&err, "GetUnit(%q, %q)", um.Path, um.ModulePath)
m, err := ds.getModule(ctx, um.ModulePath, um.Version)
@@ -206,10 +215,10 @@
}
// GetLatestInfo returns latest information for unitPath and modulePath.
-func (ds *dataSource) GetLatestInfo(ctx context.Context, unitPath, modulePath string, latestUnitMeta *internal.UnitMeta) (latest internal.LatestInfo, err error) {
+func (ds *DataSource) GetLatestInfo(ctx context.Context, unitPath, modulePath string, latestUnitMeta *internal.UnitMeta) (latest internal.LatestInfo, err error) {
defer derrors.Wrap(&err, "GetLatestInfo(ctx, %q, %q)", unitPath, modulePath)
- if ds.prox == nil {
+ if ds.opts.ProxyClientForLatest == nil {
return internal.LatestInfo{}, nil
}
@@ -235,10 +244,10 @@
// of the latest version found in the proxy by iterating through vN versions.
// This function does not attempt to find whether the full path exists
// in the new major version.
-func (ds *dataSource) getLatestMajorVersion(ctx context.Context, fullPath, modulePath string) (_ string, _ string, err error) {
+func (ds *DataSource) getLatestMajorVersion(ctx context.Context, fullPath, modulePath string) (_ string, _ string, err error) {
// We are checking if the full path is valid so that we can forward the error if not.
seriesPath := internal.SeriesPathForModule(modulePath)
- info, err := ds.prox.Info(ctx, seriesPath, version.Latest)
+ info, err := ds.opts.ProxyClientForLatest.Info(ctx, seriesPath, version.Latest)
if err != nil {
return "", "", err
}
@@ -262,7 +271,7 @@
for v := startVersion; ; v++ {
query := fmt.Sprintf("%s/v%d", seriesPath, v)
- _, err := ds.prox.Info(ctx, query, version.Latest)
+ _, err := ds.opts.ProxyClientForLatest.Info(ctx, query, version.Latest)
if errors.Is(err, derrors.NotFound) {
if v == 2 {
return modulePath, fullPath, nil
@@ -275,3 +284,13 @@
}
}
}
+
+// GetNestedModules is not implemented.
+func (ds *DataSource) GetNestedModules(ctx context.Context, modulePath string) ([]*internal.ModuleInfo, error) {
+ return nil, nil
+}
+
+// GetModuleReadme is not implemented.
+func (*DataSource) GetModuleReadme(ctx context.Context, modulePath, resolvedVersion string) (*internal.Readme, error) {
+ return nil, nil
+}
diff --git a/internal/datasource/datasource_test.go b/internal/datasource/datasource_test.go
index 88b8978..dbaf735 100644
--- a/internal/datasource/datasource_test.go
+++ b/internal/datasource/datasource_test.go
@@ -5,15 +5,507 @@
package datasource
import (
+ "context"
+ "errors"
+ "fmt"
+ "log"
+ "os"
"testing"
+ "time"
+ "github.com/google/go-cmp/cmp"
+ "github.com/google/go-cmp/cmp/cmpopts"
+ "github.com/google/safehtml/template"
"golang.org/x/pkgsite/internal"
"golang.org/x/pkgsite/internal/derrors"
"golang.org/x/pkgsite/internal/fetch"
+ "golang.org/x/pkgsite/internal/godoc/dochtml"
+ "golang.org/x/pkgsite/internal/licenses"
+ "golang.org/x/pkgsite/internal/proxy"
+ "golang.org/x/pkgsite/internal/proxy/proxytest"
+ "golang.org/x/pkgsite/internal/source"
+ "golang.org/x/pkgsite/internal/stdlib"
+ "golang.org/x/pkgsite/internal/testing/testhelper"
+ "golang.org/x/pkgsite/internal/version"
)
+var (
+ defaultTestModules []*proxytest.Module
+ localGetters []fetch.ModuleGetter
+)
+
+func TestMain(m *testing.M) {
+ dochtml.LoadTemplates(template.TrustedSourceFromConstant("../../static/doc"))
+ defaultTestModules = proxytest.LoadTestModules("../proxy/testdata")
+ var cleanup func()
+ localGetters, cleanup = buildLocalGetters()
+ defer cleanup()
+ licenses.OmitExceptions = true
+ os.Exit(m.Run())
+}
+
+func buildLocalGetters() ([]fetch.ModuleGetter, func()) {
+ modules := []map[string]string{
+ {
+ "go.mod": "module github.com/my/module\n\ngo 1.12",
+ "LICENSE": testhelper.BSD0License,
+ "README.md": "README FILE FOR TESTING.",
+ "bar/COPYING": testhelper.MITLicense,
+ "bar/README.md": "Another README FILE FOR TESTING.",
+ "bar/bar.go": `
+ // package bar
+ package bar
+
+ // Bar returns the string "bar".
+ func Bar() string {
+ return "bar"
+ }`,
+ "foo/LICENSE.md": testhelper.MITLicense,
+ "foo/foo.go": `
+ // package foo
+ package foo
+
+ import (
+ "fmt"
+
+ "github.com/my/module/bar"
+ )
+
+ // FooBar returns the string "foo bar".
+ func FooBar() string {
+ return fmt.Sprintf("foo %s", bar.Bar())
+ }`,
+ },
+ {
+ "go.mod": "module github.com/no/license\n\ngo 1.12",
+ "LICENSE": "unknown",
+ "bar/bar.go": `
+ // package bar
+ package bar
+
+ // Bar returns the string "bar".
+ func Bar() string {
+ return "bar"
+ }`,
+ },
+ }
+
+ var (
+ dirs []string
+ getters []fetch.ModuleGetter
+ )
+ for _, module := range modules {
+ directory, err := testhelper.CreateTestDirectory(module)
+ if err != nil {
+ log.Fatal(err)
+ }
+ dirs = append(dirs, directory)
+ mg, err := fetch.NewDirectoryModuleGetter("", directory)
+ if err != nil {
+ log.Fatal(err)
+ }
+ getters = append(getters, mg)
+ }
+ return getters, func() {
+ for _, d := range dirs {
+ os.RemoveAll(d)
+ }
+ }
+}
+
+func setup(t *testing.T, testModules []*proxytest.Module, bypassLicenseCheck bool) (context.Context, *DataSource, func()) {
+ t.Helper()
+ ctx, cancel := context.WithTimeout(context.Background(), 40*time.Second)
+
+ var client *proxy.Client
+ teardownProxy := func() {}
+ if testModules != nil {
+ client, teardownProxy = proxytest.SetupTestClient(t, testModules)
+ }
+
+ getters := localGetters
+ if testModules != nil {
+ getters = append(getters, fetch.NewProxyModuleGetter(client))
+ }
+
+ return ctx, Options{
+ Getters: getters,
+ SourceClient: source.NewClientForTesting(),
+ ProxyClientForLatest: client,
+ BypassLicenseCheck: bypassLicenseCheck,
+ }.New(), func() {
+ teardownProxy()
+ cancel()
+ }
+}
+
+func TestProxyGetUnitMeta(t *testing.T) {
+ ctx, ds, teardown := setup(t, defaultTestModules, false)
+ defer teardown()
+
+ singleModInfo := internal.ModuleInfo{
+ ModulePath: "example.com/single",
+ Version: "v1.0.0",
+ IsRedistributable: true,
+ CommitTime: proxytest.CommitTime,
+ HasGoMod: true,
+ }
+
+ for _, test := range []struct {
+ path, modulePath, version string
+ want *internal.UnitMeta
+ }{
+ {
+ path: "example.com/single",
+ modulePath: "example.com/single",
+ version: "v1.0.0",
+ want: &internal.UnitMeta{
+ ModuleInfo: singleModInfo,
+ IsRedistributable: true,
+ },
+ },
+ {
+ path: "example.com/single/pkg",
+ modulePath: "example.com/single",
+ version: "v1.0.0",
+ want: &internal.UnitMeta{
+ ModuleInfo: singleModInfo,
+ Name: "pkg",
+ IsRedistributable: true,
+ },
+ },
+ {
+ path: "example.com/single/pkg",
+ modulePath: internal.UnknownModulePath,
+ version: "v1.0.0",
+ want: &internal.UnitMeta{
+ ModuleInfo: singleModInfo,
+ Name: "pkg",
+ IsRedistributable: true,
+ },
+ },
+ {
+ path: "example.com/basic",
+ modulePath: internal.UnknownModulePath,
+ version: version.Latest,
+ want: &internal.UnitMeta{
+ ModuleInfo: internal.ModuleInfo{
+ ModulePath: "example.com/basic",
+ Version: "v1.1.0",
+ IsRedistributable: true,
+ CommitTime: proxytest.CommitTime,
+ HasGoMod: true,
+ },
+ Name: "basic",
+ IsRedistributable: true,
+ },
+ },
+ } {
+ t.Run(test.path, func(t *testing.T) {
+ got, err := ds.GetUnitMeta(ctx, test.path, test.modulePath, test.version)
+ if err != nil {
+ t.Fatal(err)
+ }
+ test.want.Path = test.path
+ if diff := cmp.Diff(test.want, got, cmpopts.IgnoreFields(internal.ModuleInfo{}, "SourceInfo")); diff != "" {
+ t.Errorf("mismatch (-want +got):\n%s", diff)
+ }
+ })
+ }
+}
+
+func TestBypass(t *testing.T) {
+ for _, bypass := range []bool{false, true} {
+ t.Run(fmt.Sprintf("bypass=%t", bypass), func(t *testing.T) {
+ // re-create the data source to get around caching
+ ctx, ds, teardown := setup(t, defaultTestModules, bypass)
+ defer teardown()
+ for _, test := range []struct {
+ path string
+ wantEmpty bool
+ }{
+ {"example.com/basic", false},
+ {"example.com/nonredist/unk", !bypass},
+ } {
+ t.Run(test.path, func(t *testing.T) {
+ um, err := ds.GetUnitMeta(ctx, test.path, internal.UnknownModulePath, "v1.0.0")
+ if err != nil {
+ t.Fatal(err)
+ }
+ got, err := ds.GetUnit(ctx, um, 0, internal.BuildContext{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Assume internal.Module.RemoveNonRedistributableData is correct; we just
+ // need to check one value to confirm that it was called.
+ if gotEmpty := (got.Documentation == nil); gotEmpty != test.wantEmpty {
+ t.Errorf("got empty %t, want %t", gotEmpty, test.wantEmpty)
+ }
+ })
+ }
+ })
+ }
+}
+
+func TestGetLatestInfo(t *testing.T) {
+ testModules := []*proxytest.Module{
+ {
+ ModulePath: "foo.com/bar",
+ Version: "v1.1.0",
+ Files: map[string]string{
+ "baz.go": "package bar",
+ },
+ },
+ {
+ ModulePath: "foo.com/bar/v2",
+ Version: "v2.0.5",
+ },
+ {
+ ModulePath: "foo.com/bar/v3",
+ },
+ {
+ ModulePath: "bar.com/foo",
+ Version: "v1.1.0",
+ Files: map[string]string{
+ "baz.go": "package foo",
+ },
+ },
+ {
+ ModulePath: "incompatible.com/bar",
+ Version: "v2.1.1+incompatible",
+ Files: map[string]string{
+ "baz.go": "package bar",
+ },
+ },
+ {
+ ModulePath: "incompatible.com/bar/v3",
+ },
+ }
+ ctx, ds, teardown := setup(t, testModules, false)
+ defer teardown()
+ for _, test := range []struct {
+ fullPath string
+ modulePath string
+ wantModulePath string
+ wantPackagePath string
+ wantErr error
+ }{
+ {
+ fullPath: "foo.com/bar",
+ modulePath: "foo.com/bar",
+ wantModulePath: "foo.com/bar/v3",
+ wantPackagePath: "foo.com/bar/v3",
+ },
+ {
+ fullPath: "bar.com/foo",
+ modulePath: "bar.com/foo",
+ wantModulePath: "bar.com/foo",
+ wantPackagePath: "bar.com/foo",
+ },
+ {
+ fullPath: "boo.com/far",
+ modulePath: "boo.com/far",
+ wantErr: derrors.NotFound,
+ },
+ {
+ fullPath: "foo.com/bar/baz",
+ modulePath: "foo.com/bar",
+ wantModulePath: "foo.com/bar/v3",
+ wantPackagePath: "foo.com/bar/v3",
+ },
+ {
+ fullPath: "incompatible.com/bar",
+ modulePath: "incompatible.com/bar",
+ wantModulePath: "incompatible.com/bar/v3",
+ wantPackagePath: "incompatible.com/bar/v3",
+ },
+ } {
+ gotLatest, err := ds.GetLatestInfo(ctx, test.fullPath, test.modulePath, nil)
+ if err != nil {
+ if test.wantErr == nil {
+ t.Fatalf("got unexpected error %v", err)
+ }
+ if !errors.Is(err, test.wantErr) {
+ t.Errorf("got err = %v, want Is(%v)", err, test.wantErr)
+ }
+ }
+ if gotLatest.MajorModulePath != test.wantModulePath || gotLatest.MajorUnitPath != test.wantPackagePath {
+ t.Errorf("ds.GetLatestMajorVersion(%v, %v) = (%v, %v), want = (%v, %v)",
+ test.fullPath, test.modulePath, gotLatest.MajorModulePath, gotLatest.MajorUnitPath, test.wantModulePath, test.wantPackagePath)
+ }
+ }
+}
+
+func TestLocalGetUnitMeta(t *testing.T) {
+ ctx, ds, teardown := setup(t, nil, true)
+ defer teardown()
+
+ sourceInfo := source.NewGitHubInfo("https://github.com/my/module", "", "v0.0.0")
+ for _, test := range []struct {
+ path, modulePath string
+ want *internal.UnitMeta
+ wantErr error
+ }{
+ {
+ path: "github.com/my/module",
+ modulePath: "github.com/my/module",
+ want: &internal.UnitMeta{
+ Path: "github.com/my/module",
+ ModuleInfo: internal.ModuleInfo{
+ ModulePath: "github.com/my/module",
+ Version: fetch.LocalVersion,
+ CommitTime: fetch.LocalCommitTime,
+ IsRedistributable: true,
+ HasGoMod: true,
+ SourceInfo: sourceInfo,
+ },
+ IsRedistributable: true,
+ },
+ },
+ {
+ path: "github.com/my/module/bar",
+ modulePath: "github.com/my/module",
+ want: &internal.UnitMeta{
+ Path: "github.com/my/module/bar",
+ Name: "bar",
+ ModuleInfo: internal.ModuleInfo{
+ ModulePath: "github.com/my/module",
+ Version: fetch.LocalVersion,
+ CommitTime: fetch.LocalCommitTime,
+ IsRedistributable: true,
+ HasGoMod: true,
+ SourceInfo: sourceInfo,
+ },
+ IsRedistributable: true,
+ },
+ },
+ {
+ path: "github.com/my/module/foo",
+ modulePath: "github.com/my/module",
+ want: &internal.UnitMeta{
+ Path: "github.com/my/module/foo",
+ Name: "foo",
+ ModuleInfo: internal.ModuleInfo{
+ ModulePath: "github.com/my/module",
+ IsRedistributable: true,
+ Version: fetch.LocalVersion,
+ CommitTime: fetch.LocalCommitTime,
+ HasGoMod: true,
+ SourceInfo: sourceInfo,
+ },
+ IsRedistributable: true,
+ },
+ },
+ {
+ path: "github.com/my/module/bar",
+ modulePath: internal.UnknownModulePath,
+ want: &internal.UnitMeta{
+ Path: "github.com/my/module/bar",
+ Name: "bar",
+ IsRedistributable: true,
+ ModuleInfo: internal.ModuleInfo{
+ ModulePath: "github.com/my/module",
+ Version: fetch.LocalVersion,
+ CommitTime: fetch.LocalCommitTime,
+ IsRedistributable: true,
+ HasGoMod: true,
+ SourceInfo: sourceInfo,
+ },
+ },
+ },
+ {
+ path: "github.com/not/loaded",
+ modulePath: internal.UnknownModulePath,
+ wantErr: derrors.NotFound,
+ },
+ {
+ path: "net/http",
+ modulePath: stdlib.ModulePath,
+ wantErr: derrors.InvalidArgument,
+ },
+ } {
+ t.Run(test.path, func(t *testing.T) {
+ got, err := ds.GetUnitMeta(ctx, test.path, test.modulePath, fetch.LocalVersion)
+ if test.wantErr != nil {
+ if !errors.Is(err, test.wantErr) {
+ t.Errorf("GetUnitMeta(%q, %q): %v; wantErr = %v)", test.path, test.modulePath, err, test.wantErr)
+ }
+ } else {
+ if err != nil {
+ t.Fatal(err)
+ }
+ if diff := cmp.Diff(test.want, got, cmp.AllowUnexported(source.Info{})); diff != "" {
+ t.Errorf("mismatch (-want +got):\n%s", diff)
+
+ }
+ }
+ })
+ }
+}
+
+func TestLocalGetUnit(t *testing.T) {
+ // This is a simple test to verify that data is fetched correctly. The
+ // return value of FetchResult is tested in internal/fetch so no need
+ // to repeat it.
+ ctx, ds, teardown := setup(t, nil, true)
+ defer teardown()
+
+ for _, test := range []struct {
+ path, modulePath string
+ wantLoaded bool
+ }{
+ {
+ path: "github.com/my/module",
+ modulePath: "github.com/my/module",
+ wantLoaded: true,
+ },
+ {
+ path: "github.com/my/module/foo",
+ modulePath: "github.com/my/module",
+ wantLoaded: true,
+ },
+ {
+ path: "github.com/no/license/bar",
+ modulePath: "github.com/no/license",
+ wantLoaded: true,
+ },
+ {
+ path: "github.com/not/loaded",
+ modulePath: internal.UnknownModulePath,
+ },
+ } {
+ t.Run(test.path, func(t *testing.T) {
+ um := &internal.UnitMeta{
+ Path: test.path,
+ ModuleInfo: internal.ModuleInfo{ModulePath: test.modulePath},
+ }
+ got, err := ds.GetUnit(ctx, um, 0, internal.BuildContext{})
+ if !test.wantLoaded {
+ if err == nil {
+ t.Fatal("returned not loaded module")
+ }
+ return
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if gotEmpty := (got.Documentation == nil && got.Readme == nil); gotEmpty {
+ t.Errorf("gotEmpty = %t", gotEmpty)
+ }
+ if got.Documentation != nil {
+ want := []internal.BuildContext{internal.BuildContextAll}
+ if !cmp.Equal(got.BuildContexts, want) {
+ t.Errorf("got %v, want %v", got.BuildContexts, want)
+ }
+ }
+ })
+ }
+}
+
func TestCache(t *testing.T) {
- ds := newDataSource(nil, nil, false, nil)
+ ds := Options{}.New()
m1 := &internal.Module{}
ds.cachePut("m1", fetch.LocalVersion, m1, nil)
ds.cachePut("m2", "v1.0.0", nil, derrors.NotFound)
diff --git a/internal/datasource/gopath_getter.go b/internal/datasource/gopath_getter.go
new file mode 100644
index 0000000..26f19c3
--- /dev/null
+++ b/internal/datasource/gopath_getter.go
@@ -0,0 +1,41 @@
+// Copyright 2021 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 datasource
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+
+ "golang.org/x/pkgsite/internal/derrors"
+ "golang.org/x/pkgsite/internal/fetch"
+)
+
+// NewGOPATHModuleGetter returns a module getter that uses the GOPATH
+// environment variable to find the module with the given import path.
+func NewGOPATHModuleGetter(importPath string) (_ fetch.ModuleGetter, err error) {
+ defer derrors.Wrap(&err, "NewGOPATHModuleGetter(%q)", importPath)
+
+ dir := getFullPath(importPath)
+ if dir == "" {
+ return nil, fmt.Errorf("path %s doesn't exist: %w", importPath, derrors.NotFound)
+ }
+ return fetch.NewDirectoryModuleGetter(importPath, dir)
+}
+
+// getFullPath takes an import path, tests it relative to each GOPATH, and returns
+// a full path to the module. If the given import path doesn't exist in any GOPATH,
+// an empty string is returned.
+func getFullPath(modulePath string) string {
+ gopaths := filepath.SplitList(os.Getenv("GOPATH"))
+ for _, gopath := range gopaths {
+ path := filepath.Join(gopath, "src", modulePath)
+ info, err := os.Stat(path)
+ if err == nil && info.IsDir() {
+ return path
+ }
+ }
+ return ""
+}
diff --git a/internal/datasource/local.go b/internal/datasource/local.go
deleted file mode 100644
index feffa36..0000000
--- a/internal/datasource/local.go
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2020 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 datasource
-
-import (
- "context"
- "fmt"
- "os"
- "path/filepath"
-
- "golang.org/x/pkgsite/internal"
- "golang.org/x/pkgsite/internal/derrors"
- "golang.org/x/pkgsite/internal/fetch"
- "golang.org/x/pkgsite/internal/source"
-)
-
-// LocalDataSource implements an in-memory internal.DataSource used to display documentation
-// locally. It is not backed by a database or a proxy instance.
-type LocalDataSource struct {
- sourceClient *source.Client
- ds *dataSource
-}
-
-// New creates and returns a new local datasource that bypasses license
-// checks by default.
-func NewLocal(getters []fetch.ModuleGetter, sc *source.Client) *LocalDataSource {
- return &LocalDataSource{
- sourceClient: sc,
- ds: newDataSource(getters, sc, true, nil),
- }
-}
-
-// NewGOPATHModuleGetter returns a module getter that uses the GOPATH
-// environment variable to find the module with the given import path.
-func NewGOPATHModuleGetter(importPath string) (_ fetch.ModuleGetter, err error) {
- defer derrors.Wrap(&err, "NewGOPATHModuleGetter(%q)", importPath)
-
- dir := getFullPath(importPath)
- if dir == "" {
- return nil, fmt.Errorf("path %s doesn't exist: %w", importPath, derrors.NotFound)
- }
- return fetch.NewDirectoryModuleGetter(importPath, dir)
-}
-
-// getFullPath takes an import path, tests it relative to each GOPATH, and returns
-// a full path to the module. If the given import path doesn't exist in any GOPATH,
-// an empty string is returned.
-func getFullPath(modulePath string) string {
- gopaths := filepath.SplitList(os.Getenv("GOPATH"))
- for _, gopath := range gopaths {
- path := filepath.Join(gopath, "src", modulePath)
- info, err := os.Stat(path)
- if err == nil && info.IsDir() {
- return path
- }
- }
- return ""
-}
-
-func (ds *LocalDataSource) GetUnitMeta(ctx context.Context, path, requestedModulePath, requestedVersion string) (_ *internal.UnitMeta, err error) {
- return ds.ds.GetUnitMeta(ctx, path, requestedModulePath, requestedVersion)
-}
-
-// GetUnit returns information about a unit. Both the module path and package
-// path must be known.
-func (ds *LocalDataSource) GetUnit(ctx context.Context, pathInfo *internal.UnitMeta, fields internal.FieldSet, bc internal.BuildContext) (_ *internal.Unit, err error) {
- return ds.ds.GetUnit(ctx, pathInfo, fields, bc)
-}
-
-// GetLatestInfo is not implemented.
-func (ds *LocalDataSource) GetLatestInfo(ctx context.Context, unitPath, modulePath string, latestUnitMeta *internal.UnitMeta) (internal.LatestInfo, error) {
- return ds.ds.GetLatestInfo(ctx, unitPath, modulePath, latestUnitMeta)
-}
-
-// GetNestedModules is not implemented.
-func (ds *LocalDataSource) GetNestedModules(ctx context.Context, modulePath string) ([]*internal.ModuleInfo, error) {
- return nil, nil
-}
-
-// GetModuleReadme is not implemented.
-func (*LocalDataSource) GetModuleReadme(ctx context.Context, modulePath, resolvedVersion string) (*internal.Readme, error) {
- return nil, nil
-}
diff --git a/internal/datasource/local_test.go b/internal/datasource/local_test.go
deleted file mode 100644
index 9f0ee78..0000000
--- a/internal/datasource/local_test.go
+++ /dev/null
@@ -1,262 +0,0 @@
-// Copyright 2020 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 datasource
-
-import (
- "context"
- "errors"
- "log"
- "os"
- "testing"
- "time"
-
- "github.com/google/go-cmp/cmp"
- "golang.org/x/pkgsite/internal"
- "golang.org/x/pkgsite/internal/derrors"
- "golang.org/x/pkgsite/internal/fetch"
- "golang.org/x/pkgsite/internal/source"
- "golang.org/x/pkgsite/internal/stdlib"
- "golang.org/x/pkgsite/internal/testing/testhelper"
-)
-
-var datasource *LocalDataSource
-
-func setupLocal() func() {
- modules := []map[string]string{
- {
- "go.mod": "module github.com/my/module\n\ngo 1.12",
- "LICENSE": testhelper.BSD0License,
- "README.md": "README FILE FOR TESTING.",
- "bar/COPYING": testhelper.MITLicense,
- "bar/README.md": "Another README FILE FOR TESTING.",
- "bar/bar.go": `
- // package bar
- package bar
-
- // Bar returns the string "bar".
- func Bar() string {
- return "bar"
- }`,
- "foo/LICENSE.md": testhelper.MITLicense,
- "foo/foo.go": `
- // package foo
- package foo
-
- import (
- "fmt"
-
- "github.com/my/module/bar"
- )
-
- // FooBar returns the string "foo bar".
- func FooBar() string {
- return fmt.Sprintf("foo %s", bar.Bar())
- }`,
- },
- {
- "go.mod": "module github.com/no/license\n\ngo 1.12",
- "LICENSE": "unknown",
- "bar/bar.go": `
- // package bar
- package bar
-
- // Bar returns the string "bar".
- func Bar() string {
- return "bar"
- }`,
- },
- }
-
- var (
- dirs []string
- getters []fetch.ModuleGetter
- )
- for _, module := range modules {
- directory, err := testhelper.CreateTestDirectory(module)
- if err != nil {
- log.Fatal(err)
- }
- dirs = append(dirs, directory)
- mg, err := fetch.NewDirectoryModuleGetter("", directory)
- if err != nil {
- log.Fatal(err)
- }
- getters = append(getters, mg)
- }
- datasource = NewLocal(getters, source.NewClientForTesting())
-
- return func() {
- for _, d := range dirs {
- os.RemoveAll(d)
- }
- }
-}
-
-func TestLocalGetUnitMeta(t *testing.T) {
- ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
- defer cancel()
-
- sourceInfo := source.NewGitHubInfo("https://github.com/my/module", "", "v0.0.0")
- for _, test := range []struct {
- path, modulePath string
- want *internal.UnitMeta
- wantErr error
- }{
- {
- path: "github.com/my/module",
- modulePath: "github.com/my/module",
- want: &internal.UnitMeta{
- Path: "github.com/my/module",
- ModuleInfo: internal.ModuleInfo{
- ModulePath: "github.com/my/module",
- Version: fetch.LocalVersion,
- CommitTime: fetch.LocalCommitTime,
- IsRedistributable: true,
- HasGoMod: true,
- SourceInfo: sourceInfo,
- },
- IsRedistributable: true,
- },
- },
- {
- path: "github.com/my/module/bar",
- modulePath: "github.com/my/module",
- want: &internal.UnitMeta{
- Path: "github.com/my/module/bar",
- Name: "bar",
- ModuleInfo: internal.ModuleInfo{
- ModulePath: "github.com/my/module",
- Version: fetch.LocalVersion,
- CommitTime: fetch.LocalCommitTime,
- IsRedistributable: true,
- HasGoMod: true,
- SourceInfo: sourceInfo,
- },
- IsRedistributable: true,
- },
- },
- {
- path: "github.com/my/module/foo",
- modulePath: "github.com/my/module",
- want: &internal.UnitMeta{
- Path: "github.com/my/module/foo",
- Name: "foo",
- ModuleInfo: internal.ModuleInfo{
- ModulePath: "github.com/my/module",
- IsRedistributable: true,
- Version: fetch.LocalVersion,
- CommitTime: fetch.LocalCommitTime,
- HasGoMod: true,
- SourceInfo: sourceInfo,
- },
- IsRedistributable: true,
- },
- },
- {
- path: "github.com/my/module/bar",
- modulePath: internal.UnknownModulePath,
- want: &internal.UnitMeta{
- Path: "github.com/my/module/bar",
- Name: "bar",
- IsRedistributable: true,
- ModuleInfo: internal.ModuleInfo{
- ModulePath: "github.com/my/module",
- Version: fetch.LocalVersion,
- CommitTime: fetch.LocalCommitTime,
- IsRedistributable: true,
- HasGoMod: true,
- SourceInfo: sourceInfo,
- },
- },
- },
- {
- path: "github.com/not/loaded",
- modulePath: internal.UnknownModulePath,
- wantErr: derrors.NotFound,
- },
- {
- path: "net/http",
- modulePath: stdlib.ModulePath,
- wantErr: derrors.InvalidArgument,
- },
- } {
- t.Run(test.path, func(t *testing.T) {
- got, err := datasource.GetUnitMeta(ctx, test.path, test.modulePath, fetch.LocalVersion)
- if test.wantErr != nil {
- if !errors.Is(err, test.wantErr) {
- t.Errorf("GetUnitMeta(%q, %q): %v; wantErr = %v)", test.path, test.modulePath, err, test.wantErr)
- }
- } else {
- if err != nil {
- t.Fatal(err)
- }
- if diff := cmp.Diff(test.want, got, cmp.AllowUnexported(source.Info{})); diff != "" {
- t.Errorf("mismatch (-want +got):\n%s", diff)
-
- }
- }
- })
- }
-}
-
-func TestLocalGetUnit(t *testing.T) {
- // This is a simple test to verify that data is fetched correctly. The
- // return value of FetchResult is tested in internal/fetch so no need
- // to repeat it.
- ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
- defer cancel()
-
- for _, test := range []struct {
- path, modulePath string
- wantLoaded bool
- }{
- {
- path: "github.com/my/module",
- modulePath: "github.com/my/module",
- wantLoaded: true,
- },
- {
- path: "github.com/my/module/foo",
- modulePath: "github.com/my/module",
- wantLoaded: true,
- },
- {
- path: "github.com/no/license/bar",
- modulePath: "github.com/no/license",
- wantLoaded: true,
- },
- {
- path: "github.com/not/loaded",
- modulePath: internal.UnknownModulePath,
- },
- } {
- t.Run(test.path, func(t *testing.T) {
- um := &internal.UnitMeta{
- Path: test.path,
- ModuleInfo: internal.ModuleInfo{ModulePath: test.modulePath},
- }
- got, err := datasource.GetUnit(ctx, um, 0, internal.BuildContext{})
- if !test.wantLoaded {
- if err == nil {
- t.Fatal("returned not loaded module")
- }
- return
- }
- if err != nil {
- t.Fatal(err)
- }
-
- if gotEmpty := (got.Documentation == nil && got.Readme == nil); gotEmpty {
- t.Errorf("gotEmpty = %t", gotEmpty)
- }
- if got.Documentation != nil {
- want := []internal.BuildContext{internal.BuildContextAll}
- if !cmp.Equal(got.BuildContexts, want) {
- t.Errorf("got %v, want %v", got.BuildContexts, want)
- }
- }
- })
- }
-}
diff --git a/internal/datasource/proxy.go b/internal/datasource/proxy.go
deleted file mode 100644
index bafd6d5..0000000
--- a/internal/datasource/proxy.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2019 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 datasource
-
-import (
- "context"
- "time"
-
- "golang.org/x/pkgsite/internal"
- "golang.org/x/pkgsite/internal/fetch"
- "golang.org/x/pkgsite/internal/proxy"
- "golang.org/x/pkgsite/internal/source"
-)
-
-var _ internal.DataSource = (*ProxyDataSource)(nil)
-
-// New returns a new direct proxy datasource.
-func NewProxy(proxyClient *proxy.Client) *ProxyDataSource {
- return newProxyDataSource(proxyClient, source.NewClient(1*time.Minute), false)
-}
-
-func NewForTesting(proxyClient *proxy.Client, bypassLicenseCheck bool) *ProxyDataSource {
- return newProxyDataSource(proxyClient, source.NewClientForTesting(), bypassLicenseCheck)
-}
-
-func newProxyDataSource(proxyClient *proxy.Client, sourceClient *source.Client, bypassLicenseCheck bool) *ProxyDataSource {
- ds := newDataSource([]fetch.ModuleGetter{fetch.NewProxyModuleGetter(proxyClient)}, sourceClient, bypassLicenseCheck, proxyClient)
- return &ProxyDataSource{
- ds: ds,
- }
-}
-
-// NewBypassingLicenseCheck returns a new direct proxy datasource that bypasses
-// license checks. That means all data will be returned for non-redistributable
-// modules, packages and directories.
-func NewBypassingLicenseCheck(c *proxy.Client) *ProxyDataSource {
- return newProxyDataSource(c, source.NewClient(1*time.Minute), true)
-}
-
-// ProxyDataSource implements the frontend.DataSource interface, by querying a
-// module proxy directly and caching the results in memory.
-type ProxyDataSource struct {
- ds *dataSource
-}
-
-// GetLatestInfo returns latest information for unitPath and modulePath.
-func (ds *ProxyDataSource) GetLatestInfo(ctx context.Context, unitPath, modulePath string, latestUnitMeta *internal.UnitMeta) (latest internal.LatestInfo, err error) {
- return ds.ds.GetLatestInfo(ctx, unitPath, modulePath, latestUnitMeta)
-}
diff --git a/internal/datasource/proxy_details.go b/internal/datasource/proxy_details.go
deleted file mode 100644
index 77f29fa..0000000
--- a/internal/datasource/proxy_details.go
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2019 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 datasource
-
-import (
- "context"
-
- "golang.org/x/pkgsite/internal"
- "golang.org/x/pkgsite/internal/derrors"
-)
-
-// GetUnit returns information about a directory at a path.
-func (ds *ProxyDataSource) GetUnit(ctx context.Context, um *internal.UnitMeta, field internal.FieldSet, bc internal.BuildContext) (_ *internal.Unit, err error) {
- defer derrors.Wrap(&err, "GetUnit(%q, %q, %q)", um.Path, um.ModulePath, um.Version)
- return ds.ds.GetUnit(ctx, um, field, bc)
-}
-
-func (ds *ProxyDataSource) GetUnitMeta(ctx context.Context, path, requestedModulePath, requestedVersion string) (_ *internal.UnitMeta, err error) {
- return ds.ds.GetUnitMeta(ctx, path, requestedModulePath, requestedVersion)
-}
-
-// GetExperiments is unimplemented.
-func (*ProxyDataSource) GetExperiments(ctx context.Context) ([]*internal.Experiment, error) {
- return nil, nil
-}
-
-// GetNestedModules will return an empty slice since it is not implemented in proxy mode.
-func (ds *ProxyDataSource) GetNestedModules(ctx context.Context, modulePath string) (_ []*internal.ModuleInfo, err error) {
- return nil, nil
-}
-
-// GetModuleReadme is unimplemented.
-func (ds *ProxyDataSource) GetModuleReadme(ctx context.Context, modulePath, resolvedVersion string) (*internal.Readme, error) {
- return nil, nil
-}
diff --git a/internal/datasource/proxy_test.go b/internal/datasource/proxy_test.go
deleted file mode 100644
index 9730c66..0000000
--- a/internal/datasource/proxy_test.go
+++ /dev/null
@@ -1,272 +0,0 @@
-// Copyright 2019 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 datasource
-
-import (
- "context"
- "errors"
- "fmt"
- "os"
- "testing"
- "time"
-
- "github.com/google/go-cmp/cmp"
- "github.com/google/go-cmp/cmp/cmpopts"
- "github.com/google/safehtml/template"
- "golang.org/x/pkgsite/internal"
- "golang.org/x/pkgsite/internal/derrors"
- "golang.org/x/pkgsite/internal/godoc/dochtml"
- "golang.org/x/pkgsite/internal/licenses"
- "golang.org/x/pkgsite/internal/proxy/proxytest"
- "golang.org/x/pkgsite/internal/testing/sample"
- "golang.org/x/pkgsite/internal/version"
-)
-
-var testModules []*proxytest.Module
-
-func TestMain(m *testing.M) {
- dochtml.LoadTemplates(template.TrustedSourceFromConstant("../../static/doc"))
- testModules = proxytest.LoadTestModules("../proxy/testdata")
- licenses.OmitExceptions = true
- defer setupLocal()()
- os.Exit(m.Run())
-}
-
-func setup(t *testing.T, bypassLicenseCheck bool) (context.Context, *ProxyDataSource, func()) {
- t.Helper()
- client, teardownProxy := proxytest.SetupTestClient(t, testModules)
- ctx, cancel := context.WithTimeout(context.Background(), 40*time.Second)
- return ctx, NewForTesting(client, bypassLicenseCheck), func() {
- teardownProxy()
- cancel()
- }
-}
-
-var (
- wantLicenseMD = sample.LicenseMetadata()[0]
- wantPackage = internal.Unit{
- UnitMeta: internal.UnitMeta{
- Path: "foo.com/bar/baz",
- Name: "baz",
- ModuleInfo: internal.ModuleInfo{
- ModulePath: "foo.com/bar",
- Version: "v1.2.0",
- CommitTime: time.Date(2019, 1, 30, 0, 0, 0, 0, time.UTC),
- IsRedistributable: true,
- },
- Licenses: []*licenses.Metadata{wantLicenseMD},
- IsRedistributable: true,
- },
- Imports: []string{"net/http"},
- Documentation: []*internal.Documentation{{
- Synopsis: "Package baz provides a helpful constant.",
- GOOS: "linux",
- GOARCH: "amd64",
- }},
- }
-)
-
-func TestProxyGetUnitMeta(t *testing.T) {
- ctx, ds, teardown := setup(t, false)
- defer teardown()
-
- singleModInfo := internal.ModuleInfo{
- ModulePath: "example.com/single",
- Version: "v1.0.0",
- IsRedistributable: true,
- CommitTime: proxytest.CommitTime,
- HasGoMod: true,
- }
-
- for _, test := range []struct {
- path, modulePath, version string
- want *internal.UnitMeta
- }{
- {
- path: "example.com/single",
- modulePath: "example.com/single",
- version: "v1.0.0",
- want: &internal.UnitMeta{
- ModuleInfo: singleModInfo,
- IsRedistributable: true,
- },
- },
- {
- path: "example.com/single/pkg",
- modulePath: "example.com/single",
- version: "v1.0.0",
- want: &internal.UnitMeta{
- ModuleInfo: singleModInfo,
- Name: "pkg",
- IsRedistributable: true,
- },
- },
- {
- path: "example.com/single/pkg",
- modulePath: internal.UnknownModulePath,
- version: "v1.0.0",
- want: &internal.UnitMeta{
- ModuleInfo: singleModInfo,
- Name: "pkg",
- IsRedistributable: true,
- },
- },
- {
- path: "example.com/basic",
- modulePath: internal.UnknownModulePath,
- version: version.Latest,
- want: &internal.UnitMeta{
- ModuleInfo: internal.ModuleInfo{
- ModulePath: "example.com/basic",
- Version: "v1.1.0",
- IsRedistributable: true,
- CommitTime: proxytest.CommitTime,
- HasGoMod: true,
- },
- Name: "basic",
- IsRedistributable: true,
- },
- },
- } {
- t.Run(test.path, func(t *testing.T) {
- got, err := ds.GetUnitMeta(ctx, test.path, test.modulePath, test.version)
- if err != nil {
- t.Fatal(err)
- }
- test.want.Path = test.path
- if diff := cmp.Diff(test.want, got, cmpopts.IgnoreFields(internal.ModuleInfo{}, "SourceInfo")); diff != "" {
- t.Errorf("mismatch (-want +got):\n%s", diff)
- }
- })
- }
-}
-
-func TestBypass(t *testing.T) {
- for _, bypass := range []bool{false, true} {
- t.Run(fmt.Sprintf("bypass=%t", bypass), func(t *testing.T) {
- // re-create the data source to get around caching
- ctx, ds, teardown := setup(t, bypass)
- defer teardown()
- for _, test := range []struct {
- path string
- wantEmpty bool
- }{
- {"example.com/basic", false},
- {"example.com/nonredist/unk", !bypass},
- } {
- t.Run(test.path, func(t *testing.T) {
- um, err := ds.GetUnitMeta(ctx, test.path, internal.UnknownModulePath, "v1.0.0")
- if err != nil {
- t.Fatal(err)
- }
- got, err := ds.GetUnit(ctx, um, 0, internal.BuildContext{})
- if err != nil {
- t.Fatal(err)
- }
-
- // Assume internal.Module.RemoveNonRedistributableData is correct; we just
- // need to check one value to confirm that it was called.
- if gotEmpty := (got.Documentation == nil); gotEmpty != test.wantEmpty {
- t.Errorf("got empty %t, want %t", gotEmpty, test.wantEmpty)
- }
- })
- }
- })
- }
-}
-
-func TestGetLatestInfo(t *testing.T) {
- t.Helper()
- testModules := []*proxytest.Module{
- {
- ModulePath: "foo.com/bar",
- Version: "v1.1.0",
- Files: map[string]string{
- "baz.go": "package bar",
- },
- },
- {
- ModulePath: "foo.com/bar/v2",
- Version: "v2.0.5",
- },
- {
- ModulePath: "foo.com/bar/v3",
- },
- {
- ModulePath: "bar.com/foo",
- Version: "v1.1.0",
- Files: map[string]string{
- "baz.go": "package foo",
- },
- },
- {
- ModulePath: "incompatible.com/bar",
- Version: "v2.1.1+incompatible",
- Files: map[string]string{
- "baz.go": "package bar",
- },
- },
- {
- ModulePath: "incompatible.com/bar/v3",
- },
- }
- client, teardownProxy := proxytest.SetupTestClient(t, testModules)
- defer teardownProxy()
- ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
- defer cancel()
- ds := NewForTesting(client, false)
-
- for _, test := range []struct {
- fullPath string
- modulePath string
- wantModulePath string
- wantPackagePath string
- wantErr error
- }{
- {
- fullPath: "foo.com/bar",
- modulePath: "foo.com/bar",
- wantModulePath: "foo.com/bar/v3",
- wantPackagePath: "foo.com/bar/v3",
- },
- {
- fullPath: "bar.com/foo",
- modulePath: "bar.com/foo",
- wantModulePath: "bar.com/foo",
- wantPackagePath: "bar.com/foo",
- },
- {
- fullPath: "boo.com/far",
- modulePath: "boo.com/far",
- wantErr: derrors.NotFound,
- },
- {
- fullPath: "foo.com/bar/baz",
- modulePath: "foo.com/bar",
- wantModulePath: "foo.com/bar/v3",
- wantPackagePath: "foo.com/bar/v3",
- },
- {
- fullPath: "incompatible.com/bar",
- modulePath: "incompatible.com/bar",
- wantModulePath: "incompatible.com/bar/v3",
- wantPackagePath: "incompatible.com/bar/v3",
- },
- } {
- gotLatest, err := ds.GetLatestInfo(ctx, test.fullPath, test.modulePath, nil)
- if err != nil {
- if test.wantErr == nil {
- t.Fatalf("got unexpected error %v", err)
- }
- if !errors.Is(err, test.wantErr) {
- t.Errorf("got err = %v, want Is(%v)", err, test.wantErr)
- }
- }
- if gotLatest.MajorModulePath != test.wantModulePath || gotLatest.MajorUnitPath != test.wantPackagePath {
- t.Errorf("ds.GetLatestMajorVersion(%v, %v) = (%v, %v), want = (%v, %v)",
- test.fullPath, test.modulePath, gotLatest.MajorModulePath, gotLatest.MajorUnitPath, test.wantModulePath, test.wantPackagePath)
- }
- }
-}