From ffb393213d2f1269aad3c019d039cf60d0fe4b10 Mon Sep 17 00:00:00 2001 From: Gusted Date: Tue, 22 Aug 2023 19:32:53 +0200 Subject: [PATCH] [MODERATION] Refactor integration testing (squash) - Motivation for this PR is that I'd noticed that a lot of repeated calls are happening between the test functions and that certain tests weren't using helper functions like `GetCSRF`, therefor this refactor of the integration tests to keep it: clean, small and hopefully more maintainable and understandable. - There are now three integration tests: `TestBlockUser`, `TestBlockUserFromOrganization` and `TestBlockActions` (and has been moved in that order in the source code). - `TestBlockUser` is for doing blocking related actions as an user and `TestBlockUserFromOrganization` as an organisation, even though they execute the same kind of tests they do not share any database calls or logic and therefor it currently doesn't make sense to merge them together (hopefully such oppurtinutiy might be presented in the future). - `TestBlockActions` now contain all tests for actions that should be blocked after blocking has happened, most tests now share the same doer and blocked users and a extra fixture has been added to make this possible for the comment test. - Less code, more comments and more re-use between tests. --- models/fixtures/comment.yml | 9 + models/fixtures/issue.yml | 2 +- tests/integration/api_nodeinfo_test.go | 2 +- tests/integration/block_test.go | 402 ++++++++++++------------- 4 files changed, 201 insertions(+), 214 deletions(-) diff --git a/models/fixtures/comment.yml b/models/fixtures/comment.yml index bd64680c8c..28381eb4b0 100644 --- a/models/fixtures/comment.yml +++ b/models/fixtures/comment.yml @@ -66,3 +66,12 @@ tree_path: "README.md" created_unix: 946684812 invalidated: true + +- + id: 8 + type: 0 # comment + poster_id: 2 + issue_id: 4 # in repo_id 2 + content: "I just wanted to add.." + created_unix: 946684812 + updated_unix: 946684812 diff --git a/models/fixtures/issue.yml b/models/fixtures/issue.yml index fa72f9b647..166ee0da9b 100644 --- a/models/fixtures/issue.yml +++ b/models/fixtures/issue.yml @@ -61,7 +61,7 @@ priority: 0 is_closed: true is_pull: false - num_comments: 0 + num_comments: 1 created_unix: 946684830 updated_unix: 978307200 is_locked: false diff --git a/tests/integration/api_nodeinfo_test.go b/tests/integration/api_nodeinfo_test.go index a347ec5b3b..c99e9ef59b 100644 --- a/tests/integration/api_nodeinfo_test.go +++ b/tests/integration/api_nodeinfo_test.go @@ -34,6 +34,6 @@ func TestNodeinfo(t *testing.T) { assert.Equal(t, "gitea", nodeinfo.Software.Name) assert.Equal(t, 25, nodeinfo.Usage.Users.Total) assert.Equal(t, 19, nodeinfo.Usage.LocalPosts) - assert.Equal(t, 2, nodeinfo.Usage.LocalComments) + assert.Equal(t, 3, nodeinfo.Usage.LocalComments) }) } diff --git a/tests/integration/block_test.go b/tests/integration/block_test.go index 3a45bf5db5..926ca46905 100644 --- a/tests/integration/block_test.go +++ b/tests/integration/block_test.go @@ -11,7 +11,6 @@ import ( "strconv" "testing" - "code.gitea.io/gitea/models/db" issue_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" @@ -45,6 +44,8 @@ func BlockUser(t *testing.T, doer, blockedUser *user_model.User) { assert.True(t, unittest.BeanExists(t, &user_model.BlockedUser{BlockID: blockedUser.ID, UserID: doer.ID})) } +// TestBlockUser ensures that users can execute blocking related actions can +// happen under the correct conditions. func TestBlockUser(t *testing.T) { defer tests.PrepareTestEnv(t)() @@ -97,191 +98,6 @@ func TestBlockUser(t *testing.T) { }) } -func TestBlockIssueCreation(t *testing.T) { - defer tests.PrepareTestEnv(t)() - - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - blockedUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2, OwnerID: doer.ID}) - BlockUser(t, doer, blockedUser) - - session := loginUser(t, blockedUser.Name) - req := NewRequest(t, "GET", "/"+repo.OwnerName+"/"+repo.Name+"/issues/new") - resp := session.MakeRequest(t, req, http.StatusOK) - - htmlDoc := NewHTMLParser(t, resp.Body) - link, exists := htmlDoc.doc.Find("form.ui.form").Attr("action") - assert.True(t, exists) - req = NewRequestWithValues(t, "POST", link, map[string]string{ - "_csrf": htmlDoc.GetCSRF(), - "title": "Title", - "content": "Hello!", - }) - - resp = session.MakeRequest(t, req, http.StatusOK) - htmlDoc = NewHTMLParser(t, resp.Body) - assert.Contains(t, - htmlDoc.doc.Find(".ui.negative.message").Text(), - translation.NewLocale("en-US").Tr("repo.issues.blocked_by_user"), - ) -} - -func TestBlockCommentCreation(t *testing.T) { - defer tests.PrepareTestEnv(t)() - - expectedFlash := "error%3DYou%2Bcannot%2Bcreate%2Ba%2Bcomment%2Bon%2Bthis%2Bissue%2Bbecause%2Byou%2Bare%2Bblocked%2Bby%2Bthe%2Brepository%2Bowner%2Bor%2Bthe%2Bposter%2Bof%2Bthe%2Bissue." - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - blockedUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) - - BlockUser(t, doer, blockedUser) - - t.Run("Blocked by repository owner", func(t *testing.T) { - defer tests.PrintCurrentTest(t)() - - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2, OwnerID: doer.ID}) - issue := unittest.AssertExistsAndLoadBean(t, &issue_model.Issue{ID: 4, RepoID: repo.ID}) - issueURL := fmt.Sprintf("/%s/%s/issues/%d", url.PathEscape(repo.OwnerName), url.PathEscape(repo.Name), issue.Index) - - session := loginUser(t, blockedUser.Name) - req := NewRequest(t, "GET", issueURL) - resp := session.MakeRequest(t, req, http.StatusOK) - htmlDoc := NewHTMLParser(t, resp.Body) - - req = NewRequestWithValues(t, "POST", path.Join(issueURL, "/comments"), map[string]string{ - "_csrf": htmlDoc.GetCSRF(), - "content": "Not a kind comment", - }) - session.MakeRequest(t, req, http.StatusOK) - - flashCookie := session.GetCookie(forgejo_context.CookieNameFlash) - assert.NotNil(t, flashCookie) - assert.EqualValues(t, expectedFlash, flashCookie.Value) - }) - - t.Run("Blocked by issue poster", func(t *testing.T) { - defer tests.PrintCurrentTest(t)() - - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 5}) - issue := unittest.AssertExistsAndLoadBean(t, &issue_model.Issue{ID: 15, RepoID: repo.ID, PosterID: doer.ID}) - issueURL := fmt.Sprintf("/%s/%s/issues/%d", url.PathEscape(repo.OwnerName), url.PathEscape(repo.Name), issue.Index) - - session := loginUser(t, blockedUser.Name) - req := NewRequest(t, "GET", issueURL) - resp := session.MakeRequest(t, req, http.StatusOK) - htmlDoc := NewHTMLParser(t, resp.Body) - - req = NewRequestWithValues(t, "POST", path.Join(issueURL, "/comments"), map[string]string{ - "_csrf": htmlDoc.GetCSRF(), - "content": "Not a kind comment", - }) - session.MakeRequest(t, req, http.StatusOK) - - flashCookie := session.GetCookie(forgejo_context.CookieNameFlash) - assert.NotNil(t, flashCookie) - assert.EqualValues(t, expectedFlash, flashCookie.Value) - }) -} - -func TestBlockIssueReaction(t *testing.T) { - defer tests.PrepareTestEnv(t)() - - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - blockedUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) - issue := unittest.AssertExistsAndLoadBean(t, &issue_model.Issue{ID: 4, PosterID: doer.ID, RepoID: repo.ID}) - issueURL := fmt.Sprintf("/%s/%s/issues/%d", url.PathEscape(repo.OwnerName), url.PathEscape(repo.Name), issue.Index) - - BlockUser(t, doer, blockedUser) - - session := loginUser(t, blockedUser.Name) - req := NewRequest(t, "GET", issueURL) - resp := session.MakeRequest(t, req, http.StatusOK) - htmlDoc := NewHTMLParser(t, resp.Body) - - req = NewRequestWithValues(t, "POST", path.Join(issueURL, "/reactions/react"), map[string]string{ - "_csrf": htmlDoc.GetCSRF(), - "content": "eyes", - }) - resp = session.MakeRequest(t, req, http.StatusOK) - type reactionResponse struct { - Empty bool `json:"empty"` - } - - var respBody reactionResponse - DecodeJSON(t, resp, &respBody) - - assert.EqualValues(t, true, respBody.Empty) -} - -func TestBlockCommentReaction(t *testing.T) { - defer tests.PrepareTestEnv(t)() - - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) - blockedUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - issue := unittest.AssertExistsAndLoadBean(t, &issue_model.Issue{ID: 1, RepoID: repo.ID}) - comment := unittest.AssertExistsAndLoadBean(t, &issue_model.Comment{ID: 3, PosterID: doer.ID, IssueID: issue.ID}) - _ = comment.LoadIssue(db.DefaultContext) - issueURL := fmt.Sprintf("/%s/%s/issues/%d", url.PathEscape(repo.OwnerName), url.PathEscape(repo.Name), issue.Index) - - BlockUser(t, doer, blockedUser) - - session := loginUser(t, blockedUser.Name) - req := NewRequest(t, "GET", issueURL) - resp := session.MakeRequest(t, req, http.StatusOK) - htmlDoc := NewHTMLParser(t, resp.Body) - - req = NewRequestWithValues(t, "POST", path.Join(repo.Link(), "/comments/", strconv.FormatInt(comment.ID, 10), "/reactions/react"), map[string]string{ - "_csrf": htmlDoc.GetCSRF(), - "content": "eyes", - }) - resp = session.MakeRequest(t, req, http.StatusOK) - type reactionResponse struct { - Empty bool `json:"empty"` - } - - var respBody reactionResponse - DecodeJSON(t, resp, &respBody) - - assert.EqualValues(t, true, respBody.Empty) -} - -// TestBlockFollow ensures that the doer and blocked user cannot follow each other. -func TestBlockFollow(t *testing.T) { - defer tests.PrepareTestEnv(t)() - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) - blockedUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) - - BlockUser(t, doer, blockedUser) - - // Doer cannot follow blocked user. - t.Run("Doer follow blocked user", func(t *testing.T) { - defer tests.PrintCurrentTest(t)() - session := loginUser(t, doer.Name) - - req := NewRequestWithValues(t, "POST", "/"+blockedUser.Name, map[string]string{ - "_csrf": GetCSRF(t, session, "/"+blockedUser.Name), - "action": "follow", - }) - session.MakeRequest(t, req, http.StatusSeeOther) - unittest.AssertNotExistsBean(t, &user_model.Follow{UserID: doer.ID, FollowID: blockedUser.ID}) - }) - - // Blocked user cannot follow doer. - t.Run("Blocked user follow doer", func(t *testing.T) { - defer tests.PrintCurrentTest(t)() - session := loginUser(t, blockedUser.Name) - - req := NewRequestWithValues(t, "POST", "/"+doer.Name, map[string]string{ - "_csrf": GetCSRF(t, session, "/"+doer.Name), - "action": "follow", - }) - session.MakeRequest(t, req, http.StatusSeeOther) - - unittest.AssertNotExistsBean(t, &user_model.Follow{UserID: blockedUser.ID, FollowID: doer.ID}) - }) -} - // TestBlockUserFromOrganization ensures that an organisation can block and unblock an user. func TestBlockUserFromOrganization(t *testing.T) { defer tests.PrepareTestEnv(t)() @@ -340,46 +156,208 @@ func TestBlockUserFromOrganization(t *testing.T) { }) } -// TestBlockAddCollaborator ensures that the doer and blocked user cannot add each each other as collaborators. -func TestBlockAddCollaborator(t *testing.T) { +// TestBlockActions ensures that certain actions cannot be performed as a doer +// and as a blocked user and are handled cleanly after the blocking has taken +// place. +func TestBlockActions(t *testing.T) { defer tests.PrepareTestEnv(t)() - user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 10}) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + blockedUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2, OwnerID: doer.ID}) + issue4 := unittest.AssertExistsAndLoadBean(t, &issue_model.Issue{ID: 4, RepoID: repo2.ID}) + issue4URL := fmt.Sprintf("/%s/issues/%d", repo2.FullName(), issue4.Index) + // NOTE: Sessions shouldn't be shared, because in some situations flash + // messages are persistent and that would interfere with accurate test + // results. - BlockUser(t, user1, user2) + BlockUser(t, doer, blockedUser) - t.Run("BlockedUser Add Doer", func(t *testing.T) { + // Ensures that issue creation on doer's ownen repositories are blocked. + t.Run("Issue creation", func(t *testing.T) { defer tests.PrintCurrentTest(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2, OwnerID: user2.ID}) + session := loginUser(t, blockedUser.Name) + link := fmt.Sprintf("%s/issues/new", repo2.FullName()) - session := loginUser(t, user2.Name) - req := NewRequestWithValues(t, "POST", path.Join(repo.Link(), "/settings/collaboration"), map[string]string{ - "_csrf": GetCSRF(t, session, path.Join(repo.Link(), "/settings/collaboration")), - "collaborator": user1.Name, + req := NewRequestWithValues(t, "POST", link, map[string]string{ + "_csrf": GetCSRF(t, session, link), + "title": "Title", + "content": "Hello!", }) - session.MakeRequest(t, req, http.StatusSeeOther) + resp := session.MakeRequest(t, req, http.StatusOK) - flashCookie := session.GetCookie(forgejo_context.CookieNameFlash) - assert.NotNil(t, flashCookie) - assert.EqualValues(t, "error%3DCannot%2Badd%2Bthe%2Bcollaborator%252C%2Bbecause%2Bthey%2Bhave%2Bblocked%2Bthe%2Brepository%2Bowner.", flashCookie.Value) + htmlDoc := NewHTMLParser(t, resp.Body) + assert.Contains(t, + htmlDoc.doc.Find(".ui.negative.message").Text(), + translation.NewLocale("en-US").Tr("repo.issues.blocked_by_user"), + ) }) - t.Run("Doer Add BlockedUser", func(t *testing.T) { - defer tests.PrintCurrentTest(t)() + // Ensures that comment creation on doer's owned repositories and doer's + // posted issues are blocked. + t.Run("Comment creation", func(t *testing.T) { + expectedFlash := "error%3DYou%2Bcannot%2Bcreate%2Ba%2Bcomment%2Bon%2Bthis%2Bissue%2Bbecause%2Byou%2Bare%2Bblocked%2Bby%2Bthe%2Brepository%2Bowner%2Bor%2Bthe%2Bposter%2Bof%2Bthe%2Bissue." - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 7, OwnerID: user1.ID}) + t.Run("Blocked by repository owner", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() - session := loginUser(t, user1.Name) - req := NewRequestWithValues(t, "POST", path.Join(repo.Link(), "/settings/collaboration"), map[string]string{ - "_csrf": GetCSRF(t, session, path.Join(repo.Link(), "/settings/collaboration")), - "collaborator": user2.Name, + session := loginUser(t, blockedUser.Name) + + req := NewRequestWithValues(t, "POST", path.Join(issue4URL, "/comments"), map[string]string{ + "_csrf": GetCSRF(t, session, issue4URL), + "content": "Not a kind comment", + }) + session.MakeRequest(t, req, http.StatusOK) + + flashCookie := session.GetCookie(forgejo_context.CookieNameFlash) + assert.NotNil(t, flashCookie) + assert.EqualValues(t, expectedFlash, flashCookie.Value) }) - session.MakeRequest(t, req, http.StatusSeeOther) - flashCookie := session.GetCookie(forgejo_context.CookieNameFlash) - assert.NotNil(t, flashCookie) - assert.EqualValues(t, "error%3DCannot%2Badd%2Bthe%2Bcollaborator%252C%2Bbecause%2Bthe%2Brepository%2Bowner%2Bhas%2Bblocked%2Bthem.", flashCookie.Value) + t.Run("Blocked by issue poster", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + repo5 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 5}) + issue15 := unittest.AssertExistsAndLoadBean(t, &issue_model.Issue{ID: 15, RepoID: repo5.ID, PosterID: doer.ID}) + + session := loginUser(t, blockedUser.Name) + issueURL := fmt.Sprintf("/%s/%s/issues/%d", url.PathEscape(repo5.OwnerName), url.PathEscape(repo5.Name), issue15.Index) + + req := NewRequestWithValues(t, "POST", path.Join(issueURL, "/comments"), map[string]string{ + "_csrf": GetCSRF(t, session, issueURL), + "content": "Not a kind comment", + }) + session.MakeRequest(t, req, http.StatusOK) + + flashCookie := session.GetCookie(forgejo_context.CookieNameFlash) + assert.NotNil(t, flashCookie) + assert.EqualValues(t, expectedFlash, flashCookie.Value) + }) + }) + + // Ensures that reactions on doer's owned issues and doer's owned comments are + // blocked. + t.Run("Add a reaction", func(t *testing.T) { + type reactionResponse struct { + Empty bool `json:"empty"` + } + + t.Run("On a issue", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + session := loginUser(t, blockedUser.Name) + + req := NewRequestWithValues(t, "POST", path.Join(issue4URL, "/reactions/react"), map[string]string{ + "_csrf": GetCSRF(t, session, issue4URL), + "content": "eyes", + }) + resp := session.MakeRequest(t, req, http.StatusOK) + + var respBody reactionResponse + DecodeJSON(t, resp, &respBody) + + assert.EqualValues(t, true, respBody.Empty) + }) + + t.Run("On a comment", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + comment := unittest.AssertExistsAndLoadBean(t, &issue_model.Comment{ID: 8, PosterID: doer.ID, IssueID: issue4.ID}) + + session := loginUser(t, blockedUser.Name) + + req := NewRequestWithValues(t, "POST", fmt.Sprintf("%s/comments/%d/reactions/react", repo2.FullName(), comment.ID), map[string]string{ + "_csrf": GetCSRF(t, session, issue4URL), + "content": "eyes", + }) + resp := session.MakeRequest(t, req, http.StatusOK) + + var respBody reactionResponse + DecodeJSON(t, resp, &respBody) + + assert.EqualValues(t, true, respBody.Empty) + }) + }) + + // Ensures that the doer and blocked user cannot follow each other. + t.Run("Follow", func(t *testing.T) { + // Sanity checks to make sure doing these tests are valid. + unittest.AssertNotExistsBean(t, &user_model.Follow{UserID: doer.ID, FollowID: blockedUser.ID}) + unittest.AssertNotExistsBean(t, &user_model.Follow{UserID: blockedUser.ID, FollowID: doer.ID}) + + // Doer cannot follow blocked user. + t.Run("Doer follow blocked user", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + session := loginUser(t, doer.Name) + + req := NewRequestWithValues(t, "POST", "/"+blockedUser.Name, map[string]string{ + "_csrf": GetCSRF(t, session, "/"+blockedUser.Name), + "action": "follow", + }) + session.MakeRequest(t, req, http.StatusSeeOther) + + // Assert it still doesn't exist. + unittest.AssertNotExistsBean(t, &user_model.Follow{UserID: doer.ID, FollowID: blockedUser.ID}) + }) + + // Blocked user cannot follow doer. + t.Run("Blocked user follow doer", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + session := loginUser(t, blockedUser.Name) + + req := NewRequestWithValues(t, "POST", "/"+doer.Name, map[string]string{ + "_csrf": GetCSRF(t, session, "/"+doer.Name), + "action": "follow", + }) + session.MakeRequest(t, req, http.StatusSeeOther) + + unittest.AssertNotExistsBean(t, &user_model.Follow{UserID: blockedUser.ID, FollowID: doer.ID}) + }) + }) + + // Ensures that the doer and blocked user cannot add each each other as collaborators. + t.Run("Add collaborator", func(t *testing.T) { + blockedUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 10}) + + BlockUser(t, doer, blockedUser) + + t.Run("Doer Add BlockedUser", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + session := loginUser(t, doer.Name) + link := fmt.Sprintf("/%s/settings/collaboration", repo2.FullName()) + + req := NewRequestWithValues(t, "POST", link, map[string]string{ + "_csrf": GetCSRF(t, session, link), + "collaborator": blockedUser.Name, + }) + session.MakeRequest(t, req, http.StatusSeeOther) + + flashCookie := session.GetCookie(forgejo_context.CookieNameFlash) + assert.NotNil(t, flashCookie) + assert.EqualValues(t, "error%3DCannot%2Badd%2Bthe%2Bcollaborator%252C%2Bbecause%2Bthe%2Brepository%2Bowner%2Bhas%2Bblocked%2Bthem.", flashCookie.Value) + }) + + t.Run("BlockedUser Add doer", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 7, OwnerID: blockedUser.ID}) + + session := loginUser(t, blockedUser.Name) + link := fmt.Sprintf("/%s/settings/collaboration", repo.FullName()) + + req := NewRequestWithValues(t, "POST", link, map[string]string{ + "_csrf": GetCSRF(t, session, link), + "collaborator": doer.Name, + }) + session.MakeRequest(t, req, http.StatusSeeOther) + + flashCookie := session.GetCookie(forgejo_context.CookieNameFlash) + assert.NotNil(t, flashCookie) + assert.EqualValues(t, "error%3DCannot%2Badd%2Bthe%2Bcollaborator%252C%2Bbecause%2Bthey%2Bhave%2Bblocked%2Bthe%2Brepository%2Bowner.", flashCookie.Value) + }) }) }