github.com/bazelbuild/bazel-gazelle@v0.36.1-0.20240520142334-61b277ba6fed/repo/remote_test.go (about) 1 /* Copyright 2018 The Bazel Authors. All rights reserved. 2 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 */ 15 16 package repo 17 18 import ( 19 "errors" 20 "os" 21 "path/filepath" 22 "testing" 23 24 "golang.org/x/tools/go/vcs" 25 ) 26 27 func TestRootSpecialCases(t *testing.T) { 28 for _, tc := range []struct { 29 in, wantRoot, wantName string 30 repos []Repo 31 wantError bool 32 }{ 33 {in: "golang.org/x/net/context", wantRoot: "golang.org/x/net", wantName: "org_golang_x_net"}, 34 {in: "golang.org/x/tools/go/vcs", wantRoot: "golang.org/x/tools", wantName: "org_golang_x_tools"}, 35 {in: "golang.org/x/goimports", wantRoot: "golang.org/x/goimports", wantName: "org_golang_x_goimports"}, 36 {in: "cloud.google.com/fashion/industry", wantRoot: "cloud.google.com/fashion", wantName: "com_google_cloud_fashion"}, 37 {in: "github.com/foo", wantError: true}, 38 {in: "github.com/foo/bar", wantRoot: "github.com/foo/bar", wantName: "com_github_foo_bar"}, 39 {in: "github.com/foo/bar/baz", wantRoot: "github.com/foo/bar", wantName: "com_github_foo_bar"}, 40 {in: "gopkg.in/yaml.v2", wantRoot: "gopkg.in/yaml.v2", wantName: "in_gopkg_yaml_v2"}, 41 {in: "gopkg.in/src-d/go-git.v4", wantRoot: "gopkg.in/src-d/go-git.v4", wantName: "in_gopkg_src_d_go_git_v4"}, 42 {in: "unsupported.org/x/net/context", wantError: true}, 43 { 44 in: "private.com/my/repo/package/path", 45 repos: []Repo{ 46 { 47 Name: "com_other_host_repo", 48 GoPrefix: "other-host.com/repo", 49 }, { 50 Name: "com_private_my_repo", 51 GoPrefix: "private.com/my/repo", 52 }, 53 }, 54 wantRoot: "private.com/my/repo", 55 wantName: "com_private_my_repo", 56 }, 57 { 58 in: "unsupported.org/x/net/context", 59 repos: []Repo{ 60 { 61 Name: "com_private_my_repo", 62 GoPrefix: "private.com/my/repo", 63 }, 64 }, 65 wantError: true, 66 }, 67 { 68 in: "github.com/foo/bar", 69 repos: []Repo{{ 70 Name: "custom_repo", 71 GoPrefix: "github.com/foo/bar", 72 }}, 73 wantRoot: "github.com/foo/bar", 74 wantName: "custom_repo", 75 }, 76 } { 77 t.Run(tc.in, func(t *testing.T) { 78 rc := NewStubRemoteCache(tc.repos) 79 if gotRoot, gotName, err := rc.Root(tc.in); err != nil { 80 if !tc.wantError { 81 t.Errorf("unexpected error: %v", err) 82 } 83 } else if tc.wantError { 84 t.Errorf("unexpected success: %v", tc.in) 85 } else if gotRoot != tc.wantRoot { 86 t.Errorf("root for %q: got %q; want %q", tc.in, gotRoot, tc.wantRoot) 87 } else if gotName != tc.wantName { 88 t.Errorf("name for %q: got %q; want %q", tc.in, gotName, tc.wantName) 89 } 90 }) 91 } 92 } 93 94 func TestRootStatic(t *testing.T) { 95 for _, tc := range []struct { 96 in, wantRoot, wantName string 97 repos []Repo 98 }{ 99 { 100 in: "private.com/my/repo/package/path", 101 repos: []Repo{ 102 { 103 Name: "com_other_host_repo", 104 GoPrefix: "other-host.com/repo", 105 }, { 106 Name: "com_private_my_repo", 107 GoPrefix: "private.com/my/repo", 108 }, 109 }, 110 wantRoot: "private.com/my/repo", 111 wantName: "com_private_my_repo", 112 }, 113 { 114 in: "unsupported.org/x/net/context", 115 repos: []Repo{ 116 { 117 Name: "com_private_my_repo", 118 GoPrefix: "private.com/my/repo", 119 }, 120 }, 121 wantRoot: "", 122 wantName: "", 123 }, 124 } { 125 t.Run(tc.in, func(t *testing.T) { 126 rc := NewStubRemoteCache(tc.repos) 127 if gotRoot, gotName, err := rc.RootStatic(tc.in); err != nil { 128 t.Errorf("unexpected error: %v", err) 129 } else if gotRoot != tc.wantRoot { 130 t.Errorf("root for %q: got %q; want %q", tc.in, gotRoot, tc.wantRoot) 131 } else if gotName != tc.wantName { 132 t.Errorf("name for %q: got %q; want %q", tc.in, gotName, tc.wantName) 133 } 134 }) 135 } 136 } 137 138 func TestRootPopulatedFromGoMod(t *testing.T) { 139 tmpDir := t.TempDir() 140 goModPath := filepath.Join(tmpDir, "go.mod") 141 goModData := []byte(` 142 module example.com/use 143 go 1.19 144 require example.com/good v1.0.0 145 `) 146 if err := os.WriteFile(goModPath, goModData, 0666); err != nil { 147 t.Fatal(err) 148 } 149 150 rc := NewStubRemoteCache(nil) 151 if err := rc.PopulateFromGoMod(goModPath); err != nil { 152 t.Fatal(err) 153 } 154 errResolve := errors.New("test cannot lookup external package") 155 rc.RepoRootForImportPath = func(string, bool) (*vcs.RepoRoot, error) { 156 return nil, errResolve 157 } 158 159 // Resolving golang.org/x/mod/module from go.mod should work. 160 goodPkgPath := "example.com/good/pkg" 161 wantRoot := "example.com/good" 162 wantName := "com_example_good" 163 root, name, err := rc.Root(goodPkgPath) 164 if err != nil { 165 t.Fatalf("could not resolve %q from go.mod: %v", goodPkgPath, err) 166 } 167 if root != wantRoot { 168 t.Errorf("got root %q; want %q", root, wantRoot) 169 } 170 if name != wantName { 171 t.Errorf("got name %q; want %q", root, wantName) 172 } 173 174 // Resolving another module should fail because RepoRootForImportPath 175 // is stubbed out. 176 badPkgPath := "example.com/bad/pkg" 177 if _, _, err := rc.Root(badPkgPath); err == nil { 178 t.Errorf("resolving %q: unexpected success", badPkgPath) 179 } else if !errors.Is(err, errResolve) { 180 t.Errorf("resolving %q: got error %v, want %v", badPkgPath, err, errResolve) 181 } 182 } 183 184 func TestRemote(t *testing.T) { 185 for _, tc := range []struct { 186 desc, root string 187 repos []Repo 188 wantRemote, wantVCS string 189 wantError bool 190 }{ 191 { 192 desc: "unstubbed_remote", 193 root: "github.com/bazelbuild/bazel-gazelle", 194 wantError: true, // stub should return an error 195 }, { 196 desc: "known_repo", 197 root: "github.com/example/project", 198 repos: []Repo{{ 199 Name: "com_github_example_project", 200 GoPrefix: "github.com/example/project", 201 Remote: "https://private.com/example/project", 202 VCS: "git", 203 }}, 204 wantRemote: "https://private.com/example/project", 205 wantVCS: "git", 206 }, { 207 desc: "git_repo", 208 root: "example.com/repo", // stub knows this 209 wantRemote: "https://example.com/repo.git", 210 wantVCS: "git", 211 }, { 212 desc: "local_repo", 213 root: "github.com/example/project", 214 repos: []Repo{{ 215 Name: "com_github_example_project", 216 GoPrefix: "github.com/example/project", 217 Remote: "/home/joebob/go/src/github.com/example/project", 218 VCS: "local", 219 }}, 220 wantRemote: "/home/joebob/go/src/github.com/example/project", 221 wantVCS: "local", 222 }, 223 } { 224 t.Run(tc.desc, func(t *testing.T) { 225 rc := NewStubRemoteCache(tc.repos) 226 if gotRemote, gotVCS, err := rc.Remote(tc.root); err != nil { 227 if !tc.wantError { 228 t.Errorf("unexpected error: %v", err) 229 } 230 } else if tc.wantError { 231 t.Errorf("unexpected success") 232 } else if gotRemote != tc.wantRemote { 233 t.Errorf("remote for %q: got %q ; want %q", tc.root, gotRemote, tc.wantRemote) 234 } else if gotVCS != tc.wantVCS { 235 t.Errorf("vcs for %q: got %q ; want %q", tc.root, gotVCS, tc.wantVCS) 236 } 237 }) 238 } 239 } 240 241 func TestHead(t *testing.T) { 242 for _, tc := range []struct { 243 desc, remote, vcs string 244 wantCommit, wantTag string 245 wantError bool 246 }{ 247 { 248 desc: "unstubbed_remote", 249 remote: "https://github.com/bazelbuild/bazel-gazelle", 250 vcs: "git", 251 wantError: true, // stub should return an error 252 }, 253 } { 254 t.Run(tc.desc, func(t *testing.T) { 255 rc := NewStubRemoteCache(nil) 256 if gotCommit, gotTag, err := rc.Head(tc.remote, tc.vcs); err != nil { 257 if !tc.wantError { 258 t.Errorf("unexpected error: %v", err) 259 } 260 } else if tc.wantError { 261 t.Errorf("unexpected success") 262 } else if gotCommit != tc.wantCommit { 263 t.Errorf("commit for %q: got %q ; want %q", tc.remote, gotCommit, tc.wantCommit) 264 } else if gotTag != tc.wantTag { 265 t.Errorf("tag for %q: got %q ; want %q", tc.remote, gotTag, tc.wantTag) 266 } 267 }) 268 } 269 } 270 271 func TestMod(t *testing.T) { 272 for _, tc := range []struct { 273 desc, importPath string 274 repos []Repo 275 wantModPath, wantName string 276 wantErr bool 277 }{ 278 { 279 desc: "no_special_cases", 280 importPath: "golang.org/x/exp", 281 wantErr: true, 282 }, { 283 desc: "known", 284 importPath: "example.com/known/v2/foo", 285 repos: []Repo{{ 286 Name: "known", 287 GoPrefix: "example.com/known", 288 }}, 289 wantModPath: "example.com/known", 290 wantName: "known", 291 }, { 292 desc: "semver_less_path_is_safe", 293 importPath: "example.com/known/internal/endpoints", 294 repos: []Repo{{ 295 Name: "known", 296 GoPrefix: "example.com/known", 297 }, { 298 Name: "known_internal_endpoints_v2", 299 GoPrefix: "example.com/known/internal/endpoints/v2", 300 }}, 301 wantModPath: "example.com/known", 302 wantName: "known", 303 }, { 304 desc: "lookup", 305 importPath: "example.com/stub/v2/foo", 306 wantModPath: "example.com/stub/v2", 307 wantName: "com_example_stub_v2", 308 }, 309 } { 310 t.Run(tc.desc, func(t *testing.T) { 311 rc := NewStubRemoteCache(tc.repos) 312 modPath, name, err := rc.Mod(tc.importPath) 313 if err != nil && tc.wantErr { 314 return 315 } else if err == nil && tc.wantErr { 316 t.Error("want error; got success") 317 } else if err != nil { 318 t.Fatal(err) 319 } 320 if modPath != tc.wantModPath { 321 t.Errorf("modPath: got %s; want %s", modPath, tc.wantModPath) 322 } 323 if name != tc.wantName { 324 t.Errorf("name: got %s; want %s", name, tc.wantName) 325 } 326 }) 327 } 328 } 329 330 func TestModVersion(t *testing.T) { 331 for _, tc := range []struct { 332 desc, modPath, query string 333 repos []Repo 334 wantName, wantVersion, wantSum string 335 }{ 336 { 337 desc: "known", 338 modPath: "example.com/known", 339 query: "latest", 340 repos: []Repo{{ 341 Name: "known", 342 GoPrefix: "example.com/known", 343 }}, 344 wantName: "known", 345 wantVersion: "v1.2.3", 346 wantSum: "h1:abcdef", 347 }, { 348 desc: "unknown", 349 modPath: "example.com/unknown", 350 query: "latest", 351 wantName: "com_example_unknown", 352 wantVersion: "v1.2.3", 353 wantSum: "h1:abcdef", 354 }, 355 } { 356 t.Run(tc.desc, func(t *testing.T) { 357 rc := NewStubRemoteCache(tc.repos) 358 name, version, sum, err := rc.ModVersion(tc.modPath, tc.query) 359 if err != nil { 360 t.Fatal(err) 361 } 362 if name != tc.wantName { 363 t.Errorf("name: got %q; want %q", name, tc.wantName) 364 } 365 if version != tc.wantVersion { 366 t.Errorf("version: got %q; want %q", version, tc.wantVersion) 367 } 368 if sum != tc.wantSum { 369 t.Errorf("sum: got %q; want %q", sum, tc.wantSum) 370 } 371 }) 372 } 373 }