mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2026-03-26 15:33:02 -04:00
It is unfortunately all mixed up, because refreshing the data, means breaking the tests. And changing the code means needing fresh data. - tests: ignore some more headers and sort the rest when dumping http responses - code: fixed #10234 by requesting the latest issues first. - tests: created a new repo to replace the disappeared repo, needed for the skip-numbers test - refreshed the testdata. - follow-up fixes to get the tests green. - including a cherry-pick of https://github.com/go-gitea/gitea/pull/36295 and #11272 Co-authored-by: Joakim Olsson <joakim@unbound.se> Co-authored-by: Robert Wolff <mahlzahn@posteo.de> Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11282 Reviewed-by: Robert Wolff <mahlzahn@posteo.de> Reviewed-by: Gusted <gusted@noreply.codeberg.org> Reviewed-by: patdyn <patdyn@noreply.codeberg.org> Co-authored-by: oliverpool <git@olivier.pfad.fr> Co-committed-by: oliverpool <git@olivier.pfad.fr>
841 lines
24 KiB
Go
841 lines
24 KiB
Go
// Copyright 2019 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package migrations
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
|
|
"forgejo.org/models/unittest"
|
|
"forgejo.org/modules/json"
|
|
base "forgejo.org/modules/migration"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
gitlab "gitlab.com/gitlab-org/api/client-go"
|
|
)
|
|
|
|
func TestGitlabDownloadRepo(t *testing.T) {
|
|
// If a GitLab access token is provided, this test will make HTTP requests to the live gitlab.com instance.
|
|
// When doing so, the responses from gitlab.com will be saved as test data files.
|
|
// If no access token is available, those cached responses will be used instead.
|
|
gitlabPersonalAccessToken := os.Getenv("GITLAB_READ_TOKEN")
|
|
fixturePath := "./testdata/gitlab/full_download"
|
|
server := unittest.NewMockWebServer(t, "https://gitlab.com", fixturePath, gitlabPersonalAccessToken != "")
|
|
defer server.Close()
|
|
|
|
downloader, err := NewGitlabDownloader(t.Context(), server.URL, "forgejo/test_repo", "", "", gitlabPersonalAccessToken)
|
|
if err != nil {
|
|
t.Fatalf("NewGitlabDownloader is nil: %v", err)
|
|
}
|
|
repo, err := downloader.GetRepoInfo()
|
|
require.NoError(t, err)
|
|
// Repo Owner is blank in Gitlab Group repos
|
|
assertRepositoryEqual(t, &base.Repository{
|
|
Name: "test_repo",
|
|
Owner: "",
|
|
Description: "Test repository for testing migration from gitlab to forgejo",
|
|
CloneURL: server.URL + "/forgejo/test_repo.git",
|
|
OriginalURL: server.URL + "/forgejo/test_repo",
|
|
DefaultBranch: "master",
|
|
}, repo)
|
|
|
|
topics, err := downloader.GetTopics()
|
|
require.NoError(t, err)
|
|
assert.Len(t, topics, 3)
|
|
assert.Equal(t, []string{"migration", "migration test", "test"}, topics)
|
|
|
|
milestones, err := downloader.GetMilestones()
|
|
require.NoError(t, err)
|
|
assertMilestonesEqual(t, []*base.Milestone{
|
|
{
|
|
Title: "1.0.0",
|
|
Created: time.Date(2024, 9, 3, 13, 53, 8, 516000000, time.UTC),
|
|
Updated: timePtr(time.Date(2024, 9, 3, 20, 3, 57, 786000000, time.UTC)),
|
|
Closed: timePtr(time.Date(2024, 9, 3, 20, 3, 57, 786000000, time.UTC)),
|
|
State: "closed",
|
|
},
|
|
{
|
|
Title: "1.1.0",
|
|
Created: time.Date(2024, 9, 3, 13, 52, 48, 414000000, time.UTC),
|
|
Updated: timePtr(time.Date(2024, 9, 3, 14, 52, 14, 93000000, time.UTC)),
|
|
State: "active",
|
|
},
|
|
}, milestones)
|
|
|
|
labels, err := downloader.GetLabels()
|
|
require.NoError(t, err)
|
|
assertLabelsEqual(t, []*base.Label{
|
|
{
|
|
Name: "bug",
|
|
Color: "d9534f",
|
|
},
|
|
{
|
|
Name: "confirmed",
|
|
Color: "d9534f",
|
|
},
|
|
{
|
|
Name: "critical",
|
|
Color: "d9534f",
|
|
},
|
|
{
|
|
Name: "discussion",
|
|
Color: "428bca",
|
|
},
|
|
{
|
|
Name: "documentation",
|
|
Color: "f0ad4e",
|
|
},
|
|
{
|
|
Name: "duplicate",
|
|
Color: "7f8c8d",
|
|
},
|
|
{
|
|
Name: "enhancement",
|
|
Color: "5cb85c",
|
|
},
|
|
{
|
|
Name: "suggestion",
|
|
Color: "428bca",
|
|
},
|
|
{
|
|
Name: "support",
|
|
Color: "f0ad4e",
|
|
},
|
|
{
|
|
Name: "test-scope/label0",
|
|
Color: "6699cc",
|
|
Description: "scoped label",
|
|
Exclusive: true,
|
|
},
|
|
{
|
|
Name: "test-scope/label1",
|
|
Color: "dc143c",
|
|
Exclusive: true,
|
|
},
|
|
}, labels)
|
|
|
|
releases, err := downloader.GetReleases()
|
|
require.NoError(t, err)
|
|
// TODO: fix size, currently reported as 0
|
|
// See https://codeberg.org/forgejo/forgejo/issues/11471
|
|
size := 0
|
|
dc := 0
|
|
assertReleasesEqual(t, []*base.Release{
|
|
{
|
|
TagName: "v0.9.99",
|
|
TargetCommitish: "0720a3ec57c1f843568298117b874319e7deee75",
|
|
Name: "First Release",
|
|
Body: "A test release",
|
|
Created: time.Date(2024, 9, 3, 15, 1, 1, 513000000, time.UTC),
|
|
PublisherID: 548513,
|
|
PublisherName: "mkobel",
|
|
Assets: []*base.ReleaseAsset{
|
|
{
|
|
ID: 10694714,
|
|
Name: "Forgejo logo",
|
|
Size: &size,
|
|
DownloadCount: &dc,
|
|
},
|
|
{
|
|
// TODO: fix name or URL, doesn't make sense to download without extension
|
|
// See https://codeberg.org/forgejo/forgejo/issues/11471
|
|
ID: 10687293,
|
|
Name: "zip (other)",
|
|
Size: &size,
|
|
DownloadCount: &dc,
|
|
// TODO: fix date, currently time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC)
|
|
// See https://codeberg.org/forgejo/forgejo/issues/11471
|
|
// Created: time.Date(2025, time.August, 7, 23, 39, 27, 0, time.UTC),
|
|
// Updated: time.Date(2025, time.August, 7, 23, 39, 29, 0, time.UTC),
|
|
},
|
|
{
|
|
ID: 10687292,
|
|
Name: "Forgejo",
|
|
Size: &size,
|
|
DownloadCount: &dc,
|
|
},
|
|
{
|
|
ID: 10687291,
|
|
Name: "Frogejo 🐸",
|
|
Size: &size,
|
|
DownloadCount: &dc,
|
|
},
|
|
{
|
|
ID: 10687290,
|
|
Name: "tar.bz2 (runbook)",
|
|
Size: &size,
|
|
DownloadCount: &dc,
|
|
},
|
|
{
|
|
ID: 10687289,
|
|
Name: "tar.gz (package)",
|
|
Size: &size,
|
|
DownloadCount: &dc,
|
|
},
|
|
},
|
|
},
|
|
}, releases)
|
|
|
|
issues, isEnd, err := downloader.GetIssues(1, 3)
|
|
require.NoError(t, err)
|
|
assert.False(t, isEnd)
|
|
assertIssuesEqual(t, []*base.Issue{
|
|
{
|
|
Number: 4,
|
|
Title: "Missing \"migration_test\" and \"migration_test_migration_test_migration_test\" topic",
|
|
Content: "This is required for https://codeberg.org/forgejo/forgejo/pulls/10336.",
|
|
Milestone: "",
|
|
PosterID: 29018602,
|
|
PosterName: "amadaluzia",
|
|
State: "opened",
|
|
Created: time.Date(2025, time.December, 6, 14, 2, 59, 995000000, time.UTC),
|
|
Updated: time.Date(2025, time.December, 6, 15, 4, 37, 324000000, time.UTC),
|
|
Labels: []*base.Label{},
|
|
Reactions: []*base.Reaction{},
|
|
},
|
|
{
|
|
Number: 3,
|
|
Title: "Fix plz",
|
|
Content: "Can we do something about it? !6 is maybe related to that.", // was "!2" on gitlab, now !6 on forgejo
|
|
Milestone: "",
|
|
PosterID: 10529876,
|
|
PosterName: "patdyn",
|
|
State: "opened",
|
|
Created: time.Date(2025, time.November, 25, 9, 49, 31, 991000000, time.UTC),
|
|
Updated: time.Date(2025, time.November, 25, 9, 49, 31, 991000000, time.UTC),
|
|
Labels: []*base.Label{},
|
|
Reactions: []*base.Reaction{},
|
|
},
|
|
{
|
|
Number: 2,
|
|
Title: "Test issue",
|
|
Content: "This is test issue 2, do not touch!",
|
|
Milestone: "1.0.0",
|
|
PosterID: 548513,
|
|
PosterName: "mkobel",
|
|
State: "closed",
|
|
Created: time.Date(2024, 9, 3, 14, 42, 35, 371000000, time.UTC),
|
|
Updated: time.Date(2026, 2, 13, 20, 46, 11, 889000000, time.UTC),
|
|
Labels: []*base.Label{
|
|
{
|
|
Name: "duplicate",
|
|
},
|
|
},
|
|
Reactions: []*base.Reaction{
|
|
{
|
|
UserID: 548513,
|
|
UserName: "mkobel",
|
|
Content: "thumbsup",
|
|
},
|
|
{
|
|
UserID: 548513,
|
|
UserName: "mkobel",
|
|
Content: "thumbsdown",
|
|
},
|
|
{
|
|
UserID: 548513,
|
|
UserName: "mkobel",
|
|
Content: "laughing",
|
|
},
|
|
{
|
|
UserID: 548513,
|
|
UserName: "mkobel",
|
|
Content: "tada",
|
|
},
|
|
{
|
|
UserID: 548513,
|
|
UserName: "mkobel",
|
|
Content: "confused",
|
|
},
|
|
{
|
|
UserID: 548513,
|
|
UserName: "mkobel",
|
|
Content: "hearts",
|
|
},
|
|
},
|
|
Closed: timePtr(time.Date(2024, 9, 3, 14, 43, 10, 906000000, time.UTC)),
|
|
},
|
|
}, issues)
|
|
issues, isEnd, err = downloader.GetIssues(2, 3)
|
|
require.NoError(t, err)
|
|
assert.True(t, isEnd)
|
|
assertIssuesEqual(t, []*base.Issue{
|
|
{
|
|
Number: 1,
|
|
Title: "Please add an animated gif icon to the merge button",
|
|
Content: "I just want the merge button to hurt my eyes a little. :stuck_out_tongue_closed_eyes:",
|
|
Milestone: "1.0.0",
|
|
PosterID: 548513,
|
|
PosterName: "mkobel",
|
|
State: "closed",
|
|
Created: time.Date(2024, 9, 3, 14, 42, 34, 924000000, time.UTC),
|
|
Updated: time.Date(2024, 9, 3, 14, 48, 43, 756000000, time.UTC),
|
|
Labels: []*base.Label{
|
|
{
|
|
Name: "bug",
|
|
},
|
|
{
|
|
Name: "discussion",
|
|
},
|
|
},
|
|
Reactions: []*base.Reaction{
|
|
{
|
|
UserID: 548513,
|
|
UserName: "mkobel",
|
|
Content: "thumbsup",
|
|
},
|
|
{
|
|
UserID: 548513,
|
|
UserName: "mkobel",
|
|
Content: "open_mouth",
|
|
},
|
|
},
|
|
Closed: timePtr(time.Date(2024, 9, 3, 14, 43, 10, 708000000, time.UTC)),
|
|
},
|
|
}, issues)
|
|
|
|
comments, _, err := downloader.GetComments(&base.Issue{
|
|
Number: 2,
|
|
ForeignIndex: 2,
|
|
Context: gitlabIssueContext{IsMergeRequest: false},
|
|
})
|
|
require.NoError(t, err)
|
|
assertCommentsEqual(t, []*base.Comment{
|
|
{
|
|
IssueIndex: 2,
|
|
PosterID: 548513,
|
|
PosterName: "mkobel",
|
|
Created: time.Date(2024, 9, 3, 14, 45, 20, 848000000, time.UTC),
|
|
Content: "This is a comment",
|
|
Reactions: nil,
|
|
},
|
|
{
|
|
IssueIndex: 2,
|
|
PosterID: 548513,
|
|
PosterName: "mkobel",
|
|
Created: time.Date(2024, 9, 3, 14, 45, 30, 59000000, time.UTC),
|
|
Content: "A second comment",
|
|
Reactions: nil,
|
|
},
|
|
{
|
|
IssueIndex: 2,
|
|
PosterID: 2005797,
|
|
PosterName: "oliverpool",
|
|
Created: time.Date(2026, 2, 13, 20, 46, 11, 841000000, time.UTC),
|
|
Content: "with an image {width=217 height=280}",
|
|
Reactions: nil,
|
|
CommentType: "close",
|
|
},
|
|
{
|
|
IssueIndex: 2,
|
|
PosterID: 548513,
|
|
PosterName: "mkobel",
|
|
Created: time.Date(2024, 9, 3, 14, 43, 10, 947000000, time.UTC),
|
|
Content: "",
|
|
Reactions: nil,
|
|
CommentType: "close",
|
|
},
|
|
}, comments)
|
|
|
|
comments, _, err = downloader.GetComments(&base.Issue{
|
|
Number: 3,
|
|
ForeignIndex: 3,
|
|
Context: gitlabIssueContext{IsMergeRequest: false},
|
|
})
|
|
require.NoError(t, err)
|
|
assertCommentsEqual(t, []*base.Comment{
|
|
{
|
|
IssueIndex: 3,
|
|
PosterID: 10529876,
|
|
PosterName: "patdyn",
|
|
Created: time.Date(2025, time.November, 25, 9, 49, 50, 899000000, time.UTC),
|
|
Content: "No actually its !5",
|
|
Reactions: nil,
|
|
},
|
|
}, comments)
|
|
|
|
comments, _, err = downloader.GetComments(&base.Issue{
|
|
Number: 5,
|
|
ForeignIndex: 2,
|
|
Context: gitlabIssueContext{IsMergeRequest: true},
|
|
})
|
|
require.NoError(t, err)
|
|
assertCommentsEqual(t, []*base.Comment{
|
|
{
|
|
IssueIndex: 5,
|
|
PosterID: 10529876,
|
|
PosterName: "patdyn",
|
|
Created: time.Date(2025, time.November, 25, 9, 49, 0, 750000000, time.UTC),
|
|
Content: "Although we had some trouble with !5.",
|
|
Reactions: nil,
|
|
},
|
|
{
|
|
IssueIndex: 5,
|
|
PosterID: 10529876,
|
|
PosterName: "patdyn",
|
|
Created: time.Date(2025, time.November, 25, 9, 49, 32, 263000000, time.UTC),
|
|
Content: "mentioned in issue #3",
|
|
Reactions: nil,
|
|
},
|
|
}, comments)
|
|
|
|
prs, _, err := downloader.GetPullRequests(1, 2)
|
|
require.NoError(t, err)
|
|
assertPullRequestsEqual(t, []*base.PullRequest{
|
|
{
|
|
Number: 6,
|
|
Title: "Test/parsing",
|
|
Content: "Simillar to !5 this solves an issue.",
|
|
Milestone: "",
|
|
PosterID: 10529876,
|
|
PosterName: "patdyn",
|
|
State: "opened",
|
|
Created: time.Date(2025, time.November, 25, 9, 48, 20, 259000000, time.UTC),
|
|
Labels: []*base.Label{},
|
|
Reactions: []*base.Reaction{},
|
|
PatchURL: server.URL + "/forgejo/test_repo/-/merge_requests/2.patch",
|
|
Head: base.PullRequestBranch{
|
|
Ref: "test/parsing",
|
|
CloneURL: server.URL + "/forgejo/test_repo/-/merge_requests/2",
|
|
SHA: "c59c9b451acca9d106cc19d61d87afe3fbbb8b83",
|
|
RepoName: "test_repo",
|
|
OwnerName: "patdyn",
|
|
},
|
|
Base: base.PullRequestBranch{
|
|
Ref: "master",
|
|
SHA: "c59c9b451acca9d106cc19d61d87afe3fbbb8b83",
|
|
OwnerName: "patdyn",
|
|
RepoName: "test_repo",
|
|
},
|
|
Closed: nil,
|
|
Merged: false,
|
|
MergedTime: nil,
|
|
MergeCommitSHA: "",
|
|
ForeignIndex: 2,
|
|
Context: gitlabIssueContext{IsMergeRequest: true},
|
|
},
|
|
{
|
|
Number: 5,
|
|
Title: "Test branch",
|
|
Content: "do not merge this PR",
|
|
Milestone: "1.1.0",
|
|
PosterID: 2005797,
|
|
PosterName: "oliverpool",
|
|
State: "opened",
|
|
Created: time.Date(2024, 9, 3, 7, 57, 19, 866000000, time.UTC),
|
|
Labels: []*base.Label{
|
|
{
|
|
Name: "test-scope/label0",
|
|
},
|
|
{
|
|
Name: "test-scope/label1",
|
|
},
|
|
},
|
|
Reactions: []*base.Reaction{{
|
|
UserID: 548513,
|
|
UserName: "mkobel",
|
|
Content: "thumbsup",
|
|
}, {
|
|
UserID: 548513,
|
|
UserName: "mkobel",
|
|
Content: "tada",
|
|
}},
|
|
PatchURL: server.URL + "/forgejo/test_repo/-/merge_requests/1.patch",
|
|
Head: base.PullRequestBranch{
|
|
Ref: "feat/test",
|
|
CloneURL: server.URL + "/forgejo/test_repo/-/merge_requests/1",
|
|
SHA: "9f733b96b98a4175276edf6a2e1231489c3bdd23",
|
|
RepoName: "test_repo",
|
|
OwnerName: "oliverpool",
|
|
},
|
|
Base: base.PullRequestBranch{
|
|
Ref: "master",
|
|
SHA: "c59c9b451acca9d106cc19d61d87afe3fbbb8b83",
|
|
OwnerName: "oliverpool",
|
|
RepoName: "test_repo",
|
|
},
|
|
Closed: nil,
|
|
Merged: false,
|
|
MergedTime: nil,
|
|
MergeCommitSHA: "",
|
|
ForeignIndex: 1,
|
|
Context: gitlabIssueContext{IsMergeRequest: true},
|
|
},
|
|
}, prs)
|
|
|
|
rvs, err := downloader.GetReviews(&base.PullRequest{Number: 1, ForeignIndex: 1})
|
|
require.NoError(t, err)
|
|
assertReviewsEqual(t, []*base.Review{
|
|
{
|
|
IssueIndex: 1,
|
|
ReviewerID: 548513,
|
|
ReviewerName: "mkobel",
|
|
CreatedAt: time.Date(2024, 9, 3, 7, 57, 19, 86600000, time.UTC),
|
|
State: "APPROVED",
|
|
},
|
|
}, rvs)
|
|
}
|
|
|
|
func TestGitlabSkippedIssueNumber(t *testing.T) {
|
|
// If a GitLab access token is provided, this test will make HTTP requests to the live gitlab.com instance.
|
|
// When doing so, the responses from gitlab.com will be saved as test data files.
|
|
// If no access token is available, those cached responses will be used instead.
|
|
gitlabPersonalAccessToken := os.Getenv("GITLAB_READ_TOKEN")
|
|
fixturePath := "./testdata/gitlab/skipped_issue_number"
|
|
server := unittest.NewMockWebServer(t, "https://gitlab.com", fixturePath, gitlabPersonalAccessToken != "")
|
|
defer server.Close()
|
|
|
|
downloader, err := NewGitlabDownloader(t.Context(), server.URL, "forgejo/test_repo-skipped-numbers", "", "", gitlabPersonalAccessToken)
|
|
if err != nil {
|
|
t.Fatalf("NewGitlabDownloader is nil: %v", err)
|
|
}
|
|
repo, err := downloader.GetRepoInfo()
|
|
require.NoError(t, err)
|
|
// Repo Owner is blank in Gitlab Group repos
|
|
assertRepositoryEqual(t, &base.Repository{
|
|
Name: "test_repo-skipped-numbers",
|
|
Owner: "",
|
|
Description: "",
|
|
CloneURL: server.URL + "/forgejo/test_repo-skipped-numbers.git",
|
|
OriginalURL: server.URL + "/forgejo/test_repo-skipped-numbers",
|
|
DefaultBranch: "main",
|
|
}, repo)
|
|
|
|
issues, isEnd, err := downloader.GetIssues(1, 10)
|
|
require.NoError(t, err)
|
|
assert.True(t, isEnd)
|
|
|
|
// the only issue in this repository has number 2
|
|
assert.Len(t, issues, 1)
|
|
assert.EqualValues(t, 2, issues[0].Number)
|
|
assert.Equal(t, "2nd issue", issues[0].Title)
|
|
|
|
prs, _, err := downloader.GetPullRequests(1, 10)
|
|
require.NoError(t, err)
|
|
// the only merge request in this repository has number 1,
|
|
// but we offset it by the maximum issue number so it becomes
|
|
// pull request 3 in Forgejo
|
|
assert.Len(t, prs, 1)
|
|
assert.EqualValues(t, 3, prs[0].Number)
|
|
assert.Equal(t, "cleanup README.md", prs[0].Title)
|
|
}
|
|
|
|
func gitlabClientMockSetup(t *testing.T) (*http.ServeMux, *httptest.Server, *gitlab.Client) {
|
|
// mux is the HTTP request multiplexer used with the test server.
|
|
mux := http.NewServeMux()
|
|
|
|
// server is a test HTTP server used to provide mock API responses.
|
|
server := httptest.NewServer(mux)
|
|
|
|
// client is the Gitlab client being tested.
|
|
client, err := gitlab.NewClient("", gitlab.WithBaseURL(server.URL))
|
|
if err != nil {
|
|
server.Close()
|
|
t.Fatalf("Failed to create client: %v", err)
|
|
}
|
|
|
|
return mux, server, client
|
|
}
|
|
|
|
func gitlabClientMockTeardown(server *httptest.Server) {
|
|
server.Close()
|
|
}
|
|
|
|
type reviewTestCase struct {
|
|
repoID, prID, reviewerID int
|
|
reviewerName string
|
|
createdAt, updatedAt *time.Time
|
|
expectedCreatedAt time.Time
|
|
}
|
|
|
|
func convertTestCase(t reviewTestCase) (func(w http.ResponseWriter, r *http.Request), base.Review) {
|
|
var updatedAtField string
|
|
if t.updatedAt == nil {
|
|
updatedAtField = ""
|
|
} else {
|
|
updatedAtField = `"updated_at": "` + t.updatedAt.Format(time.RFC3339) + `",`
|
|
}
|
|
|
|
var createdAtField string
|
|
if t.createdAt == nil {
|
|
createdAtField = ""
|
|
} else {
|
|
createdAtField = `"created_at": "` + t.createdAt.Format(time.RFC3339) + `",`
|
|
}
|
|
|
|
handler := func(w http.ResponseWriter, r *http.Request) {
|
|
fmt.Fprint(w, `
|
|
{
|
|
"id": 5,
|
|
"iid": `+strconv.Itoa(t.prID)+`,
|
|
"project_id": `+strconv.Itoa(t.repoID)+`,
|
|
"title": "Approvals API",
|
|
"description": "Test",
|
|
"state": "opened",
|
|
`+createdAtField+`
|
|
`+updatedAtField+`
|
|
"merge_status": "cannot_be_merged",
|
|
"approvals_required": 2,
|
|
"approvals_left": 1,
|
|
"approved_by": [
|
|
{
|
|
"user": {
|
|
"name": "Administrator",
|
|
"username": "`+t.reviewerName+`",
|
|
"id": `+strconv.Itoa(t.reviewerID)+`,
|
|
"state": "active",
|
|
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon",
|
|
"web_url": "http://localhost:3000/root"
|
|
}
|
|
}
|
|
]
|
|
}`)
|
|
}
|
|
review := base.Review{
|
|
IssueIndex: int64(t.prID),
|
|
ReviewerID: int64(t.reviewerID),
|
|
ReviewerName: t.reviewerName,
|
|
CreatedAt: t.expectedCreatedAt,
|
|
State: "APPROVED",
|
|
}
|
|
|
|
return handler, review
|
|
}
|
|
|
|
func TestGitlabGetReviews(t *testing.T) {
|
|
mux, server, client := gitlabClientMockSetup(t)
|
|
defer gitlabClientMockTeardown(server)
|
|
|
|
repoID := 1324
|
|
|
|
downloader := &GitlabDownloader{
|
|
ctx: t.Context(),
|
|
client: client,
|
|
repoID: repoID,
|
|
}
|
|
|
|
createdAt := time.Date(2020, 4, 19, 19, 24, 21, 0, time.UTC)
|
|
|
|
for _, testCase := range []reviewTestCase{
|
|
{
|
|
repoID: repoID,
|
|
prID: 1,
|
|
reviewerID: 801,
|
|
reviewerName: "someone1",
|
|
createdAt: nil,
|
|
updatedAt: &createdAt,
|
|
expectedCreatedAt: createdAt,
|
|
},
|
|
{
|
|
repoID: repoID,
|
|
prID: 2,
|
|
reviewerID: 802,
|
|
reviewerName: "someone2",
|
|
createdAt: &createdAt,
|
|
updatedAt: nil,
|
|
expectedCreatedAt: createdAt,
|
|
},
|
|
{
|
|
repoID: repoID,
|
|
prID: 3,
|
|
reviewerID: 803,
|
|
reviewerName: "someone3",
|
|
createdAt: nil,
|
|
updatedAt: nil,
|
|
expectedCreatedAt: time.Now(),
|
|
},
|
|
} {
|
|
mock, review := convertTestCase(testCase)
|
|
mux.HandleFunc(fmt.Sprintf("/api/v4/projects/%d/merge_requests/%d/approvals", testCase.repoID, testCase.prID), mock)
|
|
|
|
id := int64(testCase.prID)
|
|
rvs, err := downloader.GetReviews(&base.Issue{Number: id, ForeignIndex: id})
|
|
require.NoError(t, err)
|
|
assertReviewsEqual(t, []*base.Review{&review}, rvs)
|
|
}
|
|
}
|
|
|
|
func TestAwardsToReactions(t *testing.T) {
|
|
downloader := &GitlabDownloader{}
|
|
// yes gitlab can have duplicated reactions (https://gitlab.com/jaywink/socialhome/-/issues/24)
|
|
testResponse := `
|
|
[
|
|
{
|
|
"name": "thumbsup",
|
|
"user": {
|
|
"id": 1241334,
|
|
"username": "lafriks"
|
|
}
|
|
},
|
|
{
|
|
"name": "thumbsup",
|
|
"user": {
|
|
"id": 1241334,
|
|
"username": "lafriks"
|
|
}
|
|
},
|
|
{
|
|
"name": "thumbsup",
|
|
"user": {
|
|
"id": 4575606,
|
|
"username": "real6543"
|
|
}
|
|
}
|
|
]
|
|
`
|
|
var awards []*gitlab.AwardEmoji
|
|
require.NoError(t, json.Unmarshal([]byte(testResponse), &awards))
|
|
|
|
reactions := downloader.awardsToReactions(awards)
|
|
assert.Equal(t, []*base.Reaction{
|
|
{
|
|
UserName: "lafriks",
|
|
UserID: 1241334,
|
|
Content: "thumbsup",
|
|
},
|
|
{
|
|
UserName: "real6543",
|
|
UserID: 4575606,
|
|
Content: "thumbsup",
|
|
},
|
|
}, reactions)
|
|
}
|
|
|
|
func makeTestNote(id int, body string, system bool, t time.Time) gitlab.Note {
|
|
return gitlab.Note{
|
|
ID: id,
|
|
Author: struct {
|
|
ID int `json:"id"`
|
|
Username string `json:"username"`
|
|
Email string `json:"email"`
|
|
Name string `json:"name"`
|
|
State string `json:"state"`
|
|
AvatarURL string `json:"avatar_url"`
|
|
WebURL string `json:"web_url"`
|
|
}{
|
|
ID: 72,
|
|
Email: "test@example.com",
|
|
Username: "test",
|
|
},
|
|
Body: body,
|
|
CreatedAt: &t,
|
|
System: system,
|
|
}
|
|
}
|
|
|
|
func TestNoteToComment(t *testing.T) {
|
|
downloader := &GitlabDownloader{}
|
|
|
|
now := time.Now()
|
|
notes := []gitlab.Note{
|
|
makeTestNote(1, "This is a regular comment", false, now),
|
|
makeTestNote(2, "enabled an automatic merge for abcd1234", true, now),
|
|
makeTestNote(3, "changed target branch from `master` to `main`", true, now),
|
|
makeTestNote(4, "canceled the automatic merge", true, now),
|
|
}
|
|
comments := []base.Comment{{
|
|
IssueIndex: 17,
|
|
Index: 1,
|
|
PosterID: 72,
|
|
PosterName: "test",
|
|
PosterEmail: "test@example.com",
|
|
CommentType: "",
|
|
Content: "This is a regular comment",
|
|
Created: now,
|
|
Meta: map[string]any{},
|
|
}, {
|
|
IssueIndex: 17,
|
|
Index: 2,
|
|
PosterID: 72,
|
|
PosterName: "test",
|
|
PosterEmail: "test@example.com",
|
|
CommentType: "pull_scheduled_merge",
|
|
Content: "enabled an automatic merge for abcd1234",
|
|
Created: now,
|
|
Meta: map[string]any{},
|
|
}, {
|
|
IssueIndex: 17,
|
|
Index: 3,
|
|
PosterID: 72,
|
|
PosterName: "test",
|
|
PosterEmail: "test@example.com",
|
|
CommentType: "change_target_branch",
|
|
Content: "changed target branch from `master` to `main`",
|
|
Created: now,
|
|
Meta: map[string]any{
|
|
"OldRef": "master",
|
|
"NewRef": "main",
|
|
},
|
|
}, {
|
|
IssueIndex: 17,
|
|
Index: 4,
|
|
PosterID: 72,
|
|
PosterName: "test",
|
|
PosterEmail: "test@example.com",
|
|
CommentType: "pull_cancel_scheduled_merge",
|
|
Content: "canceled the automatic merge",
|
|
Created: now,
|
|
Meta: map[string]any{},
|
|
}}
|
|
|
|
for i, note := range notes {
|
|
actualComment := *downloader.convertNoteToComment(17, ¬e)
|
|
assert.Equal(t, actualComment, comments[i])
|
|
}
|
|
}
|
|
|
|
func TestGitlabIIDResolver(t *testing.T) {
|
|
r := gitlabIIDResolver{}
|
|
r.recordIssueIID(1)
|
|
r.recordIssueIID(2)
|
|
r.recordIssueIID(3)
|
|
r.recordIssueIID(2)
|
|
assert.EqualValues(t, 4, r.generatePullRequestNumber(1))
|
|
assert.EqualValues(t, 13, r.generatePullRequestNumber(10))
|
|
|
|
assert.Panics(t, func() {
|
|
r := gitlabIIDResolver{}
|
|
r.recordIssueIID(1)
|
|
assert.EqualValues(t, 2, r.generatePullRequestNumber(1))
|
|
r.recordIssueIID(3) // the generation procedure has been started, it shouldn't accept any new issue IID, so it panics
|
|
})
|
|
}
|
|
|
|
func TestCommentBodyParser(t *testing.T) {
|
|
downloader := GitlabDownloader{}
|
|
downloader.iidResolver.maxIssueIID = int64(10)
|
|
now := time.Now()
|
|
|
|
// Gitlab note references issue with #N and PR with !M, with N and M being arbitrary integers, so N == M is possible
|
|
testNote1 := makeTestNote(1, "Simillar to #9, may be solved in !4", false, now)
|
|
testNote2 := makeTestNote(2, "Simillar to #21, may be solved in !144", false, now)
|
|
testNote3 := makeTestNote(3, "Should actually be discussed in !5 or !6 and not in #2 (here)", false, now)
|
|
testNote4 := makeTestNote(4, "Closed by !1 and !14", false, now)
|
|
testNote5 := makeTestNote(5, "Actually !1 and !1 are the same but !100 and !214 are not", false, now)
|
|
testNote6 := makeTestNote(6, "!11 and !1 are simillar but !201 and !100 are not!", false, now)
|
|
testNote7 := makeTestNote(1, "Simillar to #9, may be solved in !004", false, now)
|
|
|
|
parsedBody1 := downloader.convertMRReference(testNote1.Body)
|
|
parsedBody2 := downloader.convertMRReference(testNote2.Body)
|
|
parsedBody3 := downloader.convertMRReference(testNote3.Body)
|
|
parsedBody4 := downloader.convertMRReference(testNote4.Body)
|
|
parsedBody5 := downloader.convertMRReference(testNote5.Body)
|
|
parsedBody6 := downloader.convertMRReference(testNote6.Body)
|
|
parsedBody7 := downloader.convertMRReference(testNote7.Body)
|
|
|
|
// Assuming a total of 20 comments + PRs
|
|
assert.Equal(t, "Simillar to #9, may be solved in !14", parsedBody1)
|
|
assert.Equal(t, "Simillar to #21, may be solved in !154", parsedBody2)
|
|
assert.Equal(t, "Should actually be discussed in !15 or !16 and not in #2 (here)", parsedBody3)
|
|
assert.Equal(t, "Closed by !11 and !24", parsedBody4)
|
|
assert.Equal(t, "Actually !11 and !11 are the same but !110 and !224 are not", parsedBody5)
|
|
assert.Equal(t, "!21 and !11 are simillar but !211 and !110 are not!", parsedBody6)
|
|
assert.Equal(t, "Simillar to #9, may be solved in !14", parsedBody7)
|
|
}
|