blob: b7010c2a73e69a54ae164c39ef28b8213dfc46d3 [file] [log] [blame]
// 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 fetch
import (
"context"
"errors"
"io"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"golang.org/x/pkgsite/internal"
"golang.org/x/pkgsite/internal/derrors"
"golang.org/x/pkgsite/internal/godoc"
"golang.org/x/pkgsite/internal/proxy"
"golang.org/x/pkgsite/internal/source"
"golang.org/x/pkgsite/internal/stdlib"
"golang.org/x/pkgsite/internal/testing/sample"
)
var (
testTimeout = 30 * time.Second
sourceTimeout = 1 * time.Second
)
func TestFetchModule(t *testing.T) {
stdlib.UseTestData = true
// Stub out the function used to share playground snippets
origPost := httpPost
httpPost = func(url string, contentType string, body io.Reader) (resp *http.Response, err error) {
w := httptest.NewRecorder()
w.WriteHeader(http.StatusOK)
return w.Result(), nil
}
defer func() { httpPost = origPost }()
defer func(oldmax int) { godoc.MaxDocumentationHTML = oldmax }(godoc.MaxDocumentationHTML)
godoc.MaxDocumentationHTML = 1 * megabyte
for _, test := range []struct {
name string
mod *testModule
fetchVersion string
}{
{name: "basic", mod: moduleNoGoMod},
{name: "wasm", mod: moduleWasm},
{name: "no go.mod file", mod: moduleOnePackage},
{name: "has go.mod", mod: moduleMultiPackage},
{name: "module with bad packages", mod: moduleBadPackages},
{name: "module with build constraints", mod: moduleBuildConstraints},
{name: "module with packages with bad import paths", mod: moduleBadImportPath},
{name: "module with documentation", mod: moduleDocTest},
{name: "documentation too large", mod: moduleDocTooLarge},
{name: "module with package-level example", mod: modulePackageExample},
{name: "module with function example", mod: moduleFuncExample},
{name: "module with type example", mod: moduleTypeExample},
{name: "module with method example", mod: moduleMethodExample},
{name: "module with nonredistributable packages", mod: moduleNonRedist},
{name: "stdlib module", mod: moduleStd},
{name: "master version of module", mod: moduleMaster, fetchVersion: "master"},
{name: "latest version of module", mod: moduleLatest, fetchVersion: "latest"},
} {
t.Run(test.name, func(t *testing.T) {
ctx := context.Background()
ctx, cancel := context.WithTimeout(ctx, 60*time.Second)
defer cancel()
modulePath := test.mod.mod.ModulePath
version := test.mod.mod.Version
fetchVersion := test.fetchVersion
if version == "" {
version = "v1.0.0"
}
if fetchVersion == "" {
fetchVersion = version
}
sourceClient := source.NewClient(sourceTimeout)
proxyClient, teardownProxy := proxy.SetupTestClient(t, []*proxy.Module{{
ModulePath: modulePath,
Version: version,
Files: test.mod.mod.Files,
}})
defer teardownProxy()
got := FetchModule(ctx, modulePath, fetchVersion, proxyClient, sourceClient)
defer got.Defer()
if got.Error != nil {
t.Fatal(got.Error)
}
d := licenseDetector(ctx, t, modulePath, got.ResolvedVersion, proxyClient)
fr := cleanFetchResult(test.mod.fr, d)
sortFetchResult(fr)
sortFetchResult(got)
opts := []cmp.Option{
cmpopts.IgnoreFields(internal.LegacyPackage{}, "DocumentationHTML"),
cmpopts.IgnoreFields(internal.Documentation{}, "HTML"),
cmpopts.IgnoreFields(internal.PackageVersionState{}, "Error"),
cmpopts.IgnoreFields(FetchResult{}, "Defer"),
cmp.AllowUnexported(source.Info{}),
cmpopts.EquateEmpty(),
}
opts = append(opts, sample.LicenseCmpOpts...)
if diff := cmp.Diff(fr, got, opts...); diff != "" {
t.Fatalf("mismatch (-want +got):\n%s", diff)
}
validateDocumentationHTML(t, got.Module, fr.Module)
})
}
}
func TestFetchModule_Errors(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), testTimeout)
defer cancel()
for _, test := range []struct {
name string
mod *testModule
wantErr error
wantGoModPath string
}{
{name: "alternative", mod: moduleAlternative, wantErr: derrors.AlternativeModule, wantGoModPath: "canonical"},
{name: "empty module", mod: moduleEmpty, wantErr: derrors.BadModule},
} {
t.Run(test.name, func(t *testing.T) {
modulePath := test.mod.mod.ModulePath
version := test.mod.mod.Version
if version == "" {
version = "v1.0.0"
}
proxyClient, teardownProxy := proxy.SetupTestClient(t, []*proxy.Module{{
ModulePath: modulePath,
Files: test.mod.mod.Files,
}})
defer teardownProxy()
sourceClient := source.NewClient(sourceTimeout)
got := FetchModule(ctx, modulePath, "v1.0.0", proxyClient, sourceClient)
defer got.Defer()
if !errors.Is(got.Error, test.wantErr) {
t.Fatalf("FetchModule(ctx, %q, v1.0.0, proxyClient, sourceClient): %v; wantErr = %v)", modulePath, got.Error, test.wantErr)
}
if test.wantGoModPath != "" {
if got == nil || got.GoModPath != test.wantGoModPath {
t.Errorf("got %+v, wanted GoModPath %q", got, test.wantGoModPath)
}
}
})
}
}