code.gitea.io/gitea@v1.21.7/services/migrations/gitlab_test.go (about) 1 // Copyright 2019 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package migrations 5 6 import ( 7 "context" 8 "fmt" 9 "net/http" 10 "net/http/httptest" 11 "os" 12 "strconv" 13 "testing" 14 "time" 15 16 "code.gitea.io/gitea/modules/json" 17 base "code.gitea.io/gitea/modules/migration" 18 19 "github.com/stretchr/testify/assert" 20 "github.com/xanzy/go-gitlab" 21 ) 22 23 func TestGitlabDownloadRepo(t *testing.T) { 24 // Skip tests if Gitlab token is not found 25 gitlabPersonalAccessToken := os.Getenv("GITLAB_READ_TOKEN") 26 if gitlabPersonalAccessToken == "" { 27 t.Skip("skipped test because GITLAB_READ_TOKEN was not in the environment") 28 } 29 30 resp, err := http.Get("https://gitlab.com/gitea/test_repo") 31 if err != nil || resp.StatusCode != http.StatusOK { 32 t.Skipf("Can't access test repo, skipping %s", t.Name()) 33 } 34 35 downloader, err := NewGitlabDownloader(context.Background(), "https://gitlab.com", "gitea/test_repo", "", "", gitlabPersonalAccessToken) 36 if err != nil { 37 t.Fatalf("NewGitlabDownloader is nil: %v", err) 38 } 39 repo, err := downloader.GetRepoInfo() 40 assert.NoError(t, err) 41 // Repo Owner is blank in Gitlab Group repos 42 assertRepositoryEqual(t, &base.Repository{ 43 Name: "test_repo", 44 Owner: "", 45 Description: "Test repository for testing migration from gitlab to gitea", 46 CloneURL: "https://gitlab.com/gitea/test_repo.git", 47 OriginalURL: "https://gitlab.com/gitea/test_repo", 48 DefaultBranch: "master", 49 }, repo) 50 51 topics, err := downloader.GetTopics() 52 assert.NoError(t, err) 53 assert.True(t, len(topics) == 2) 54 assert.EqualValues(t, []string{"migration", "test"}, topics) 55 56 milestones, err := downloader.GetMilestones() 57 assert.NoError(t, err) 58 assertMilestonesEqual(t, []*base.Milestone{ 59 { 60 Title: "1.1.0", 61 Created: time.Date(2019, 11, 28, 8, 42, 44, 575000000, time.UTC), 62 Updated: timePtr(time.Date(2019, 11, 28, 8, 42, 44, 575000000, time.UTC)), 63 State: "active", 64 }, 65 { 66 Title: "1.0.0", 67 Created: time.Date(2019, 11, 28, 8, 42, 30, 301000000, time.UTC), 68 Updated: timePtr(time.Date(2019, 11, 28, 15, 57, 52, 401000000, time.UTC)), 69 Closed: timePtr(time.Date(2019, 11, 28, 15, 57, 52, 401000000, time.UTC)), 70 State: "closed", 71 }, 72 }, milestones) 73 74 labels, err := downloader.GetLabels() 75 assert.NoError(t, err) 76 assertLabelsEqual(t, []*base.Label{ 77 { 78 Name: "bug", 79 Color: "d9534f", 80 }, 81 { 82 Name: "confirmed", 83 Color: "d9534f", 84 }, 85 { 86 Name: "critical", 87 Color: "d9534f", 88 }, 89 { 90 Name: "discussion", 91 Color: "428bca", 92 }, 93 { 94 Name: "documentation", 95 Color: "f0ad4e", 96 }, 97 { 98 Name: "duplicate", 99 Color: "7f8c8d", 100 }, 101 { 102 Name: "enhancement", 103 Color: "5cb85c", 104 }, 105 { 106 Name: "suggestion", 107 Color: "428bca", 108 }, 109 { 110 Name: "support", 111 Color: "f0ad4e", 112 }, 113 }, labels) 114 115 releases, err := downloader.GetReleases() 116 assert.NoError(t, err) 117 assertReleasesEqual(t, []*base.Release{ 118 { 119 TagName: "v0.9.99", 120 TargetCommitish: "0720a3ec57c1f843568298117b874319e7deee75", 121 Name: "First Release", 122 Body: "A test release", 123 Created: time.Date(2019, 11, 28, 9, 9, 48, 840000000, time.UTC), 124 PublisherID: 1241334, 125 PublisherName: "lafriks", 126 }, 127 }, releases) 128 129 issues, isEnd, err := downloader.GetIssues(1, 2) 130 assert.NoError(t, err) 131 assert.False(t, isEnd) 132 133 assertIssuesEqual(t, []*base.Issue{ 134 { 135 Number: 1, 136 Title: "Please add an animated gif icon to the merge button", 137 Content: "I just want the merge button to hurt my eyes a little. :stuck_out_tongue_closed_eyes:", 138 Milestone: "1.0.0", 139 PosterID: 1241334, 140 PosterName: "lafriks", 141 State: "closed", 142 Created: time.Date(2019, 11, 28, 8, 43, 35, 459000000, time.UTC), 143 Updated: time.Date(2019, 11, 28, 8, 46, 23, 304000000, time.UTC), 144 Labels: []*base.Label{ 145 { 146 Name: "bug", 147 }, 148 { 149 Name: "discussion", 150 }, 151 }, 152 Reactions: []*base.Reaction{ 153 { 154 UserID: 1241334, 155 UserName: "lafriks", 156 Content: "thumbsup", 157 }, 158 { 159 UserID: 1241334, 160 UserName: "lafriks", 161 Content: "open_mouth", 162 }, 163 }, 164 Closed: timePtr(time.Date(2019, 11, 28, 8, 46, 23, 275000000, time.UTC)), 165 }, 166 { 167 Number: 2, 168 Title: "Test issue", 169 Content: "This is test issue 2, do not touch!", 170 Milestone: "1.1.0", 171 PosterID: 1241334, 172 PosterName: "lafriks", 173 State: "closed", 174 Created: time.Date(2019, 11, 28, 8, 44, 46, 277000000, time.UTC), 175 Updated: time.Date(2019, 11, 28, 8, 45, 44, 987000000, time.UTC), 176 Labels: []*base.Label{ 177 { 178 Name: "duplicate", 179 }, 180 }, 181 Reactions: []*base.Reaction{ 182 { 183 UserID: 1241334, 184 UserName: "lafriks", 185 Content: "thumbsup", 186 }, 187 { 188 UserID: 1241334, 189 UserName: "lafriks", 190 Content: "thumbsdown", 191 }, 192 { 193 UserID: 1241334, 194 UserName: "lafriks", 195 Content: "laughing", 196 }, 197 { 198 UserID: 1241334, 199 UserName: "lafriks", 200 Content: "tada", 201 }, 202 { 203 UserID: 1241334, 204 UserName: "lafriks", 205 Content: "confused", 206 }, 207 { 208 UserID: 1241334, 209 UserName: "lafriks", 210 Content: "hearts", 211 }, 212 }, 213 Closed: timePtr(time.Date(2019, 11, 28, 8, 45, 44, 959000000, time.UTC)), 214 }, 215 }, issues) 216 217 comments, _, err := downloader.GetComments(&base.Issue{ 218 Number: 2, 219 ForeignIndex: 2, 220 Context: gitlabIssueContext{IsMergeRequest: false}, 221 }) 222 assert.NoError(t, err) 223 assertCommentsEqual(t, []*base.Comment{ 224 { 225 IssueIndex: 2, 226 PosterID: 1241334, 227 PosterName: "lafriks", 228 Created: time.Date(2019, 11, 28, 8, 44, 52, 501000000, time.UTC), 229 Content: "This is a comment", 230 Reactions: nil, 231 }, 232 { 233 IssueIndex: 2, 234 PosterID: 1241334, 235 PosterName: "lafriks", 236 Created: time.Date(2019, 11, 28, 8, 45, 2, 329000000, time.UTC), 237 Content: "changed milestone to %2", 238 Reactions: nil, 239 }, 240 { 241 IssueIndex: 2, 242 PosterID: 1241334, 243 PosterName: "lafriks", 244 Created: time.Date(2019, 11, 28, 8, 45, 45, 7000000, time.UTC), 245 Content: "closed", 246 Reactions: nil, 247 }, 248 { 249 IssueIndex: 2, 250 PosterID: 1241334, 251 PosterName: "lafriks", 252 Created: time.Date(2019, 11, 28, 8, 45, 53, 501000000, time.UTC), 253 Content: "A second comment", 254 Reactions: nil, 255 }, 256 }, comments) 257 258 prs, _, err := downloader.GetPullRequests(1, 1) 259 assert.NoError(t, err) 260 assertPullRequestsEqual(t, []*base.PullRequest{ 261 { 262 Number: 4, 263 Title: "Test branch", 264 Content: "do not merge this PR", 265 Milestone: "1.0.0", 266 PosterID: 1241334, 267 PosterName: "lafriks", 268 State: "opened", 269 Created: time.Date(2019, 11, 28, 15, 56, 54, 104000000, time.UTC), 270 Labels: []*base.Label{ 271 { 272 Name: "bug", 273 }, 274 }, 275 Reactions: []*base.Reaction{{ 276 UserID: 4575606, 277 UserName: "real6543", 278 Content: "thumbsup", 279 }, { 280 UserID: 4575606, 281 UserName: "real6543", 282 Content: "tada", 283 }}, 284 PatchURL: "https://gitlab.com/gitea/test_repo/-/merge_requests/2.patch", 285 Head: base.PullRequestBranch{ 286 Ref: "feat/test", 287 CloneURL: "https://gitlab.com/gitea/test_repo/-/merge_requests/2", 288 SHA: "9f733b96b98a4175276edf6a2e1231489c3bdd23", 289 RepoName: "test_repo", 290 OwnerName: "lafriks", 291 }, 292 Base: base.PullRequestBranch{ 293 Ref: "master", 294 SHA: "", 295 OwnerName: "lafriks", 296 RepoName: "test_repo", 297 }, 298 Closed: nil, 299 Merged: false, 300 MergedTime: nil, 301 MergeCommitSHA: "", 302 ForeignIndex: 2, 303 Context: gitlabIssueContext{IsMergeRequest: true}, 304 }, 305 }, prs) 306 307 rvs, err := downloader.GetReviews(&base.PullRequest{Number: 1, ForeignIndex: 1}) 308 assert.NoError(t, err) 309 assertReviewsEqual(t, []*base.Review{ 310 { 311 IssueIndex: 1, 312 ReviewerID: 4102996, 313 ReviewerName: "zeripath", 314 CreatedAt: time.Date(2019, 11, 28, 16, 2, 8, 377000000, time.UTC), 315 State: "APPROVED", 316 }, 317 { 318 IssueIndex: 1, 319 ReviewerID: 527793, 320 ReviewerName: "axifive", 321 CreatedAt: time.Date(2019, 11, 28, 16, 2, 8, 377000000, time.UTC), 322 State: "APPROVED", 323 }, 324 }, rvs) 325 326 rvs, err = downloader.GetReviews(&base.PullRequest{Number: 2, ForeignIndex: 2}) 327 assert.NoError(t, err) 328 assertReviewsEqual(t, []*base.Review{ 329 { 330 IssueIndex: 2, 331 ReviewerID: 4575606, 332 ReviewerName: "real6543", 333 CreatedAt: time.Date(2020, 4, 19, 19, 24, 21, 108000000, time.UTC), 334 State: "APPROVED", 335 }, 336 }, rvs) 337 } 338 339 func gitlabClientMockSetup(t *testing.T) (*http.ServeMux, *httptest.Server, *gitlab.Client) { 340 // mux is the HTTP request multiplexer used with the test server. 341 mux := http.NewServeMux() 342 343 // server is a test HTTP server used to provide mock API responses. 344 server := httptest.NewServer(mux) 345 346 // client is the Gitlab client being tested. 347 client, err := gitlab.NewClient("", gitlab.WithBaseURL(server.URL)) 348 if err != nil { 349 server.Close() 350 t.Fatalf("Failed to create client: %v", err) 351 } 352 353 return mux, server, client 354 } 355 356 func gitlabClientMockTeardown(server *httptest.Server) { 357 server.Close() 358 } 359 360 type reviewTestCase struct { 361 repoID, prID, reviewerID int 362 reviewerName string 363 createdAt, updatedAt *time.Time 364 expectedCreatedAt time.Time 365 } 366 367 func convertTestCase(t reviewTestCase) (func(w http.ResponseWriter, r *http.Request), base.Review) { 368 var updatedAtField string 369 if t.updatedAt == nil { 370 updatedAtField = "" 371 } else { 372 updatedAtField = `"updated_at": "` + t.updatedAt.Format(time.RFC3339) + `",` 373 } 374 375 var createdAtField string 376 if t.createdAt == nil { 377 createdAtField = "" 378 } else { 379 createdAtField = `"created_at": "` + t.createdAt.Format(time.RFC3339) + `",` 380 } 381 382 handler := func(w http.ResponseWriter, r *http.Request) { 383 fmt.Fprint(w, ` 384 { 385 "id": 5, 386 "iid": `+strconv.Itoa(t.prID)+`, 387 "project_id": `+strconv.Itoa(t.repoID)+`, 388 "title": "Approvals API", 389 "description": "Test", 390 "state": "opened", 391 `+createdAtField+` 392 `+updatedAtField+` 393 "merge_status": "cannot_be_merged", 394 "approvals_required": 2, 395 "approvals_left": 1, 396 "approved_by": [ 397 { 398 "user": { 399 "name": "Administrator", 400 "username": "`+t.reviewerName+`", 401 "id": `+strconv.Itoa(t.reviewerID)+`, 402 "state": "active", 403 "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon", 404 "web_url": "http://localhost:3000/root" 405 } 406 } 407 ] 408 }`) 409 } 410 review := base.Review{ 411 IssueIndex: int64(t.prID), 412 ReviewerID: int64(t.reviewerID), 413 ReviewerName: t.reviewerName, 414 CreatedAt: t.expectedCreatedAt, 415 State: "APPROVED", 416 } 417 418 return handler, review 419 } 420 421 func TestGitlabGetReviews(t *testing.T) { 422 mux, server, client := gitlabClientMockSetup(t) 423 defer gitlabClientMockTeardown(server) 424 425 repoID := 1324 426 427 downloader := &GitlabDownloader{ 428 ctx: context.Background(), 429 client: client, 430 repoID: repoID, 431 } 432 433 createdAt := time.Date(2020, 4, 19, 19, 24, 21, 0, time.UTC) 434 435 for _, testCase := range []reviewTestCase{ 436 { 437 repoID: repoID, 438 prID: 1, 439 reviewerID: 801, 440 reviewerName: "someone1", 441 createdAt: nil, 442 updatedAt: &createdAt, 443 expectedCreatedAt: createdAt, 444 }, 445 { 446 repoID: repoID, 447 prID: 2, 448 reviewerID: 802, 449 reviewerName: "someone2", 450 createdAt: &createdAt, 451 updatedAt: nil, 452 expectedCreatedAt: createdAt, 453 }, 454 { 455 repoID: repoID, 456 prID: 3, 457 reviewerID: 803, 458 reviewerName: "someone3", 459 createdAt: nil, 460 updatedAt: nil, 461 expectedCreatedAt: time.Now(), 462 }, 463 } { 464 mock, review := convertTestCase(testCase) 465 mux.HandleFunc(fmt.Sprintf("/api/v4/projects/%d/merge_requests/%d/approvals", testCase.repoID, testCase.prID), mock) 466 467 id := int64(testCase.prID) 468 rvs, err := downloader.GetReviews(&base.Issue{Number: id, ForeignIndex: id}) 469 assert.NoError(t, err) 470 assertReviewsEqual(t, []*base.Review{&review}, rvs) 471 } 472 } 473 474 func TestAwardsToReactions(t *testing.T) { 475 downloader := &GitlabDownloader{} 476 // yes gitlab can have duplicated reactions (https://gitlab.com/jaywink/socialhome/-/issues/24) 477 testResponse := ` 478 [ 479 { 480 "name": "thumbsup", 481 "user": { 482 "id": 1241334, 483 "username": "lafriks" 484 } 485 }, 486 { 487 "name": "thumbsup", 488 "user": { 489 "id": 1241334, 490 "username": "lafriks" 491 } 492 }, 493 { 494 "name": "thumbsup", 495 "user": { 496 "id": 4575606, 497 "username": "real6543" 498 } 499 } 500 ] 501 ` 502 var awards []*gitlab.AwardEmoji 503 assert.NoError(t, json.Unmarshal([]byte(testResponse), &awards)) 504 505 reactions := downloader.awardsToReactions(awards) 506 assert.EqualValues(t, []*base.Reaction{ 507 { 508 UserName: "lafriks", 509 UserID: 1241334, 510 Content: "thumbsup", 511 }, 512 { 513 UserName: "real6543", 514 UserID: 4575606, 515 Content: "thumbsup", 516 }, 517 }, reactions) 518 } 519 520 func TestGitlabIIDResolver(t *testing.T) { 521 r := gitlabIIDResolver{} 522 r.recordIssueIID(1) 523 r.recordIssueIID(2) 524 r.recordIssueIID(3) 525 r.recordIssueIID(2) 526 assert.EqualValues(t, 4, r.generatePullRequestNumber(1)) 527 assert.EqualValues(t, 13, r.generatePullRequestNumber(10)) 528 529 assert.Panics(t, func() { 530 r := gitlabIIDResolver{} 531 r.recordIssueIID(1) 532 assert.EqualValues(t, 2, r.generatePullRequestNumber(1)) 533 r.recordIssueIID(3) // the generation procedure has been started, it shouldn't accept any new issue IID, so it panics 534 }) 535 }