blob: 4ddd332dcb40e760e911df05810ebece22d165ce [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 (
"archive/zip"
"context"
"net/http"
"sort"
"strings"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/google/safehtml"
"golang.org/x/pkgsite/internal"
"golang.org/x/pkgsite/internal/licenses"
"golang.org/x/pkgsite/internal/log"
"golang.org/x/pkgsite/internal/proxy"
"golang.org/x/pkgsite/internal/stdlib"
"golang.org/x/pkgsite/internal/version"
)
var testProxyCommitTime = time.Date(2019, 1, 30, 0, 0, 0, 0, time.UTC)
func cleanFetchResult(fr *FetchResult, detector *licenses.Detector) *FetchResult {
fr.ModulePath = fr.Module.ModulePath
if fr.GoModPath == "" {
fr.GoModPath = fr.ModulePath
}
if fr.Status == 0 {
fr.Status = 200
}
if fr.Module.Version == "" {
fr.Module.Version = "v1.0.0"
}
fr.RequestedVersion = fr.Module.Version
fr.ResolvedVersion = fr.Module.Version
if fr.Module.VersionType == "" {
fr.Module.VersionType = version.TypeRelease
}
if fr.Module.CommitTime.IsZero() {
fr.Module.CommitTime = testProxyCommitTime
}
allLicenses := detector.AllLicenses()
if len(allLicenses) > 0 {
fr.Module.Licenses = allLicenses
fr.Module.IsRedistributable = true
for _, d := range fr.Module.Directories {
isRedist, lics := detector.PackageInfo(internal.Suffix(d.Path, fr.ModulePath))
for _, l := range lics {
d.Licenses = append(d.Licenses, l.Metadata)
}
d.IsRedistributable = isRedist
}
}
shouldSetPVS := (fr.PackageVersionStates == nil)
for _, dir := range fr.Module.Directories {
if dir.Package != nil {
if dir.Package.Documentation.GOOS == "" {
dir.Package.Documentation.GOOS = "linux"
dir.Package.Documentation.GOARCH = "amd64"
}
dir.Package.Path = dir.Path
fr.Module.LegacyPackages = append(fr.Module.LegacyPackages, &internal.LegacyPackage{
Path: dir.Path,
V1Path: dir.V1Path,
Licenses: dir.Licenses,
Name: dir.Package.Name,
Synopsis: dir.Package.Documentation.Synopsis,
DocumentationHTML: dir.Package.Documentation.HTML,
Imports: dir.Package.Imports,
GOOS: dir.Package.Documentation.GOOS,
GOARCH: dir.Package.Documentation.GOARCH,
IsRedistributable: dir.IsRedistributable,
})
if shouldSetPVS {
fr.PackageVersionStates = append(
fr.PackageVersionStates, &internal.PackageVersionState{
PackagePath: dir.Path,
ModulePath: fr.Module.ModulePath,
Version: fr.Module.Version,
Status: http.StatusOK,
},
)
}
}
}
return fr
}
func licenseDetector(ctx context.Context, t *testing.T, modulePath, version string, proxyClient *proxy.Client) *licenses.Detector {
t.Helper()
var (
zipReader *zip.Reader
err error
)
if modulePath == stdlib.ModulePath {
zipReader, _, err = stdlib.Zip(version)
if err != nil {
t.Fatal(err)
}
} else {
zipReader, err = proxyClient.GetZip(ctx, modulePath, version)
if err != nil {
t.Fatal(err)
}
}
logf := func(format string, args ...interface{}) {
log.Infof(ctx, format, args...)
}
return licenses.NewDetector(modulePath, version, zipReader, logf)
}
func sortFetchResult(fr *FetchResult) {
sort.Slice(fr.Module.LegacyPackages, func(i, j int) bool {
return fr.Module.LegacyPackages[i].Path < fr.Module.LegacyPackages[j].Path
})
sort.Slice(fr.Module.Directories, func(i, j int) bool {
return fr.Module.Directories[i].Path < fr.Module.Directories[j].Path
})
sort.Slice(fr.Module.Licenses, func(i, j int) bool {
return fr.Module.Licenses[i].FilePath < fr.Module.Licenses[j].FilePath
})
sort.Slice(fr.PackageVersionStates, func(i, j int) bool {
return fr.PackageVersionStates[i].PackagePath < fr.PackageVersionStates[j].PackagePath
})
for _, dir := range fr.Module.Directories {
sort.Slice(dir.Licenses, func(i, j int) bool {
return dir.Licenses[i].FilePath < dir.Licenses[j].FilePath
})
}
for _, pkg := range fr.Module.LegacyPackages {
sort.Slice(pkg.Licenses, func(i, j int) bool {
return pkg.Licenses[i].FilePath < pkg.Licenses[j].FilePath
})
}
}
// validateDocumentationHTML checks that the doc HTML contains a set of
// substrings. The desired strings consist of the "want" module's documentation
// fields, with multiple substrings separated by '~'.
func validateDocumentationHTML(t *testing.T, got, want *internal.Module) {
t.Helper()
defer func() {
if r := recover(); r != nil {
t.Fatalf("Recovered in checkDocumentationHTML: %v \n; diff = %s", r, cmp.Diff(want, got))
}
}()
checkHTML := func(msg string, i int, hGot, hWant safehtml.HTML) {
t.Helper()
got := hGot.String()
// Treat the wanted DocumentationHTML as a set of substrings to look for, separated by ~.
for _, want := range strings.Split(hWant.String(), "~") {
want = strings.TrimSpace(want)
if !strings.Contains(got, want) {
t.Errorf("doc for %s[%d]:\nmissing %q; got\n%q", msg, i, want, got)
}
}
}
for i := 0; i < len(want.LegacyPackages); i++ {
checkHTML("LegacyPackages", i, got.LegacyPackages[i].DocumentationHTML, want.LegacyPackages[i].DocumentationHTML)
}
for i := 0; i < len(want.Directories); i++ {
if want.Directories[i].Package == nil {
continue
}
checkHTML("Directories", i, got.Directories[i].Package.Documentation.HTML, want.Directories[i].Package.Documentation.HTML)
}
}