summaryrefslogtreecommitdiffstats
path: root/src/cmd/go/internal/modload/query_test.go
blob: 93f8f0d00d1c8d9756d485e97fe87116a56d575d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
// Copyright 2018 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 modload

import (
	"context"
	"flag"
	"internal/testenv"
	"log"
	"os"
	"path"
	"path/filepath"
	"strings"
	"testing"

	"cmd/go/internal/cfg"
	"cmd/go/internal/vcweb/vcstest"

	"golang.org/x/mod/module"
)

func TestMain(m *testing.M) {
	flag.Parse()
	if err := testMain(m); err != nil {
		log.Fatal(err)
	}
}

func testMain(m *testing.M) (err error) {
	cfg.GOPROXY = "direct"
	cfg.ModCacheRW = true

	srv, err := vcstest.NewServer()
	if err != nil {
		return err
	}
	defer func() {
		if closeErr := srv.Close(); err == nil {
			err = closeErr
		}
	}()

	dir, err := os.MkdirTemp("", "modload-test-")
	if err != nil {
		return err
	}
	defer func() {
		if rmErr := os.RemoveAll(dir); err == nil {
			err = rmErr
		}
	}()

	os.Setenv("GOPATH", dir)
	cfg.BuildContext.GOPATH = dir
	cfg.GOMODCACHE = filepath.Join(dir, "pkg/mod")
	cfg.SumdbDir = filepath.Join(dir, "pkg/sumdb")
	m.Run()
	return nil
}

var (
	queryRepo   = "vcs-test.golang.org/git/querytest.git"
	queryRepoV2 = queryRepo + "/v2"
	queryRepoV3 = queryRepo + "/v3"

	// Empty version list (no semver tags), not actually empty.
	emptyRepoPath = "vcs-test.golang.org/git/emptytest.git"
)

var queryTests = []struct {
	path    string
	query   string
	current string
	allow   string
	vers    string
	err     string
}{
	{path: queryRepo, query: "<v0.0.0", vers: "v0.0.0-pre1"},
	{path: queryRepo, query: "<v0.0.0-pre1", err: `no matching versions for query "<v0.0.0-pre1"`},
	{path: queryRepo, query: "<=v0.0.0", vers: "v0.0.0"},
	{path: queryRepo, query: ">v0.0.0", vers: "v0.0.1"},
	{path: queryRepo, query: ">=v0.0.0", vers: "v0.0.0"},
	{path: queryRepo, query: "v0.0.1", vers: "v0.0.1"},
	{path: queryRepo, query: "v0.0.1+foo", vers: "v0.0.1"},
	{path: queryRepo, query: "v0.0.99", err: `vcs-test.golang.org/git/querytest.git@v0.0.99: invalid version: unknown revision v0.0.99`},
	{path: queryRepo, query: "v0", vers: "v0.3.0"},
	{path: queryRepo, query: "v0.1", vers: "v0.1.2"},
	{path: queryRepo, query: "v0.2", err: `no matching versions for query "v0.2"`},
	{path: queryRepo, query: "v0.0", vers: "v0.0.3"},
	{path: queryRepo, query: "v1.9.10-pre2+metadata", vers: "v1.9.10-pre2.0.20190513201126-42abcb6df8ee"},
	{path: queryRepo, query: "ed5ffdaa", vers: "v1.9.10-pre2.0.20191220134614-ed5ffdaa1f5e"},

	// golang.org/issue/29262: The major version for a module without a suffix
	// should be based on the most recent tag (v1 as appropriate, not v0
	// unconditionally).
	{path: queryRepo, query: "42abcb6df8ee", vers: "v1.9.10-pre2.0.20190513201126-42abcb6df8ee"},

	{path: queryRepo, query: "v1.9.10-pre2+wrongmetadata", err: `vcs-test.golang.org/git/querytest.git@v1.9.10-pre2+wrongmetadata: invalid version: unknown revision v1.9.10-pre2+wrongmetadata`},
	{path: queryRepo, query: "v1.9.10-pre2", err: `vcs-test.golang.org/git/querytest.git@v1.9.10-pre2: invalid version: unknown revision v1.9.10-pre2`},
	{path: queryRepo, query: "latest", vers: "v1.9.9"},
	{path: queryRepo, query: "latest", current: "v1.9.10-pre1", vers: "v1.9.9"},
	{path: queryRepo, query: "upgrade", vers: "v1.9.9"},
	{path: queryRepo, query: "upgrade", current: "v1.9.10-pre1", vers: "v1.9.10-pre1"},
	{path: queryRepo, query: "upgrade", current: "v1.9.10-pre2+metadata", vers: "v1.9.10-pre2.0.20190513201126-42abcb6df8ee"},
	{path: queryRepo, query: "upgrade", current: "v0.0.0-20190513201126-42abcb6df8ee", vers: "v0.0.0-20190513201126-42abcb6df8ee"},
	{path: queryRepo, query: "upgrade", allow: "NOMATCH", err: `no matching versions for query "upgrade"`},
	{path: queryRepo, query: "upgrade", current: "v1.9.9", allow: "NOMATCH", err: `vcs-test.golang.org/git/querytest.git@v1.9.9: disallowed module version`},
	{path: queryRepo, query: "upgrade", current: "v1.99.99", err: `vcs-test.golang.org/git/querytest.git@v1.99.99: invalid version: unknown revision v1.99.99`},
	{path: queryRepo, query: "patch", current: "", err: `can't query version "patch" of module vcs-test.golang.org/git/querytest.git: no existing version is required`},
	{path: queryRepo, query: "patch", current: "v0.1.0", vers: "v0.1.2"},
	{path: queryRepo, query: "patch", current: "v1.9.0", vers: "v1.9.9"},
	{path: queryRepo, query: "patch", current: "v1.9.10-pre1", vers: "v1.9.10-pre1"},
	{path: queryRepo, query: "patch", current: "v1.9.10-pre2+metadata", vers: "v1.9.10-pre2.0.20190513201126-42abcb6df8ee"},
	{path: queryRepo, query: "patch", current: "v1.99.99", err: `vcs-test.golang.org/git/querytest.git@v1.99.99: invalid version: unknown revision v1.99.99`},
	{path: queryRepo, query: ">v1.9.9", vers: "v1.9.10-pre1"},
	{path: queryRepo, query: ">v1.10.0", err: `no matching versions for query ">v1.10.0"`},
	{path: queryRepo, query: ">=v1.10.0", err: `no matching versions for query ">=v1.10.0"`},
	{path: queryRepo, query: "6cf84eb", vers: "v0.0.2-0.20180704023347-6cf84ebaea54"},

	// golang.org/issue/27173: A pseudo-version may be based on the highest tag on
	// any parent commit, or any existing semantically-lower tag: a given commit
	// could have been a pre-release for a backport tag at any point.
	{path: queryRepo, query: "3ef0cec634e0", vers: "v0.1.2-0.20180704023347-3ef0cec634e0"},
	{path: queryRepo, query: "v0.1.2-0.20180704023347-3ef0cec634e0", vers: "v0.1.2-0.20180704023347-3ef0cec634e0"},
	{path: queryRepo, query: "v0.1.1-0.20180704023347-3ef0cec634e0", vers: "v0.1.1-0.20180704023347-3ef0cec634e0"},
	{path: queryRepo, query: "v0.0.4-0.20180704023347-3ef0cec634e0", vers: "v0.0.4-0.20180704023347-3ef0cec634e0"},

	// Invalid tags are tested in cmd/go/testdata/script/mod_pseudo_invalid.txt.

	{path: queryRepo, query: "start", vers: "v0.0.0-20180704023101-5e9e31667ddf"},
	{path: queryRepo, query: "5e9e31667ddf", vers: "v0.0.0-20180704023101-5e9e31667ddf"},
	{path: queryRepo, query: "v0.0.0-20180704023101-5e9e31667ddf", vers: "v0.0.0-20180704023101-5e9e31667ddf"},

	{path: queryRepo, query: "7a1b6bf", vers: "v0.1.0"},

	{path: queryRepoV2, query: "<v0.0.0", err: `no matching versions for query "<v0.0.0"`},
	{path: queryRepoV2, query: "<=v0.0.0", err: `no matching versions for query "<=v0.0.0"`},
	{path: queryRepoV2, query: ">v0.0.0", vers: "v2.0.0"},
	{path: queryRepoV2, query: ">=v0.0.0", vers: "v2.0.0"},

	{path: queryRepoV2, query: "v2", vers: "v2.5.5"},
	{path: queryRepoV2, query: "v2.5", vers: "v2.5.5"},
	{path: queryRepoV2, query: "v2.6", err: `no matching versions for query "v2.6"`},
	{path: queryRepoV2, query: "v2.6.0-pre1", vers: "v2.6.0-pre1"},
	{path: queryRepoV2, query: "latest", vers: "v2.5.5"},

	// Commit e0cf3de987e6 is actually v1.19.10-pre1, not anything resembling v3,
	// and it has a go.mod file with a non-v3 module path. Attempting to query it
	// as the v3 module should fail.
	{path: queryRepoV3, query: "e0cf3de987e6", err: `vcs-test.golang.org/git/querytest.git/v3@v3.0.0-20180704024501-e0cf3de987e6: invalid version: go.mod has non-.../v3 module path "vcs-test.golang.org/git/querytest.git" (and .../v3/go.mod does not exist) at revision e0cf3de987e6`},

	// The querytest repo does not have any commits tagged with major version 3,
	// and the latest commit in the repo has a go.mod file specifying a non-v3 path.
	// That should prevent us from resolving any version for the /v3 path.
	{path: queryRepoV3, query: "latest", err: `no matching versions for query "latest"`},

	{path: emptyRepoPath, query: "latest", vers: "v0.0.0-20180704023549-7bb914627242"},
	{path: emptyRepoPath, query: ">v0.0.0", err: `no matching versions for query ">v0.0.0"`},
	{path: emptyRepoPath, query: "<v10.0.0", err: `no matching versions for query "<v10.0.0"`},
}

func TestQuery(t *testing.T) {
	testenv.MustHaveExternalNetwork(t)
	testenv.MustHaveExecPath(t, "git")

	ctx := context.Background()

	for _, tt := range queryTests {
		allow := tt.allow
		if allow == "" {
			allow = "*"
		}
		allowed := func(ctx context.Context, m module.Version) error {
			if ok, _ := path.Match(allow, m.Version); !ok {
				return module.VersionError(m, ErrDisallowed)
			}
			return nil
		}
		tt := tt
		t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.query+"/"+tt.current+"/"+allow, func(t *testing.T) {
			t.Parallel()

			info, err := Query(ctx, tt.path, tt.query, tt.current, allowed)
			if tt.err != "" {
				if err == nil {
					t.Errorf("Query(_, %q, %q, %q, %v) = %v, want error %q", tt.path, tt.query, tt.current, allow, info.Version, tt.err)
				} else if err.Error() != tt.err {
					t.Errorf("Query(_, %q, %q, %q, %v): %v\nwant error %q", tt.path, tt.query, tt.current, allow, err, tt.err)
				}
				return
			}
			if err != nil {
				t.Fatalf("Query(_, %q, %q, %q, %v): %v\nwant %v", tt.path, tt.query, tt.current, allow, err, tt.vers)
			}
			if info.Version != tt.vers {
				t.Errorf("Query(_, %q, %q, %q, %v) = %v, want %v", tt.path, tt.query, tt.current, allow, info.Version, tt.vers)
			}
		})
	}
}