This commit is contained in:
@@ -12,15 +12,16 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
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/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
"code.gitea.io/gitea/tests"
|
||||
auth_model "gitea.dev/models/auth"
|
||||
"gitea.dev/models/db"
|
||||
issues_model "gitea.dev/models/issues"
|
||||
repo_model "gitea.dev/models/repo"
|
||||
"gitea.dev/models/unittest"
|
||||
user_model "gitea.dev/models/user"
|
||||
"gitea.dev/modules/setting"
|
||||
api "gitea.dev/modules/structs"
|
||||
"gitea.dev/modules/test"
|
||||
"gitea.dev/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -35,6 +36,8 @@ func TestAPIIssue(t *testing.T) {
|
||||
t.Run("IssueContentVersion", testAPIIssueContentVersion)
|
||||
t.Run("CreateIssue", testAPICreateIssue)
|
||||
t.Run("CreateIssueParallel", testAPICreateIssueParallel)
|
||||
t.Run("IssueAssignees", testAPIIssueAssignees)
|
||||
t.Run("IssueProjects", testAPIIssueProjects)
|
||||
}
|
||||
|
||||
func testAPIListIssues(t *testing.T) {
|
||||
@@ -47,8 +50,7 @@ func testAPIListIssues(t *testing.T) {
|
||||
|
||||
link.RawQuery = url.Values{"token": {token}, "state": {"all"}}.Encode()
|
||||
resp := MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||
var apiIssues []*api.Issue
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues := DecodeJSON(t, resp, []*api.Issue{})
|
||||
assert.Len(t, apiIssues, unittest.GetCount(t, &issues_model.Issue{RepoID: repo.ID}))
|
||||
for _, apiIssue := range apiIssues {
|
||||
unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: apiIssue.ID, RepoID: repo.ID})
|
||||
@@ -57,7 +59,7 @@ func testAPIListIssues(t *testing.T) {
|
||||
// test milestone filter
|
||||
link.RawQuery = url.Values{"token": {token}, "state": {"all"}, "type": {"all"}, "milestones": {"ignore,milestone1,3,4"}}.Encode()
|
||||
resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
if assert.Len(t, apiIssues, 2) {
|
||||
assert.EqualValues(t, 3, apiIssues[0].Milestone.ID)
|
||||
assert.EqualValues(t, 1, apiIssues[1].Milestone.ID)
|
||||
@@ -65,21 +67,21 @@ func testAPIListIssues(t *testing.T) {
|
||||
|
||||
link.RawQuery = url.Values{"token": {token}, "state": {"all"}, "created_by": {"user2"}}.Encode()
|
||||
resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
if assert.Len(t, apiIssues, 1) {
|
||||
assert.EqualValues(t, 5, apiIssues[0].ID)
|
||||
}
|
||||
|
||||
link.RawQuery = url.Values{"token": {token}, "state": {"all"}, "assigned_by": {"user1"}}.Encode()
|
||||
resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
if assert.Len(t, apiIssues, 1) {
|
||||
assert.EqualValues(t, 1, apiIssues[0].ID)
|
||||
}
|
||||
|
||||
link.RawQuery = url.Values{"token": {token}, "state": {"all"}, "mentioned_by": {"user4"}}.Encode()
|
||||
resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
if assert.Len(t, apiIssues, 1) {
|
||||
assert.EqualValues(t, 1, apiIssues[0].ID)
|
||||
}
|
||||
@@ -126,8 +128,7 @@ func testAPICreateIssue(t *testing.T) {
|
||||
Assignee: owner.Name,
|
||||
}).AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
var apiIssue api.Issue
|
||||
DecodeJSON(t, resp, &apiIssue)
|
||||
apiIssue := DecodeJSON(t, resp, &api.Issue{})
|
||||
assert.Equal(t, body, apiIssue.Body)
|
||||
assert.Equal(t, title, apiIssue.Title)
|
||||
|
||||
@@ -150,16 +151,16 @@ func testAPICreateIssue(t *testing.T) {
|
||||
}
|
||||
|
||||
func testAPICreateIssueParallel(t *testing.T) {
|
||||
// FIXME: There seems to be a bug in github.com/mattn/go-sqlite3 with sqlite_unlock_notify, when doing concurrent writes to the same database,
|
||||
// HINT: There seems to be a bug in github.com/mattn/go-sqlite3 with sqlite_unlock_notify, when doing concurrent writes to the same database,
|
||||
// some requests may get stuck in "go-sqlite3.(*SQLiteRows).Next", "go-sqlite3.(*SQLiteStmt).exec" and "go-sqlite3.unlock_notify_wait",
|
||||
// because the "unlock_notify_wait" never returns and the internal lock never gets releases.
|
||||
// because the "unlock_notify_wait" never returns and the internal lock never gets released.
|
||||
//
|
||||
// The trigger is: a previous test created issues and made the real issue indexer queue start processing, then this test does concurrent writing.
|
||||
// Adding this "Sleep" makes go-sqlite3 "finish" some internal operations before concurrent writes and then won't get stuck.
|
||||
// To reproduce: make a new test run these 2 tests enough times:
|
||||
// > func testBug() { for i := 0; i < 100; i++ { testAPICreateIssue(t); testAPICreateIssueParallel(t) } }
|
||||
// Usually the test gets stuck in fewer than 10 iterations without this "sleep".
|
||||
time.Sleep(time.Second)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
const body, title = "apiTestBody", "apiTestTitle"
|
||||
|
||||
@@ -172,9 +173,8 @@ func testAPICreateIssueParallel(t *testing.T) {
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for i := range 10 {
|
||||
wg.Add(1)
|
||||
go func(parentT *testing.T, i int) {
|
||||
parentT.Run(fmt.Sprintf("ParallelCreateIssue_%d", i), func(t *testing.T) {
|
||||
wg.Go(func() {
|
||||
t.Run(fmt.Sprintf("ParallelCreateIssue_%d", i), func(t *testing.T) {
|
||||
newTitle := title + strconv.Itoa(i)
|
||||
newBody := body + strconv.Itoa(i)
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateIssueOption{
|
||||
@@ -183,8 +183,7 @@ func testAPICreateIssueParallel(t *testing.T) {
|
||||
Assignee: owner.Name,
|
||||
}).AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
var apiIssue api.Issue
|
||||
DecodeJSON(t, resp, &apiIssue)
|
||||
apiIssue := DecodeJSON(t, resp, &api.Issue{})
|
||||
assert.Equal(t, newBody, apiIssue.Body)
|
||||
assert.Equal(t, newTitle, apiIssue.Title)
|
||||
|
||||
@@ -194,10 +193,8 @@ func testAPICreateIssueParallel(t *testing.T) {
|
||||
Content: newBody,
|
||||
Title: newTitle,
|
||||
})
|
||||
|
||||
wg.Done()
|
||||
})
|
||||
}(t, i)
|
||||
})
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
@@ -231,8 +228,7 @@ func testAPIEditIssue(t *testing.T) {
|
||||
// ToDo change more
|
||||
}).AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
var apiIssue api.Issue
|
||||
DecodeJSON(t, resp, &apiIssue)
|
||||
apiIssue := DecodeJSON(t, resp, &api.Issue{})
|
||||
|
||||
issueAfter := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10})
|
||||
repoAfter := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID})
|
||||
@@ -278,13 +274,13 @@ func testAPISearchIssues(t *testing.T) {
|
||||
link.RawQuery = query.Encode()
|
||||
req := NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
assert.Len(t, apiIssues, expectedIssueCount)
|
||||
|
||||
publicOnlyToken := getUserToken(t, "user1", auth_model.AccessTokenScopeReadIssue, auth_model.AccessTokenScopePublicOnly)
|
||||
req = NewRequest(t, "GET", link.String()).AddTokenAuth(publicOnlyToken)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
assert.Len(t, apiIssues, 15) // 15 public issues
|
||||
|
||||
since := "2000-01-01T00:50:01+00:00" // 946687801
|
||||
@@ -294,7 +290,7 @@ func testAPISearchIssues(t *testing.T) {
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
assert.Len(t, apiIssues, 11)
|
||||
query.Del("since")
|
||||
query.Del("before")
|
||||
@@ -303,14 +299,14 @@ func testAPISearchIssues(t *testing.T) {
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
query.Set("state", "all")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
assert.Equal(t, "22", resp.Header().Get("X-Total-Count"))
|
||||
assert.Len(t, apiIssues, 20)
|
||||
|
||||
@@ -318,7 +314,7 @@ func testAPISearchIssues(t *testing.T) {
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
assert.Equal(t, "22", resp.Header().Get("X-Total-Count"))
|
||||
assert.Len(t, apiIssues, 10)
|
||||
|
||||
@@ -326,70 +322,70 @@ func testAPISearchIssues(t *testing.T) {
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
query = url.Values{"milestones": {"milestone1"}, "state": {"all"}}
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
assert.Len(t, apiIssues, 1)
|
||||
|
||||
query = url.Values{"milestones": {"milestone1,milestone3"}, "state": {"all"}}
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
query = url.Values{"owner": {"user2"}} // user
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
assert.Len(t, apiIssues, 8)
|
||||
|
||||
query = url.Values{"owner": {"org3"}} // organization
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
assert.Len(t, apiIssues, 5)
|
||||
|
||||
query = url.Values{"owner": {"org3"}, "team": {"team1"}} // organization + team
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
query = url.Values{"created": {"1"}} // issues created by the auth user
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
assert.Len(t, apiIssues, 5)
|
||||
|
||||
query = url.Values{"created": {"1"}, "type": {"pulls"}} // prs created by the auth user
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
assert.Len(t, apiIssues, 3)
|
||||
|
||||
query = url.Values{"created_by": {"user2"}} // issues created by the user2
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
assert.Len(t, apiIssues, 9)
|
||||
|
||||
query = url.Values{"created_by": {"user2"}, "type": {"pulls"}} // prs created by user2
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
assert.Len(t, apiIssues, 3)
|
||||
}
|
||||
|
||||
@@ -405,14 +401,14 @@ func testAPISearchIssuesWithLabels(t *testing.T) {
|
||||
link.RawQuery = query.Encode()
|
||||
req := NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
assert.Len(t, apiIssues, expectedIssueCount)
|
||||
|
||||
query.Add("labels", "label1")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
// multiple labels
|
||||
@@ -420,7 +416,7 @@ func testAPISearchIssuesWithLabels(t *testing.T) {
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
// an org label
|
||||
@@ -428,7 +424,7 @@ func testAPISearchIssuesWithLabels(t *testing.T) {
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
assert.Len(t, apiIssues, 1)
|
||||
|
||||
// org and repo label
|
||||
@@ -437,7 +433,7 @@ func testAPISearchIssuesWithLabels(t *testing.T) {
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
// org and repo label which share the same issue
|
||||
@@ -445,7 +441,7 @@ func testAPISearchIssuesWithLabels(t *testing.T) {
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
apiIssues = DecodeJSON(t, resp, []*api.Issue{})
|
||||
assert.Len(t, apiIssues, 2)
|
||||
}
|
||||
|
||||
@@ -500,3 +496,150 @@ func testAPIIssueContentVersion(t *testing.T) {
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
})
|
||||
}
|
||||
|
||||
func testAPIIssueAssignees(t *testing.T) {
|
||||
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
|
||||
session := loginUser(t, owner.Name)
|
||||
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteIssue)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/assignees", owner.Name, repo.Name, issue.Index)
|
||||
getAssigneeIDs := func(issueID int64) []int64 {
|
||||
assigneeIDs, err := issues_model.GetAssigneeIDsByIssue(t.Context(), issueID)
|
||||
assert.NoError(t, err)
|
||||
return assigneeIDs
|
||||
}
|
||||
|
||||
t.Run("NonWriter", func(t *testing.T) {
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.IssueAssigneesOption{Assignees: []string{"user40"}}).
|
||||
AddTokenAuth(getUserToken(t, "user5", auth_model.AccessTokenScopeWriteIssue))
|
||||
MakeRequest(t, req, http.StatusForbidden)
|
||||
})
|
||||
|
||||
t.Run("MissingIssue", func(t *testing.T) {
|
||||
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/issues/99999/assignees", owner.Name, repo.Name), &api.IssueAssigneesOption{Assignees: []string{"user40"}}).
|
||||
AddTokenAuth(token)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
|
||||
t.Run("UnknownAssignee", func(t *testing.T) {
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.IssueAssigneesOption{Assignees: []string{"does-not-exist"}}).
|
||||
AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
apiErr := DecodeJSON(t, resp, &api.APIError{})
|
||||
assert.Equal(t, "user does not exist [uid: 0, name: does-not-exist]", apiErr.Message)
|
||||
})
|
||||
|
||||
t.Run("OrganizationAssignee", func(t *testing.T) {
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.IssueAssigneesOption{Assignees: []string{"org3"}}).
|
||||
AddTokenAuth(token)
|
||||
MakeRequest(t, req, http.StatusBadRequest)
|
||||
|
||||
checkReq := NewRequest(t, "GET", fmt.Sprintf("%s/%s", urlStr, "org3")).AddTokenAuth(token)
|
||||
MakeRequest(t, checkReq, http.StatusBadRequest)
|
||||
})
|
||||
|
||||
t.Run("BlockedAssigneeIsAtomic", func(t *testing.T) {
|
||||
blockedIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 5})
|
||||
blockedURL := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/assignees", owner.Name, repo.Name, blockedIssue.Index)
|
||||
blockedToken := getUserToken(t, "user40", auth_model.AccessTokenScopeWriteIssue)
|
||||
|
||||
assert.Empty(t, getAssigneeIDs(blockedIssue.ID))
|
||||
assert.NoError(t, db.Insert(t.Context(), &user_model.Blocking{
|
||||
BlockerID: owner.ID,
|
||||
BlockeeID: 40,
|
||||
}))
|
||||
|
||||
req := NewRequestWithJSON(t, "POST", blockedURL, &api.IssueAssigneesOption{Assignees: []string{"user1", "user2"}}).
|
||||
AddTokenAuth(blockedToken)
|
||||
MakeRequest(t, req, http.StatusForbidden)
|
||||
assert.Empty(t, getAssigneeIDs(blockedIssue.ID))
|
||||
})
|
||||
|
||||
t.Run("HappyPath", func(t *testing.T) {
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.IssueAssigneesOption{Assignees: []string{"user40"}}).
|
||||
AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
apiIssue := DecodeJSON(t, resp, &api.Issue{})
|
||||
assert.Len(t, apiIssue.Assignees, 2)
|
||||
assert.ElementsMatch(t, []int64{1, 40}, []int64{apiIssue.Assignees[0].ID, apiIssue.Assignees[1].ID})
|
||||
|
||||
checkReq := NewRequest(t, "GET", fmt.Sprintf("%s/%s", urlStr, "user40")).AddTokenAuth(token)
|
||||
MakeRequest(t, checkReq, http.StatusNoContent)
|
||||
|
||||
// This endpoint checks assignability, not current assignment membership.
|
||||
checkReq = NewRequest(t, "GET", fmt.Sprintf("%s/%s", urlStr, "user5")).AddTokenAuth(token)
|
||||
MakeRequest(t, checkReq, http.StatusNoContent)
|
||||
|
||||
req = NewRequestWithJSON(t, "DELETE", urlStr, &api.IssueAssigneesOption{Assignees: []string{"user1"}}).
|
||||
AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
apiIssue = DecodeJSON(t, resp, &api.Issue{})
|
||||
assert.Len(t, apiIssue.Assignees, 1)
|
||||
assert.Equal(t, int64(40), apiIssue.Assignees[0].ID)
|
||||
})
|
||||
}
|
||||
|
||||
func testAPIIssueProjects(t *testing.T) {
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
|
||||
session := loginUser(t, owner.Name)
|
||||
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteIssue)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues", owner.Name, repo.Name)
|
||||
|
||||
// Create issue with a project
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateIssueOption{
|
||||
Title: "issue with project",
|
||||
Body: "test body",
|
||||
Projects: []int64{1},
|
||||
}).AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
apiIssue := DecodeJSON(t, resp, &api.Issue{})
|
||||
assert.Len(t, apiIssue.Projects, 1)
|
||||
assert.EqualValues(t, 1, apiIssue.Projects[0].ID)
|
||||
|
||||
// Get issue should include projects
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/%d", urlStr, apiIssue.Index)).AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
apiIssue = DecodeJSON(t, resp, &api.Issue{})
|
||||
assert.Len(t, apiIssue.Projects, 1)
|
||||
assert.EqualValues(t, 1, apiIssue.Projects[0].ID)
|
||||
|
||||
// Edit issue to remove projects
|
||||
emptyProjects := []int64{}
|
||||
req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("%s/%d", urlStr, apiIssue.Index), &api.EditIssueOption{
|
||||
Projects: &emptyProjects,
|
||||
}).AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusCreated)
|
||||
apiIssue = DecodeJSON(t, resp, &api.Issue{})
|
||||
assert.Empty(t, apiIssue.Projects)
|
||||
|
||||
// Edit issue to add project back
|
||||
projects := []int64{1}
|
||||
req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("%s/%d", urlStr, apiIssue.Index), &api.EditIssueOption{
|
||||
Projects: &projects,
|
||||
}).AddTokenAuth(token)
|
||||
resp = MakeRequest(t, req, http.StatusCreated)
|
||||
apiIssue = DecodeJSON(t, resp, &api.Issue{})
|
||||
assert.Len(t, apiIssue.Projects, 1)
|
||||
assert.EqualValues(t, 1, apiIssue.Projects[0].ID)
|
||||
|
||||
// Test invalid project ID
|
||||
req = NewRequestWithJSON(t, "POST", urlStr, &api.CreateIssueOption{
|
||||
Title: "issue with invalid project",
|
||||
Body: "test body",
|
||||
Projects: []int64{99999},
|
||||
}).AddTokenAuth(token)
|
||||
MakeRequest(t, req, http.StatusBadRequest)
|
||||
|
||||
// Test project from different repo (project 2 is for repo 3)
|
||||
req = NewRequestWithJSON(t, "POST", urlStr, &api.CreateIssueOption{
|
||||
Title: "issue with inaccessible project",
|
||||
Body: "test body",
|
||||
Projects: []int64{2},
|
||||
}).AddTokenAuth(token)
|
||||
MakeRequest(t, req, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user