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  }