github.com/argoproj/argo-cd/v2@v2.10.9/applicationset/services/scm_provider/bitbucket_server_test.go (about)

     1  package scm_provider
     2  
     3  import (
     4  	"context"
     5  	"io"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  )
    12  
    13  func defaultHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
    14  	return func(w http.ResponseWriter, r *http.Request) {
    15  		w.Header().Set("Content-Type", "application/json")
    16  		var err error
    17  		switch r.RequestURI {
    18  		case "/rest/api/1.0/projects/PROJECT/repos?limit=100":
    19  			_, err = io.WriteString(w, `{
    20  				"size": 1,
    21  				"limit": 100,
    22  				"isLastPage": true,
    23  				"values": [
    24  					{
    25  						"id": 1,
    26  						"name": "REPO",
    27  						"project": {
    28  							"key": "PROJECT"
    29  						},
    30  						"links": {
    31  							"clone": [
    32  								{
    33  									"href": "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
    34  									"name": "ssh"
    35  								},
    36  								{
    37  									"href": "https://mycompany.bitbucket.org/scm/PROJECT/REPO.git",
    38  									"name": "http"
    39  								}
    40  							]
    41  						}
    42  					}
    43  				],
    44  				"start": 0
    45  			}`)
    46  		case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches?limit=100":
    47  			_, err = io.WriteString(w, `{
    48  				"size": 1,
    49  				"limit": 100,
    50  				"isLastPage": true,
    51  				"values": [
    52  					{
    53  						"id": "refs/heads/main",
    54  						"displayId": "main",
    55  						"type": "BRANCH",
    56  						"latestCommit": "8d51122def5632836d1cb1026e879069e10a1e13",
    57  						"latestChangeset": "8d51122def5632836d1cb1026e879069e10a1e13",
    58  						"isDefault": true
    59  					}
    60  				],
    61  				"start": 0
    62  			}`)
    63  		case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default":
    64  			_, err = io.WriteString(w, `{
    65  				"id": "refs/heads/main",
    66  				"displayId": "main",
    67  				"type": "BRANCH",
    68  				"latestCommit": "8d51122def5632836d1cb1026e879069e10a1e13",
    69  				"latestChangeset": "8d51122def5632836d1cb1026e879069e10a1e13",
    70  				"isDefault": true
    71  			}`)
    72  		default:
    73  			t.Fail()
    74  		}
    75  		if err != nil {
    76  			t.Fail()
    77  		}
    78  	}
    79  }
    80  
    81  func verifyDefaultRepo(t *testing.T, err error, repos []*Repository) {
    82  	assert.NoError(t, err)
    83  	assert.Equal(t, 1, len(repos))
    84  	assert.Equal(t, Repository{
    85  		Organization: "PROJECT",
    86  		Repository:   "REPO",
    87  		URL:          "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
    88  		Branch:       "main",
    89  		SHA:          "8d51122def5632836d1cb1026e879069e10a1e13",
    90  		Labels:       []string{},
    91  		RepositoryId: 1,
    92  	}, *repos[0])
    93  }
    94  
    95  func TestListReposNoAuth(t *testing.T) {
    96  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    97  		assert.Empty(t, r.Header.Get("Authorization"))
    98  		defaultHandler(t)(w, r)
    99  	}))
   100  	defer ts.Close()
   101  	provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true)
   102  	assert.NoError(t, err)
   103  	repos, err := provider.ListRepos(context.Background(), "ssh")
   104  	verifyDefaultRepo(t, err, repos)
   105  }
   106  
   107  func TestListReposPagination(t *testing.T) {
   108  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   109  		assert.Empty(t, r.Header.Get("Authorization"))
   110  		var err error
   111  		switch r.RequestURI {
   112  		case "/rest/api/1.0/projects/PROJECT/repos?limit=100":
   113  			_, err = io.WriteString(w, `{
   114  				"size": 1,
   115  				"limit": 100,
   116  				"isLastPage": false,
   117  				"values": [
   118  					{
   119  						"id": 100,
   120  						"name": "REPO",
   121  						"project": {
   122  							"key": "PROJECT"
   123  						},
   124  						"links": {
   125  							"clone": [
   126  								{
   127  									"href": "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
   128  									"name": "ssh"
   129  								},
   130  								{
   131  									"href": "https://mycompany.bitbucket.org/scm/PROJECT/REPO.git",
   132  									"name": "http"
   133  								}
   134  							]
   135  						}
   136  					}
   137  				],
   138  				"start": 0,
   139  				"nextPageStart": 200
   140  			}`)
   141  		case "/rest/api/1.0/projects/PROJECT/repos?limit=100&start=200":
   142  			_, err = io.WriteString(w, `{
   143  				"size": 1,
   144  				"limit": 100,
   145  				"isLastPage": true,
   146  				"values": [
   147  					{
   148  						"id": 200,
   149  						"name": "REPO2",
   150  						"project": {
   151  							"key": "PROJECT"
   152  						},
   153  						"links": {
   154  							"clone": [
   155  								{
   156  									"href": "ssh://git@mycompany.bitbucket.org/PROJECT/REPO2.git",
   157  									"name": "ssh"
   158  								},
   159  								{
   160  									"href": "https://mycompany.bitbucket.org/scm/PROJECT/REPO2.git",
   161  									"name": "http"
   162  								}
   163  							]
   164  						}
   165  					}
   166  				],
   167  				"start": 200
   168  			}`)
   169  		case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default":
   170  			_, err = io.WriteString(w, `{
   171  				"id": "refs/heads/main",
   172  				"displayId": "main",
   173  				"type": "BRANCH",
   174  				"latestCommit": "8d51122def5632836d1cb1026e879069e10a1e13",
   175  				"isDefault": true
   176  			}`)
   177  		case "/rest/api/1.0/projects/PROJECT/repos/REPO2/branches/default":
   178  			_, err = io.WriteString(w, `{
   179  				"id": "refs/heads/development",
   180  				"displayId": "development",
   181  				"type": "BRANCH",
   182  				"latestCommit": "2d51122def5632836d1cb1026e879069e10a1e13",
   183  				"isDefault": true
   184  			}`)
   185  		default:
   186  			t.Fail()
   187  		}
   188  		if err != nil {
   189  			t.Fail()
   190  		}
   191  	}))
   192  	defer ts.Close()
   193  	provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true)
   194  	assert.NoError(t, err)
   195  	repos, err := provider.ListRepos(context.Background(), "ssh")
   196  	assert.NoError(t, err)
   197  	assert.Equal(t, 2, len(repos))
   198  	assert.Equal(t, Repository{
   199  		Organization: "PROJECT",
   200  		Repository:   "REPO",
   201  		URL:          "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
   202  		Branch:       "main",
   203  		SHA:          "8d51122def5632836d1cb1026e879069e10a1e13",
   204  		Labels:       []string{},
   205  		RepositoryId: 100,
   206  	}, *repos[0])
   207  
   208  	assert.Equal(t, Repository{
   209  		Organization: "PROJECT",
   210  		Repository:   "REPO2",
   211  		URL:          "ssh://git@mycompany.bitbucket.org/PROJECT/REPO2.git",
   212  		Branch:       "development",
   213  		SHA:          "2d51122def5632836d1cb1026e879069e10a1e13",
   214  		Labels:       []string{},
   215  		RepositoryId: 200,
   216  	}, *repos[1])
   217  }
   218  
   219  func TestGetBranchesBranchPagination(t *testing.T) {
   220  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   221  		assert.Empty(t, r.Header.Get("Authorization"))
   222  		switch r.RequestURI {
   223  		case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches?limit=100":
   224  			_, err := io.WriteString(w, `{
   225  				"size": 1,
   226  				"limit": 100,
   227  				"isLastPage": false,
   228  				"values": [
   229  					{
   230  						"id": "refs/heads/main",
   231  						"displayId": "main",
   232  						"type": "BRANCH",
   233  						"latestCommit": "8d51122def5632836d1cb1026e879069e10a1e13",
   234  						"latestChangeset": "8d51122def5632836d1cb1026e879069e10a1e13",
   235  						"isDefault": true
   236  					}
   237  				],
   238  				"start": 0,
   239  				"nextPageStart": 200
   240  			}`)
   241  			if err != nil {
   242  				t.Fail()
   243  			}
   244  			return
   245  		case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches?limit=100&start=200":
   246  			_, err := io.WriteString(w, `{
   247  				"size": 1,
   248  				"limit": 100,
   249  				"isLastPage": true,
   250  				"values": [
   251  					{
   252  						"id": "refs/heads/feature",
   253  						"displayId": "feature",
   254  						"type": "BRANCH",
   255  						"latestCommit": "9d51122def5632836d1cb1026e879069e10a1e13",
   256  						"latestChangeset": "9d51122def5632836d1cb1026e879069e10a1e13",
   257  						"isDefault": true
   258  					}
   259  				],
   260  				"start": 200
   261  			}`)
   262  			if err != nil {
   263  				t.Fail()
   264  			}
   265  			return
   266  		}
   267  		defaultHandler(t)(w, r)
   268  	}))
   269  	defer ts.Close()
   270  	provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true)
   271  	assert.NoError(t, err)
   272  	repos, err := provider.GetBranches(context.Background(), &Repository{
   273  		Organization: "PROJECT",
   274  		Repository:   "REPO",
   275  		URL:          "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
   276  		Labels:       []string{},
   277  		RepositoryId: 1,
   278  	})
   279  	assert.NoError(t, err)
   280  	assert.Equal(t, 2, len(repos))
   281  	assert.Equal(t, Repository{
   282  		Organization: "PROJECT",
   283  		Repository:   "REPO",
   284  		URL:          "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
   285  		Branch:       "main",
   286  		SHA:          "8d51122def5632836d1cb1026e879069e10a1e13",
   287  		Labels:       []string{},
   288  		RepositoryId: 1,
   289  	}, *repos[0])
   290  
   291  	assert.Equal(t, Repository{
   292  		Organization: "PROJECT",
   293  		Repository:   "REPO",
   294  		URL:          "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
   295  		Branch:       "feature",
   296  		SHA:          "9d51122def5632836d1cb1026e879069e10a1e13",
   297  		Labels:       []string{},
   298  		RepositoryId: 1,
   299  	}, *repos[1])
   300  }
   301  
   302  func TestGetBranchesDefaultOnly(t *testing.T) {
   303  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   304  		assert.Empty(t, r.Header.Get("Authorization"))
   305  		switch r.RequestURI {
   306  		case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default":
   307  			_, err := io.WriteString(w, `{
   308  				"id": "refs/heads/default",
   309  				"displayId": "default",
   310  				"type": "BRANCH",
   311  				"latestCommit": "ab51122def5632836d1cb1026e879069e10a1e13",
   312  				"latestChangeset": "ab51122def5632836d1cb1026e879069e10a1e13",
   313  				"isDefault": true
   314  			}`)
   315  			if err != nil {
   316  				t.Fail()
   317  			}
   318  			return
   319  		}
   320  		defaultHandler(t)(w, r)
   321  	}))
   322  	defer ts.Close()
   323  	provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false)
   324  	assert.NoError(t, err)
   325  	repos, err := provider.GetBranches(context.Background(), &Repository{
   326  		Organization: "PROJECT",
   327  		Repository:   "REPO",
   328  		URL:          "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
   329  		Labels:       []string{},
   330  		RepositoryId: 1,
   331  	})
   332  	assert.NoError(t, err)
   333  	assert.Equal(t, 1, len(repos))
   334  	assert.Equal(t, Repository{
   335  		Organization: "PROJECT",
   336  		Repository:   "REPO",
   337  		URL:          "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
   338  		Branch:       "default",
   339  		SHA:          "ab51122def5632836d1cb1026e879069e10a1e13",
   340  		Labels:       []string{},
   341  		RepositoryId: 1,
   342  	}, *repos[0])
   343  }
   344  
   345  func TestGetBranchesMissingDefault(t *testing.T) {
   346  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   347  		assert.Empty(t, r.Header.Get("Authorization"))
   348  		switch r.RequestURI {
   349  		case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default":
   350  			http.Error(w, "Not found", http.StatusNotFound)
   351  		}
   352  		defaultHandler(t)(w, r)
   353  	}))
   354  	defer ts.Close()
   355  	provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false)
   356  	assert.NoError(t, err)
   357  	repos, err := provider.GetBranches(context.Background(), &Repository{
   358  		Organization: "PROJECT",
   359  		Repository:   "REPO",
   360  		URL:          "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
   361  		Labels:       []string{},
   362  		RepositoryId: 1,
   363  	})
   364  	assert.NoError(t, err)
   365  	assert.Empty(t, repos)
   366  }
   367  
   368  func TestGetBranchesEmptyRepo(t *testing.T) {
   369  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   370  		assert.Empty(t, r.Header.Get("Authorization"))
   371  		switch r.RequestURI {
   372  		case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default":
   373  			return
   374  		}
   375  	}))
   376  	defer ts.Close()
   377  	provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false)
   378  	assert.NoError(t, err)
   379  	repos, err := provider.GetBranches(context.Background(), &Repository{
   380  		Organization: "PROJECT",
   381  		Repository:   "REPO",
   382  		URL:          "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
   383  		Labels:       []string{},
   384  		RepositoryId: 1,
   385  	})
   386  	assert.Empty(t, repos)
   387  	assert.NoError(t, err)
   388  }
   389  
   390  func TestGetBranchesErrorDefaultBranch(t *testing.T) {
   391  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   392  		assert.Empty(t, r.Header.Get("Authorization"))
   393  		switch r.RequestURI {
   394  		case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default":
   395  			http.Error(w, "Internal server error", http.StatusInternalServerError)
   396  		}
   397  		defaultHandler(t)(w, r)
   398  	}))
   399  	defer ts.Close()
   400  	provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false)
   401  	assert.NoError(t, err)
   402  	_, err = provider.GetBranches(context.Background(), &Repository{
   403  		Organization: "PROJECT",
   404  		Repository:   "REPO",
   405  		URL:          "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
   406  		Labels:       []string{},
   407  		RepositoryId: 1,
   408  	})
   409  	assert.Error(t, err)
   410  }
   411  
   412  func TestListReposBasicAuth(t *testing.T) {
   413  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   414  		assert.Equal(t, "Basic dXNlcjpwYXNzd29yZA==", r.Header.Get("Authorization"))
   415  		assert.Equal(t, "no-check", r.Header.Get("X-Atlassian-Token"))
   416  		defaultHandler(t)(w, r)
   417  	}))
   418  	defer ts.Close()
   419  	provider, err := NewBitbucketServerProviderBasicAuth(context.Background(), "user", "password", ts.URL, "PROJECT", true)
   420  	assert.NoError(t, err)
   421  	repos, err := provider.ListRepos(context.Background(), "ssh")
   422  	verifyDefaultRepo(t, err, repos)
   423  }
   424  
   425  func TestListReposDefaultBranch(t *testing.T) {
   426  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   427  		assert.Empty(t, r.Header.Get("Authorization"))
   428  		switch r.RequestURI {
   429  		case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default":
   430  			_, err := io.WriteString(w, `{
   431  				"id": "refs/heads/default",
   432  				"displayId": "default",
   433  				"type": "BRANCH",
   434  				"latestCommit": "1d51122def5632836d1cb1026e879069e10a1e13",
   435  				"latestChangeset": "1d51122def5632836d1cb1026e879069e10a1e13",
   436  				"isDefault": true
   437  			}`)
   438  			if err != nil {
   439  				t.Fail()
   440  			}
   441  			return
   442  		}
   443  		defaultHandler(t)(w, r)
   444  	}))
   445  	defer ts.Close()
   446  	provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false)
   447  	assert.NoError(t, err)
   448  	repos, err := provider.ListRepos(context.Background(), "ssh")
   449  	assert.NoError(t, err)
   450  	assert.Equal(t, 1, len(repos))
   451  	assert.Equal(t, Repository{
   452  		Organization: "PROJECT",
   453  		Repository:   "REPO",
   454  		URL:          "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
   455  		Branch:       "default",
   456  		SHA:          "1d51122def5632836d1cb1026e879069e10a1e13",
   457  		Labels:       []string{},
   458  		RepositoryId: 1,
   459  	}, *repos[0])
   460  }
   461  
   462  func TestListReposMissingDefaultBranch(t *testing.T) {
   463  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   464  		assert.Empty(t, r.Header.Get("Authorization"))
   465  		switch r.RequestURI {
   466  		case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default":
   467  			http.Error(w, "Not found", http.StatusNotFound)
   468  		}
   469  		defaultHandler(t)(w, r)
   470  	}))
   471  	defer ts.Close()
   472  	provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false)
   473  	assert.NoError(t, err)
   474  	repos, err := provider.ListRepos(context.Background(), "ssh")
   475  	assert.NoError(t, err)
   476  	assert.Empty(t, repos)
   477  }
   478  
   479  func TestListReposErrorDefaultBranch(t *testing.T) {
   480  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   481  		assert.Empty(t, r.Header.Get("Authorization"))
   482  		switch r.RequestURI {
   483  		case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default":
   484  			http.Error(w, "Internal server error", http.StatusInternalServerError)
   485  		}
   486  		defaultHandler(t)(w, r)
   487  	}))
   488  	defer ts.Close()
   489  	provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false)
   490  	assert.NoError(t, err)
   491  	_, err = provider.ListRepos(context.Background(), "ssh")
   492  	assert.Error(t, err)
   493  }
   494  
   495  func TestListReposCloneProtocol(t *testing.T) {
   496  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   497  		assert.Empty(t, r.Header.Get("Authorization"))
   498  		defaultHandler(t)(w, r)
   499  	}))
   500  	defer ts.Close()
   501  	provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true)
   502  	assert.NoError(t, err)
   503  	repos, err := provider.ListRepos(context.Background(), "https")
   504  	assert.NoError(t, err)
   505  	assert.Equal(t, 1, len(repos))
   506  	assert.Equal(t, Repository{
   507  		Organization: "PROJECT",
   508  		Repository:   "REPO",
   509  		URL:          "https://mycompany.bitbucket.org/scm/PROJECT/REPO.git",
   510  		Branch:       "main",
   511  		SHA:          "8d51122def5632836d1cb1026e879069e10a1e13",
   512  		Labels:       []string{},
   513  		RepositoryId: 1,
   514  	}, *repos[0])
   515  }
   516  
   517  func TestListReposUnknownProtocol(t *testing.T) {
   518  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   519  		assert.Empty(t, r.Header.Get("Authorization"))
   520  		defaultHandler(t)(w, r)
   521  	}))
   522  	defer ts.Close()
   523  	provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true)
   524  	assert.NoError(t, err)
   525  	_, errProtocol := provider.ListRepos(context.Background(), "http")
   526  	assert.NotNil(t, errProtocol)
   527  }
   528  
   529  func TestBitbucketServerHasPath(t *testing.T) {
   530  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   531  		var err error
   532  		switch r.RequestURI {
   533  		case "/rest/api/1.0/projects/PROJECT/repos/REPO/browse/pkg?at=main&limit=100&type=true":
   534  			_, err = io.WriteString(w, `{"type":"DIRECTORY"}`)
   535  		case "/rest/api/1.0/projects/PROJECT/repos/REPO/browse/pkg/?at=main&limit=100&type=true":
   536  			_, err = io.WriteString(w, `{"type":"DIRECTORY"}`)
   537  		case "/rest/api/1.0/projects/PROJECT/repos/REPO/browse/anotherpkg/file.txt?at=main&limit=100&type=true":
   538  			_, err = io.WriteString(w, `{"type":"FILE"}`)
   539  
   540  		case "/rest/api/1.0/projects/PROJECT/repos/REPO/browse/anotherpkg/missing.txt?at=main&limit=100&type=true":
   541  			http.Error(w, "The path \"anotherpkg/missing.txt\" does not exist at revision \"main\"", http.StatusNotFound)
   542  		case "/rest/api/1.0/projects/PROJECT/repos/REPO/browse/notathing?at=main&limit=100&type=true":
   543  			http.Error(w, "The path \"notathing\" does not exist at revision \"main\"", http.StatusNotFound)
   544  
   545  		case "/rest/api/1.0/projects/PROJECT/repos/REPO/browse/return-redirect?at=main&limit=100&type=true":
   546  			http.Redirect(w, r, "http://"+r.Host+"/rest/api/1.0/projects/PROJECT/repos/REPO/browse/redirected?at=main&limit=100&type=true", http.StatusMovedPermanently)
   547  		case "/rest/api/1.0/projects/PROJECT/repos/REPO/browse/redirected?at=main&limit=100&type=true":
   548  			_, err = io.WriteString(w, `{"type":"DIRECTORY"}`)
   549  
   550  		case "/rest/api/1.0/projects/PROJECT/repos/REPO/browse/unauthorized-response?at=main&limit=100&type=true":
   551  			http.Error(w, "Authentication failed", http.StatusUnauthorized)
   552  
   553  		default:
   554  			t.Fail()
   555  		}
   556  		if err != nil {
   557  			t.Fail()
   558  		}
   559  	}))
   560  	defer ts.Close()
   561  	provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true)
   562  	assert.NoError(t, err)
   563  	repo := &Repository{
   564  		Organization: "PROJECT",
   565  		Repository:   "REPO",
   566  		Branch:       "main",
   567  	}
   568  	ok, err := provider.RepoHasPath(context.Background(), repo, "pkg")
   569  	assert.NoError(t, err)
   570  	assert.True(t, ok)
   571  
   572  	ok, err = provider.RepoHasPath(context.Background(), repo, "pkg/")
   573  	assert.NoError(t, err)
   574  	assert.True(t, ok)
   575  
   576  	ok, err = provider.RepoHasPath(context.Background(), repo, "anotherpkg/file.txt")
   577  	assert.NoError(t, err)
   578  	assert.True(t, ok)
   579  
   580  	ok, err = provider.RepoHasPath(context.Background(), repo, "anotherpkg/missing.txt")
   581  	assert.NoError(t, err)
   582  	assert.False(t, ok)
   583  
   584  	ok, err = provider.RepoHasPath(context.Background(), repo, "notathing")
   585  	assert.NoError(t, err)
   586  	assert.False(t, ok)
   587  
   588  	ok, err = provider.RepoHasPath(context.Background(), repo, "return-redirect")
   589  	assert.NoError(t, err)
   590  	assert.True(t, ok)
   591  
   592  	_, err = provider.RepoHasPath(context.Background(), repo, "unauthorized-response")
   593  	assert.Error(t, err)
   594  }