github.com/argoproj/argo-cd/v3@v3.2.1/applicationset/services/pull_request/bitbucket_cloud_test.go (about) 1 package pull_request 2 3 import ( 4 "fmt" 5 "io" 6 "net/http" 7 "net/http/httptest" 8 "testing" 9 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 13 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1" 14 ) 15 16 func defaultHandlerCloud(t *testing.T) func(http.ResponseWriter, *http.Request) { 17 t.Helper() 18 return func(w http.ResponseWriter, r *http.Request) { 19 w.Header().Set("Content-Type", "application/json") 20 var err error 21 switch r.RequestURI { 22 case "/repositories/OWNER/REPO/pullrequests/": 23 _, err = io.WriteString(w, `{ 24 "size": 1, 25 "pagelen": 10, 26 "page": 1, 27 "values": [ 28 { 29 "id": 101, 30 "title": "feat(foo-bar)", 31 "source": { 32 "branch": { 33 "name": "feature/foo-bar" 34 }, 35 "commit": { 36 "type": "commit", 37 "hash": "1a8dd249c04a" 38 } 39 }, 40 "author": { 41 "nickname": "testName" 42 } 43 } 44 ] 45 }`) 46 default: 47 t.Fail() 48 } 49 if err != nil { 50 t.Fail() 51 } 52 } 53 } 54 55 func TestParseUrlEmptyUrl(t *testing.T) { 56 url, err := parseURL("") 57 bitbucketURL, _ := url.Parse("https://api.bitbucket.org/2.0") 58 59 require.NoError(t, err) 60 assert.Equal(t, bitbucketURL, url) 61 } 62 63 func TestInvalidBaseUrlBasicAuthCloud(t *testing.T) { 64 _, err := NewBitbucketCloudServiceBasicAuth("http:// example.org", "user", "password", "OWNER", "REPO") 65 66 require.Error(t, err) 67 } 68 69 func TestInvalidBaseUrlBearerTokenCloud(t *testing.T) { 70 _, err := NewBitbucketCloudServiceBearerToken("http:// example.org", "TOKEN", "OWNER", "REPO") 71 72 require.Error(t, err) 73 } 74 75 func TestInvalidBaseUrlNoAuthCloud(t *testing.T) { 76 _, err := NewBitbucketCloudServiceNoAuth("http:// example.org", "OWNER", "REPO") 77 78 require.Error(t, err) 79 } 80 81 func TestListPullRequestBearerTokenCloud(t *testing.T) { 82 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 83 assert.Equal(t, "Bearer TOKEN", r.Header.Get("Authorization")) 84 defaultHandlerCloud(t)(w, r) 85 })) 86 defer ts.Close() 87 svc, err := NewBitbucketCloudServiceBearerToken(ts.URL, "TOKEN", "OWNER", "REPO") 88 require.NoError(t, err) 89 pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{}) 90 require.NoError(t, err) 91 assert.Len(t, pullRequests, 1) 92 assert.Equal(t, 101, pullRequests[0].Number) 93 assert.Equal(t, "feat(foo-bar)", pullRequests[0].Title) 94 assert.Equal(t, "feature/foo-bar", pullRequests[0].Branch) 95 assert.Equal(t, "1a8dd249c04a", pullRequests[0].HeadSHA) 96 assert.Equal(t, "testName", pullRequests[0].Author) 97 } 98 99 func TestListPullRequestNoAuthCloud(t *testing.T) { 100 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 101 assert.Empty(t, r.Header.Get("Authorization")) 102 defaultHandlerCloud(t)(w, r) 103 })) 104 defer ts.Close() 105 svc, err := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO") 106 require.NoError(t, err) 107 pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{}) 108 require.NoError(t, err) 109 assert.Len(t, pullRequests, 1) 110 assert.Equal(t, 101, pullRequests[0].Number) 111 assert.Equal(t, "feat(foo-bar)", pullRequests[0].Title) 112 assert.Equal(t, "feature/foo-bar", pullRequests[0].Branch) 113 assert.Equal(t, "1a8dd249c04a", pullRequests[0].HeadSHA) 114 assert.Equal(t, "testName", pullRequests[0].Author) 115 } 116 117 func TestListPullRequestBasicAuthCloud(t *testing.T) { 118 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 119 assert.Equal(t, "Basic dXNlcjpwYXNzd29yZA==", r.Header.Get("Authorization")) 120 defaultHandlerCloud(t)(w, r) 121 })) 122 defer ts.Close() 123 svc, err := NewBitbucketCloudServiceBasicAuth(ts.URL, "user", "password", "OWNER", "REPO") 124 require.NoError(t, err) 125 pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{}) 126 require.NoError(t, err) 127 assert.Len(t, pullRequests, 1) 128 assert.Equal(t, 101, pullRequests[0].Number) 129 assert.Equal(t, "feat(foo-bar)", pullRequests[0].Title) 130 assert.Equal(t, "feature/foo-bar", pullRequests[0].Branch) 131 assert.Equal(t, "1a8dd249c04a", pullRequests[0].HeadSHA) 132 assert.Equal(t, "testName", pullRequests[0].Author) 133 } 134 135 func TestListPullRequestPaginationCloud(t *testing.T) { 136 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 137 w.Header().Set("Content-Type", "application/json") 138 var err error 139 switch r.RequestURI { 140 case "/repositories/OWNER/REPO/pullrequests/": 141 _, err = fmt.Fprintf(w, `{ 142 "size": 2, 143 "pagelen": 1, 144 "page": 1, 145 "next": "http://%s/repositories/OWNER/REPO/pullrequests/?pagelen=1&page=2", 146 "values": [ 147 { 148 "id": 101, 149 "title": "feat(101)", 150 "source": { 151 "branch": { 152 "name": "feature-101" 153 }, 154 "commit": { 155 "type": "commit", 156 "hash": "1a8dd249c04a" 157 } 158 }, 159 "author": { 160 "nickname": "testName" 161 } 162 }, 163 { 164 "id": 102, 165 "title": "feat(102)", 166 "source": { 167 "branch": { 168 "name": "feature-102" 169 }, 170 "commit": { 171 "type": "commit", 172 "hash": "4cf807e67a6d" 173 } 174 }, 175 "author": { 176 "nickname": "testName" 177 } 178 } 179 ] 180 }`, r.Host) 181 case "/repositories/OWNER/REPO/pullrequests/?pagelen=1&page=2": 182 _, err = fmt.Fprintf(w, `{ 183 "size": 2, 184 "pagelen": 1, 185 "page": 2, 186 "previous": "http://%s/repositories/OWNER/REPO/pullrequests/?pagelen=1&page=1", 187 "values": [ 188 { 189 "id": 103, 190 "title": "feat(103)", 191 "source": { 192 "branch": { 193 "name": "feature-103" 194 }, 195 "commit": { 196 "type": "commit", 197 "hash": "6344d9623e3b" 198 } 199 }, 200 "author": { 201 "nickname": "testName" 202 } 203 } 204 ] 205 }`, r.Host) 206 default: 207 t.Fail() 208 } 209 if err != nil { 210 t.Fail() 211 } 212 })) 213 defer ts.Close() 214 svc, err := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO") 215 require.NoError(t, err) 216 pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{}) 217 require.NoError(t, err) 218 assert.Len(t, pullRequests, 3) 219 assert.Equal(t, PullRequest{ 220 Number: 101, 221 Title: "feat(101)", 222 Branch: "feature-101", 223 HeadSHA: "1a8dd249c04a", 224 Author: "testName", 225 }, *pullRequests[0]) 226 assert.Equal(t, PullRequest{ 227 Number: 102, 228 Title: "feat(102)", 229 Branch: "feature-102", 230 HeadSHA: "4cf807e67a6d", 231 Author: "testName", 232 }, *pullRequests[1]) 233 assert.Equal(t, PullRequest{ 234 Number: 103, 235 Title: "feat(103)", 236 Branch: "feature-103", 237 HeadSHA: "6344d9623e3b", 238 Author: "testName", 239 }, *pullRequests[2]) 240 } 241 242 func TestListResponseErrorCloud(t *testing.T) { 243 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { 244 w.WriteHeader(http.StatusInternalServerError) 245 })) 246 defer ts.Close() 247 svc, _ := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO") 248 _, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{}) 249 require.Error(t, err) 250 } 251 252 func TestListResponseMalformedCloud(t *testing.T) { 253 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 254 w.Header().Set("Content-Type", "application/json") 255 switch r.RequestURI { 256 case "/repositories/OWNER/REPO/pullrequests/": 257 _, err := io.WriteString(w, `[{ 258 "size": 1, 259 "pagelen": 10, 260 "page": 1, 261 "values": [{ "id": 101 }] 262 }]`) 263 if err != nil { 264 t.Fail() 265 } 266 default: 267 t.Fail() 268 } 269 })) 270 defer ts.Close() 271 svc, _ := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO") 272 _, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{}) 273 require.Error(t, err) 274 } 275 276 func TestListResponseMalformedValuesCloud(t *testing.T) { 277 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 278 w.Header().Set("Content-Type", "application/json") 279 switch r.RequestURI { 280 case "/repositories/OWNER/REPO/pullrequests/": 281 _, err := io.WriteString(w, `{ 282 "size": 1, 283 "pagelen": 10, 284 "page": 1, 285 "values": { "id": 101 } 286 }`) 287 if err != nil { 288 t.Fail() 289 } 290 default: 291 t.Fail() 292 } 293 })) 294 defer ts.Close() 295 svc, _ := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO") 296 _, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{}) 297 require.Error(t, err) 298 } 299 300 func TestListResponseEmptyCloud(t *testing.T) { 301 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 302 w.Header().Set("Content-Type", "application/json") 303 switch r.RequestURI { 304 case "/repositories/OWNER/REPO/pullrequests/": 305 _, err := io.WriteString(w, `{ 306 "size": 1, 307 "pagelen": 10, 308 "page": 1, 309 "values": [] 310 }`) 311 if err != nil { 312 t.Fail() 313 } 314 default: 315 t.Fail() 316 } 317 })) 318 defer ts.Close() 319 svc, err := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO") 320 require.NoError(t, err) 321 pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{}) 322 require.NoError(t, err) 323 assert.Empty(t, pullRequests) 324 } 325 326 func TestListPullRequestBranchMatchCloud(t *testing.T) { 327 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 328 w.Header().Set("Content-Type", "application/json") 329 var err error 330 switch r.RequestURI { 331 case "/repositories/OWNER/REPO/pullrequests/": 332 _, err = fmt.Fprintf(w, `{ 333 "size": 2, 334 "pagelen": 1, 335 "page": 1, 336 "next": "http://%s/repositories/OWNER/REPO/pullrequests/?pagelen=1&page=2", 337 "values": [ 338 { 339 "id": 101, 340 "title": "feat(101)", 341 "source": { 342 "branch": { 343 "name": "feature-101" 344 }, 345 "commit": { 346 "type": "commit", 347 "hash": "1a8dd249c04a" 348 } 349 }, 350 "author": { 351 "nickname": "testName" 352 }, 353 "destination": { 354 "branch": { 355 "name": "master" 356 } 357 } 358 }, 359 { 360 "id": 200, 361 "title": "feat(200)", 362 "source": { 363 "branch": { 364 "name": "feature-200" 365 }, 366 "commit": { 367 "type": "commit", 368 "hash": "4cf807e67a6d" 369 } 370 }, 371 "author": { 372 "nickname": "testName" 373 }, 374 "destination": { 375 "branch": { 376 "name": "branch-200" 377 } 378 } 379 } 380 ] 381 }`, r.Host) 382 case "/repositories/OWNER/REPO/pullrequests/?pagelen=1&page=2": 383 _, err = fmt.Fprintf(w, `{ 384 "size": 2, 385 "pagelen": 1, 386 "page": 2, 387 "previous": "http://%s/repositories/OWNER/REPO/pullrequests/?pagelen=1&page=1", 388 "values": [ 389 { 390 "id": 102, 391 "title": "feat(102)", 392 "source": { 393 "branch": { 394 "name": "feature-102" 395 }, 396 "commit": { 397 "type": "commit", 398 "hash": "6344d9623e3b" 399 } 400 }, 401 "author": { 402 "nickname": "testName" 403 }, 404 "destination": { 405 "branch": { 406 "name": "master" 407 } 408 } 409 } 410 ] 411 }`, r.Host) 412 default: 413 t.Fail() 414 } 415 if err != nil { 416 t.Fail() 417 } 418 })) 419 defer ts.Close() 420 regexp := `feature-1[\d]{2}` 421 svc, err := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO") 422 require.NoError(t, err) 423 pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{ 424 { 425 BranchMatch: ®exp, 426 }, 427 }) 428 require.NoError(t, err) 429 assert.Len(t, pullRequests, 2) 430 assert.Equal(t, PullRequest{ 431 Number: 101, 432 Title: "feat(101)", 433 Branch: "feature-101", 434 HeadSHA: "1a8dd249c04a", 435 Author: "testName", 436 TargetBranch: "master", 437 }, *pullRequests[0]) 438 assert.Equal(t, PullRequest{ 439 Number: 102, 440 Title: "feat(102)", 441 Branch: "feature-102", 442 HeadSHA: "6344d9623e3b", 443 Author: "testName", 444 TargetBranch: "master", 445 }, *pullRequests[1]) 446 447 regexp = `.*2$` 448 svc, err = NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO") 449 require.NoError(t, err) 450 pullRequests, err = ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{ 451 { 452 BranchMatch: ®exp, 453 }, 454 }) 455 require.NoError(t, err) 456 assert.Len(t, pullRequests, 1) 457 assert.Equal(t, PullRequest{ 458 Number: 102, 459 Title: "feat(102)", 460 Branch: "feature-102", 461 HeadSHA: "6344d9623e3b", 462 Author: "testName", 463 TargetBranch: "master", 464 }, *pullRequests[0]) 465 466 regexp = `[\d{2}` 467 svc, err = NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO") 468 require.NoError(t, err) 469 _, err = ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{ 470 { 471 BranchMatch: ®exp, 472 }, 473 }) 474 require.Error(t, err) 475 476 regexp = `feature-2[\d]{2}` 477 targetRegexp := `branch.*` 478 pullRequests, err = ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{ 479 { 480 BranchMatch: ®exp, 481 TargetBranchMatch: &targetRegexp, 482 }, 483 }) 484 require.NoError(t, err) 485 assert.Len(t, pullRequests, 1) 486 assert.Equal(t, PullRequest{ 487 Number: 200, 488 Title: "feat(200)", 489 Branch: "feature-200", 490 HeadSHA: "4cf807e67a6d", 491 Author: "testName", 492 TargetBranch: "branch-200", 493 }, *pullRequests[0]) 494 } 495 496 func TestBitbucketCloudListReturnsRepositoryNotFoundError(t *testing.T) { 497 mux := http.NewServeMux() 498 server := httptest.NewServer(mux) 499 defer server.Close() 500 501 path := "/repositories/nonexistent/nonexistent/pullrequests/" 502 503 mux.HandleFunc(path, func(w http.ResponseWriter, _ *http.Request) { 504 // Return 404 status to simulate repository not found 505 w.WriteHeader(http.StatusNotFound) 506 _, _ = w.Write([]byte(`{"message": "404 Project Not Found"}`)) 507 }) 508 509 svc, err := NewBitbucketCloudServiceNoAuth(server.URL, "nonexistent", "nonexistent") 510 require.NoError(t, err) 511 512 prs, err := svc.List(t.Context()) 513 514 // Should return empty pull requests list 515 assert.Empty(t, prs) 516 517 // Should return RepositoryNotFoundError 518 require.Error(t, err) 519 assert.True(t, IsRepositoryNotFoundError(err), "Expected RepositoryNotFoundError but got: %v", err) 520 }