blob: d4713a5f360e9329248b40b071446a3186d53e04 [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 postgres
import (
"context"
"database/sql"
"errors"
"fmt"
"testing"
"github.com/google/go-cmp/cmp"
"golang.org/x/pkgsite/internal"
"golang.org/x/pkgsite/internal/source"
"golang.org/x/pkgsite/internal/stdlib"
"golang.org/x/pkgsite/internal/testing/sample"
)
func TestGetVersions(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), testTimeout)
defer cancel()
var (
taggedAndPseudoModule = "path.to/foo"
taggedModuleV2 = "path.to/foo/v2"
taggedModuleV3 = "path.to/foo/v3"
pseudoModule = "golang.org/x/tools"
otherModule = "path.to/other"
incompatibleModule = "path.to/incompatible"
rootModule = "golang.org/foo/bar"
nestedModule = "golang.org/foo/bar/api"
testModules = []*internal.Module{
sample.Module(stdlib.ModulePath, "v1.15.0-beta.1", "cmd/go"),
sample.Module(stdlib.ModulePath, "v1.14.6", "cmd/go"),
sample.Module(taggedModuleV3, "v3.2.0-beta", "bar"),
sample.Module(taggedModuleV3, "v3.2.0-alpha.2", "bar"),
sample.Module(taggedModuleV3, "v3.2.0-alpha.1", "bar"),
sample.Module(taggedModuleV3, "v3.1.0", "bar"),
sample.Module(taggedModuleV3, "v3.0.0", "bar"),
sample.Module(taggedModuleV2, "v2.0.1", "bar"),
sample.Module(taggedAndPseudoModule, "v1.5.3-pre1", "bar"),
sample.Module(taggedAndPseudoModule, "v1.5.2", "bar"),
sample.Module(taggedAndPseudoModule, "v0.0.0-20200101120000-000000000000", "bar"),
sample.Module(otherModule, "v3.0.0", "thing"),
sample.Module(incompatibleModule, "v2.0.0+incompatible", "module"),
sample.Module(incompatibleModule, "v0.0.0", "module"),
sample.Module(rootModule, "v1.0.3", "api"),
sample.Module(rootModule, "v0.11.6", "api"),
sample.Module(nestedModule, "v1.0.4", "api"),
sample.Module(nestedModule, "v1.0.3", "api"),
}
)
// Add 12 pseudo versions to the test modules. Below we only
// expect to return the 10 most recent.
for i := 1; i <= 12; i++ {
testModules = append(testModules, sample.Module(pseudoModule, fmt.Sprintf("v0.0.0-202001011200%02d-000000000000", i), "blog"))
}
defer ResetTestDB(testDB, t)
for _, m := range testModules {
if err := testDB.InsertModule(ctx, m); err != nil {
t.Fatal(err)
}
}
stdModuleVersions := []*internal.ModuleInfo{
{
ModulePath: stdlib.ModulePath,
Version: "v1.15.0-beta.1",
},
{
ModulePath: stdlib.ModulePath,
Version: "v1.14.6",
},
}
fooModuleVersions := []*internal.ModuleInfo{
{
ModulePath: taggedModuleV3,
Version: "v3.2.0-beta",
},
{
ModulePath: taggedModuleV3,
Version: "v3.2.0-alpha.2",
},
{
ModulePath: taggedModuleV3,
Version: "v3.2.0-alpha.1",
},
{
ModulePath: taggedModuleV3,
Version: "v3.1.0",
},
{
ModulePath: taggedModuleV3,
Version: "v3.0.0",
},
{
ModulePath: taggedModuleV2,
Version: "v2.0.1",
},
{
ModulePath: taggedAndPseudoModule,
Version: "v1.5.3-pre1",
},
{
ModulePath: taggedAndPseudoModule,
Version: "v1.5.2",
},
}
testCases := []struct {
name, path string
want []*internal.ModuleInfo
}{
{
name: "std_module",
path: stdlib.ModulePath,
want: stdModuleVersions,
},
{
name: "stdlib_path",
path: "cmd",
want: stdModuleVersions,
},
{
name: "stdlib_package",
path: "cmd/go",
want: stdModuleVersions,
},
{
name: "want_tagged_versions_only",
path: "path.to/foo/bar",
want: fooModuleVersions,
},
{
name: "want_all_tagged_versions_at_v2_path",
path: "path.to/foo/v2/bar",
want: fooModuleVersions,
},
{
name: "want_pseudo_versions_only",
path: "golang.org/x/tools/blog",
want: func() []*internal.ModuleInfo {
versions := []*internal.ModuleInfo{}
// Expect the 10 most recent in DESC order
for i := 12; i > 2; i-- {
versions = append(versions, &internal.ModuleInfo{
ModulePath: pseudoModule,
Version: fmt.Sprintf("v0.0.0-202001011200%02d-000000000000", i),
})
}
return versions
}(),
},
{
name: "want_tagged_versions_includes_incompatible",
path: "path.to/incompatible/module",
want: []*internal.ModuleInfo{
{
ModulePath: incompatibleModule,
Version: "v0.0.0",
},
{
ModulePath: incompatibleModule,
Version: "v2.0.0+incompatible",
},
},
},
{
name: "nested_module_path",
path: "golang.org/foo/bar/api",
want: []*internal.ModuleInfo{
{
ModulePath: nestedModule,
Version: "v1.0.4",
},
{
ModulePath: nestedModule,
Version: "v1.0.3",
},
{
ModulePath: rootModule,
Version: "v1.0.3",
},
{
ModulePath: rootModule,
Version: "v0.11.6",
},
},
},
{
name: "root_module_path",
path: "golang.org/foo/bar",
want: []*internal.ModuleInfo{
{
ModulePath: rootModule,
Version: "v1.0.3",
},
{
ModulePath: rootModule,
Version: "v0.11.6",
},
},
},
{
name: "want_zero_results_in_non_empty_db",
path: "not.a/real/path",
},
}
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
var want []*internal.ModuleInfo
for _, w := range test.want {
mod := sample.ModuleInfo(w.ModulePath, w.Version)
want = append(want, mod)
}
got, err := testDB.GetVersionsForPath(ctx, test.path)
if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(want, got, cmp.AllowUnexported(source.Info{})); diff != "" {
t.Errorf("testDB.GetVersionsForPath(%q) mismatch (-want +got):\n%s", test.path, diff)
}
})
}
}
func TestGetLatestMajorVersion(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), testTimeout)
defer cancel()
defer ResetTestDB(testDB, t)
for _, m := range []*internal.Module{
sample.Module("foo.com/bar", "v1.1.1", "baz", "faz"),
sample.Module("foo.com/bar/v2", "v2.0.5", "baz", "faz"),
sample.Module("foo.com/bar/v3", "v3.0.1", "baz"),
sample.Module("bar.com/foo", sample.VersionString, sample.Suffix),
} {
if err := testDB.InsertModule(ctx, m); err != nil {
t.Fatal(err)
}
}
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: sql.ErrNoRows,
},
{
fullPath: "foo.com/bar/baz",
modulePath: "foo.com/bar",
wantModulePath: "foo.com/bar/v3",
wantPackagePath: "foo.com/bar/v3/baz",
},
{
fullPath: "foo.com/bar/faz",
modulePath: "foo.com/bar",
wantModulePath: "foo.com/bar/v3",
wantPackagePath: "foo.com/bar/v3",
},
} {
gotVersion, gotPath, err := testDB.GetLatestMajorVersion(ctx, test.fullPath, test.modulePath)
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 gotVersion != test.wantModulePath || gotPath != test.wantPackagePath {
t.Errorf("testDB.GetLatestMajorVersion(%v, %v) = (%v, %v), want = (%v, %v)", test.fullPath, test.modulePath, gotVersion, gotPath, test.wantModulePath, test.wantPackagePath)
}
}
}
func TestGetLatestMinorModuleVersion(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), testTimeout)
defer cancel()
defer ResetTestDB(testDB, t)
const (
modulePath = "foo.com/M"
latestVersion = "v1.2.0"
)
for _, m := range []*internal.Module{
sample.Module(modulePath, "v1.1.0", "p1", "p2"),
sample.Module(modulePath, latestVersion, "p1"),
sample.Module(modulePath+"/v2", "v2.0.5", "p1", "p2"),
} {
if err := testDB.InsertModule(ctx, m); err != nil {
t.Fatal(err)
}
}
for _, test := range []struct {
unitSuffix string
wantPresent bool
}{
{"p1", true},
{"p2", false},
} {
gotVersion, gotPresent, err := testDB.GetLatestMinorModuleVersion(ctx, modulePath+"/"+test.unitSuffix, modulePath)
if err != nil {
t.Fatal(err)
}
if gotVersion != latestVersion {
t.Errorf("%s: got version %q, want %q", test.unitSuffix, gotVersion, latestVersion)
}
if gotPresent != test.wantPresent {
t.Errorf("%s: got present %t, want %t", test.unitSuffix, gotPresent, test.wantPresent)
}
}
}