Merge branch 'rebase-forgejo-dependency' into wip-forgejo
This commit is contained in:
commit
094c84ed6d
292 changed files with 8842 additions and 1269 deletions
1
tests/gitea-repositories-meta/user2/repo59.git/HEAD
Normal file
1
tests/gitea-repositories-meta/user2/repo59.git/HEAD
Normal file
|
@ -0,0 +1 @@
|
|||
ref: refs/heads/master
|
4
tests/gitea-repositories-meta/user2/repo59.git/config
Normal file
4
tests/gitea-repositories-meta/user2/repo59.git/config
Normal file
|
@ -0,0 +1,4 @@
|
|||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = true
|
|
@ -0,0 +1 @@
|
|||
Unnamed repository; edit this file 'description' to name the repository.
|
|
@ -0,0 +1,6 @@
|
|||
# git ls-files --others --exclude-from=.git/info/exclude
|
||||
# Lines that start with '#' are comments.
|
||||
# For a project mostly in C, the following would be a good set of
|
||||
# exclude patterns (uncomment them if you want to use them):
|
||||
# *.[oa]
|
||||
# *~
|
Binary file not shown.
|
@ -0,0 +1,2 @@
|
|||
P pack-6dd3a6fe138f1d77e14c2e6b8e6c41e5ae242adf.pack
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,4 @@
|
|||
# pack-refs with: peeled fully-peeled sorted
|
||||
d8f53dfb33f6ccf4169c34970b5e747511c18beb refs/heads/cake-recipe
|
||||
80b83c5c8220c3aa3906e081f202a2a7563ec879 refs/heads/master
|
||||
d8f53dfb33f6ccf4169c34970b5e747511c18beb refs/tags/v1.0
|
50
tests/integration/actions_route_test.go
Normal file
50
tests/integration/actions_route_test.go
Normal file
|
@ -0,0 +1,50 @@
|
|||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
actions_model "code.gitea.io/gitea/models/actions"
|
||||
unit_model "code.gitea.io/gitea/models/unit"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
files_service "code.gitea.io/gitea/services/repository/files"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestActionsWebRouteLatestRun(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
// create the repo
|
||||
repo, _, f := CreateDeclarativeRepo(t, user2, "",
|
||||
[]unit_model.Type{unit_model.TypeActions}, nil,
|
||||
[]*files_service.ChangeRepoFile{
|
||||
{
|
||||
Operation: "create",
|
||||
TreePath: ".gitea/workflows/pr.yml",
|
||||
ContentReader: strings.NewReader("name: test\non:\n push:\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - run: echo helloworld\n"),
|
||||
},
|
||||
},
|
||||
)
|
||||
defer f()
|
||||
|
||||
// a run has been created
|
||||
assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: repo.ID}))
|
||||
|
||||
// Hit the `/actions/runs/latest` route
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/actions/runs/latest", repo.HTMLURL()))
|
||||
resp := MakeRequest(t, req, http.StatusTemporaryRedirect)
|
||||
|
||||
// Verify that it redirects to the run we just created
|
||||
expectedURI := fmt.Sprintf("%s/actions/runs/1", repo.HTMLURL())
|
||||
assert.Equal(t, expectedURI, resp.Header().Get("Location"))
|
||||
})
|
||||
}
|
|
@ -11,9 +11,7 @@ import (
|
|||
"time"
|
||||
|
||||
actions_model "code.gitea.io/gitea/models/actions"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
unit_model "code.gitea.io/gitea/models/unit"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
|
@ -33,25 +31,10 @@ func TestPullRequestTargetEvent(t *testing.T) {
|
|||
org3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of the forked repo
|
||||
|
||||
// create the base repo
|
||||
baseRepo, err := repo_service.CreateRepository(db.DefaultContext, user2, user2, repo_service.CreateRepoOptions{
|
||||
Name: "repo-pull-request-target",
|
||||
Description: "test pull-request-target event",
|
||||
AutoInit: true,
|
||||
Gitignores: "Go",
|
||||
License: "MIT",
|
||||
Readme: "Default",
|
||||
DefaultBranch: "main",
|
||||
IsPrivate: false,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, baseRepo)
|
||||
|
||||
// enable actions
|
||||
err = repo_service.UpdateRepositoryUnits(db.DefaultContext, baseRepo, []repo_model.RepoUnit{{
|
||||
RepoID: baseRepo.ID,
|
||||
Type: unit_model.TypeActions,
|
||||
}}, nil)
|
||||
assert.NoError(t, err)
|
||||
baseRepo, _, f := CreateDeclarativeRepo(t, user2, "repo-pull-request-target",
|
||||
[]unit_model.Type{unit_model.TypeActions}, nil, nil,
|
||||
)
|
||||
defer f()
|
||||
|
||||
// create the forked repo
|
||||
forkedRepo, err := repo_service.ForkRepository(git.DefaultContext, user2, org3, repo_service.ForkRepoOptions{
|
||||
|
@ -202,53 +185,17 @@ func TestSkipCI(t *testing.T) {
|
|||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
// create the repo
|
||||
repo, err := repo_service.CreateRepository(db.DefaultContext, user2, user2, repo_service.CreateRepoOptions{
|
||||
Name: "skip-ci",
|
||||
Description: "test skip ci functionality",
|
||||
AutoInit: true,
|
||||
Gitignores: "Go",
|
||||
License: "MIT",
|
||||
Readme: "Default",
|
||||
DefaultBranch: "main",
|
||||
IsPrivate: false,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, repo)
|
||||
|
||||
// enable actions
|
||||
err = repo_service.UpdateRepositoryUnits(db.DefaultContext, repo, []repo_model.RepoUnit{{
|
||||
RepoID: repo.ID,
|
||||
Type: unit_model.TypeActions,
|
||||
}}, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// add workflow file to the repo
|
||||
addWorkflowToBaseResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{
|
||||
Files: []*files_service.ChangeRepoFile{
|
||||
repo, _, f := CreateDeclarativeRepo(t, user2, "skip-ci",
|
||||
[]unit_model.Type{unit_model.TypeActions}, nil,
|
||||
[]*files_service.ChangeRepoFile{
|
||||
{
|
||||
Operation: "create",
|
||||
TreePath: ".gitea/workflows/pr.yml",
|
||||
ContentReader: strings.NewReader("name: test\non:\n push:\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - run: echo helloworld\n"),
|
||||
},
|
||||
},
|
||||
Message: "add workflow",
|
||||
OldBranch: "main",
|
||||
NewBranch: "main",
|
||||
Author: &files_service.IdentityOptions{
|
||||
Name: user2.Name,
|
||||
Email: user2.Email,
|
||||
},
|
||||
Committer: &files_service.IdentityOptions{
|
||||
Name: user2.Name,
|
||||
Email: user2.Email,
|
||||
},
|
||||
Dates: &files_service.CommitDateOptions{
|
||||
Author: time.Now(),
|
||||
Committer: time.Now(),
|
||||
},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, addWorkflowToBaseResp)
|
||||
)
|
||||
defer f()
|
||||
|
||||
// a run has been created
|
||||
assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: repo.ID}))
|
||||
|
|
40
tests/integration/api_feed_plain_text_titles_test.go
Normal file
40
tests/integration/api_feed_plain_text_titles_test.go
Normal file
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2023 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFeedPlainTextTitles(t *testing.T) {
|
||||
// This test verifies that items' titles in feeds are generated as plain text.
|
||||
// See https://codeberg.org/forgejo/forgejo/pulls/1595
|
||||
|
||||
t.Run("Feed plain text titles", func(t *testing.T) {
|
||||
t.Run("Atom", func(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user2/repo1.atom")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
data := resp.Body.String()
|
||||
assert.Contains(t, data, "<title>the_1-user.with.all.allowedChars closed issue user2/repo1#4</title>")
|
||||
})
|
||||
|
||||
t.Run("RSS", func(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user2/repo1.rss")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
data := resp.Body.String()
|
||||
assert.Contains(t, data, "<title>the_1-user.with.all.allowedChars closed issue user2/repo1#4</title>")
|
||||
})
|
||||
})
|
||||
}
|
|
@ -7,15 +7,19 @@ import (
|
|||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFeed(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
t.Run("User", func(t *testing.T) {
|
||||
t.Run("Atom", func(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user2.atom")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
@ -25,7 +29,7 @@ func TestFeed(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("RSS", func(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user2.rss")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
@ -34,4 +38,51 @@ func TestFeed(t *testing.T) {
|
|||
assert.Contains(t, data, `<rss version="2.0"`)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Repo", func(t *testing.T) {
|
||||
t.Run("Normal", func(t *testing.T) {
|
||||
t.Run("Atom", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user2/repo1/atom/branch/master")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
data := resp.Body.String()
|
||||
assert.Contains(t, data, `<feed xmlns="http://www.w3.org/2005/Atom"`)
|
||||
})
|
||||
t.Run("RSS", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user2/repo1/rss/branch/master")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
data := resp.Body.String()
|
||||
assert.Contains(t, data, `<rss version="2.0"`)
|
||||
})
|
||||
})
|
||||
t.Run("Empty", func(t *testing.T) {
|
||||
err := user_model.UpdateUserCols(db.DefaultContext, &user_model.User{ID: 30, ProhibitLogin: false}, "prohibit_login")
|
||||
assert.NoError(t, err)
|
||||
|
||||
session := loginUser(t, "user30")
|
||||
t.Run("Atom", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user30/empty/atom/branch/master")
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", "/user30/empty.atom/src/branch/master")
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
t.Run("RSS", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user30/empty/rss/branch/master")
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", "/user30/empty.rss/src/branch/master")
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
|
@ -33,7 +34,6 @@ import (
|
|||
chef_router "code.gitea.io/gitea/routers/api/packages/chef"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/minio/sha256-simd"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ package integration
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
@ -24,7 +25,6 @@ import (
|
|||
"code.gitea.io/gitea/modules/test"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/minio/sha256-simd"
|
||||
oci "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
|
@ -5,6 +5,7 @@ package integration
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
@ -24,7 +25,6 @@ import (
|
|||
packages_cleanup_service "code.gitea.io/gitea/services/packages/cleanup"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/minio/sha256-simd"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
|
|
@ -18,8 +18,130 @@ import (
|
|||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAPIPullReviewCreateDeleteComment(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
pullIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 3})
|
||||
assert.NoError(t, pullIssue.LoadAttributes(db.DefaultContext))
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue.RepoID})
|
||||
|
||||
username := "user2"
|
||||
session := loginUser(t, username)
|
||||
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
|
||||
|
||||
// as of e522e774cae2240279fc48c349fc513c9d3353ee
|
||||
// There should be no reason for CreateComment to behave differently
|
||||
// depending on the event associated with the review. But the logic of the implementation
|
||||
// at this point in time is very involved and deserves these seemingly redundant
|
||||
// test.
|
||||
for _, event := range []api.ReviewStateType{
|
||||
api.ReviewStatePending,
|
||||
api.ReviewStateRequestChanges,
|
||||
api.ReviewStateApproved,
|
||||
api.ReviewStateComment,
|
||||
} {
|
||||
t.Run("Event_"+string(event), func(t *testing.T) {
|
||||
path := "README.md"
|
||||
var review api.PullReview
|
||||
var reviewLine int64 = 1
|
||||
|
||||
// cleanup
|
||||
{
|
||||
session := loginUser(t, "user1")
|
||||
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll)
|
||||
|
||||
req := NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/pulls/%d/reviews", repo.FullName(), pullIssue.Index).AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
var reviews []*api.PullReview
|
||||
DecodeJSON(t, resp, &reviews)
|
||||
for _, review := range reviews {
|
||||
req := NewRequestf(t, http.MethodDelete, "/api/v1/repos/%s/pulls/%d/reviews/%d", repo.FullName(), pullIssue.Index, review.ID).
|
||||
AddTokenAuth(token)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
|
||||
requireReviewCount := func(count int) {
|
||||
req := NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/pulls/%d/reviews", repo.FullName(), pullIssue.Index).AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
var reviews []*api.PullReview
|
||||
DecodeJSON(t, resp, &reviews)
|
||||
require.EqualValues(t, count, len(reviews))
|
||||
}
|
||||
|
||||
{
|
||||
req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/pulls/%d/reviews", repo.FullName(), pullIssue.Index), &api.CreatePullReviewOptions{
|
||||
Body: "body1",
|
||||
Event: event,
|
||||
}).AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &review)
|
||||
require.EqualValues(t, string(event), review.State)
|
||||
require.EqualValues(t, 0, review.CodeCommentsCount)
|
||||
}
|
||||
|
||||
{
|
||||
req := NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/pulls/%d/reviews/%d", repo.FullName(), pullIssue.Index, review.ID).
|
||||
AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
var getReview api.PullReview
|
||||
DecodeJSON(t, resp, &getReview)
|
||||
require.EqualValues(t, getReview, review)
|
||||
}
|
||||
requireReviewCount(1)
|
||||
|
||||
newCommentBody := "first new line"
|
||||
var reviewComment api.PullReviewComment
|
||||
|
||||
{
|
||||
req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/pulls/%d/reviews/%d/comments", repo.FullName(), pullIssue.Index, review.ID), &api.CreatePullReviewCommentOptions{
|
||||
Path: path,
|
||||
Body: newCommentBody,
|
||||
OldLineNum: reviewLine,
|
||||
}).AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &reviewComment)
|
||||
assert.EqualValues(t, review.ID, reviewComment.ReviewID)
|
||||
assert.EqualValues(t, newCommentBody, reviewComment.Body)
|
||||
assert.EqualValues(t, reviewLine, reviewComment.OldLineNum)
|
||||
assert.EqualValues(t, 0, reviewComment.LineNum)
|
||||
assert.EqualValues(t, path, reviewComment.Path)
|
||||
}
|
||||
|
||||
{
|
||||
req := NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/pulls/%d/reviews/%d/comments/%d", repo.FullName(), pullIssue.Index, review.ID, reviewComment.ID).
|
||||
AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var comment api.PullReviewComment
|
||||
DecodeJSON(t, resp, &comment)
|
||||
assert.EqualValues(t, reviewComment, comment)
|
||||
}
|
||||
|
||||
{
|
||||
req := NewRequestf(t, http.MethodDelete, "/api/v1/repos/%s/pulls/%d/reviews/%d/comments/%d", repo.FullName(), pullIssue.Index, review.ID, reviewComment.ID).
|
||||
AddTokenAuth(token)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
}
|
||||
|
||||
{
|
||||
req := NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/pulls/%d/reviews/%d/comments/%d", repo.FullName(), pullIssue.Index, review.ID, reviewComment.ID).
|
||||
AddTokenAuth(token)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
||||
|
||||
{
|
||||
req := NewRequestf(t, http.MethodDelete, "/api/v1/repos/%s/pulls/%d/reviews/%d", repo.FullName(), pullIssue.Index, review.ID).
|
||||
AddTokenAuth(token)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
}
|
||||
requireReviewCount(0)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIPullReview(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
pullIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 3})
|
||||
|
|
|
@ -32,18 +32,21 @@ func TestAPIDownloadArchive(t *testing.T) {
|
|||
bs, err := io.ReadAll(resp.Body)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, bs, 320)
|
||||
assert.EqualValues(t, "application/zip", resp.Header().Get("Content-Type"))
|
||||
|
||||
link, _ = url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/archive/master.tar.gz", user2.Name, repo.Name))
|
||||
resp = MakeRequest(t, NewRequest(t, "GET", link.String()).AddTokenAuth(token), http.StatusOK)
|
||||
bs, err = io.ReadAll(resp.Body)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, bs, 266)
|
||||
assert.EqualValues(t, "application/gzip", resp.Header().Get("Content-Type"))
|
||||
|
||||
link, _ = url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/archive/master.bundle", user2.Name, repo.Name))
|
||||
resp = MakeRequest(t, NewRequest(t, "GET", link.String()).AddTokenAuth(token), http.StatusOK)
|
||||
bs, err = io.ReadAll(resp.Body)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, bs, 382)
|
||||
assert.EqualValues(t, "application/octet-stream", resp.Header().Get("Content-Type"))
|
||||
|
||||
link, _ = url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/archive/master", user2.Name, repo.Name))
|
||||
MakeRequest(t, NewRequest(t, "GET", link.String()).AddTokenAuth(token), http.StatusBadRequest)
|
||||
|
|
|
@ -26,11 +26,12 @@ func TestRepoLanguages(t *testing.T) {
|
|||
|
||||
// Save new file to master branch
|
||||
req = NewRequestWithValues(t, "POST", "/user2/repo1/_new/master/", map[string]string{
|
||||
"_csrf": doc.GetCSRF(),
|
||||
"last_commit": lastCommit,
|
||||
"tree_path": "test.go",
|
||||
"content": "package main",
|
||||
"commit_choice": "direct",
|
||||
"_csrf": doc.GetCSRF(),
|
||||
"last_commit": lastCommit,
|
||||
"tree_path": "test.go",
|
||||
"content": "package main",
|
||||
"commit_choice": "direct",
|
||||
"commit_mail_id": "3",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
||||
|
|
|
@ -93,9 +93,9 @@ func TestAPISearchRepo(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
name: "RepositoriesMax50", requestURL: "/api/v1/repos/search?limit=50&private=false", expectedResults: expectedResults{
|
||||
nil: {count: 33},
|
||||
user: {count: 33},
|
||||
user2: {count: 33},
|
||||
nil: {count: 34},
|
||||
user: {count: 34},
|
||||
user2: {count: 34},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2024 The Forgejo Authors c/o Codeberg e.V.. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package integration
|
||||
|
@ -19,6 +20,35 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPITopicSearchPaging(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
var topics struct {
|
||||
TopicNames []*api.TopicResponse `json:"topics"`
|
||||
}
|
||||
|
||||
// Add 20 unique topics to user2/repo2, and 20 unique ones to user2/repo3
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
token2 := getUserToken(t, user2.Name, auth_model.AccessTokenScopeWriteRepository)
|
||||
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
|
||||
for i := 0; i < 20; i++ {
|
||||
req := NewRequestf(t, "PUT", "/api/v1/repos/%s/%s/topics/paging-topic-%d", user2.Name, repo2.Name, i).
|
||||
AddTokenAuth(token2)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
req = NewRequestf(t, "PUT", "/api/v1/repos/%s/%s/topics/paging-topic-%d", user2.Name, repo3.Name, i+30).
|
||||
AddTokenAuth(token2)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
}
|
||||
|
||||
res := MakeRequest(t, NewRequest(t, "GET", "/api/v1/topics/search"), http.StatusOK)
|
||||
DecodeJSON(t, res, &topics)
|
||||
assert.Len(t, topics.TopicNames, 30)
|
||||
|
||||
res = MakeRequest(t, NewRequest(t, "GET", "/api/v1/topics/search?page=2"), http.StatusOK)
|
||||
DecodeJSON(t, res, &topics)
|
||||
assert.Greater(t, len(topics.TopicNames), 0)
|
||||
}
|
||||
|
||||
func TestAPITopicSearch(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
searchURL, _ := url.Parse("/api/v1/topics/search")
|
||||
|
|
|
@ -1,21 +1,51 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2024 The Forgejo Authors c/o Codeberg e.V.. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
unit_model "code.gitea.io/gitea/models/unit"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIRenameWikiBranch(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
username := "user2"
|
||||
session := loginUser(t, username)
|
||||
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
|
||||
|
||||
repoURLStr := fmt.Sprintf("/api/v1/repos/%s/%s", username, "repo1")
|
||||
wikiBranch := "wiki"
|
||||
req := NewRequestWithJSON(t, "PATCH", repoURLStr, &api.EditRepoOption{
|
||||
WikiBranch: &wikiBranch,
|
||||
}).AddTokenAuth(token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
assert.Equal(t, "wiki", repo.WikiBranch)
|
||||
|
||||
req = NewRequest(t, "GET", repoURLStr)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
var repoData *api.Repository
|
||||
DecodeJSON(t, resp, &repoData)
|
||||
assert.Equal(t, "wiki", repoData.WikiBranch)
|
||||
}
|
||||
|
||||
func TestAPIGetWikiPage(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
|
@ -209,6 +239,53 @@ func TestAPIEditWikiPage(t *testing.T) {
|
|||
MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
|
||||
func TestAPIEditOtherWikiPage(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
// (drive-by-user) user, session, and token for a drive-by wiki editor
|
||||
username := "drive-by-user"
|
||||
req := NewRequestWithValues(t, "POST", "/user/sign_up", map[string]string{
|
||||
"user_name": username,
|
||||
"email": "drive-by@example.com",
|
||||
"password": "examplePassword!1",
|
||||
"retype": "examplePassword!1",
|
||||
})
|
||||
MakeRequest(t, req, http.StatusSeeOther)
|
||||
session := loginUserWithPassword(t, username, "examplePassword!1")
|
||||
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
|
||||
|
||||
// (user2) user for the user whose wiki we're going to edit (as drive-by-user)
|
||||
otherUsername := "user2"
|
||||
|
||||
// Creating a new Wiki page on user2's repo as user1 fails
|
||||
testCreateWiki := func(expectedStatusCode int) {
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/wiki/new", otherUsername, "repo1")
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateWikiPageOptions{
|
||||
Title: "Globally Edited Page",
|
||||
ContentBase64: base64.StdEncoding.EncodeToString([]byte("Wiki page content for API unit tests")),
|
||||
Message: "",
|
||||
}).AddTokenAuth(token)
|
||||
session.MakeRequest(t, req, expectedStatusCode)
|
||||
}
|
||||
testCreateWiki(http.StatusForbidden)
|
||||
|
||||
// Update the repo settings for user2's repo to enable globally writeable wiki
|
||||
ctx := context.Background()
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
var units []repo_model.RepoUnit
|
||||
units = append(units, repo_model.RepoUnit{
|
||||
RepoID: repo.ID,
|
||||
Type: unit_model.TypeWiki,
|
||||
Config: new(repo_model.UnitConfig),
|
||||
DefaultPermissions: repo_model.UnitAccessModeWrite,
|
||||
})
|
||||
err := repo_service.UpdateRepositoryUnits(ctx, repo, units, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Creating a new Wiki page on user2's repo works now
|
||||
testCreateWiki(http.StatusCreated)
|
||||
}
|
||||
|
||||
func TestAPIListPageRevisions(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
username := "user2"
|
||||
|
|
|
@ -4,72 +4,55 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
"code.gitea.io/gitea/tests"
|
||||
git_model "code.gitea.io/gitea/models/git"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
gitea_context "code.gitea.io/gitea/modules/context"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestViewBranches(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user2/repo1/branches")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
_, exists := htmlDoc.doc.Find(".delete-branch-button").Attr("data-url")
|
||||
assert.False(t, exists, "The template has changed")
|
||||
}
|
||||
|
||||
func TestDeleteBranch(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
deleteBranch(t)
|
||||
}
|
||||
|
||||
func TestUndoDeleteBranch(t *testing.T) {
|
||||
func TestBranchActions(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
deleteBranch(t)
|
||||
htmlDoc, name := branchAction(t, ".restore-branch-button")
|
||||
assert.Contains(t,
|
||||
htmlDoc.doc.Find(".ui.positive.message").Text(),
|
||||
translation.NewLocale("en-US").Tr("repo.branch.restore_success", name),
|
||||
)
|
||||
session := loginUser(t, "user2")
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
branch3 := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{ID: 3, RepoID: repo1.ID})
|
||||
branchesLink := repo1.FullName() + "/branches"
|
||||
|
||||
t.Run("View", func(t *testing.T) {
|
||||
req := NewRequest(t, "GET", branchesLink)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
})
|
||||
|
||||
t.Run("Delete branch", func(t *testing.T) {
|
||||
link := fmt.Sprintf("/%s/branches/delete?name=%s", repo1.FullName(), branch3.Name)
|
||||
req := NewRequestWithValues(t, "POST", link, map[string]string{
|
||||
"_csrf": GetCSRF(t, session, branchesLink),
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
flashCookie := session.GetCookie(gitea_context.CookieNameFlash)
|
||||
assert.NotNil(t, flashCookie)
|
||||
assert.Contains(t, flashCookie.Value, "success%3DBranch%2B%2522branch2%2522%2Bhas%2Bbeen%2Bdeleted.")
|
||||
|
||||
assert.True(t, unittest.AssertExistsAndLoadBean(t, &git_model.Branch{ID: 3, RepoID: repo1.ID}).IsDeleted)
|
||||
})
|
||||
|
||||
t.Run("Restore branch", func(t *testing.T) {
|
||||
link := fmt.Sprintf("/%s/branches/restore?branch_id=%d&name=%s", repo1.FullName(), branch3.ID, branch3.Name)
|
||||
req := NewRequestWithValues(t, "POST", link, map[string]string{
|
||||
"_csrf": GetCSRF(t, session, branchesLink),
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
flashCookie := session.GetCookie(gitea_context.CookieNameFlash)
|
||||
assert.NotNil(t, flashCookie)
|
||||
assert.Contains(t, flashCookie.Value, "success%3DBranch%2B%2522branch2%2522%2Bhas%2Bbeen%2Brestored")
|
||||
|
||||
assert.False(t, unittest.AssertExistsAndLoadBean(t, &git_model.Branch{ID: 3, RepoID: repo1.ID}).IsDeleted)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func deleteBranch(t *testing.T) {
|
||||
htmlDoc, name := branchAction(t, ".delete-branch-button")
|
||||
assert.Contains(t,
|
||||
htmlDoc.doc.Find(".ui.positive.message").Text(),
|
||||
translation.NewLocale("en-US").Tr("repo.branch.deletion_success", name),
|
||||
)
|
||||
}
|
||||
|
||||
func branchAction(t *testing.T, button string) (*HTMLDoc, string) {
|
||||
session := loginUser(t, "user2")
|
||||
req := NewRequest(t, "GET", "/user2/repo1/branches")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
link, exists := htmlDoc.doc.Find(button).Attr("data-url")
|
||||
if !assert.True(t, exists, "The template has changed") {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
req = NewRequestWithValues(t, "POST", link, map[string]string{
|
||||
"_csrf": htmlDoc.GetCSRF(),
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
url, err := url.Parse(link)
|
||||
assert.NoError(t, err)
|
||||
req = NewRequest(t, "GET", "/user2/repo1/branches")
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
return NewHTMLParser(t, resp.Body), url.Query().Get("name")
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2024 The Forgejo Authors c/o Codeberg e.V.. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package integration
|
||||
|
@ -6,9 +7,14 @@ package integration
|
|||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
unit_model "code.gitea.io/gitea/models/unit"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -118,3 +124,61 @@ func TestCompareBranches(t *testing.T) {
|
|||
|
||||
inspectCompare(t, htmlDoc, diffCount, diffChanges)
|
||||
}
|
||||
|
||||
func TestCompareWithPRsDisabled(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
session := loginUser(t, "user1")
|
||||
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
|
||||
testCreateBranch(t, session, "user1", "repo1", "branch/master", "recent-push", http.StatusSeeOther)
|
||||
testEditFile(t, session, "user1", "repo1", "recent-push", "README.md", "Hello recently!\n")
|
||||
|
||||
repo, err := repo_model.GetRepositoryByOwnerAndName(db.DefaultContext, "user1", "repo1")
|
||||
assert.NoError(t, err)
|
||||
|
||||
defer func() {
|
||||
// Reenable PRs on the repo
|
||||
err := repo_service.UpdateRepositoryUnits(db.DefaultContext, repo,
|
||||
[]repo_model.RepoUnit{{
|
||||
RepoID: repo.ID,
|
||||
Type: unit_model.TypePullRequests,
|
||||
}},
|
||||
nil)
|
||||
assert.NoError(t, err)
|
||||
}()
|
||||
|
||||
// Disable PRs on the repo
|
||||
err = repo_service.UpdateRepositoryUnits(db.DefaultContext, repo, nil,
|
||||
[]unit_model.Type{unit_model.TypePullRequests})
|
||||
assert.NoError(t, err)
|
||||
|
||||
t.Run("branch view doesn't offer creating PRs", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user1/repo1/branches")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
htmlDoc.AssertElement(t, "a[href='/user1/repo1/compare/master...recent-push']", false)
|
||||
})
|
||||
|
||||
t.Run("compare doesn't offer local branches", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user2/repo1/compare/master...user1/repo1:recent-push")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
branches := htmlDoc.Find(".choose.branch .menu .reference-list-menu.base-branch-list .item, .choose.branch .menu .reference-list-menu.base-tag-list .item")
|
||||
|
||||
expectedPrefix := "user2:"
|
||||
for i := 0; i < len(branches.Nodes); i++ {
|
||||
assert.True(t, strings.HasPrefix(branches.Eq(i).Text(), expectedPrefix))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("comparing against a disabled-PR repo is 404", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user1/repo1/compare/master...recent-push")
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2024 The Forgejo Authors c/o Codeberg e.V.. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/xorm"
|
||||
|
@ -19,6 +23,29 @@ type TestCollationTbl struct {
|
|||
Txt string `xorm:"VARCHAR(10) UNIQUE"`
|
||||
}
|
||||
|
||||
func TestDatabaseCollationSelfCheckUI(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
assertSelfCheckExists := func(exists bool) {
|
||||
expectedHTTPResponse := http.StatusOK
|
||||
if !exists {
|
||||
expectedHTTPResponse = http.StatusNotFound
|
||||
}
|
||||
session := loginUser(t, "user1")
|
||||
req := NewRequest(t, "GET", "/admin/self_check")
|
||||
resp := session.MakeRequest(t, req, expectedHTTPResponse)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
htmlDoc.AssertElement(t, "a.item[href*='/admin/self_check']", exists)
|
||||
}
|
||||
|
||||
if setting.Database.Type.IsMySQL() || setting.Database.Type.IsMSSQL() {
|
||||
assertSelfCheckExists(true)
|
||||
} else {
|
||||
assertSelfCheckExists(false)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDatabaseCollation(t *testing.T) {
|
||||
x := db.GetEngine(db.DefaultContext).(*xorm.Engine)
|
||||
|
||||
|
@ -48,6 +75,8 @@ func TestDatabaseCollation(t *testing.T) {
|
|||
}
|
||||
|
||||
t.Run("Default startup makes database collation case-sensitive", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
r, err := db.CheckCollations(x)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, r.IsCollationCaseSensitive(r.DatabaseCollation))
|
||||
|
@ -78,8 +107,12 @@ func TestDatabaseCollation(t *testing.T) {
|
|||
}
|
||||
|
||||
t.Run("Convert tables to utf8mb4_bin", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
defer test.MockVariableValue(&setting.Database.CharsetCollation, "utf8mb4_bin")()
|
||||
assert.NoError(t, db.ConvertDatabaseTable())
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
r, err := db.CheckCollations(x)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "utf8mb4_bin", r.DatabaseCollation)
|
||||
|
@ -95,8 +128,12 @@ func TestDatabaseCollation(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("Convert tables to utf8mb4_general_ci", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
defer test.MockVariableValue(&setting.Database.CharsetCollation, "utf8mb4_general_ci")()
|
||||
assert.NoError(t, db.ConvertDatabaseTable())
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
r, err := db.CheckCollations(x)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "utf8mb4_general_ci", r.DatabaseCollation)
|
||||
|
@ -112,8 +149,12 @@ func TestDatabaseCollation(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("Convert tables to default case-sensitive collation", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
defer test.MockVariableValue(&setting.Database.CharsetCollation, "")()
|
||||
assert.NoError(t, db.ConvertDatabaseTable())
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
r, err := db.CheckCollations(x)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, r.IsCollationCaseSensitive(r.DatabaseCollation))
|
||||
|
|
|
@ -4,14 +4,21 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
gitea_context "code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -30,11 +37,12 @@ func TestCreateFile(t *testing.T) {
|
|||
|
||||
// Save new file to master branch
|
||||
req = NewRequestWithValues(t, "POST", "/user2/repo1/_new/master/", map[string]string{
|
||||
"_csrf": doc.GetCSRF(),
|
||||
"last_commit": lastCommit,
|
||||
"tree_path": "test.txt",
|
||||
"content": "Content",
|
||||
"commit_choice": "direct",
|
||||
"_csrf": doc.GetCSRF(),
|
||||
"last_commit": lastCommit,
|
||||
"tree_path": "test.txt",
|
||||
"content": "Content",
|
||||
"commit_choice": "direct",
|
||||
"commit_mail_id": "3",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
})
|
||||
|
@ -67,11 +75,12 @@ func TestCreateFileOnProtectedBranch(t *testing.T) {
|
|||
|
||||
// Save new file to master branch
|
||||
req = NewRequestWithValues(t, "POST", "/user2/repo1/_new/master/", map[string]string{
|
||||
"_csrf": doc.GetCSRF(),
|
||||
"last_commit": lastCommit,
|
||||
"tree_path": "test.txt",
|
||||
"content": "Content",
|
||||
"commit_choice": "direct",
|
||||
"_csrf": doc.GetCSRF(),
|
||||
"last_commit": lastCommit,
|
||||
"tree_path": "test.txt",
|
||||
"content": "Content",
|
||||
"commit_choice": "direct",
|
||||
"commit_mail_id": "3",
|
||||
})
|
||||
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
|
@ -111,11 +120,12 @@ func testEditFile(t *testing.T, session *TestSession, user, repo, branch, filePa
|
|||
// Submit the edits
|
||||
req = NewRequestWithValues(t, "POST", path.Join(user, repo, "_edit", branch, filePath),
|
||||
map[string]string{
|
||||
"_csrf": htmlDoc.GetCSRF(),
|
||||
"last_commit": lastCommit,
|
||||
"tree_path": filePath,
|
||||
"content": newContent,
|
||||
"commit_choice": "direct",
|
||||
"_csrf": htmlDoc.GetCSRF(),
|
||||
"last_commit": lastCommit,
|
||||
"tree_path": filePath,
|
||||
"content": newContent,
|
||||
"commit_choice": "direct",
|
||||
"commit_mail_id": "-1",
|
||||
},
|
||||
)
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
@ -146,6 +156,7 @@ func testEditFileToNewBranch(t *testing.T, session *TestSession, user, repo, bra
|
|||
"content": newContent,
|
||||
"commit_choice": "commit-to-new-branch",
|
||||
"new_branch_name": targetBranch,
|
||||
"commit_mail_id": "-1",
|
||||
},
|
||||
)
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
@ -171,3 +182,136 @@ func TestEditFileToNewBranch(t *testing.T) {
|
|||
testEditFileToNewBranch(t, session, "user2", "repo1", "master", "feature/test", "README.md", "Hello, World (Edited)\n")
|
||||
})
|
||||
}
|
||||
|
||||
func TestEditFileCommitMail(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, _ *url.URL) {
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
session := loginUser(t, user.Name)
|
||||
link := path.Join("user2", "repo1", "_edit", "master", "README.md")
|
||||
|
||||
lastCommitAndCSRF := func() (string, string) {
|
||||
req := NewRequest(t, "GET", link)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
lastCommit := htmlDoc.GetInputValueByName("last_commit")
|
||||
assert.NotEmpty(t, lastCommit)
|
||||
|
||||
return lastCommit, htmlDoc.GetCSRF()
|
||||
}
|
||||
|
||||
t.Run("Not activated", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
email := unittest.AssertExistsAndLoadBean(t, &user_model.EmailAddress{ID: 35, UID: user.ID})
|
||||
assert.False(t, email.IsActivated)
|
||||
|
||||
lastCommit, csrf := lastCommitAndCSRF()
|
||||
req := NewRequestWithValues(t, "POST", link, map[string]string{
|
||||
"_csrf": csrf,
|
||||
"last_commit": lastCommit,
|
||||
"tree_path": "README.md",
|
||||
"content": "new_content",
|
||||
"commit_choice": "direct",
|
||||
"commit_mail_id": fmt.Sprintf("%d", email.ID),
|
||||
})
|
||||
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.editor.invalid_commit_mail"),
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("Not belong to user", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
email := unittest.AssertExistsAndLoadBean(t, &user_model.EmailAddress{ID: 1, IsActivated: true})
|
||||
assert.NotEqualValues(t, email.UID, user.ID)
|
||||
|
||||
lastCommit, csrf := lastCommitAndCSRF()
|
||||
req := NewRequestWithValues(t, "POST", link, map[string]string{
|
||||
"_csrf": csrf,
|
||||
"last_commit": lastCommit,
|
||||
"tree_path": "README.md",
|
||||
"content": "new_content",
|
||||
"commit_choice": "direct",
|
||||
"commit_mail_id": fmt.Sprintf("%d", email.ID),
|
||||
})
|
||||
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.editor.invalid_commit_mail"),
|
||||
)
|
||||
})
|
||||
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
gitRepo, _ := git.OpenRepository(git.DefaultContext, repo1.RepoPath())
|
||||
defer gitRepo.Close()
|
||||
|
||||
t.Run("Placeholder mail", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
lastCommit, csrf := lastCommitAndCSRF()
|
||||
req := NewRequestWithValues(t, "POST", link, map[string]string{
|
||||
"_csrf": csrf,
|
||||
"last_commit": lastCommit,
|
||||
"tree_path": "README.md",
|
||||
"content": "authored by placeholder mail",
|
||||
"commit_choice": "direct",
|
||||
"commit_mail_id": "-1",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
||||
commit, err := gitRepo.GetCommitByPath("README.md")
|
||||
assert.NoError(t, err)
|
||||
|
||||
fileContent, err := commit.GetFileContent("README.md", 64)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "authored by placeholder mail", fileContent)
|
||||
|
||||
assert.EqualValues(t, "user2", commit.Author.Name)
|
||||
assert.EqualValues(t, "user2@noreply.example.org", commit.Author.Email)
|
||||
assert.EqualValues(t, "user2", commit.Committer.Name)
|
||||
assert.EqualValues(t, "user2@noreply.example.org", commit.Committer.Email)
|
||||
})
|
||||
|
||||
t.Run("Normal", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
// Require that the user has KeepEmailPrivate enabled, because it needs
|
||||
// to be tested that even with this setting enabled, it will use the
|
||||
// provided mail and not revert to the placeholder one.
|
||||
assert.True(t, user.KeepEmailPrivate)
|
||||
|
||||
email := unittest.AssertExistsAndLoadBean(t, &user_model.EmailAddress{ID: 3, UID: user.ID, IsActivated: true})
|
||||
|
||||
lastCommit, csrf := lastCommitAndCSRF()
|
||||
req := NewRequestWithValues(t, "POST", link, map[string]string{
|
||||
"_csrf": csrf,
|
||||
"last_commit": lastCommit,
|
||||
"tree_path": "README.md",
|
||||
"content": "authored by activated mail",
|
||||
"commit_choice": "direct",
|
||||
"commit_mail_id": fmt.Sprintf("%d", email.ID),
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
||||
commit, err := gitRepo.GetCommitByPath("README.md")
|
||||
assert.NoError(t, err)
|
||||
|
||||
fileContent, err := commit.GetFileContent("README.md", 64)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "authored by activated mail", fileContent)
|
||||
|
||||
assert.EqualValues(t, "user2", commit.Author.Name)
|
||||
assert.EqualValues(t, email.Email, commit.Author.Email)
|
||||
assert.EqualValues(t, "user2", commit.Committer.Name)
|
||||
assert.EqualValues(t, email.Email, commit.Committer.Email)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -50,10 +50,11 @@ func TestEmptyRepoAddFile(t *testing.T) {
|
|||
doc := NewHTMLParser(t, resp.Body).Find(`input[name="commit_choice"]`)
|
||||
assert.Empty(t, doc.AttrOr("checked", "_no_"))
|
||||
req = NewRequestWithValues(t, "POST", "/user30/empty/_new/"+setting.Repository.DefaultBranch, map[string]string{
|
||||
"_csrf": GetCSRF(t, session, "/user/settings"),
|
||||
"commit_choice": "direct",
|
||||
"tree_path": "test-file.md",
|
||||
"content": "newly-added-test-file",
|
||||
"_csrf": GetCSRF(t, session, "/user/settings"),
|
||||
"commit_choice": "direct",
|
||||
"tree_path": "test-file.md",
|
||||
"content": "newly-added-test-file",
|
||||
"commit_mail_id": "32",
|
||||
})
|
||||
|
||||
resp = session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
|
17
tests/integration/fixtures/TestCommitRefComment/comment.yml
Normal file
17
tests/integration/fixtures/TestCommitRefComment/comment.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
-
|
||||
id: 1000
|
||||
type: 4 # commit ref
|
||||
poster_id: 2
|
||||
issue_id: 2 # in repo_id 2
|
||||
content: 4a357436d925b5c974181ff12a994538ddc5a269
|
||||
created_unix: 1706469348
|
||||
updated_unix: 1706469348
|
||||
|
||||
-
|
||||
id: 1001
|
||||
type: 4 # commit ref
|
||||
poster_id: 2
|
||||
issue_id: 1 # in repo_id 2
|
||||
content: 4a357436d925b5c974181ff12a994538ddc5a269
|
||||
created_unix: 1706469348
|
||||
updated_unix: 1706469348
|
|
@ -0,0 +1,17 @@
|
|||
-
|
||||
id: 1
|
||||
issue_id: 1
|
||||
comment_id: 3
|
||||
edited_unix: 1687612839
|
||||
content_text: Original Text
|
||||
is_first_created: true
|
||||
is_deleted: false
|
||||
|
||||
-
|
||||
id: 2
|
||||
issue_id: 1
|
||||
comment_id: 3
|
||||
edited_unix: 1687612840
|
||||
content_text: "meh..." # This has to be consistent with comment.yml
|
||||
is_first_created: false
|
||||
is_deleted: false
|
|
@ -89,6 +89,39 @@ func TestDangerZoneConfirmation(t *testing.T) {
|
|||
})
|
||||
})
|
||||
|
||||
t.Run("Rename wiki branch", func(t *testing.T) {
|
||||
session := loginUser(t, "user2")
|
||||
|
||||
// NOTE: No need to rename the wiki branch here to make the form appear.
|
||||
// We can submit it anyway, even if it doesn't appear on the web.
|
||||
|
||||
t.Run("Fail", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithValues(t, "POST", "/user2/repo1/settings", map[string]string{
|
||||
"_csrf": GetCSRF(t, session, "/user2/repo1/settings"),
|
||||
"action": "rename-wiki-branch",
|
||||
"repo_name": "repo1",
|
||||
})
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
mustInvalidRepoName(resp)
|
||||
})
|
||||
t.Run("Pass", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithValues(t, "POST", "/user2/repo1/settings", map[string]string{
|
||||
"_csrf": GetCSRF(t, session, "/user2/repo1/settings"),
|
||||
"action": "rename-wiki-branch",
|
||||
"repo_name": "user2/repo1",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
||||
flashCookie := session.GetCookie(gitea_context.CookieNameFlash)
|
||||
assert.NotNil(t, flashCookie)
|
||||
assert.EqualValues(t, "success%3DThe%2Brepository%2Bwiki%2527s%2Bbranch%2Bname%2Bhas%2Bbeen%2Bsuccessfully%2Bnormalized.", flashCookie.Value)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Delete wiki", func(t *testing.T) {
|
||||
session := loginUser(t, "user2")
|
||||
|
||||
|
|
139
tests/integration/forgejo_git_test.go
Normal file
139
tests/integration/forgejo_git_test.go
Normal file
|
@ -0,0 +1,139 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
actions_model "code.gitea.io/gitea/models/actions"
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestActionsUserGit(t *testing.T) {
|
||||
onGiteaRun(t, testActionsUserGit)
|
||||
}
|
||||
|
||||
func NewActionsUserTestContext(t *testing.T, username, reponame string) APITestContext {
|
||||
t.Helper()
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame})
|
||||
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: username})
|
||||
|
||||
task := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 47})
|
||||
task.RepoID = repo.ID
|
||||
task.OwnerID = repoOwner.ID
|
||||
task.GenerateToken()
|
||||
|
||||
actions_model.UpdateTask(db.DefaultContext, task)
|
||||
return APITestContext{
|
||||
Session: emptyTestSession(t),
|
||||
Token: task.Token,
|
||||
Username: username,
|
||||
Reponame: reponame,
|
||||
}
|
||||
}
|
||||
|
||||
func testActionsUserGit(t *testing.T, u *url.URL) {
|
||||
username := "user2"
|
||||
reponame := "repo1"
|
||||
httpContext := NewAPITestContext(t, username, reponame, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
|
||||
|
||||
for _, testCase := range []struct {
|
||||
name string
|
||||
head string
|
||||
ctx APITestContext
|
||||
}{
|
||||
{
|
||||
name: "UserTypeIndividual",
|
||||
head: "individualhead",
|
||||
ctx: httpContext,
|
||||
},
|
||||
{
|
||||
name: "ActionsUser",
|
||||
head: "actionsuserhead",
|
||||
ctx: NewActionsUserTestContext(t, username, reponame),
|
||||
},
|
||||
} {
|
||||
t.Run("CreatePR "+testCase.name, func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
dstPath := t.TempDir()
|
||||
u.Path = httpContext.GitPath()
|
||||
u.User = url.UserPassword(httpContext.Username, userPassword)
|
||||
t.Run("Clone", doGitClone(dstPath, u))
|
||||
t.Run("PopulateBranch", doActionsUserPopulateBranch(dstPath, &httpContext, "master", testCase.head))
|
||||
t.Run("CreatePR", doActionsUserPR(httpContext, testCase.ctx, "master", testCase.head))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func doActionsUserPopulateBranch(dstPath string, ctx *APITestContext, baseBranch, headBranch string) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
t.Run("CreateHeadBranch", doGitCreateBranch(dstPath, headBranch))
|
||||
|
||||
t.Run("AddCommit", func(t *testing.T) {
|
||||
err := os.WriteFile(path.Join(dstPath, "test_file"), []byte("## test content"), 0o666)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
err = git.AddChanges(dstPath, true)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = git.CommitChanges(dstPath, git.CommitChangesOptions{
|
||||
Committer: &git.Signature{
|
||||
Email: "user2@example.com",
|
||||
Name: "user2",
|
||||
When: time.Now(),
|
||||
},
|
||||
Author: &git.Signature{
|
||||
Email: "user2@example.com",
|
||||
Name: "user2",
|
||||
When: time.Now(),
|
||||
},
|
||||
Message: "Testing commit 1",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("Push", func(t *testing.T) {
|
||||
err := git.NewCommand(git.DefaultContext, "push", "origin").AddDynamicArguments("HEAD:refs/heads/" + headBranch).Run(&git.RunOpts{Dir: dstPath})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func doActionsUserPR(ctx, doerCtx APITestContext, baseBranch, headBranch string) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
var pr api.PullRequest
|
||||
var err error
|
||||
|
||||
// Create a test pullrequest
|
||||
t.Run("CreatePullRequest", func(t *testing.T) {
|
||||
pr, err = doAPICreatePullRequest(doerCtx, ctx.Username, ctx.Reponame, baseBranch, headBranch)(t)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
doerCtx.ExpectedCode = http.StatusCreated
|
||||
t.Run("AutoMergePR", doAPIAutoMergePullRequest(doerCtx, ctx.Username, ctx.Reponame, pr.Index))
|
||||
// Ensure the PR page works
|
||||
t.Run("EnsureCanSeePull", doEnsureCanSeePull(ctx, pr, true))
|
||||
}
|
||||
}
|
|
@ -455,8 +455,19 @@ func doMergeFork(ctx, baseCtx APITestContext, baseBranch, headBranch string) fun
|
|||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
// Ensure the PR page works
|
||||
t.Run("EnsureCanSeePull", doEnsureCanSeePull(baseCtx, pr))
|
||||
// Ensure the PR page works.
|
||||
// For the base repository owner, the PR is not editable (maintainer edits are not enabled):
|
||||
t.Run("EnsureCanSeePull", doEnsureCanSeePull(baseCtx, pr, false))
|
||||
// For the head repository owner, the PR is editable:
|
||||
headSession := loginUser(t, "user2")
|
||||
headToken := getTokenForLoggedInUser(t, headSession, auth_model.AccessTokenScopeReadRepository, auth_model.AccessTokenScopeReadUser)
|
||||
headCtx := APITestContext{
|
||||
Session: headSession,
|
||||
Token: headToken,
|
||||
Username: baseCtx.Username,
|
||||
Reponame: baseCtx.Reponame,
|
||||
}
|
||||
t.Run("EnsureCanSeePull", doEnsureCanSeePull(headCtx, pr, true))
|
||||
|
||||
// Then get the diff string
|
||||
var diffHash string
|
||||
|
@ -470,7 +481,9 @@ func doMergeFork(ctx, baseCtx APITestContext, baseBranch, headBranch string) fun
|
|||
|
||||
// Now: Merge the PR & make sure that doesn't break the PR page or change its diff
|
||||
t.Run("MergePR", doAPIMergePullRequest(baseCtx, baseCtx.Username, baseCtx.Reponame, pr.Index))
|
||||
t.Run("EnsureCanSeePull", doEnsureCanSeePull(baseCtx, pr))
|
||||
// for both users the PR is still visible but not editable anymore after it was merged
|
||||
t.Run("EnsureCanSeePull", doEnsureCanSeePull(baseCtx, pr, false))
|
||||
t.Run("EnsureCanSeePull", doEnsureCanSeePull(headCtx, pr, false))
|
||||
t.Run("CheckPR", func(t *testing.T) {
|
||||
oldMergeBase := pr.MergeBase
|
||||
pr2, err := doAPIGetPullRequest(baseCtx, baseCtx.Username, baseCtx.Reponame, pr.Index)(t)
|
||||
|
@ -481,12 +494,12 @@ func doMergeFork(ctx, baseCtx APITestContext, baseBranch, headBranch string) fun
|
|||
|
||||
// Then: Delete the head branch & make sure that doesn't break the PR page or change its diff
|
||||
t.Run("DeleteHeadBranch", doBranchDelete(baseCtx, baseCtx.Username, baseCtx.Reponame, headBranch))
|
||||
t.Run("EnsureCanSeePull", doEnsureCanSeePull(baseCtx, pr))
|
||||
t.Run("EnsureCanSeePull", doEnsureCanSeePull(baseCtx, pr, false))
|
||||
t.Run("EnsureDiffNoChange", doEnsureDiffNoChange(baseCtx, pr, diffHash, diffLength))
|
||||
|
||||
// Delete the head repository & make sure that doesn't break the PR page or change its diff
|
||||
t.Run("DeleteHeadRepository", doAPIDeleteRepository(ctx))
|
||||
t.Run("EnsureCanSeePull", doEnsureCanSeePull(baseCtx, pr))
|
||||
t.Run("EnsureCanSeePull", doEnsureCanSeePull(baseCtx, pr, false))
|
||||
t.Run("EnsureDiffNoChange", doEnsureDiffNoChange(baseCtx, pr, diffHash, diffLength))
|
||||
}
|
||||
}
|
||||
|
@ -520,12 +533,19 @@ func doCreatePRAndSetManuallyMerged(ctx, baseCtx APITestContext, dstPath, baseBr
|
|||
}
|
||||
}
|
||||
|
||||
func doEnsureCanSeePull(ctx APITestContext, pr api.PullRequest) func(t *testing.T) {
|
||||
func doEnsureCanSeePull(ctx APITestContext, pr api.PullRequest, editable bool) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame), pr.Index))
|
||||
ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d/files", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame), pr.Index))
|
||||
ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
resp := ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
editButtonCount := doc.doc.Find("div.diff-file-header-actions a[href*='/_edit/']").Length()
|
||||
if editable {
|
||||
assert.Greater(t, editButtonCount, 0, "Expected to find a button to edit a file in the PR diff view but there were none")
|
||||
} else {
|
||||
assert.Equal(t, 0, editButtonCount, "Expected not to find any buttons to edit files in PR diff view but there were some")
|
||||
}
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d/commits", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame), pr.Index))
|
||||
ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2024 The Forgejo Authors c/o Codeberg e.V.. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//nolint:forbidigo
|
||||
|
@ -25,9 +26,12 @@ import (
|
|||
|
||||
"code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
unit_model "code.gitea.io/gitea/models/unit"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
gitea_context "code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
|
@ -36,15 +40,18 @@ import (
|
|||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
"code.gitea.io/gitea/routers"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
files_service "code.gitea.io/gitea/services/repository/files"
|
||||
user_service "code.gitea.io/gitea/services/user"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
gouuid "github.com/google/uuid"
|
||||
"github.com/markbates/goth"
|
||||
"github.com/markbates/goth/gothic"
|
||||
goth_gitlab "github.com/markbates/goth/providers/gitlab"
|
||||
"github.com/santhosh-tekuri/jsonschema/v5"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/xeipuuv/gojsonschema"
|
||||
)
|
||||
|
||||
var testWebRoutes *web.Route
|
||||
|
@ -509,6 +516,24 @@ func logUnexpectedResponse(t testing.TB, recorder *httptest.ResponseRecorder) {
|
|||
t.Helper()
|
||||
respBytes := recorder.Body.Bytes()
|
||||
if len(respBytes) == 0 {
|
||||
// log the content of the flash cookie
|
||||
for _, cookie := range recorder.Result().Cookies() {
|
||||
if cookie.Name != gitea_context.CookieNameFlash {
|
||||
continue
|
||||
}
|
||||
flash, _ := url.ParseQuery(cookie.Value)
|
||||
for key, value := range flash {
|
||||
// the key is itself url-encoded
|
||||
if flash, err := url.ParseQuery(key); err == nil {
|
||||
for key, value := range flash {
|
||||
t.Logf("FlashCookie %q: %q", key, value)
|
||||
}
|
||||
} else {
|
||||
t.Logf("FlashCookie %q: %q", key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
} else if len(respBytes) < 500 {
|
||||
// if body is short, just log the whole thing
|
||||
|
@ -543,16 +568,15 @@ func VerifyJSONSchema(t testing.TB, resp *httptest.ResponseRecorder, schemaFile
|
|||
_, schemaFileErr := os.Stat(schemaFilePath)
|
||||
assert.Nil(t, schemaFileErr)
|
||||
|
||||
schema, schemaFileReadErr := os.ReadFile(schemaFilePath)
|
||||
assert.Nil(t, schemaFileReadErr)
|
||||
assert.True(t, len(schema) > 0)
|
||||
schema, err := jsonschema.Compile(schemaFilePath)
|
||||
assert.NoError(t, err)
|
||||
|
||||
nodeinfoSchema := gojsonschema.NewStringLoader(string(schema))
|
||||
nodeinfoString := gojsonschema.NewStringLoader(resp.Body.String())
|
||||
result, schemaValidationErr := gojsonschema.Validate(nodeinfoSchema, nodeinfoString)
|
||||
assert.Nil(t, schemaValidationErr)
|
||||
assert.Empty(t, result.Errors())
|
||||
assert.True(t, result.Valid())
|
||||
var data interface{}
|
||||
err = json.Unmarshal(resp.Body.Bytes(), &data)
|
||||
assert.NoError(t, err)
|
||||
|
||||
schemaValidation := schema.Validate(data)
|
||||
assert.Nil(t, schemaValidation)
|
||||
}
|
||||
|
||||
func GetCSRF(t testing.TB, session *TestSession, urlStr string) string {
|
||||
|
@ -562,3 +586,83 @@ func GetCSRF(t testing.TB, session *TestSession, urlStr string) string {
|
|||
doc := NewHTMLParser(t, resp.Body)
|
||||
return doc.GetCSRF()
|
||||
}
|
||||
|
||||
func GetHTMLTitle(t testing.TB, session *TestSession, urlStr string) string {
|
||||
t.Helper()
|
||||
|
||||
req := NewRequest(t, "GET", urlStr)
|
||||
var resp *httptest.ResponseRecorder
|
||||
if session == nil {
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
} else {
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
return doc.Find("head title").Text()
|
||||
}
|
||||
|
||||
func CreateDeclarativeRepo(t *testing.T, owner *user_model.User, name string, enabledUnits, disabledUnits []unit_model.Type, files []*files_service.ChangeRepoFile) (*repo_model.Repository, string, func()) {
|
||||
t.Helper()
|
||||
|
||||
repoName := name
|
||||
if repoName == "" {
|
||||
repoName = gouuid.NewString()
|
||||
}
|
||||
|
||||
// Create a new repository
|
||||
repo, err := repo_service.CreateRepository(db.DefaultContext, owner, owner, repo_service.CreateRepoOptions{
|
||||
Name: repoName,
|
||||
Description: "Temporary Repo",
|
||||
AutoInit: true,
|
||||
Gitignores: "",
|
||||
License: "WTFPL",
|
||||
Readme: "Default",
|
||||
DefaultBranch: "main",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, repo)
|
||||
|
||||
if enabledUnits != nil || disabledUnits != nil {
|
||||
units := make([]repo_model.RepoUnit, len(enabledUnits))
|
||||
for i, unitType := range enabledUnits {
|
||||
units[i] = repo_model.RepoUnit{
|
||||
RepoID: repo.ID,
|
||||
Type: unitType,
|
||||
}
|
||||
}
|
||||
|
||||
err := repo_model.UpdateRepositoryUnits(db.DefaultContext, repo, units, disabledUnits)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
var sha string
|
||||
if len(files) > 0 {
|
||||
resp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, owner, &files_service.ChangeRepoFilesOptions{
|
||||
Files: files,
|
||||
Message: "add files",
|
||||
OldBranch: "main",
|
||||
NewBranch: "main",
|
||||
Author: &files_service.IdentityOptions{
|
||||
Name: owner.Name,
|
||||
Email: owner.Email,
|
||||
},
|
||||
Committer: &files_service.IdentityOptions{
|
||||
Name: owner.Name,
|
||||
Email: owner.Email,
|
||||
},
|
||||
Dates: &files_service.CommitDateOptions{
|
||||
Author: time.Now(),
|
||||
Committer: time.Now(),
|
||||
},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, resp)
|
||||
|
||||
sha = resp.Commit.SHA
|
||||
}
|
||||
|
||||
return repo, sha, func() {
|
||||
repo_service.DeleteRepository(db.DefaultContext, owner, repo, false)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -227,6 +227,56 @@ func TestIssueCommentDelete(t *testing.T) {
|
|||
unittest.AssertNotExistsBean(t, &issues_model.Comment{ID: commentID})
|
||||
}
|
||||
|
||||
func TestIssueCommentAttachment(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
const repoURL = "user2/repo1"
|
||||
const content = "Test comment 4"
|
||||
const status = ""
|
||||
session := loginUser(t, "user2")
|
||||
issueURL := testNewIssue(t, session, "user2", "repo1", "Title", "Description")
|
||||
|
||||
req := NewRequest(t, "GET", issueURL)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
link, exists := htmlDoc.doc.Find("#comment-form").Attr("action")
|
||||
assert.True(t, exists, "The template has changed")
|
||||
|
||||
uuid := createAttachment(t, session, repoURL, "image.png", generateImg(), http.StatusOK)
|
||||
|
||||
commentCount := htmlDoc.doc.Find(".comment-list .comment .render-content").Length()
|
||||
|
||||
req = NewRequestWithValues(t, "POST", link, map[string]string{
|
||||
"_csrf": htmlDoc.GetCSRF(),
|
||||
"content": content,
|
||||
"status": status,
|
||||
"files": uuid,
|
||||
})
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
req = NewRequest(t, "GET", test.RedirectURL(resp))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc = NewHTMLParser(t, resp.Body)
|
||||
|
||||
val := htmlDoc.doc.Find(".comment-list .comment .render-content p").Eq(commentCount).Text()
|
||||
assert.Equal(t, content, val)
|
||||
|
||||
idAttr, has := htmlDoc.doc.Find(".comment-list .comment").Eq(commentCount).Attr("id")
|
||||
idStr := idAttr[strings.LastIndexByte(idAttr, '-')+1:]
|
||||
assert.True(t, has)
|
||||
id, err := strconv.Atoi(idStr)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, 0, id)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s/comments/%d/attachments", "user2", "repo1", id))
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// Using the ID of a comment that does not belong to the repository must fail
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s/comments/%d/attachments", "user5", "repo4", id))
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
||||
|
||||
func TestIssueCommentUpdate(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
session := loginUser(t, "user2")
|
||||
|
@ -579,6 +629,48 @@ func TestGetIssueInfo(t *testing.T) {
|
|||
assert.EqualValues(t, issue.ID, apiIssue.ID)
|
||||
}
|
||||
|
||||
func TestIssuePinMove(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
session := loginUser(t, "user2")
|
||||
issueURL, issue := testIssueWithBean(t, "user2", 1, "Title", "Content")
|
||||
assert.EqualValues(t, 0, issue.PinOrder)
|
||||
|
||||
req := NewRequestWithValues(t, "POST", fmt.Sprintf("%s/pin", issueURL), map[string]string{
|
||||
"_csrf": GetCSRF(t, session, issueURL),
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
issue = unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issue.ID})
|
||||
|
||||
position := 1
|
||||
assert.EqualValues(t, position, issue.PinOrder)
|
||||
|
||||
newPosition := 2
|
||||
|
||||
// Using the ID of an issue that does not belong to the repository must fail
|
||||
{
|
||||
session5 := loginUser(t, "user5")
|
||||
movePinURL := "/user5/repo4/issues/move_pin?_csrf=" + GetCSRF(t, session5, issueURL)
|
||||
req = NewRequestWithJSON(t, "POST", movePinURL, map[string]any{
|
||||
"id": issue.ID,
|
||||
"position": newPosition,
|
||||
})
|
||||
session5.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
issue = unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issue.ID})
|
||||
assert.EqualValues(t, position, issue.PinOrder)
|
||||
}
|
||||
|
||||
movePinURL := issueURL[:strings.LastIndexByte(issueURL, '/')] + "/move_pin?_csrf=" + GetCSRF(t, session, issueURL)
|
||||
req = NewRequestWithJSON(t, "POST", movePinURL, map[string]any{
|
||||
"id": issue.ID,
|
||||
"position": newPosition,
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
issue = unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issue.ID})
|
||||
assert.EqualValues(t, newPosition, issue.PinOrder)
|
||||
}
|
||||
|
||||
func TestUpdateIssueDeadline(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
|
@ -626,3 +718,82 @@ func TestIssueReferenceURL(t *testing.T) {
|
|||
ref, _ = htmlDoc.Find(`.timeline-item.comment:not(.first) .reference-issue`).Attr("data-reference")
|
||||
assert.EqualValues(t, "/user2/repo1/issues/1#issuecomment-2", ref)
|
||||
}
|
||||
|
||||
func TestGetContentHistory(t *testing.T) {
|
||||
defer tests.AddFixtures("tests/integration/fixtures/TestGetContentHistory/")()
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
||||
issueURL := fmt.Sprintf("%s/issues/%d", repo.FullName(), issue.Index)
|
||||
contentHistory := unittest.AssertExistsAndLoadBean(t, &issues_model.ContentHistory{ID: 2, IssueID: issue.ID})
|
||||
contentHistoryURL := fmt.Sprintf("%s/issues/%d/content-history/detail?comment_id=%d&history_id=%d", repo.FullName(), issue.Index, contentHistory.CommentID, contentHistory.ID)
|
||||
|
||||
type contentHistoryResp struct {
|
||||
CanSoftDelete bool `json:"canSoftDelete"`
|
||||
HistoryID int `json:"historyId"`
|
||||
PrevHistoryID int `json:"prevHistoryId"`
|
||||
}
|
||||
|
||||
testCase := func(t *testing.T, session *TestSession, canDelete bool) {
|
||||
t.Helper()
|
||||
contentHistoryURL := contentHistoryURL + "&_csrf=" + GetCSRF(t, session, issueURL)
|
||||
|
||||
req := NewRequest(t, "GET", contentHistoryURL)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var respJSON contentHistoryResp
|
||||
DecodeJSON(t, resp, &respJSON)
|
||||
|
||||
assert.EqualValues(t, canDelete, respJSON.CanSoftDelete)
|
||||
assert.EqualValues(t, contentHistory.ID, respJSON.HistoryID)
|
||||
assert.EqualValues(t, contentHistory.ID-1, respJSON.PrevHistoryID)
|
||||
}
|
||||
|
||||
t.Run("Anonymous", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
testCase(t, emptyTestSession(t), false)
|
||||
})
|
||||
|
||||
t.Run("Another user", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
testCase(t, loginUser(t, "user8"), false)
|
||||
})
|
||||
|
||||
t.Run("Repo owner", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
testCase(t, loginUser(t, "user2"), true)
|
||||
})
|
||||
|
||||
t.Run("Poster", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
testCase(t, loginUser(t, "user5"), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCommitRefComment(t *testing.T) {
|
||||
defer tests.AddFixtures("tests/integration/fixtures/TestCommitRefComment/")()
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
t.Run("Pull request", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user2/repo1/pulls/2")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
event := htmlDoc.Find("#issuecomment-1000 .text").Text()
|
||||
assert.Contains(t, event, "referenced this pull request")
|
||||
})
|
||||
|
||||
t.Run("Issue", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user2/repo1/issues/1")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
event := htmlDoc.Find("#issuecomment-1001 .text").Text()
|
||||
assert.Contains(t, event, "referenced this issue")
|
||||
})
|
||||
}
|
||||
|
|
|
@ -18,9 +18,9 @@ import (
|
|||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/lfs"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/routers/web"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/klauspost/compress/gzhttp"
|
||||
gzipp "github.com/klauspost/compress/gzip"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -132,7 +132,7 @@ func TestGetLFSSmallTokenFail(t *testing.T) {
|
|||
|
||||
func TestGetLFSLarge(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
content := make([]byte, web.GzipMinSize*10)
|
||||
content := make([]byte, gzhttp.DefaultMinSize*10)
|
||||
for i := range content {
|
||||
content[i] = byte(i % 256)
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ func TestGetLFSLarge(t *testing.T) {
|
|||
|
||||
func TestGetLFSGzip(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
b := make([]byte, web.GzipMinSize*10)
|
||||
b := make([]byte, gzhttp.DefaultMinSize*10)
|
||||
for i := range b {
|
||||
b[i] = byte(i % 256)
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ func TestGetLFSGzip(t *testing.T) {
|
|||
|
||||
func TestGetLFSZip(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
b := make([]byte, web.GzipMinSize*10)
|
||||
b := make([]byte, gzhttp.DefaultMinSize*10)
|
||||
for i := range b {
|
||||
b[i] = byte(i % 256)
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/gitrepo"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
doctor "code.gitea.io/gitea/services/doctor"
|
||||
"code.gitea.io/gitea/services/migrations"
|
||||
mirror_service "code.gitea.io/gitea/services/mirror"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
|
@ -48,10 +49,11 @@ func testMirrorPush(t *testing.T, u *url.URL) {
|
|||
ctx := NewAPITestContext(t, user.LowerName, srcRepo.Name)
|
||||
|
||||
doCreatePushMirror(ctx, fmt.Sprintf("%s%s/%s", u.String(), url.PathEscape(ctx.Username), url.PathEscape(mirrorRepo.Name)), user.LowerName, userPassword)(t)
|
||||
doCreatePushMirror(ctx, fmt.Sprintf("%s%s/%s", u.String(), url.PathEscape(ctx.Username), url.PathEscape("does-not-matter")), user.LowerName, userPassword)(t)
|
||||
|
||||
mirrors, _, err := repo_model.GetPushMirrorsByRepoID(db.DefaultContext, srcRepo.ID, db.ListOptions{})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, mirrors, 1)
|
||||
assert.Len(t, mirrors, 2)
|
||||
|
||||
ok := mirror_service.SyncPushMirror(context.Background(), mirrors[0].ID)
|
||||
assert.True(t, ok)
|
||||
|
@ -72,6 +74,30 @@ func testMirrorPush(t *testing.T, u *url.URL) {
|
|||
|
||||
assert.Equal(t, srcCommit.ID, mirrorCommit.ID)
|
||||
|
||||
// Test that we can "repair" push mirrors where the remote doesn't exist in git's state.
|
||||
// To do that, we artificially remove the remote...
|
||||
cmd := git.NewCommand(db.DefaultContext, "remote", "rm").AddDynamicArguments(mirrors[0].RemoteName)
|
||||
_, _, err = cmd.RunStdString(&git.RunOpts{Dir: srcRepo.RepoPath()})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// ...then ensure that trying to get its remote address fails
|
||||
_, err = repo_model.GetPushMirrorRemoteAddress(srcRepo.OwnerName, srcRepo.Name, mirrors[0].RemoteName)
|
||||
assert.Error(t, err)
|
||||
|
||||
// ...and that we can fix it.
|
||||
err = doctor.FixPushMirrorsWithoutGitRemote(db.DefaultContext, nil, true)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// ...and after fixing, we only have one remote
|
||||
mirrors, _, err = repo_model.GetPushMirrorsByRepoID(db.DefaultContext, srcRepo.ID, db.ListOptions{})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, mirrors, 1)
|
||||
|
||||
// ...one we can get the address of, and it's not the one we removed
|
||||
remoteAddress, err := repo_model.GetPushMirrorRemoteAddress(srcRepo.OwnerName, srcRepo.Name, mirrors[0].RemoteName)
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, remoteAddress, "does-not-matter")
|
||||
|
||||
// Cleanup
|
||||
doRemovePushMirror(ctx, fmt.Sprintf("%s%s/%s", u.String(), url.PathEscape(ctx.Username), url.PathEscape(mirrorRepo.Name)), user.LowerName, userPassword, int(mirrors[0].ID))(t)
|
||||
mirrors, _, err = repo_model.GetPushMirrorsByRepoID(db.DefaultContext, srcRepo.ID, db.ListOptions{})
|
||||
|
|
|
@ -469,3 +469,30 @@ func TestSignInOAuthCallbackSignIn(t *testing.T) {
|
|||
userAfterLogin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userGitLab.ID})
|
||||
assert.Greater(t, userAfterLogin.LastLoginUnix, userGitLab.LastLoginUnix)
|
||||
}
|
||||
|
||||
func TestSignUpViaOAuthWithMissingFields(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
// enable auto-creation of accounts via OAuth2
|
||||
enableAutoRegistration := setting.OAuth2Client.EnableAutoRegistration
|
||||
setting.OAuth2Client.EnableAutoRegistration = true
|
||||
defer func() {
|
||||
setting.OAuth2Client.EnableAutoRegistration = enableAutoRegistration
|
||||
}()
|
||||
|
||||
// OAuth2 authentication source GitLab
|
||||
gitlabName := "gitlab"
|
||||
addAuthSource(t, authSourcePayloadGitLabCustom(gitlabName))
|
||||
userGitLabUserID := "5678"
|
||||
|
||||
// The Goth User returned by the oauth2 integration is missing
|
||||
// an email address, so we won't be able to automatically create a local account for it.
|
||||
defer mockCompleteUserAuth(func(res http.ResponseWriter, req *http.Request) (goth.User, error) {
|
||||
return goth.User{
|
||||
Provider: gitlabName,
|
||||
UserID: userGitLabUserID,
|
||||
}, nil
|
||||
})()
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/user/oauth2/%s/callback?code=XYZ&state=XYZ", gitlabName))
|
||||
resp := MakeRequest(t, req, http.StatusSeeOther)
|
||||
assert.Equal(t, test.RedirectURL(resp), "/user/link_account")
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2024 The Forgejo Authors c/o Codeberg e.V.. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package integration
|
||||
|
@ -12,7 +13,16 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
unit_model "code.gitea.io/gitea/models/unit"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
files_service "code.gitea.io/gitea/services/repository/files"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -175,3 +185,222 @@ func TestPullBranchDelete(t *testing.T) {
|
|||
session.MakeRequest(t, req, http.StatusOK)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRecentlyPushed(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
session := loginUser(t, "user1")
|
||||
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
|
||||
|
||||
testCreateBranch(t, session, "user1", "repo1", "branch/master", "recent-push", http.StatusSeeOther)
|
||||
testEditFile(t, session, "user1", "repo1", "recent-push", "README.md", "Hello recently!\n")
|
||||
|
||||
testCreateBranch(t, session, "user2", "repo1", "branch/master", "recent-push-base", http.StatusSeeOther)
|
||||
testEditFile(t, session, "user2", "repo1", "recent-push-base", "README.md", "Hello, recently, from base!\n")
|
||||
|
||||
baseRepo, err := repo_model.GetRepositoryByOwnerAndName(db.DefaultContext, "user2", "repo1")
|
||||
assert.NoError(t, err)
|
||||
repo, err := repo_model.GetRepositoryByOwnerAndName(db.DefaultContext, "user1", "repo1")
|
||||
assert.NoError(t, err)
|
||||
|
||||
enablePRs := func(t *testing.T, repo *repo_model.Repository) {
|
||||
t.Helper()
|
||||
|
||||
err := repo_service.UpdateRepositoryUnits(db.DefaultContext, repo,
|
||||
[]repo_model.RepoUnit{{
|
||||
RepoID: repo.ID,
|
||||
Type: unit_model.TypePullRequests,
|
||||
}},
|
||||
nil)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
disablePRs := func(t *testing.T, repo *repo_model.Repository) {
|
||||
t.Helper()
|
||||
|
||||
err := repo_service.UpdateRepositoryUnits(db.DefaultContext, repo, nil,
|
||||
[]unit_model.Type{unit_model.TypePullRequests})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
testBanner := func(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
req := NewRequest(t, "GET", "/user1/repo1")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
message := strings.TrimSpace(htmlDoc.Find(".ui.message").Text())
|
||||
link, _ := htmlDoc.Find(".ui.message a").Attr("href")
|
||||
expectedMessage := "You pushed on branch recent-push"
|
||||
|
||||
assert.Contains(t, message, expectedMessage)
|
||||
assert.Equal(t, "/user1/repo1/src/branch/recent-push", link)
|
||||
}
|
||||
|
||||
// Test that there's a recently pushed branches banner, and it contains
|
||||
// a link to the branch.
|
||||
t.Run("recently-pushed-banner", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
testBanner(t)
|
||||
})
|
||||
|
||||
// Test that it is still there if the fork has PRs disabled, but the
|
||||
// base repo still has them enabled.
|
||||
t.Run("with-fork-prs-disabled", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
defer func() {
|
||||
enablePRs(t, repo)
|
||||
}()
|
||||
|
||||
disablePRs(t, repo)
|
||||
testBanner(t)
|
||||
})
|
||||
|
||||
// Test that it is still there if the fork has PRs enabled, but the base
|
||||
// repo does not.
|
||||
t.Run("with-base-prs-disabled", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
defer func() {
|
||||
enablePRs(t, baseRepo)
|
||||
}()
|
||||
|
||||
disablePRs(t, baseRepo)
|
||||
testBanner(t)
|
||||
})
|
||||
|
||||
// Test that the banner is not present if both the base and current
|
||||
// repo have PRs disabled.
|
||||
t.Run("with-prs-disabled", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
defer func() {
|
||||
enablePRs(t, baseRepo)
|
||||
enablePRs(t, repo)
|
||||
}()
|
||||
|
||||
disablePRs(t, repo)
|
||||
disablePRs(t, baseRepo)
|
||||
|
||||
req := NewRequest(t, "GET", "/user1/repo1")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
htmlDoc.AssertElement(t, ".ui.message", false)
|
||||
})
|
||||
|
||||
// Test that visiting the base repo has the banner too, and includes
|
||||
// recent push notifications from both the fork, and the base repo.
|
||||
t.Run("on the base repo", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
// Count recently pushed branches on the fork
|
||||
req := NewRequest(t, "GET", "/user1/repo1")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
htmlDoc.AssertElement(t, ".ui.message", true)
|
||||
|
||||
// Count recently pushed branches on the base repo
|
||||
req = NewRequest(t, "GET", "/user2/repo1")
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc = NewHTMLParser(t, resp.Body)
|
||||
messageCountOnBase := htmlDoc.Find(".ui.message").Length()
|
||||
|
||||
// We have two messages on the base: one from the fork, one on the
|
||||
// base itself.
|
||||
assert.Equal(t, 2, messageCountOnBase)
|
||||
})
|
||||
|
||||
// Test that the banner's links point to the right repos
|
||||
t.Run("link validity", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
// We're testing against the origin repo, because that has both
|
||||
// local branches, and another from a fork, so we can test both in
|
||||
// one test!
|
||||
|
||||
req := NewRequest(t, "GET", "/user2/repo1")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
messages := htmlDoc.Find(".ui.message")
|
||||
|
||||
prButtons := messages.Find("a[role='button']")
|
||||
branchLinks := messages.Find("a[href*='/src/branch/']")
|
||||
|
||||
// ** base repo tests **
|
||||
basePRLink, _ := prButtons.First().Attr("href")
|
||||
baseBranchLink, _ := branchLinks.First().Attr("href")
|
||||
baseBranchName := branchLinks.First().Text()
|
||||
|
||||
// branch in the same repo does not have a `user/repo:` qualifier.
|
||||
assert.Equal(t, "recent-push-base", baseBranchName)
|
||||
// branch link points to the same repo
|
||||
assert.Equal(t, "/user2/repo1/src/branch/recent-push-base", baseBranchLink)
|
||||
// PR link compares against the correct rep, and unqualified branch name
|
||||
assert.Equal(t, "/user2/repo1/compare/master...recent-push-base", basePRLink)
|
||||
|
||||
// ** forked repo tests **
|
||||
forkPRLink, _ := prButtons.Last().Attr("href")
|
||||
forkBranchLink, _ := branchLinks.Last().Attr("href")
|
||||
forkBranchName := branchLinks.Last().Text()
|
||||
|
||||
// branch in the forked repo has a `user/repo:` qualifier.
|
||||
assert.Equal(t, "user1/repo1:recent-push", forkBranchName)
|
||||
// branch link points to the forked repo
|
||||
assert.Equal(t, "/user1/repo1/src/branch/recent-push", forkBranchLink)
|
||||
// PR link compares against the correct rep, and qualified branch name
|
||||
assert.Equal(t, "/user2/repo1/compare/master...user1/repo1:recent-push", forkPRLink)
|
||||
})
|
||||
|
||||
t.Run("unrelated branches are not shown", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
adminUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{IsAdmin: true})
|
||||
|
||||
// Create a new branch with no relation to the default branch.
|
||||
// 1. Create a new Tree object
|
||||
cmd := git.NewCommand(db.DefaultContext, "write-tree")
|
||||
treeID, _, gitErr := cmd.RunStdString(&git.RunOpts{Dir: repo.RepoPath()})
|
||||
assert.NoError(t, gitErr)
|
||||
treeID = strings.TrimSpace(treeID)
|
||||
// 2. Create a new (empty) commit
|
||||
cmd = git.NewCommand(db.DefaultContext, "commit-tree", "-m", "Initial orphan commit").AddDynamicArguments(treeID)
|
||||
commitID, _, gitErr := cmd.RunStdString(&git.RunOpts{Dir: repo.RepoPath()})
|
||||
assert.NoError(t, gitErr)
|
||||
commitID = strings.TrimSpace(commitID)
|
||||
// 3. Create a new ref pointing to the orphaned commit
|
||||
cmd = git.NewCommand(db.DefaultContext, "update-ref", "refs/heads/orphan1").AddDynamicArguments(commitID)
|
||||
_, _, gitErr = cmd.RunStdString(&git.RunOpts{Dir: repo.RepoPath()})
|
||||
assert.NoError(t, gitErr)
|
||||
// 4. Sync the git repo to the database
|
||||
syncErr := repo_service.AddAllRepoBranchesToSyncQueue(graceful.GetManager().ShutdownContext(), adminUser.ID)
|
||||
assert.NoError(t, syncErr)
|
||||
// 5. Add a fresh commit, so that FindRecentlyPushedBranches has
|
||||
// something to find.
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user1"})
|
||||
changeResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, owner,
|
||||
&files_service.ChangeRepoFilesOptions{
|
||||
Files: []*files_service.ChangeRepoFile{
|
||||
{
|
||||
Operation: "create",
|
||||
TreePath: "README.md",
|
||||
ContentReader: strings.NewReader("a readme file"),
|
||||
},
|
||||
},
|
||||
Message: "Add README.md",
|
||||
OldBranch: "orphan1",
|
||||
NewBranch: "orphan1",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, changeResp)
|
||||
|
||||
// Check that we only have 1 message on the main repo, the orphaned
|
||||
// one is not shown.
|
||||
req := NewRequest(t, "GET", "/user1/repo1")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
htmlDoc.AssertElement(t, ".ui.message", true)
|
||||
link, _ := htmlDoc.Find(".ui.message a[href*='/src/branch/']").Attr("href")
|
||||
assert.Equal(t, "/user1/repo1/src/branch/recent-push", link)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ import (
|
|||
"code.gitea.io/gitea/modules/test"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
"code.gitea.io/gitea/services/pull"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
files_service "code.gitea.io/gitea/services/repository/files"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -370,18 +369,11 @@ func TestConflictChecking(t *testing.T) {
|
|||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
// Create new clean repo to test conflict checking.
|
||||
baseRepo, err := repo_service.CreateRepository(db.DefaultContext, user, user, repo_service.CreateRepoOptions{
|
||||
Name: "conflict-checking",
|
||||
Description: "Tempo repo",
|
||||
AutoInit: true,
|
||||
Readme: "Default",
|
||||
DefaultBranch: "main",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, baseRepo)
|
||||
baseRepo, _, f := CreateDeclarativeRepo(t, user, "conflict-checking", nil, nil, nil)
|
||||
defer f()
|
||||
|
||||
// create a commit on new branch.
|
||||
_, err = files_service.ChangeRepoFiles(git.DefaultContext, baseRepo, user, &files_service.ChangeRepoFilesOptions{
|
||||
_, err := files_service.ChangeRepoFiles(git.DefaultContext, baseRepo, user, &files_service.ChangeRepoFilesOptions{
|
||||
Files: []*files_service.ChangeRepoFile{
|
||||
{
|
||||
Operation: "create",
|
||||
|
|
86
tests/integration/pull_request_task_test.go
Normal file
86
tests/integration/pull_request_task_test.go
Normal file
|
@ -0,0 +1,86 @@
|
|||
// Copyright 2024 The Forgejo Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
repo_module "code.gitea.io/gitea/modules/repository"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
pull_service "code.gitea.io/gitea/services/pull"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestPullRequestSynchronized(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
// unmerged pull request of user2/repo1 from branch2 to master
|
||||
pull := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2})
|
||||
// tip of tests/gitea-repositories-meta/user2/repo1 branch2
|
||||
pull.HeadCommitID = "985f0301dba5e7b34be866819cd15ad3d8f508ee"
|
||||
|
||||
require.Equal(t, pull.HeadRepoID, pull.BaseRepoID)
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pull.HeadRepoID})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
|
||||
t.Run("AddTestPullRequestTask", func(t *testing.T) {
|
||||
logChecker, cleanup := test.NewLogChecker(log.DEFAULT, log.TRACE)
|
||||
logChecker.Filter("Updating PR").StopMark("TestPullRequest ")
|
||||
defer cleanup()
|
||||
|
||||
opt := &repo_module.PushUpdateOptions{
|
||||
PusherID: owner.ID,
|
||||
PusherName: owner.Name,
|
||||
RepoUserName: owner.Name,
|
||||
RepoName: repo.Name,
|
||||
RefFullName: git.RefName("refs/heads/branch2"),
|
||||
OldCommitID: pull.HeadCommitID,
|
||||
NewCommitID: pull.HeadCommitID,
|
||||
}
|
||||
require.NoError(t, repo_service.PushUpdate(opt))
|
||||
logFiltered, logStopped := logChecker.Check(5 * time.Second)
|
||||
assert.True(t, logStopped)
|
||||
assert.True(t, logFiltered[0])
|
||||
})
|
||||
|
||||
for _, testCase := range []struct {
|
||||
name string
|
||||
maxPR int64
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "TestPullRequest process PR",
|
||||
maxPR: pull.Index,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "TestPullRequest skip PR",
|
||||
maxPR: pull.Index - 1,
|
||||
expected: false,
|
||||
},
|
||||
} {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
logChecker, cleanup := test.NewLogChecker(log.DEFAULT, log.TRACE)
|
||||
logChecker.Filter("Updating PR").StopMark("TestPullRequest ")
|
||||
defer cleanup()
|
||||
|
||||
pull_service.TestPullRequest(context.Background(), owner, repo.ID, testCase.maxPR, "branch2", true, pull.HeadCommitID, pull.HeadCommitID)
|
||||
logFiltered, logStopped := logChecker.Check(5 * time.Second)
|
||||
assert.True(t, logStopped)
|
||||
assert.Equal(t, testCase.expected, logFiltered[0])
|
||||
})
|
||||
}
|
||||
}
|
|
@ -4,10 +4,15 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPullView_ReviewerMissed(t *testing.T) {
|
||||
|
@ -20,3 +25,68 @@ func TestPullView_ReviewerMissed(t *testing.T) {
|
|||
req = NewRequest(t, "GET", "/user2/repo1/pulls/3")
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
|
||||
func TestPullView_ResolveInvalidatedReviewComment(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
session := loginUser(t, "user1")
|
||||
|
||||
req := NewRequest(t, "GET", "/user2/repo1/pulls/3/files")
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
req = NewRequest(t, "GET", "/user2/repo1/pulls/3/files/reviews/new_comment")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
req = NewRequestWithValues(t, "POST", "/user2/repo1/pulls/3/files/reviews/comments", map[string]string{
|
||||
"_csrf": doc.GetInputValueByName("_csrf"),
|
||||
"origin": doc.GetInputValueByName("origin"),
|
||||
"latest_commit_id": doc.GetInputValueByName("latest_commit_id"),
|
||||
"side": "proposed",
|
||||
"line": "1",
|
||||
"path": "iso-8859-1.txt",
|
||||
"diff_start_cid": doc.GetInputValueByName("diff_start_cid"),
|
||||
"diff_end_cid": doc.GetInputValueByName("diff_end_cid"),
|
||||
"diff_base_cid": doc.GetInputValueByName("diff_base_cid"),
|
||||
"content": "nitpicking comment",
|
||||
"pending_review": "",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
req = NewRequestWithValues(t, "POST", "/user2/repo1/pulls/3/files/reviews/submit", map[string]string{
|
||||
"_csrf": doc.GetInputValueByName("_csrf"),
|
||||
"commit_id": doc.GetInputValueByName("latest_commit_id"),
|
||||
"content": "looks good",
|
||||
"type": "comment",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// retrieve comment_id by reloading the comment page
|
||||
req = NewRequest(t, "GET", "/user2/repo1/pulls/3")
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
doc = NewHTMLParser(t, resp.Body)
|
||||
commentID, ok := doc.Find(`[data-action="Resolve"]`).Attr("data-comment-id")
|
||||
assert.True(t, ok)
|
||||
|
||||
// adjust the database to mark the comment as invalidated
|
||||
// (to invalidate it properly, one should push a commit which should trigger this logic,
|
||||
// in the meantime, use this quick-and-dirty trick)
|
||||
id, err := strconv.ParseInt(commentID, 10, 64)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, issues.UpdateCommentInvalidate(context.Background(), &issues.Comment{
|
||||
ID: id,
|
||||
Invalidated: true,
|
||||
}))
|
||||
|
||||
req = NewRequestWithValues(t, "POST", "/user2/repo1/issues/resolve_conversation", map[string]string{
|
||||
"_csrf": doc.GetInputValueByName("_csrf"),
|
||||
"origin": "timeline",
|
||||
"action": "Resolve",
|
||||
"comment_id": commentID,
|
||||
})
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// even on template error, the page returns HTTP 200
|
||||
// search the button to mark the comment as unresolved to ensure success.
|
||||
doc = NewHTMLParser(t, resp.Body)
|
||||
assert.Len(t, doc.Find(`[data-action="UnResolve"][data-comment-id="`+commentID+`"]`).Nodes, 1)
|
||||
}
|
||||
|
|
|
@ -82,17 +82,7 @@ func TestAPIPullUpdateByRebase(t *testing.T) {
|
|||
}
|
||||
|
||||
func createOutdatedPR(t *testing.T, actor, forkOrg *user_model.User) *issues_model.PullRequest {
|
||||
baseRepo, err := repo_service.CreateRepository(db.DefaultContext, actor, actor, repo_service.CreateRepoOptions{
|
||||
Name: "repo-pr-update",
|
||||
Description: "repo-tmp-pr-update description",
|
||||
AutoInit: true,
|
||||
Gitignores: "C,C++",
|
||||
License: "MIT",
|
||||
Readme: "Default",
|
||||
IsPrivate: false,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, baseRepo)
|
||||
baseRepo, _, _ := CreateDeclarativeRepo(t, actor, "repo-pr-update", nil, nil, nil)
|
||||
|
||||
headRepo, err := repo_service.ForkRepository(git.DefaultContext, actor, forkOrg, repo_service.ForkRepoOptions{
|
||||
BaseRepo: baseRepo,
|
||||
|
@ -112,8 +102,8 @@ func createOutdatedPR(t *testing.T, actor, forkOrg *user_model.User) *issues_mod
|
|||
},
|
||||
},
|
||||
Message: "Add File A",
|
||||
OldBranch: "master",
|
||||
NewBranch: "master",
|
||||
OldBranch: "main",
|
||||
NewBranch: "main",
|
||||
Author: &files_service.IdentityOptions{
|
||||
Name: actor.Name,
|
||||
Email: actor.Email,
|
||||
|
@ -139,7 +129,7 @@ func createOutdatedPR(t *testing.T, actor, forkOrg *user_model.User) *issues_mod
|
|||
},
|
||||
},
|
||||
Message: "Add File on PR branch",
|
||||
OldBranch: "master",
|
||||
OldBranch: "main",
|
||||
NewBranch: "newBranch",
|
||||
Author: &files_service.IdentityOptions{
|
||||
Name: actor.Name,
|
||||
|
@ -168,7 +158,7 @@ func createOutdatedPR(t *testing.T, actor, forkOrg *user_model.User) *issues_mod
|
|||
HeadRepoID: headRepo.ID,
|
||||
BaseRepoID: baseRepo.ID,
|
||||
HeadBranch: "newBranch",
|
||||
BaseBranch: "master",
|
||||
BaseBranch: "main",
|
||||
HeadRepo: headRepo,
|
||||
BaseRepo: baseRepo,
|
||||
Type: issues_model.PullRequestGitea,
|
||||
|
|
|
@ -21,6 +21,10 @@ import (
|
|||
)
|
||||
|
||||
func createNewRelease(t *testing.T, session *TestSession, repoURL, tag, title string, preRelease, draft bool) {
|
||||
createNewReleaseTarget(t, session, repoURL, tag, title, "master", preRelease, draft)
|
||||
}
|
||||
|
||||
func createNewReleaseTarget(t *testing.T, session *TestSession, repoURL, tag, title, target string, preRelease, draft bool) {
|
||||
req := NewRequest(t, "GET", repoURL+"/releases/new")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
@ -31,7 +35,7 @@ func createNewRelease(t *testing.T, session *TestSession, repoURL, tag, title st
|
|||
postData := map[string]string{
|
||||
"_csrf": htmlDoc.GetCSRF(),
|
||||
"tag_name": tag,
|
||||
"tag_target": "master",
|
||||
"tag_target": target,
|
||||
"title": title,
|
||||
"content": "",
|
||||
}
|
||||
|
@ -89,6 +93,44 @@ func TestCreateRelease(t *testing.T) {
|
|||
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", translation.NewLocale("en-US").Tr("repo.release.stable"), 4)
|
||||
}
|
||||
|
||||
func TestDeleteRelease(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 57, OwnerName: "user2", LowerName: "repo-release"})
|
||||
release := unittest.AssertExistsAndLoadBean(t, &repo_model.Release{TagName: "v2.0"})
|
||||
assert.False(t, release.IsTag)
|
||||
|
||||
// Using the ID of a comment that does not belong to the repository must fail
|
||||
session5 := loginUser(t, "user5")
|
||||
otherRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user5", LowerName: "repo4"})
|
||||
|
||||
req := NewRequestWithValues(t, "POST", fmt.Sprintf("%s/releases/delete?id=%d", otherRepo.Link(), release.ID), map[string]string{
|
||||
"_csrf": GetCSRF(t, session5, otherRepo.Link()),
|
||||
})
|
||||
session5.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
req = NewRequestWithValues(t, "POST", fmt.Sprintf("%s/releases/delete?id=%d", repo.Link(), release.ID), map[string]string{
|
||||
"_csrf": GetCSRF(t, session, repo.Link()),
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
release = unittest.AssertExistsAndLoadBean(t, &repo_model.Release{ID: release.ID})
|
||||
|
||||
if assert.True(t, release.IsTag) {
|
||||
req = NewRequestWithValues(t, "POST", fmt.Sprintf("%s/tags/delete?id=%d", otherRepo.Link(), release.ID), map[string]string{
|
||||
"_csrf": GetCSRF(t, session5, otherRepo.Link()),
|
||||
})
|
||||
session5.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequestWithValues(t, "POST", fmt.Sprintf("%s/tags/delete?id=%d", repo.Link(), release.ID), map[string]string{
|
||||
"_csrf": GetCSRF(t, session, repo.Link()),
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
unittest.AssertNotExistsBean(t, &repo_model.Release{ID: release.ID})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateReleasePreRelease(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
|
@ -217,6 +259,15 @@ func TestViewReleaseListLogin(t *testing.T) {
|
|||
}, links)
|
||||
}
|
||||
|
||||
func TestReleaseOnCommit(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
createNewReleaseTarget(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", "65f1bf27bc3bf70f64657658635e66094edbcb4d", false, false)
|
||||
|
||||
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", translation.NewLocale("en-US").Tr("repo.release.stable"), 4)
|
||||
}
|
||||
|
||||
func TestViewTagsList(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
|
|
190
tests/integration/repo_badges_test.go
Normal file
190
tests/integration/repo_badges_test.go
Normal file
|
@ -0,0 +1,190 @@
|
|||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
actions_model "code.gitea.io/gitea/models/actions"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
unit_model "code.gitea.io/gitea/models/unit"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
files_service "code.gitea.io/gitea/services/repository/files"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBadges(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
prep := func(t *testing.T) (*repo_model.Repository, func()) {
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
repo, _, f := CreateDeclarativeRepo(t, owner, "",
|
||||
[]unit_model.Type{unit_model.TypeActions},
|
||||
[]unit_model.Type{unit_model.TypeIssues, unit_model.TypePullRequests, unit_model.TypeReleases},
|
||||
[]*files_service.ChangeRepoFile{
|
||||
{
|
||||
Operation: "create",
|
||||
TreePath: ".gitea/workflows/pr.yml",
|
||||
ContentReader: strings.NewReader("name: test\non:\n push:\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - run: echo helloworld\n"),
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: repo.ID}))
|
||||
|
||||
return repo, f
|
||||
}
|
||||
|
||||
assertBadge := func(t *testing.T, resp *httptest.ResponseRecorder, badge string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, fmt.Sprintf("https://img.shields.io/badge/%s", badge), test.RedirectURL(resp))
|
||||
}
|
||||
|
||||
t.Run("Workflows", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
repo, f := prep(t)
|
||||
defer f()
|
||||
|
||||
// Actions disabled
|
||||
req := NewRequest(t, "GET", "/user2/repo1/badges/workflows/test.yaml/badge.svg")
|
||||
resp := MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "test.yaml-Not%20found-crimson")
|
||||
|
||||
req = NewRequest(t, "GET", "/user2/repo1/badges/workflows/test.yaml/badge.svg?branch=no-such-branch")
|
||||
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "test.yaml-Not%20found-crimson")
|
||||
|
||||
// Actions enabled
|
||||
req = NewRequestf(t, "GET", "/user2/%s/badges/workflows/pr.yml/badge.svg", repo.Name)
|
||||
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "pr.yml-waiting-lightgrey")
|
||||
|
||||
req = NewRequestf(t, "GET", "/user2/%s/badges/workflows/pr.yml/badge.svg?branch=main", repo.Name)
|
||||
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "pr.yml-waiting-lightgrey")
|
||||
|
||||
req = NewRequestf(t, "GET", "/user2/%s/badges/workflows/pr.yml/badge.svg?branch=no-such-branch", repo.Name)
|
||||
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "pr.yml-Not%20found-crimson")
|
||||
|
||||
req = NewRequestf(t, "GET", "/user2/%s/badges/workflows/pr.yml/badge.svg?event=cron", repo.Name)
|
||||
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "pr.yml-Not%20found-crimson")
|
||||
|
||||
// GitHub compatibility
|
||||
req = NewRequestf(t, "GET", "/user2/%s/actions/workflows/pr.yml/badge.svg", repo.Name)
|
||||
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "pr.yml-waiting-lightgrey")
|
||||
|
||||
req = NewRequestf(t, "GET", "/user2/%s/actions/workflows/pr.yml/badge.svg?branch=main", repo.Name)
|
||||
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "pr.yml-waiting-lightgrey")
|
||||
|
||||
req = NewRequestf(t, "GET", "/user2/%s/actions/workflows/pr.yml/badge.svg?branch=no-such-branch", repo.Name)
|
||||
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "pr.yml-Not%20found-crimson")
|
||||
|
||||
req = NewRequestf(t, "GET", "/user2/%s/actions/workflows/pr.yml/badge.svg?event=cron", repo.Name)
|
||||
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "pr.yml-Not%20found-crimson")
|
||||
})
|
||||
|
||||
t.Run("Stars", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user2/repo1/badges/stars.svg")
|
||||
resp := MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
||||
assertBadge(t, resp, "stars-0-blue")
|
||||
})
|
||||
|
||||
t.Run("Issues", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
repo, f := prep(t)
|
||||
defer f()
|
||||
|
||||
// Issues enabled
|
||||
req := NewRequest(t, "GET", "/user2/repo1/badges/issues.svg")
|
||||
resp := MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "issues-2-blue")
|
||||
|
||||
req = NewRequest(t, "GET", "/user2/repo1/badges/issues/open.svg")
|
||||
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "issues-1%20open-blue")
|
||||
|
||||
req = NewRequest(t, "GET", "/user2/repo1/badges/issues/closed.svg")
|
||||
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "issues-1%20closed-blue")
|
||||
|
||||
// Issues disabled
|
||||
req = NewRequestf(t, "GET", "/user2/%s/badges/issues.svg", repo.Name)
|
||||
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "issues-Not%20found-crimson")
|
||||
|
||||
req = NewRequestf(t, "GET", "/user2/%s/badges/issues/open.svg", repo.Name)
|
||||
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "issues-Not%20found-crimson")
|
||||
|
||||
req = NewRequestf(t, "GET", "/user2/%s/badges/issues/closed.svg", repo.Name)
|
||||
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "issues-Not%20found-crimson")
|
||||
})
|
||||
|
||||
t.Run("Pulls", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
repo, f := prep(t)
|
||||
defer f()
|
||||
|
||||
// Pull requests enabled
|
||||
req := NewRequest(t, "GET", "/user2/repo1/badges/pulls.svg")
|
||||
resp := MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "pulls-3-blue")
|
||||
|
||||
req = NewRequest(t, "GET", "/user2/repo1/badges/pulls/open.svg")
|
||||
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "pulls-3%20open-blue")
|
||||
|
||||
req = NewRequest(t, "GET", "/user2/repo1/badges/pulls/closed.svg")
|
||||
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "pulls-0%20closed-blue")
|
||||
|
||||
// Pull requests disabled
|
||||
req = NewRequestf(t, "GET", "/user2/%s/badges/pulls.svg", repo.Name)
|
||||
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "pulls-Not%20found-crimson")
|
||||
|
||||
req = NewRequestf(t, "GET", "/user2/%s/badges/pulls/open.svg", repo.Name)
|
||||
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "pulls-Not%20found-crimson")
|
||||
|
||||
req = NewRequestf(t, "GET", "/user2/%s/badges/pulls/closed.svg", repo.Name)
|
||||
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "pulls-Not%20found-crimson")
|
||||
})
|
||||
|
||||
t.Run("Release", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
repo, f := prep(t)
|
||||
defer f()
|
||||
|
||||
req := NewRequest(t, "GET", "/user2/repo1/badges/release.svg")
|
||||
resp := MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "release-v1.1-blue")
|
||||
|
||||
req = NewRequestf(t, "GET", "/user2/%s/badges/release.svg", repo.Name)
|
||||
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||
assertBadge(t, resp, "release-Not%20found-crimson")
|
||||
})
|
||||
})
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2024 The Forgejo Authors c/o Codeberg e.V.. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package integration
|
||||
|
@ -7,12 +8,21 @@ import (
|
|||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
git_model "code.gitea.io/gitea/models/git"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -47,12 +57,14 @@ func testCreateBranches(t *testing.T, giteaURL *url.URL) {
|
|||
CreateRelease string
|
||||
FlashMessage string
|
||||
ExpectedStatus int
|
||||
CheckBranch bool
|
||||
}{
|
||||
{
|
||||
OldRefSubURL: "branch/master",
|
||||
NewBranch: "feature/test1",
|
||||
ExpectedStatus: http.StatusSeeOther,
|
||||
FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.create_success", "feature/test1"),
|
||||
CheckBranch: true,
|
||||
},
|
||||
{
|
||||
OldRefSubURL: "branch/master",
|
||||
|
@ -65,6 +77,7 @@ func testCreateBranches(t *testing.T, giteaURL *url.URL) {
|
|||
NewBranch: "feature=test1",
|
||||
ExpectedStatus: http.StatusSeeOther,
|
||||
FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.create_success", "feature=test1"),
|
||||
CheckBranch: true,
|
||||
},
|
||||
{
|
||||
OldRefSubURL: "branch/master",
|
||||
|
@ -94,6 +107,7 @@ func testCreateBranches(t *testing.T, giteaURL *url.URL) {
|
|||
NewBranch: "feature/test3",
|
||||
ExpectedStatus: http.StatusSeeOther,
|
||||
FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.create_success", "feature/test3"),
|
||||
CheckBranch: true,
|
||||
},
|
||||
{
|
||||
OldRefSubURL: "branch/master",
|
||||
|
@ -108,10 +122,15 @@ func testCreateBranches(t *testing.T, giteaURL *url.URL) {
|
|||
CreateRelease: "v1.0.1",
|
||||
ExpectedStatus: http.StatusSeeOther,
|
||||
FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.create_success", "feature/test4"),
|
||||
CheckBranch: true,
|
||||
},
|
||||
}
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
for _, test := range tests {
|
||||
session := loginUser(t, "user2")
|
||||
if test.CheckBranch {
|
||||
unittest.AssertNotExistsBean(t, &git_model.Branch{RepoID: 1, Name: test.NewBranch})
|
||||
}
|
||||
if test.CreateRelease != "" {
|
||||
createNewRelease(t, session, "/user2/repo1", test.CreateRelease, test.CreateRelease, false, false)
|
||||
}
|
||||
|
@ -125,6 +144,9 @@ func testCreateBranches(t *testing.T, giteaURL *url.URL) {
|
|||
test.FlashMessage,
|
||||
)
|
||||
}
|
||||
if test.CheckBranch {
|
||||
unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: 1, Name: test.NewBranch})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -145,3 +167,49 @@ func TestCreateBranchInvalidCSRF(t *testing.T) {
|
|||
strings.TrimSpace(htmlDoc.doc.Find(".ui.message").Text()),
|
||||
)
|
||||
}
|
||||
|
||||
func TestDatabaseMissingABranch(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, URL *url.URL) {
|
||||
adminUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{IsAdmin: true})
|
||||
session := loginUser(t, "user2")
|
||||
|
||||
// Create two branches
|
||||
testCreateBranch(t, session, "user2", "repo1", "branch/master", "will-be-present", http.StatusSeeOther)
|
||||
testCreateBranch(t, session, "user2", "repo1", "branch/master", "will-be-missing", http.StatusSeeOther)
|
||||
|
||||
// Run the repo branch sync, to ensure the db and git agree.
|
||||
err2 := repo_service.AddAllRepoBranchesToSyncQueue(graceful.GetManager().ShutdownContext(), adminUser.ID)
|
||||
assert.NoError(t, err2)
|
||||
|
||||
// Delete one branch from git only, leaving it in the database
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
cmd := git.NewCommand(db.DefaultContext, "branch", "-D").AddDynamicArguments("will-be-missing")
|
||||
_, _, err := cmd.RunStdString(&git.RunOpts{Dir: repo.RepoPath()})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Verify that loading the repo's branches page works still, and that it
|
||||
// reports at least three branches (master, will-be-present, and
|
||||
// will-be-missing).
|
||||
req := NewRequest(t, "GET", "/user2/repo1/branches")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
firstBranchCount, _ := strconv.Atoi(doc.Find(".repository-menu a[href*='/branches'] b").Text())
|
||||
assert.GreaterOrEqual(t, firstBranchCount, 3)
|
||||
|
||||
// Run the repo branch sync again
|
||||
err2 = repo_service.AddAllRepoBranchesToSyncQueue(graceful.GetManager().ShutdownContext(), adminUser.ID)
|
||||
assert.NoError(t, err2)
|
||||
|
||||
// Verify that loading the repo's branches page works still, and that it
|
||||
// reports one branch less than the first time.
|
||||
//
|
||||
// NOTE: This assumes that the branch counter on the web UI is out of
|
||||
// date before the sync. If that problem gets resolved, we'll have to
|
||||
// find another way to test that the syncing works.
|
||||
req = NewRequest(t, "GET", "/user2/repo1/branches")
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
doc = NewHTMLParser(t, resp.Body)
|
||||
secondBranchCount, _ := strconv.Atoi(doc.Find(".repository-menu a[href*='/branches'] b").Text())
|
||||
assert.Equal(t, firstBranchCount-1, secondBranchCount)
|
||||
})
|
||||
}
|
||||
|
|
391
tests/integration/repo_flags_test.go
Normal file
391
tests/integration/repo_flags_test.go
Normal file
|
@ -0,0 +1,391 @@
|
|||
// Copyright 2024 The Forgejo Authors c/o Codeberg e.V.. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"slices"
|
||||
"testing"
|
||||
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
"code.gitea.io/gitea/routers"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRepositoryFlagsUIDisabled(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
defer test.MockVariableValue(&setting.Repository.EnableFlags, false)()
|
||||
defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
|
||||
|
||||
admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{IsAdmin: true})
|
||||
session := loginUser(t, admin.Name)
|
||||
|
||||
// With the repo flags feature disabled, the /flags route is 404
|
||||
req := NewRequest(t, "GET", "/user2/repo1/flags")
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// With the repo flags feature disabled, the "Modify flags" tab does not
|
||||
// appear for instance admins
|
||||
req = NewRequest(t, "GET", "/user2/repo1")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
flagsLinkCount := doc.Find(fmt.Sprintf(`a[href="%s/flags"]`, "/user2/repo1")).Length()
|
||||
assert.Equal(t, 0, flagsLinkCount)
|
||||
}
|
||||
|
||||
func TestRepositoryFlagsAPI(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
defer test.MockVariableValue(&setting.Repository.EnableFlags, true)()
|
||||
defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
|
||||
|
||||
// *************
|
||||
// ** Helpers **
|
||||
// *************
|
||||
|
||||
adminUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{IsAdmin: true}).Name
|
||||
normalUserBean := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
assert.False(t, normalUserBean.IsAdmin)
|
||||
normalUser := normalUserBean.Name
|
||||
|
||||
assertAccess := func(t *testing.T, user, method, uri string, expectedStatus int) {
|
||||
session := loginUser(t, user)
|
||||
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeReadAdmin)
|
||||
|
||||
req := NewRequestf(t, method, "/api/v1/repos/user2/repo1/flags%s", uri).AddTokenAuth(token)
|
||||
MakeRequest(t, req, expectedStatus)
|
||||
}
|
||||
|
||||
// ***********
|
||||
// ** Tests **
|
||||
// ***********
|
||||
|
||||
t.Run("API access", func(t *testing.T) {
|
||||
t.Run("as admin", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
assertAccess(t, adminUser, "GET", "", http.StatusOK)
|
||||
})
|
||||
|
||||
t.Run("as normal user", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
assertAccess(t, normalUser, "GET", "", http.StatusForbidden)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("token scopes", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
// Trying to access the API with a token that lacks permissions, will
|
||||
// fail, even if the token owner is an instance admin.
|
||||
session := loginUser(t, adminUser)
|
||||
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
|
||||
|
||||
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo1/flags").AddTokenAuth(token)
|
||||
MakeRequest(t, req, http.StatusForbidden)
|
||||
})
|
||||
|
||||
t.Run("setting.Repository.EnableFlags is respected", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
defer test.MockVariableValue(&setting.Repository.EnableFlags, false)()
|
||||
defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
|
||||
|
||||
t.Run("as admin", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
assertAccess(t, adminUser, "GET", "", http.StatusNotFound)
|
||||
})
|
||||
|
||||
t.Run("as normal user", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
assertAccess(t, normalUser, "GET", "", http.StatusNotFound)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("API functionality", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
|
||||
defer func() {
|
||||
repo.ReplaceAllFlags(db.DefaultContext, []string{})
|
||||
}()
|
||||
|
||||
baseURLFmtStr := "/api/v1/repos/user5/repo4/flags%s"
|
||||
|
||||
session := loginUser(t, adminUser)
|
||||
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteAdmin)
|
||||
|
||||
// Listing flags
|
||||
req := NewRequestf(t, "GET", baseURLFmtStr, "").AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
var flags []string
|
||||
DecodeJSON(t, resp, &flags)
|
||||
assert.Empty(t, flags)
|
||||
|
||||
// Replacing all tags works, twice in a row
|
||||
for i := 0; i < 2; i++ {
|
||||
req = NewRequestWithJSON(t, "PUT", fmt.Sprintf(baseURLFmtStr, ""), &api.ReplaceFlagsOption{
|
||||
Flags: []string{"flag-1", "flag-2", "flag-3"},
|
||||
}).AddTokenAuth(token)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
}
|
||||
|
||||
// The list now includes all three flags
|
||||
req = NewRequestf(t, "GET", baseURLFmtStr, "").AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &flags)
|
||||
assert.Len(t, flags, 3)
|
||||
for _, flag := range []string{"flag-1", "flag-2", "flag-3"} {
|
||||
assert.True(t, slices.Contains(flags, flag))
|
||||
}
|
||||
|
||||
// Check a flag that is on the repo
|
||||
req = NewRequestf(t, "GET", baseURLFmtStr, "/flag-1").AddTokenAuth(token)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
// Check a flag that isn't on the repo
|
||||
req = NewRequestf(t, "GET", baseURLFmtStr, "/no-such-flag").AddTokenAuth(token)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// We can add the same flag twice
|
||||
for i := 0; i < 2; i++ {
|
||||
req = NewRequestf(t, "PUT", baseURLFmtStr, "/brand-new-flag").AddTokenAuth(token)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
}
|
||||
|
||||
// The new flag is there
|
||||
req = NewRequestf(t, "GET", baseURLFmtStr, "/brand-new-flag").AddTokenAuth(token)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
// We can delete a flag, twice
|
||||
for i := 0; i < 2; i++ {
|
||||
req = NewRequestf(t, "DELETE", baseURLFmtStr, "/flag-3").AddTokenAuth(token)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
}
|
||||
|
||||
// We can delete a flag that wasn't there
|
||||
req = NewRequestf(t, "DELETE", baseURLFmtStr, "/no-such-flag").AddTokenAuth(token)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
// We can delete all of the flags in one go, too
|
||||
req = NewRequestf(t, "DELETE", baseURLFmtStr, "").AddTokenAuth(token)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
// ..once all flags are deleted, none are listed, either
|
||||
req = NewRequestf(t, "GET", baseURLFmtStr, "").AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &flags)
|
||||
assert.Empty(t, flags)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRepositoryFlagsUI(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
defer test.MockVariableValue(&setting.Repository.EnableFlags, true)()
|
||||
defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
|
||||
|
||||
// *******************
|
||||
// ** Preparations **
|
||||
// *******************
|
||||
flaggedRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
unflaggedRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
|
||||
|
||||
// **************
|
||||
// ** Helpers **
|
||||
// **************
|
||||
|
||||
adminUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{IsAdmin: true}).Name
|
||||
flaggedOwner := "user2"
|
||||
flaggedRepoURLStr := "/user2/repo1"
|
||||
unflaggedOwner := "user5"
|
||||
unflaggedRepoURLStr := "/user5/repo4"
|
||||
otherUser := "user4"
|
||||
|
||||
ensureFlags := func(repo *repo_model.Repository, flags []string) func() {
|
||||
repo.ReplaceAllFlags(db.DefaultContext, flags)
|
||||
|
||||
return func() {
|
||||
repo.ReplaceAllFlags(db.DefaultContext, flags)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests:
|
||||
// - Presence of the link
|
||||
// - Number of flags listed in the admin-only message box
|
||||
// - Whether there's a link to /user/repo/flags
|
||||
// - Whether /user/repo/flags is OK or Forbidden
|
||||
assertFlagAccessAndCount := func(t *testing.T, user, repoURL string, hasAccess bool, expectedFlagCount int) {
|
||||
t.Helper()
|
||||
|
||||
var expectedLinkCount int
|
||||
var expectedStatus int
|
||||
if hasAccess {
|
||||
expectedLinkCount = 1
|
||||
expectedStatus = http.StatusOK
|
||||
} else {
|
||||
expectedLinkCount = 0
|
||||
if user != "" {
|
||||
expectedStatus = http.StatusForbidden
|
||||
} else {
|
||||
expectedStatus = http.StatusSeeOther
|
||||
}
|
||||
}
|
||||
|
||||
var resp *httptest.ResponseRecorder
|
||||
var session *TestSession
|
||||
req := NewRequest(t, "GET", repoURL)
|
||||
if user != "" {
|
||||
session = loginUser(t, user)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
} else {
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
flagsLinkCount := doc.Find(fmt.Sprintf(`a[href="%s/flags"]`, repoURL)).Length()
|
||||
assert.Equal(t, expectedLinkCount, flagsLinkCount)
|
||||
|
||||
flagCount := doc.Find(".ui.info.message .ui.label").Length()
|
||||
assert.Equal(t, expectedFlagCount, flagCount)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/flags", repoURL))
|
||||
if user != "" {
|
||||
session.MakeRequest(t, req, expectedStatus)
|
||||
} else {
|
||||
MakeRequest(t, req, expectedStatus)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensures that given a repo owner and a repo:
|
||||
// - An instance admin has access to flags, and sees the list on the repo home
|
||||
// - A repo admin does not have access to either, and does not see the list
|
||||
// - A passer by has no access to either, and does not see the list
|
||||
runTests := func(t *testing.T, ownerUser, repoURL string, expectedFlagCount int) {
|
||||
t.Run("as instance admin", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
assertFlagAccessAndCount(t, adminUser, repoURL, true, expectedFlagCount)
|
||||
})
|
||||
t.Run("as owner", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
assertFlagAccessAndCount(t, ownerUser, repoURL, false, 0)
|
||||
})
|
||||
t.Run("as other user", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
assertFlagAccessAndCount(t, otherUser, repoURL, false, 0)
|
||||
})
|
||||
t.Run("as non-logged in user", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
assertFlagAccessAndCount(t, "", repoURL, false, 0)
|
||||
})
|
||||
}
|
||||
|
||||
// **************************
|
||||
// ** The tests themselves **
|
||||
// **************************
|
||||
t.Run("unflagged repo", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
defer ensureFlags(unflaggedRepo, []string{})()
|
||||
|
||||
runTests(t, unflaggedOwner, unflaggedRepoURLStr, 0)
|
||||
})
|
||||
|
||||
t.Run("flagged repo", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
defer ensureFlags(flaggedRepo, []string{"test-flag"})()
|
||||
|
||||
runTests(t, flaggedOwner, flaggedRepoURLStr, 1)
|
||||
})
|
||||
|
||||
t.Run("modifying flags", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
session := loginUser(t, adminUser)
|
||||
flaggedRepoManageURL := fmt.Sprintf("%s/flags", flaggedRepoURLStr)
|
||||
unflaggedRepoManageURL := fmt.Sprintf("%s/flags", unflaggedRepoURLStr)
|
||||
|
||||
assertUIFlagStates := func(t *testing.T, url string, flagStates map[string]bool) {
|
||||
t.Helper()
|
||||
|
||||
req := NewRequest(t, "GET", url)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
flagBoxes := doc.Find(`input[name="flags"]`)
|
||||
assert.Equal(t, len(flagStates), flagBoxes.Length())
|
||||
|
||||
for name, state := range flagStates {
|
||||
_, checked := doc.Find(fmt.Sprintf(`input[value="%s"]`, name)).Attr("checked")
|
||||
assert.Equal(t, state, checked)
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("flag presence on the UI", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
defer ensureFlags(flaggedRepo, []string{"test-flag"})()
|
||||
|
||||
assertUIFlagStates(t, flaggedRepoManageURL, map[string]bool{"test-flag": true})
|
||||
})
|
||||
|
||||
t.Run("setting.Repository.SettableFlags is respected", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
defer test.MockVariableValue(&setting.Repository.SettableFlags, []string{"featured", "no-license"})()
|
||||
defer ensureFlags(flaggedRepo, []string{"test-flag"})()
|
||||
|
||||
assertUIFlagStates(t, flaggedRepoManageURL, map[string]bool{
|
||||
"test-flag": true,
|
||||
"featured": false,
|
||||
"no-license": false,
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("removing flags", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
defer ensureFlags(flaggedRepo, []string{"test-flag"})()
|
||||
|
||||
flagged := flaggedRepo.IsFlagged(db.DefaultContext)
|
||||
assert.True(t, flagged)
|
||||
|
||||
req := NewRequestWithValues(t, "POST", flaggedRepoManageURL, map[string]string{
|
||||
"_csrf": GetCSRF(t, session, flaggedRepoManageURL),
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
||||
flagged = flaggedRepo.IsFlagged(db.DefaultContext)
|
||||
assert.False(t, flagged)
|
||||
|
||||
assertUIFlagStates(t, flaggedRepoManageURL, map[string]bool{})
|
||||
})
|
||||
|
||||
t.Run("adding flags", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
defer ensureFlags(unflaggedRepo, []string{})()
|
||||
|
||||
flagged := unflaggedRepo.IsFlagged(db.DefaultContext)
|
||||
assert.False(t, flagged)
|
||||
|
||||
req := NewRequestWithValues(t, "POST", unflaggedRepoManageURL, map[string]string{
|
||||
"_csrf": GetCSRF(t, session, unflaggedRepoManageURL),
|
||||
"flags": "test-flag",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
||||
assertUIFlagStates(t, unflaggedRepoManageURL, map[string]bool{"test-flag": true})
|
||||
})
|
||||
})
|
||||
}
|
223
tests/integration/repo_lang_stats_test.go
Normal file
223
tests/integration/repo_lang_stats_test.go
Normal file
|
@ -0,0 +1,223 @@
|
|||
// Copyright 2024 The Forgejo Authors c/o Codeberg e.V.. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/indexer/stats"
|
||||
"code.gitea.io/gitea/modules/queue"
|
||||
files_service "code.gitea.io/gitea/services/repository/files"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRepoLangStats(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
/******************
|
||||
** Preparations **
|
||||
******************/
|
||||
prep := func(t *testing.T, attribs string) (*repo_model.Repository, string, func()) {
|
||||
t.Helper()
|
||||
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
repo, sha, f := CreateDeclarativeRepo(t, user2, "", nil, nil,
|
||||
[]*files_service.ChangeRepoFile{
|
||||
{
|
||||
Operation: "create",
|
||||
TreePath: ".gitattributes",
|
||||
ContentReader: strings.NewReader(attribs),
|
||||
},
|
||||
{
|
||||
Operation: "create",
|
||||
TreePath: "docs.md",
|
||||
ContentReader: strings.NewReader("This **is** a `markdown` file.\n"),
|
||||
},
|
||||
{
|
||||
Operation: "create",
|
||||
TreePath: "foo.c",
|
||||
ContentReader: strings.NewReader(`#include <stdio.h>\nint main() {\n printf("Hello world!\n");\n return 0;\n}\n`),
|
||||
},
|
||||
{
|
||||
Operation: "create",
|
||||
TreePath: "foo.nib",
|
||||
ContentReader: strings.NewReader("Pinky promise, this is not a generated file!\n"),
|
||||
},
|
||||
{
|
||||
Operation: "create",
|
||||
TreePath: ".dot.pas",
|
||||
ContentReader: strings.NewReader("program Hello;\nbegin\n writeln('Hello, world.');\nend.\n"),
|
||||
},
|
||||
{
|
||||
Operation: "create",
|
||||
TreePath: "cpplint.py",
|
||||
ContentReader: strings.NewReader(`#! /usr/bin/env python\n\nprint("Hello world!")\n`),
|
||||
},
|
||||
{
|
||||
Operation: "create",
|
||||
TreePath: "some-file.xml",
|
||||
ContentReader: strings.NewReader(`<?xml version="1.0"?>\n<foo>\n <bar>Hello</bar>\n</foo>\n`),
|
||||
},
|
||||
})
|
||||
|
||||
return repo, sha, f
|
||||
}
|
||||
|
||||
getFreshLanguageStats := func(t *testing.T, repo *repo_model.Repository, sha string) repo_model.LanguageStatList {
|
||||
t.Helper()
|
||||
|
||||
err := stats.UpdateRepoIndexer(repo)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.NoError(t, queue.GetManager().FlushAll(context.Background(), 10*time.Second))
|
||||
|
||||
status, err := repo_model.GetIndexerStatus(db.DefaultContext, repo, repo_model.RepoIndexerTypeStats)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, sha, status.CommitSha)
|
||||
langs, err := repo_model.GetTopLanguageStats(db.DefaultContext, repo, 5)
|
||||
assert.NoError(t, err)
|
||||
|
||||
return langs
|
||||
}
|
||||
|
||||
/***********
|
||||
** Tests **
|
||||
***********/
|
||||
|
||||
// 1. By default, documentation is not indexed
|
||||
t.Run("default", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
repo, sha, f := prep(t, "")
|
||||
defer f()
|
||||
|
||||
langs := getFreshLanguageStats(t, repo, sha)
|
||||
|
||||
// While this is a fairly short test, this exercises a number of
|
||||
// things:
|
||||
//
|
||||
// - `.gitattributes` is empty, so `isDetectable.IsFalse()`,
|
||||
// `isVendored.IsTrue()`, and `isDocumentation.IsTrue()` will be
|
||||
// false for every file, because these are only true if an
|
||||
// attribute is explicitly set.
|
||||
//
|
||||
// - There is `.dot.pas`, which would be considered Pascal source,
|
||||
// but it is a dotfile (thus, `enry.IsDotFile()` applies), and as
|
||||
// such, is not considered.
|
||||
//
|
||||
// - `some-file.xml` will be skipped because Enry considers XML
|
||||
// configuration, and `enry.IsConfiguration()` will catch it.
|
||||
//
|
||||
// - `!isVendored.IsFalse()` evaluates to true, so
|
||||
// `analyze.isVendor()` will be called on `cpplint.py`, which will
|
||||
// be considered vendored, even though both the filename and
|
||||
// contents would otherwise make it Python.
|
||||
//
|
||||
// - `!isDocumentation.IsFalse()` evaluates to true, so
|
||||
// `enry.IsDocumentation()` will be called for `docs.md`, and will
|
||||
// be considered documentation, thus, skipped.
|
||||
//
|
||||
// Thus, this exercises all of the conditions in the first big if
|
||||
// that is supposed to filter out files early. With two short asserts!
|
||||
|
||||
assert.Len(t, langs, 1)
|
||||
assert.Equal(t, "C", langs[0].Language)
|
||||
})
|
||||
|
||||
// 2. Marking foo.c as non-detectable
|
||||
t.Run("foo.c non-detectable", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
repo, sha, f := prep(t, "foo.c linguist-detectable=false\n")
|
||||
defer f()
|
||||
|
||||
langs := getFreshLanguageStats(t, repo, sha)
|
||||
assert.Empty(t, langs)
|
||||
})
|
||||
|
||||
// 3. Marking Markdown detectable
|
||||
t.Run("detectable markdown", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
repo, sha, f := prep(t, "*.md linguist-detectable\n")
|
||||
defer f()
|
||||
|
||||
langs := getFreshLanguageStats(t, repo, sha)
|
||||
assert.Len(t, langs, 2)
|
||||
assert.Equal(t, "C", langs[0].Language)
|
||||
assert.Equal(t, "Markdown", langs[1].Language)
|
||||
})
|
||||
|
||||
// 4. Marking foo.c as documentation
|
||||
t.Run("foo.c as documentation", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
repo, sha, f := prep(t, "foo.c linguist-documentation\n")
|
||||
defer f()
|
||||
|
||||
langs := getFreshLanguageStats(t, repo, sha)
|
||||
assert.Empty(t, langs)
|
||||
})
|
||||
|
||||
// 5. Overriding a generated file
|
||||
t.Run("linguist-generated=false", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
repo, sha, f := prep(t, "foo.nib linguist-generated=false\nfoo.nib linguist-language=Perl\n")
|
||||
defer f()
|
||||
|
||||
langs := getFreshLanguageStats(t, repo, sha)
|
||||
assert.Len(t, langs, 2)
|
||||
assert.Equal(t, "C", langs[0].Language)
|
||||
assert.Equal(t, "Perl", langs[1].Language)
|
||||
})
|
||||
|
||||
// 6. Disabling vendoring for a file
|
||||
t.Run("linguist-vendored=false", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
repo, sha, f := prep(t, "cpplint.py linguist-vendored=false\n")
|
||||
defer f()
|
||||
|
||||
langs := getFreshLanguageStats(t, repo, sha)
|
||||
assert.Len(t, langs, 2)
|
||||
assert.Equal(t, "C", langs[0].Language)
|
||||
assert.Equal(t, "Python", langs[1].Language)
|
||||
})
|
||||
|
||||
// 7. Disabling vendoring for a file, with -linguist-vendored
|
||||
t.Run("-linguist-vendored", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
repo, sha, f := prep(t, "cpplint.py -linguist-vendored\n")
|
||||
defer f()
|
||||
|
||||
langs := getFreshLanguageStats(t, repo, sha)
|
||||
assert.Len(t, langs, 2)
|
||||
assert.Equal(t, "C", langs[0].Language)
|
||||
assert.Equal(t, "Python", langs[1].Language)
|
||||
})
|
||||
|
||||
// 8. Marking foo.c as vendored
|
||||
t.Run("foo.c as vendored", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
repo, sha, f := prep(t, "foo.c linguist-vendored\n")
|
||||
defer f()
|
||||
|
||||
langs := getFreshLanguageStats(t, repo, sha)
|
||||
assert.Empty(t, langs)
|
||||
})
|
||||
})
|
||||
}
|
|
@ -15,8 +15,8 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func testRepoMigrate(t testing.TB, session *TestSession, cloneAddr, repoName string) *httptest.ResponseRecorder {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/repo/migrate?service_type=%d", structs.PlainGitService)) // render plain git migration page
|
||||
func testRepoMigrate(t testing.TB, session *TestSession, cloneAddr, repoName string, service structs.GitServiceType) *httptest.ResponseRecorder {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/repo/migrate?service_type=%d", service)) // render plain git migration page
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
|
@ -31,7 +31,7 @@ func testRepoMigrate(t testing.TB, session *TestSession, cloneAddr, repoName str
|
|||
"clone_addr": cloneAddr,
|
||||
"uid": uid,
|
||||
"repo_name": repoName,
|
||||
"service": fmt.Sprintf("%d", structs.PlainGitService),
|
||||
"service": fmt.Sprintf("%d", service),
|
||||
})
|
||||
resp = session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
||||
|
@ -41,5 +41,17 @@ func testRepoMigrate(t testing.TB, session *TestSession, cloneAddr, repoName str
|
|||
func TestRepoMigrate(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
session := loginUser(t, "user2")
|
||||
testRepoMigrate(t, session, "https://github.com/go-gitea/test_repo.git", "git")
|
||||
for _, s := range []struct {
|
||||
testName string
|
||||
cloneAddr string
|
||||
repoName string
|
||||
service structs.GitServiceType
|
||||
}{
|
||||
{"TestMigrateGithub", "https://github.com/go-gitea/test_repo.git", "git", structs.PlainGitService},
|
||||
{"TestMigrateGithub", "https://github.com/go-gitea/test_repo.git", "github", structs.GithubService},
|
||||
} {
|
||||
t.Run(s.testName, func(t *testing.T) {
|
||||
testRepoMigrate(t, session, s.cloneAddr, s.repoName, s.service)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,13 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
unit_model "code.gitea.io/gitea/models/unit"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
|
@ -43,6 +48,84 @@ func TestViewRepo(t *testing.T) {
|
|||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
||||
|
||||
func TestViewRepoCloneMethods(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
getCloneMethods := func() []string {
|
||||
req := NewRequest(t, "GET", "/user2/repo1")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
cloneMoreMethodsHTML := htmlDoc.doc.Find("#more-btn div a")
|
||||
|
||||
var methods []string
|
||||
cloneMoreMethodsHTML.Each(func(i int, s *goquery.Selection) {
|
||||
a, _ := s.Attr("href")
|
||||
methods = append(methods, a)
|
||||
})
|
||||
|
||||
return methods
|
||||
}
|
||||
|
||||
testCloneMethods := func(expected []string) {
|
||||
methods := getCloneMethods()
|
||||
|
||||
assert.Len(t, methods, len(expected))
|
||||
for i, expectedMethod := range expected {
|
||||
assert.Contains(t, methods[i], expectedMethod)
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("Defaults", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
testCloneMethods([]string{"/master.zip", "/master.tar.gz", "/master.bundle", "vscode://"})
|
||||
})
|
||||
|
||||
t.Run("Customized methods", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
defer test.MockVariableValue(&setting.Repository.DownloadOrCloneMethods, []string{"vscodium-clone", "download-targz"})()
|
||||
|
||||
testCloneMethods([]string{"vscodium://", "/master.tar.gz"})
|
||||
})
|
||||
|
||||
t.Run("Individual methods", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
singleMethodTest := func(method, expectedURLPart string) {
|
||||
t.Run(method, func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
defer test.MockVariableValue(&setting.Repository.DownloadOrCloneMethods, []string{method})()
|
||||
|
||||
testCloneMethods([]string{expectedURLPart})
|
||||
})
|
||||
}
|
||||
|
||||
cases := map[string]string{
|
||||
"download-zip": "/master.zip",
|
||||
"download-targz": "/master.tar.gz",
|
||||
"download-bundle": "/master.bundle",
|
||||
"vscode-clone": "vscode://",
|
||||
"vscodium-clone": "vscodium://",
|
||||
}
|
||||
for method, expectedURLPart := range cases {
|
||||
singleMethodTest(method, expectedURLPart)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("All methods", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
defer test.MockVariableValue(&setting.Repository.DownloadOrCloneMethods, setting.RecognisedRepositoryDownloadOrCloneMethods)()
|
||||
|
||||
methods := getCloneMethods()
|
||||
// We compare against
|
||||
// len(setting.RecognisedRepositoryDownloadOrCloneMethods) - 1, because
|
||||
// the test environment does not currently set things up for the cite
|
||||
// method to display.
|
||||
assert.GreaterOrEqual(t, len(methods), len(setting.RecognisedRepositoryDownloadOrCloneMethods)-1)
|
||||
})
|
||||
}
|
||||
|
||||
func testViewRepo(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
|
@ -201,6 +284,110 @@ func TestViewAsRepoAdmin(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestRepoHTMLTitle(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
t.Run("Repository homepage", func(t *testing.T) {
|
||||
t.Run("Without description", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo1")
|
||||
assert.EqualValues(t, "user2/repo1 - Gitea: Git with a cup of tea", htmlTitle)
|
||||
})
|
||||
t.Run("With description", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
htmlTitle := GetHTMLTitle(t, nil, "/user27/repo49")
|
||||
assert.EqualValues(t, "user27/repo49: A wonderful repository with more than just a README.md - Gitea: Git with a cup of tea", htmlTitle)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Code view", func(t *testing.T) {
|
||||
t.Run("Directory", func(t *testing.T) {
|
||||
t.Run("Default branch", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/branch/master/deep/nesting")
|
||||
assert.EqualValues(t, "repo59/deep/nesting at master - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
|
||||
})
|
||||
t.Run("Non-default branch", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/branch/cake-recipe/deep/nesting")
|
||||
assert.EqualValues(t, "repo59/deep/nesting at cake-recipe - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
|
||||
})
|
||||
t.Run("Commit", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/commit/d8f53dfb33f6ccf4169c34970b5e747511c18beb/deep/nesting/")
|
||||
assert.EqualValues(t, "repo59/deep/nesting at d8f53dfb33f6ccf4169c34970b5e747511c18beb - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
|
||||
})
|
||||
t.Run("Tag", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/tag/v1.0/deep/nesting/")
|
||||
assert.EqualValues(t, "repo59/deep/nesting at v1.0 - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
|
||||
})
|
||||
})
|
||||
t.Run("File", func(t *testing.T) {
|
||||
t.Run("Default branch", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/branch/master/deep/nesting/folder/secret_sauce_recipe.txt")
|
||||
assert.EqualValues(t, "repo59/deep/nesting/folder/secret_sauce_recipe.txt at master - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
|
||||
})
|
||||
t.Run("Non-default branch", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/branch/cake-recipe/deep/nesting/folder/secret_sauce_recipe.txt")
|
||||
assert.EqualValues(t, "repo59/deep/nesting/folder/secret_sauce_recipe.txt at cake-recipe - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
|
||||
})
|
||||
t.Run("Commit", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/commit/d8f53dfb33f6ccf4169c34970b5e747511c18beb/deep/nesting/folder/secret_sauce_recipe.txt")
|
||||
assert.EqualValues(t, "repo59/deep/nesting/folder/secret_sauce_recipe.txt at d8f53dfb33f6ccf4169c34970b5e747511c18beb - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
|
||||
})
|
||||
t.Run("Tag", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/tag/v1.0/deep/nesting/folder/secret_sauce_recipe.txt")
|
||||
assert.EqualValues(t, "repo59/deep/nesting/folder/secret_sauce_recipe.txt at v1.0 - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Issues view", func(t *testing.T) {
|
||||
t.Run("Overview page", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo1/issues")
|
||||
assert.EqualValues(t, "Issues - user2/repo1 - Gitea: Git with a cup of tea", htmlTitle)
|
||||
})
|
||||
t.Run("View issue page", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo1/issues/1")
|
||||
assert.EqualValues(t, "#1 - issue1 - user2/repo1 - Gitea: Git with a cup of tea", htmlTitle)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Pull requests view", func(t *testing.T) {
|
||||
t.Run("Overview page", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo1/pulls")
|
||||
assert.EqualValues(t, "Pull Requests - user2/repo1 - Gitea: Git with a cup of tea", htmlTitle)
|
||||
})
|
||||
t.Run("View pull request", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo1/pulls/2")
|
||||
assert.EqualValues(t, "#2 - issue2 - user2/repo1 - Gitea: Git with a cup of tea", htmlTitle)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// TestViewFileInRepo repo description, topics and summary should not be displayed when viewing a file
|
||||
func TestViewFileInRepo(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
@ -220,6 +407,40 @@ func TestViewFileInRepo(t *testing.T) {
|
|||
assert.EqualValues(t, 0, repoSummary.Length())
|
||||
}
|
||||
|
||||
func TestViewFileInRepoRSSFeed(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
hasFileRSSFeed := func(t *testing.T, ref string) bool {
|
||||
t.Helper()
|
||||
|
||||
req := NewRequestf(t, "GET", "/user2/repo1/src/%s/README.md", ref)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
fileFeed := htmlDoc.doc.Find(`a[href*="/user2/repo1/rss/"]`)
|
||||
|
||||
return fileFeed.Length() != 0
|
||||
}
|
||||
|
||||
t.Run("branch", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
assert.True(t, hasFileRSSFeed(t, "branch/master"))
|
||||
})
|
||||
|
||||
t.Run("tag", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
assert.False(t, hasFileRSSFeed(t, "tag/v1.1"))
|
||||
})
|
||||
|
||||
t.Run("commit", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
assert.False(t, hasFileRSSFeed(t, "commit/65f1bf27bc3bf70f64657658635e66094edbcb4d"))
|
||||
})
|
||||
}
|
||||
|
||||
// TestBlameFileInRepo repo description, topics and summary should not be displayed when running blame on a file
|
||||
func TestBlameFileInRepo(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
@ -369,6 +590,36 @@ func TestViewRepoDirectoryReadme(t *testing.T) {
|
|||
missing("symlink-loop", "/user2/readme-test/src/branch/symlink-loop/")
|
||||
}
|
||||
|
||||
func TestRenamedFileHistory(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
t.Run("Renamed file", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user2/repo59/commits/branch/master/license")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
renameNotice := htmlDoc.doc.Find(".ui.bottom.attached.header")
|
||||
assert.Equal(t, 1, renameNotice.Length())
|
||||
assert.Contains(t, renameNotice.Text(), "Renamed from licnse (Browse further)")
|
||||
|
||||
oldFileHistoryLink, ok := renameNotice.Find("a").Attr("href")
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "/user2/repo59/commits/commit/80b83c5c8220c3aa3906e081f202a2a7563ec879/licnse", oldFileHistoryLink)
|
||||
})
|
||||
|
||||
t.Run("Non renamed file", func(t *testing.T) {
|
||||
req := NewRequest(t, "GET", "/user2/repo59/commits/branch/master/README.md")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
htmlDoc.AssertElement(t, ".ui.bottom.attached.header", false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMarkDownReadmeImage(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
|
@ -458,3 +709,146 @@ func TestViewCommit(t *testing.T) {
|
|||
resp := MakeRequest(t, req, http.StatusNotFound)
|
||||
assert.True(t, test.IsNormalPageCompleted(resp.Body.String()), "non-existing commit should render 404 page")
|
||||
}
|
||||
|
||||
func TestCommitView(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
t.Run("Non-existent commit", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user2/repo1/commit/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
|
||||
req.SetHeader("Accept", "text/html")
|
||||
resp := MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Really ensure that 404 is being sent back.
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
doc.AssertElement(t, `[aria-label="Page Not Found"]`, true)
|
||||
})
|
||||
|
||||
t.Run("Too short commit ID", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user2/repo1/commit/65f")
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
|
||||
t.Run("Short commit ID", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user2/repo1/commit/65f1")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
commitTitle := doc.Find(".commit-summary").Text()
|
||||
assert.Contains(t, commitTitle, "Initial commit")
|
||||
})
|
||||
|
||||
t.Run("Full commit ID", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user2/repo1/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
commitTitle := doc.Find(".commit-summary").Text()
|
||||
assert.Contains(t, commitTitle, "Initial commit")
|
||||
})
|
||||
}
|
||||
|
||||
func TestRepoHomeViewRedirect(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
t.Run("Code", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user2/repo1")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
l := doc.Find("#repo-desc").Length()
|
||||
assert.Equal(t, 1, l)
|
||||
})
|
||||
|
||||
t.Run("No Code redirects to Issues", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
// Disable the Code unit
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
err := repo_service.UpdateRepositoryUnits(db.DefaultContext, repo, nil, []unit_model.Type{
|
||||
unit_model.TypeCode,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// The repo home should redirect to the built-in issue tracker
|
||||
req := NewRequest(t, "GET", "/user2/repo1")
|
||||
resp := MakeRequest(t, req, http.StatusSeeOther)
|
||||
redir := resp.Header().Get("Location")
|
||||
|
||||
assert.Equal(t, "/user2/repo1/issues", redir)
|
||||
})
|
||||
|
||||
t.Run("No Code and ExternalTracker redirects to Pulls", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
// Replace the internal tracker with an external one
|
||||
// Disable Code, Projects, Packages, and Actions
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
err := repo_service.UpdateRepositoryUnits(db.DefaultContext, repo, []repo_model.RepoUnit{{
|
||||
RepoID: repo.ID,
|
||||
Type: unit_model.TypeExternalTracker,
|
||||
Config: &repo_model.ExternalTrackerConfig{
|
||||
ExternalTrackerURL: "https://example.com",
|
||||
},
|
||||
}}, []unit_model.Type{
|
||||
unit_model.TypeCode,
|
||||
unit_model.TypeIssues,
|
||||
unit_model.TypeProjects,
|
||||
unit_model.TypePackages,
|
||||
unit_model.TypeActions,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// The repo home should redirect to pull requests
|
||||
req := NewRequest(t, "GET", "/user2/repo1")
|
||||
resp := MakeRequest(t, req, http.StatusSeeOther)
|
||||
redir := resp.Header().Get("Location")
|
||||
|
||||
assert.Equal(t, "/user2/repo1/pulls", redir)
|
||||
})
|
||||
|
||||
t.Run("Only external wiki results in 404", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
// Replace the internal wiki with an external, and disable everything
|
||||
// else.
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
err := repo_service.UpdateRepositoryUnits(db.DefaultContext, repo, []repo_model.RepoUnit{{
|
||||
RepoID: repo.ID,
|
||||
Type: unit_model.TypeExternalWiki,
|
||||
Config: &repo_model.ExternalWikiConfig{
|
||||
ExternalWikiURL: "https://example.com",
|
||||
},
|
||||
}}, []unit_model.Type{
|
||||
unit_model.TypeCode,
|
||||
unit_model.TypeIssues,
|
||||
unit_model.TypeExternalTracker,
|
||||
unit_model.TypeProjects,
|
||||
unit_model.TypePackages,
|
||||
unit_model.TypeActions,
|
||||
unit_model.TypePullRequests,
|
||||
unit_model.TypeReleases,
|
||||
unit_model.TypeWiki,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// The repo home ends up being 404
|
||||
req := NewRequest(t, "GET", "/user2/repo1")
|
||||
req.Header.Set("Accept", "text/html")
|
||||
resp := MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// The external wiki is linked to from the 404 page
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
txt := strings.TrimSpace(doc.Find(`a[href="https://example.com"]`).Text())
|
||||
assert.Equal(t, "Wiki", txt)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2024 The Forgejo Authors c/o Codeberg e.V.. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package integration
|
||||
|
@ -8,6 +9,10 @@ import (
|
|||
"net/url"
|
||||
"testing"
|
||||
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
|
@ -45,3 +50,32 @@ func TestTopicSearch(t *testing.T) {
|
|||
assert.EqualValues(t, 1, topics.TopicNames[0].RepoCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTopicSearchPaging(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
var topics struct {
|
||||
TopicNames []*api.TopicResponse `json:"topics"`
|
||||
}
|
||||
|
||||
// Add 20 unique topics to user2/repo2, and 20 unique ones to user2/repo3
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
token2 := getUserToken(t, user2.Name, auth_model.AccessTokenScopeWriteRepository)
|
||||
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
|
||||
for i := 0; i < 20; i++ {
|
||||
req := NewRequestf(t, "PUT", "/api/v1/repos/%s/%s/topics/paging-topic-%d", user2.Name, repo2.Name, i).
|
||||
AddTokenAuth(token2)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
req = NewRequestf(t, "PUT", "/api/v1/repos/%s/%s/topics/paging-topic-%d", user2.Name, repo3.Name, i+30).
|
||||
AddTokenAuth(token2)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
}
|
||||
|
||||
res := MakeRequest(t, NewRequest(t, "GET", "/explore/topics/search"), http.StatusOK)
|
||||
DecodeJSON(t, res, &topics)
|
||||
assert.Len(t, topics.TopicNames, 30)
|
||||
|
||||
res = MakeRequest(t, NewRequest(t, "GET", "/explore/topics/search?page=2"), http.StatusOK)
|
||||
DecodeJSON(t, res, &topics)
|
||||
assert.Greater(t, len(topics.TopicNames), 0)
|
||||
}
|
||||
|
|
74
tests/integration/repo_wiki_test.go
Normal file
74
tests/integration/repo_wiki_test.go
Normal file
|
@ -0,0 +1,74 @@
|
|||
// Copyright 2024 The Forgejo Authors c/o Codeberg e.V.. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestWikiBranchNormalize(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
username := "user2"
|
||||
session := loginUser(t, username)
|
||||
settingsURLStr := "/user2/repo1/settings"
|
||||
|
||||
assertNormalizeButton := func(present bool) string {
|
||||
req := NewRequest(t, "GET", settingsURLStr) //.AddTokenAuth(token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
htmlDoc.AssertElement(t, "button[data-modal='#rename-wiki-branch-modal']", present)
|
||||
|
||||
return htmlDoc.GetCSRF()
|
||||
}
|
||||
|
||||
// By default the repo wiki branch is empty
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
assert.Empty(t, repo.WikiBranch)
|
||||
|
||||
// This means we default to setting.Repository.DefaultBranch
|
||||
assert.Equal(t, setting.Repository.DefaultBranch, repo.GetWikiBranchName())
|
||||
|
||||
// Which further means that the "Normalize wiki branch" parts do not appear on settings
|
||||
assertNormalizeButton(false)
|
||||
|
||||
// Lets rename the branch!
|
||||
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
|
||||
repoURLStr := fmt.Sprintf("/api/v1/repos/%s/%s", username, repo.Name)
|
||||
wikiBranch := "wiki"
|
||||
req := NewRequestWithJSON(t, "PATCH", repoURLStr, &api.EditRepoOption{
|
||||
WikiBranch: &wikiBranch,
|
||||
}).AddTokenAuth(token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// The wiki branch should now be changed
|
||||
repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
assert.Equal(t, wikiBranch, repo.GetWikiBranchName())
|
||||
|
||||
// And as such, the button appears!
|
||||
csrf := assertNormalizeButton(true)
|
||||
|
||||
// Invoking the normalization renames the wiki branch back to the default
|
||||
req = NewRequestWithValues(t, "POST", settingsURLStr, map[string]string{
|
||||
"_csrf": csrf,
|
||||
"action": "rename-wiki-branch",
|
||||
"repo_name": repo.FullName(),
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
||||
repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
assert.Equal(t, setting.Repository.DefaultBranch, repo.GetWikiBranchName())
|
||||
assertNormalizeButton(false)
|
||||
}
|
|
@ -12,6 +12,7 @@ import (
|
|||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
|
@ -91,3 +92,78 @@ func TestSignupEmail(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignupEmailChangeForInactiveUser(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
// Disable the captcha & enable email confirmation for registrations
|
||||
defer test.MockVariableValue(&setting.Service.EnableCaptcha, false)()
|
||||
defer test.MockVariableValue(&setting.Service.RegisterEmailConfirm, true)()
|
||||
|
||||
// Create user
|
||||
req := NewRequestWithValues(t, "POST", "/user/sign_up", map[string]string{
|
||||
"user_name": "exampleUserX",
|
||||
"email": "wrong-email@example.com",
|
||||
"password": "examplePassword!1",
|
||||
"retype": "examplePassword!1",
|
||||
})
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
session := loginUserWithPassword(t, "exampleUserX", "examplePassword!1")
|
||||
|
||||
// Verify that the initial e-mail is the wrong one.
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "exampleUserX"})
|
||||
assert.Equal(t, "wrong-email@example.com", user.Email)
|
||||
|
||||
// Change the email address
|
||||
req = NewRequestWithValues(t, "POST", "/user/activate", map[string]string{
|
||||
"email": "fine-email@example.com",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
||||
// Verify that the email was updated
|
||||
user = unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "exampleUserX"})
|
||||
assert.Equal(t, "fine-email@example.com", user.Email)
|
||||
|
||||
// Try to change the email again
|
||||
req = NewRequestWithValues(t, "POST", "/user/activate", map[string]string{
|
||||
"email": "wrong-again@example.com",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
// Verify that the email was NOT updated
|
||||
user = unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "exampleUserX"})
|
||||
assert.Equal(t, "fine-email@example.com", user.Email)
|
||||
}
|
||||
|
||||
func TestSignupEmailChangeForActiveUser(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
// Disable the captcha & enable email confirmation for registrations
|
||||
defer test.MockVariableValue(&setting.Service.EnableCaptcha, false)()
|
||||
defer test.MockVariableValue(&setting.Service.RegisterEmailConfirm, false)()
|
||||
|
||||
// Create user
|
||||
req := NewRequestWithValues(t, "POST", "/user/sign_up", map[string]string{
|
||||
"user_name": "exampleUserY",
|
||||
"email": "wrong-email-2@example.com",
|
||||
"password": "examplePassword!1",
|
||||
"retype": "examplePassword!1",
|
||||
})
|
||||
MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
||||
session := loginUserWithPassword(t, "exampleUserY", "examplePassword!1")
|
||||
|
||||
// Verify that the initial e-mail is the wrong one.
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "exampleUserY"})
|
||||
assert.Equal(t, "wrong-email-2@example.com", user.Email)
|
||||
|
||||
// Changing the email for a validated address is not available
|
||||
req = NewRequestWithValues(t, "POST", "/user/activate", map[string]string{
|
||||
"email": "fine-email-2@example.com",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Verify that the email remained unchanged
|
||||
user = unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "exampleUserY"})
|
||||
assert.Equal(t, "wrong-email-2@example.com", user.Email)
|
||||
}
|
||||
|
|
67
tests/integration/user_profile_test.go
Normal file
67
tests/integration/user_profile_test.go
Normal file
|
@ -0,0 +1,67 @@
|
|||
// Copyright 2024 The Forgejo Authors c/o Codeberg e.V.. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
files_service "code.gitea.io/gitea/services/repository/files"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUserProfile(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
checkReadme := func(t *testing.T, title, readmeFilename string, expectedCount int) {
|
||||
t.Run(title, func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
// Prepare the test repository
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
var ops []*files_service.ChangeRepoFile
|
||||
op := "create"
|
||||
if readmeFilename != "README.md" {
|
||||
ops = append(ops, &files_service.ChangeRepoFile{
|
||||
Operation: "delete",
|
||||
TreePath: "README.md",
|
||||
})
|
||||
} else {
|
||||
op = "update"
|
||||
}
|
||||
if readmeFilename != "" {
|
||||
ops = append(ops, &files_service.ChangeRepoFile{
|
||||
Operation: op,
|
||||
TreePath: readmeFilename,
|
||||
ContentReader: strings.NewReader("# Hi!\n"),
|
||||
})
|
||||
}
|
||||
|
||||
_, _, f := CreateDeclarativeRepo(t, user2, ".profile", nil, nil, ops)
|
||||
defer f()
|
||||
|
||||
// Perform the test
|
||||
req := NewRequest(t, "GET", "/user2")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
readmeCount := doc.Find("#readme_profile").Length()
|
||||
|
||||
assert.Equal(t, expectedCount, readmeCount)
|
||||
})
|
||||
}
|
||||
|
||||
checkReadme(t, "No readme", "", 0)
|
||||
checkReadme(t, "README.md", "README.md", 1)
|
||||
checkReadme(t, "readme.md", "readme.md", 1)
|
||||
checkReadme(t, "ReadMe.mD", "ReadMe.mD", 1)
|
||||
checkReadme(t, "readme.org does not render", "README.org", 0)
|
||||
})
|
||||
}
|
|
@ -243,16 +243,25 @@ func testExportUserGPGKeys(t *testing.T, user, expected string) {
|
|||
}
|
||||
|
||||
func TestGetUserRss(t *testing.T) {
|
||||
user34 := "the_34-user.with.all.allowedChars"
|
||||
req := NewRequestf(t, "GET", "/%s.rss", user34)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
if assert.EqualValues(t, "application/rss+xml;charset=utf-8", resp.Header().Get("Content-Type")) {
|
||||
rssDoc := NewHTMLParser(t, resp.Body).Find("channel")
|
||||
title, _ := rssDoc.ChildrenFiltered("title").Html()
|
||||
assert.EqualValues(t, "Feed of "the_1-user.with.all.allowedChars"", title)
|
||||
description, _ := rssDoc.ChildrenFiltered("description").Html()
|
||||
assert.EqualValues(t, "<p dir="auto">some <a href="https://commonmark.org/" rel="nofollow">commonmark</a>!</p>\n", description)
|
||||
}
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
t.Run("Normal", func(t *testing.T) {
|
||||
user34 := "the_34-user.with.all.allowedChars"
|
||||
req := NewRequestf(t, "GET", "/%s.rss", user34)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
if assert.EqualValues(t, "application/rss+xml;charset=utf-8", resp.Header().Get("Content-Type")) {
|
||||
rssDoc := NewHTMLParser(t, resp.Body).Find("channel")
|
||||
title, _ := rssDoc.ChildrenFiltered("title").Html()
|
||||
assert.EqualValues(t, "Feed of "the_1-user.with.all.allowedChars"", title)
|
||||
description, _ := rssDoc.ChildrenFiltered("description").Html()
|
||||
assert.EqualValues(t, "<p dir="auto">some <a href="https://commonmark.org/" rel="nofollow">commonmark</a>!</p>\n", description)
|
||||
}
|
||||
})
|
||||
t.Run("Non-existent user", func(t *testing.T) {
|
||||
session := loginUser(t, "user2")
|
||||
req := NewRequestf(t, "GET", "/non-existent-user.rss")
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
}
|
||||
|
||||
func TestListStopWatches(t *testing.T) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue