1
1
mirror of https://github.com/go-gitea/gitea synced 2025-01-21 15:14:26 +00:00

tests(api): create tests for project and column handlers

This commit is contained in:
eyad-hussein 2024-09-20 11:24:17 +03:00
parent a825ba005d
commit cc57d51768
12 changed files with 965 additions and 13 deletions

View File

@ -69,3 +69,47 @@
type: 2
created_unix: 1688973000
updated_unix: 1688973000
- id: 7
title: project in archived repository
owner_id: 0
repo_id: 51
is_closed: false
creator_id: 30
board_type: 1
type: 2
created_unix: 1688973000
updated_unix: 1688973000
- id: 8
title: project1 belongs to org3
owner_id: 3
repo_id: 0
is_closed: true
creator_id: 3
board_type: 1
type: 2
created_unix: 1688973000
updated_unix: 1688973000
- id: 9
title: project2 belongs to org3
owner_id: 3
repo_id: 0
is_closed: false
creator_id: 3
board_type: 1
type: 2
created_unix: 1688973000
updated_unix: 1688973000
- id: 10
title: project2 on repo1
owner_id: 0
repo_id: 1
is_closed: false
creator_id: 2
board_type: 1
type: 2
created_unix: 1688973010
updated_unix: 1688973010

View File

@ -21,3 +21,9 @@
issue_id: 5
project_id: 1
project_board_id: 3
-
id: 5
issue_id: 5
project_id: 1
project_board_id: 1

View File

@ -47,8 +47,6 @@ func CreateProject(ctx *context.APIContext) {
// "$ref": "#/responses/error"
// "422":
// "$ref": "#/responses/validationError"
// "423":
// "$ref": "#/responses/repoArchivedError"
form := web.GetForm(ctx).(*api.CreateProjectOption)
@ -98,8 +96,6 @@ func GetProjects(ctx *context.APIContext) {
// "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/notFound"
// "423":
// "$ref": "#/responses/repoArchivedError"
listOptions := utils.GetListOptions(ctx)
sortType := ctx.FormTrim("sort")

View File

@ -49,7 +49,7 @@ func GetProject(ctx *context.APIContext) {
return
}
issuesMap, err := issues_model.LoadIssuesFromColumnList(ctx, columns)
issuesMap, err := issues_model.LoadIssuesFromColumnList(ctx, columns, &issues_model.IssuesOptions{})
if err != nil {
ctx.ServerError("LoadIssuesOfColumns", err)
return

View File

@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/convert"
project_service "code.gitea.io/gitea/services/projects"
)
// GetProjectColumn returns a project column
@ -416,7 +417,7 @@ func MoveIssues(ctx *context.APIContext) {
}
}
if err = project_model.MoveIssuesOnProjectColumn(ctx, column, sortedIssueIDs); err != nil {
if err = project_service.MoveIssuesOnProjectColumn(ctx, ctx.Doer, column, sortedIssueIDs); err != nil {
ctx.ServerError("MoveIssuesOnProjectColumn", err)
return
}

View File

@ -143,11 +143,11 @@ func CreateProject(ctx *context.APIContext) {
ctx.JSON(http.StatusCreated, convert.ToProject(ctx, project))
}
// UpdateIssueProject change an issue's project to another project in a repository
// UpdateIssueProject moves issues from a project to another in a repository
func UpdateIssueProject(ctx *context.APIContext) {
// swagger:operation PUT /repos/{owner}/{reponame}/projects/{type} project repoUpdateIssueProject
// ---
// summary: Change an issue's project
// summary: Moves issues from a project to another in a repository
// consumes:
// - application/json
// parameters:
@ -202,7 +202,7 @@ func UpdateIssueProject(ctx *context.APIContext) {
return
}
if _, err := issues.LoadRepositories(ctx); err != nil {
ctx.ServerError("LoadProjects", err)
ctx.ServerError("LoadRepositories", err)
return
}

View File

@ -42,8 +42,6 @@ func CreateProject(ctx *context.APIContext) {
// "$ref": "#/responses/error"
// "422":
// "$ref": "#/responses/validationError"
// "423":
// "$ref": "#/responses/repoArchivedError"
form := web.GetForm(ctx).(*api.CreateProjectOption)
@ -93,8 +91,6 @@ func GetProjects(ctx *context.APIContext) {
// "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/notFound"
// "423":
// "$ref": "#/responses/repoArchivedError"
listOptions := utils.GetListOptions(ctx)
sortType := ctx.FormTrim("sort")

View File

@ -0,0 +1,185 @@
// Copyright 2017 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package integration
import (
"fmt"
"net/http"
"testing"
auth_model "code.gitea.io/gitea/models/auth"
"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"
"github.com/stretchr/testify/assert"
)
func TestAPICreateOrgProject(t *testing.T) {
createOrgProjectSuccessTestCases := []struct {
testName string
orgName string
ctxUserID int64
doerID int64
title string
content string
templateType uint8
cardType uint8
}{
{
testName: "site admin create project successfully",
ctxUserID: 3,
doerID: 1,
title: "site-admin",
content: "project_description",
templateType: 1,
cardType: 2,
},
{
testName: "org owner create project successfully",
ctxUserID: 3,
doerID: 2,
title: "org-owner",
content: "project_description",
templateType: 1,
cardType: 2,
},
{
testName: "member create project successfully with write access",
ctxUserID: 3,
doerID: 4,
title: "member-with-write-access",
content: "project_description",
templateType: 1,
cardType: 2,
},
}
createOrgProjectFailTestCases := []struct {
testName string
orgName string
ctxUserID int64
doerID int64
title string
expectedStatus int
}{
{
testName: "user is not in organization",
orgName: "org3",
ctxUserID: 3,
doerID: 5,
title: "user-not-in-org",
expectedStatus: http.StatusForbidden,
},
{
testName: "user is member but not sufficient access",
orgName: "org17",
ctxUserID: 17,
doerID: 20,
title: "member-not-sufficient-access",
expectedStatus: http.StatusForbidden,
},
{
testName: "project not created as title is empty",
orgName: "org3",
ctxUserID: 3,
doerID: 2,
title: "",
expectedStatus: http.StatusUnprocessableEntity,
},
{
testName: "project not created as title is too long",
orgName: "org3",
ctxUserID: 3,
doerID: 2,
title: "This is a very long title that will exceed the maximum allowed size of 100 characters. It keeps going beyond the limit.",
expectedStatus: http.StatusUnprocessableEntity,
},
}
defer tests.PrepareTestEnv(t)()
for _, tt := range createOrgProjectFailTestCases {
t.Run(tt.testName, func(t *testing.T) {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: tt.doerID})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeWriteOrganization)
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/orgs/%s/projects", tt.orgName), &api.CreateProjectOption{
Title: tt.title,
}).AddTokenAuth(token)
MakeRequest(t, req, tt.expectedStatus)
})
}
for _, tt := range createOrgProjectSuccessTestCases {
t.Run(tt.testName, func(t *testing.T) {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: tt.doerID})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeWriteOrganization)
req := NewRequestWithJSON(t, "POST", "/api/v1/orgs/org3/projects", &api.CreateProjectOption{
Title: tt.title,
Content: tt.content,
TemplateType: tt.templateType,
CardType: tt.cardType,
}).AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusCreated)
var apiProject api.Project
DecodeJSON(t, resp, &apiProject)
assert.Equal(t, tt.title, apiProject.Title)
assert.Equal(t, tt.content, apiProject.Description)
assert.Equal(t, tt.templateType, apiProject.TemplateType)
assert.Equal(t, tt.cardType, apiProject.CardType)
assert.Equal(t, tt.ctxUserID, apiProject.OwnerID)
assert.Equal(t, tt.doerID, apiProject.CreatorID)
})
}
}
func TestAPIGetOrgProjects(t *testing.T) {
defer tests.PrepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadAdmin, auth_model.AccessTokenScopeReadOrganization)
expectedProjects := []*api.Project{
{
Title: "project1 belongs to org3",
OwnerID: 3,
IsClosed: true,
CreatorID: 3,
TemplateType: 1,
CardType: 2,
},
{
Title: "project2 belongs to org3",
OwnerID: 3,
IsClosed: false,
CreatorID: 3,
TemplateType: 1,
CardType: 2,
},
}
t.Run("failed to get projects org not found", func(t *testing.T) {
req := NewRequest(t, "GET", "/api/v1/orgs/org90/projects").AddTokenAuth(token)
MakeRequest(t, req, http.StatusNotFound)
})
t.Run("get projects successfully", func(t *testing.T) {
req := NewRequest(t, "GET", "/api/v1/orgs/org3/projects").AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusOK)
var apiProjects []*api.Project
DecodeJSON(t, resp, &apiProjects)
assert.Equal(t, len(expectedProjects), len(apiProjects))
for i, expectedProject := range expectedProjects {
assert.Equal(t, expectedProject.Title, apiProjects[i].Title)
assert.Equal(t, expectedProject.OwnerID, apiProjects[i].OwnerID)
assert.Equal(t, expectedProject.IsClosed, apiProjects[i].IsClosed)
assert.Equal(t, expectedProject.CreatorID, apiProjects[i].CreatorID)
assert.Equal(t, expectedProject.TemplateType, apiProjects[i].TemplateType)
assert.Equal(t, expectedProject.CardType, apiProjects[i].CardType)
}
})
}

View File

@ -0,0 +1,209 @@
// Copyright 2017 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package integration
import (
"fmt"
"net/http"
"testing"
auth_model "code.gitea.io/gitea/models/auth"
"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"
"github.com/stretchr/testify/assert"
)
func TestAPIGetProjectColumn(t *testing.T) {
expectedColumn := &api.Column{
ID: 1,
Title: "To Do",
}
defer tests.PrepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadAdmin, auth_model.AccessTokenScopeReadRepository, auth_model.AccessTokenScopeReadUser, auth_model.AccessTokenScopeReadOrganization)
t.Run("get column not found", func(t *testing.T) {
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/projects/columns/20")).AddTokenAuth(token)
MakeRequest(t, req, http.StatusNotFound)
})
t.Run("get column successfully", func(t *testing.T) {
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/projects/columns/1")).AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusOK)
var apiColumn *api.Column
DecodeJSON(t, resp, &apiColumn)
assert.Equal(t, expectedColumn.ID, apiColumn.ID)
assert.Equal(t, expectedColumn.Title, apiColumn.Title)
})
}
func TestAPIGetProjectColumns(t *testing.T) {
defer tests.PrepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadAdmin, auth_model.AccessTokenScopeReadRepository, auth_model.AccessTokenScopeReadUser, auth_model.AccessTokenScopeReadOrganization)
expectedColumns := []*api.Column{
{
ID: 1,
Title: "To Do",
},
{
ID: 2,
Title: "In Progress",
},
{
ID: 3,
Title: "Done",
},
}
t.Run("failed to get columns project not found", func(t *testing.T) {
req := NewRequest(t, "GET", "/api/v1/projects/70/columns").AddTokenAuth(token)
MakeRequest(t, req, http.StatusNotFound)
})
t.Run("get columns successfully", func(t *testing.T) {
req := NewRequest(t, "GET", "/api/v1/projects/1/columns").AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusOK)
var apiColumns []*api.Column
DecodeJSON(t, resp, &apiColumns)
assert.Equal(t, len(expectedColumns), len(apiColumns))
for i, expectedColumn := range expectedColumns {
assert.Equal(t, expectedColumn.ID, apiColumns[i].ID)
assert.Equal(t, expectedColumn.Title, apiColumns[i].Title)
}
})
}
func TestAPIAddColumnToProject(t *testing.T) {
defer tests.PrepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser, auth_model.AccessTokenScopeWriteOrganization)
t.Run("add column to project successfully", func(t *testing.T) {
req := NewRequestWithJSON(t, "POST", "/api/v1/projects/1/columns", &api.CreateProjectColumnOption{
Title: "New Column",
}).AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusCreated)
var apiColumn *api.Column
DecodeJSON(t, resp, &apiColumn)
assert.Equal(t, "New Column", apiColumn.Title)
})
}
func TestAPIEditProjectColumn(t *testing.T) {
defer tests.PrepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser, auth_model.AccessTokenScopeWriteOrganization)
t.Run("edit column successfully", func(t *testing.T) {
req := NewRequestWithJSON(t, "PATCH", "/api/v1/projects/columns/1", &api.EditProjectColumnOption{
Title: "Updated Column",
}).AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusOK)
var apiColumn *api.Column
DecodeJSON(t, resp, &apiColumn)
assert.Equal(t, "Updated Column", apiColumn.Title)
})
}
func TestAPIDeleteProjectColumn(t *testing.T) {
defer tests.PrepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser, auth_model.AccessTokenScopeWriteOrganization)
t.Run("delete column successfully", func(t *testing.T) {
req := NewRequest(t, "DELETE", "/api/v1/projects/columns/2").AddTokenAuth(token)
MakeRequest(t, req, http.StatusNoContent)
})
}
func TestAPISetDefaultProjectColumn(t *testing.T) {
defer tests.PrepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser, auth_model.AccessTokenScopeWriteOrganization)
t.Run("set default column successfully", func(t *testing.T) {
req := NewRequestWithJSON(t, "PUT", "/api/v1/projects/columns/2/default", nil).AddTokenAuth(token)
MakeRequest(t, req, http.StatusNoContent)
})
}
func TestAPIMoveColumns(t *testing.T) {
defer tests.PrepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser, auth_model.AccessTokenScopeWriteOrganization)
t.Run("move columns successfully", func(t *testing.T) {
req := NewRequestWithJSON(t, "PATCH", "/api/v1/projects/1/columns/move", &api.MovedColumnsOption{
Columns: []struct {
ColumnID int64 `json:"columnID"`
Sorting int64 `json:"sorting"`
}{
{
ColumnID: 3,
Sorting: 1,
},
{
ColumnID: 2,
Sorting: 2,
},
},
}).AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusOK)
var apiColumns []*api.Column
DecodeJSON(t, resp, &apiColumns)
assert.Equal(t, 2, len(apiColumns))
assert.Equal(t, int64(3), apiColumns[0].ID)
assert.Equal(t, int64(2), apiColumns[1].ID)
})
}
func TestAPIMoveIssues(t *testing.T) {
defer tests.PrepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser, auth_model.AccessTokenScopeWriteOrganization)
t.Run("move issues successfully", func(t *testing.T) {
req := NewRequestWithJSON(t, "PATCH", "/api/v1/projects/1/columns/1/move", &api.MovedIssuesOption{
Issues: []struct {
IssueID int64 `json:"issueID"`
Sorting int64 `json:"sorting"`
}{
{
IssueID: 1,
Sorting: 1,
},
{
IssueID: 5,
Sorting: 2,
},
},
}).AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusOK)
var apiIssues []*api.Issue
DecodeJSON(t, resp, &apiIssues)
assert.Equal(t, 2, len(apiIssues))
assert.Equal(t, int64(1), apiIssues[0].ID)
assert.Equal(t, int64(2), apiIssues[1].ID)
})
}

View File

@ -0,0 +1,131 @@
// Copyright 2017 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package integration
import (
"fmt"
"net/http"
"testing"
auth_model "code.gitea.io/gitea/models/auth"
"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"
"github.com/stretchr/testify/assert"
)
func TestAPIGetProject(t *testing.T) {
getProjectTestCases := []struct {
testName string
projectID int64
expectedStatus int
}{
{
testName: "get project successfully",
projectID: 1,
expectedStatus: http.StatusOK,
},
{
testName: "project not found",
projectID: 20,
expectedStatus: http.StatusNotFound,
},
}
defer tests.PrepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadAdmin, auth_model.AccessTokenScopeReadRepository, auth_model.AccessTokenScopeReadUser, auth_model.AccessTokenScopeReadOrganization)
for _, tt := range getProjectTestCases {
t.Run(tt.testName, func(t *testing.T) {
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/projects/%d", tt.projectID)).AddTokenAuth(token)
MakeRequest(t, req, tt.expectedStatus)
})
}
}
func TestAPIEditProject(t *testing.T) {
editProjectFailTestCases := []struct {
testName string
projectID int64
expectedStatus int
}{
{
testName: "repo is archived",
projectID: 7,
expectedStatus: http.StatusLocked,
},
{
testName: "insufficient access",
projectID: 2,
expectedStatus: http.StatusForbidden,
},
}
defer tests.PrepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser, auth_model.AccessTokenScopeWriteOrganization)
for _, tt := range editProjectFailTestCases {
t.Run(tt.testName, func(t *testing.T) {
req := NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/projects/%d", tt.projectID),
&api.EditProjectOption{
Title: "title",
}).AddTokenAuth(token)
MakeRequest(t, req, tt.expectedStatus)
})
}
t.Run("edit project successfully", func(t *testing.T) {
expectedProject := api.Project{
Title: "new title",
Description: "new content",
}
req := NewRequestWithJSON(t, "PATCH", "/api/v1/projects/1", &api.EditProjectOption{
Title: expectedProject.Title,
Content: expectedProject.Description,
}).AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusOK)
var apiProject api.Project
DecodeJSON(t, resp, &apiProject)
assert.Equal(t, expectedProject.Title, apiProject.Title)
assert.Equal(t, expectedProject.Description, apiProject.Description)
})
}
func TestAPIDeleteProject(t *testing.T) {
defer tests.PrepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser, auth_model.AccessTokenScopeWriteOrganization)
t.Run("delete project successfully", func(t *testing.T) {
req := NewRequest(t, "DELETE", "/api/v1/projects/1").AddTokenAuth(token)
MakeRequest(t, req, http.StatusNoContent)
})
}
func TestAPIChangeProjectStatus(t *testing.T) {
defer tests.PrepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser, auth_model.AccessTokenScopeWriteOrganization)
t.Run("change project status successfully", func(t *testing.T) {
req := NewRequest(t, "PATCH", "/api/v1/projects/1/close").AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusOK)
var apiProject api.Project
DecodeJSON(t, resp, &apiProject)
assert.Equal(t, true, apiProject.IsClosed)
})
}

View File

@ -0,0 +1,210 @@
// Copyright 2017 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package integration
import (
"fmt"
"net/http"
"testing"
auth_model "code.gitea.io/gitea/models/auth"
"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"
"github.com/stretchr/testify/assert"
)
func TestAPICreateRepoProject(t *testing.T) {
createRepoProjectSuccessTestCases := []struct {
testName string
ownerName string
repoName string
repoID int64
doerID int64
title string
content string
templateType uint8
cardType uint8
}{
{
testName: "member create project successfully with write access",
ownerName: "org3",
repoName: "repo3",
repoID: 3,
doerID: 4,
title: "member-with-write-access",
content: "project_description",
templateType: 1,
cardType: 2,
},
{
testName: "collaborator create project successfully with write access",
ownerName: "privated_org",
repoName: "public_repo_on_private_org",
repoID: 40,
doerID: 4,
title: "collaborator-with-write-access",
content: "project_description",
templateType: 1,
cardType: 2,
},
}
createRepoProjectFailTestCases := []struct {
testName string
ownerName string
repoName string
repoID int64
doerID int64
title string
expectedStatus int
}{
{
testName: "user is not in organization",
ownerName: "org3",
repoName: "repo3",
repoID: 3,
doerID: 5,
title: "user-not-in-org",
expectedStatus: http.StatusForbidden,
},
{
testName: "user is not collaborator",
ownerName: "org3",
repoName: "repo3",
repoID: 3,
doerID: 4,
title: "user-not-collaborator",
expectedStatus: http.StatusForbidden,
},
{
testName: "user is member but not sufficient access",
ownerName: "org17",
repoName: "big_test_private_4",
repoID: 24,
doerID: 20,
title: "member-not-sufficient-access",
expectedStatus: http.StatusForbidden,
},
{
testName: "project not created as title is empty",
ownerName: "org3",
repoName: "repo3",
repoID: 3,
doerID: 2,
title: "",
expectedStatus: http.StatusUnprocessableEntity,
},
{
testName: "project not created as title is too long",
ownerName: "org3",
repoName: "repo3",
repoID: 3,
doerID: 2,
title: "This is a very long title that will exceed the maximum allowed size of 100 characters. It keeps going beyond the limit.",
expectedStatus: http.StatusUnprocessableEntity,
},
}
defer tests.PrepareTestEnv(t)()
for _, tt := range createRepoProjectFailTestCases {
t.Run(tt.testName, func(t *testing.T) {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: tt.doerID})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeWriteRepository)
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/projects", tt.ownerName, tt.repoName), &api.CreateProjectOption{
Title: tt.title,
}).AddTokenAuth(token)
MakeRequest(t, req, tt.expectedStatus)
})
}
for _, tt := range createRepoProjectSuccessTestCases {
t.Run(tt.testName, func(t *testing.T) {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: tt.doerID})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeWriteRepository)
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/projects", tt.ownerName, tt.repoName), &api.CreateProjectOption{
Title: tt.title,
Content: tt.content,
TemplateType: tt.templateType,
CardType: tt.cardType,
}).AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusCreated)
var apiProject api.Project
DecodeJSON(t, resp, &apiProject)
assert.Equal(t, tt.title, apiProject.Title)
assert.Equal(t, tt.content, apiProject.Description)
assert.Equal(t, tt.templateType, apiProject.TemplateType)
assert.Equal(t, tt.cardType, apiProject.CardType)
assert.Equal(t, tt.repoID, apiProject.RepoID)
assert.Equal(t, tt.doerID, apiProject.CreatorID)
})
}
}
func TestAPIGetRepoProjects(t *testing.T) {
defer tests.PrepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadAdmin, auth_model.AccessTokenScopeReadRepository)
expectedProjects := []*api.Project{
{
Title: "First Project",
RepoID: 1,
IsClosed: false,
CreatorID: 2,
TemplateType: 1,
CardType: 2,
},
{
Title: "project2 on repo1",
RepoID: 1,
IsClosed: false,
CreatorID: 2,
TemplateType: 1,
CardType: 2,
},
}
t.Run("failed to get projects repo not found", func(t *testing.T) {
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo-not-found/projects").AddTokenAuth(token)
MakeRequest(t, req, http.StatusNotFound)
})
t.Run("get projects successfully", func(t *testing.T) {
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo1/projects").AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusOK)
var apiProjects []*api.Project
DecodeJSON(t, resp, &apiProjects)
assert.Equal(t, len(expectedProjects), len(apiProjects))
for i, expectedProject := range expectedProjects {
assert.Equal(t, expectedProject.Title, apiProjects[i].Title)
assert.Equal(t, expectedProject.RepoID, apiProjects[i].RepoID)
assert.Equal(t, expectedProject.IsClosed, apiProjects[i].IsClosed)
assert.Equal(t, expectedProject.CreatorID, apiProjects[i].CreatorID)
assert.Equal(t, expectedProject.TemplateType, apiProjects[i].TemplateType)
assert.Equal(t, expectedProject.CardType, apiProjects[i].CardType)
}
})
}
func TestAPIUpdateIssueProject(t *testing.T) {
defer tests.PrepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeWriteRepository)
req := NewRequestWithJSON(t, "PUT", "/api/v1/repos/user2/repo1/projects/issues", &api.UpdateIssuesOption{
ProjectID: 10,
Issues: []int64{1, 2},
}).AddTokenAuth(token)
MakeRequest(t, req, http.StatusNoContent)
}

View File

@ -0,0 +1,174 @@
// Copyright 2017 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package integration
import (
"net/http"
"testing"
auth_model "code.gitea.io/gitea/models/auth"
"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"
"github.com/stretchr/testify/assert"
)
func TestAPICreateUserProject(t *testing.T) {
createUserProjectSuccessTestCases := []struct {
testName string
ctxUserID int64
doerID int64
title string
content string
templateType uint8
cardType uint8
}{
{
testName: "admin create project successfully",
ctxUserID: 1,
doerID: 1,
title: "site-admin",
content: "project_description",
templateType: 1,
cardType: 2,
},
{
testName: "user create project successfully",
ctxUserID: 2,
doerID: 2,
title: "user",
content: "project_description",
templateType: 1,
cardType: 2,
},
}
createUserProjectFailTestCases := []struct {
testName string
ctxUserID int64
doerID int64
title string
expectedStatus int
}{
{
testName: "failed to create project user is not admin and not owner",
ctxUserID: 1,
doerID: 2,
title: "user-not-admin-or-owner",
expectedStatus: http.StatusForbidden,
},
{
testName: "project not created as title is empty",
ctxUserID: 2,
doerID: 2,
title: "",
expectedStatus: http.StatusUnprocessableEntity,
},
{
testName: "project not created as title is too long",
ctxUserID: 2,
doerID: 2,
title: "This is a very long title that will exceed the maximum allowed size of 100 characters. It keeps going beyond the limit.",
expectedStatus: http.StatusUnprocessableEntity,
},
}
defer tests.PrepareTestEnv(t)()
for _, tt := range createUserProjectFailTestCases {
t.Run(tt.testName, func(t *testing.T) {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: tt.doerID})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeWriteUser)
req := NewRequestWithJSON(t, "POST", "/api/v1/user/projects", &api.CreateProjectOption{
Title: tt.title,
}).AddTokenAuth(token)
MakeRequest(t, req, tt.expectedStatus)
})
}
for _, tt := range createUserProjectSuccessTestCases {
t.Run(tt.testName, func(t *testing.T) {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: tt.doerID})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeWriteUser)
req := NewRequestWithJSON(t, "POST", "/api/v1/user/projects", &api.CreateProjectOption{
Title: tt.title,
Content: tt.content,
TemplateType: tt.templateType,
CardType: tt.cardType,
}).AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusCreated)
var apiProject api.Project
DecodeJSON(t, resp, &apiProject)
assert.Equal(t, tt.title, apiProject.Title)
assert.Equal(t, tt.content, apiProject.Description)
assert.Equal(t, tt.templateType, apiProject.TemplateType)
assert.Equal(t, tt.cardType, apiProject.CardType)
assert.Equal(t, tt.ctxUserID, apiProject.OwnerID)
assert.Equal(t, tt.doerID, apiProject.CreatorID)
if tt.doerID != 1 {
assert.Equal(t, apiProject.CreatorID, apiProject.OwnerID)
}
})
}
}
func TestAPIGetUserProjects(t *testing.T) {
defer tests.PrepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadAdmin, auth_model.AccessTokenScopeReadUser)
expectedProjects := []*api.Project{
{
Title: "project on user2",
OwnerID: 2,
IsClosed: false,
CreatorID: 2,
TemplateType: 1,
CardType: 2,
},
{
Title: "project without default column",
OwnerID: 2,
IsClosed: false,
CreatorID: 2,
TemplateType: 1,
CardType: 2,
},
{
Title: "project with multiple default columns",
OwnerID: 2,
IsClosed: false,
CreatorID: 2,
TemplateType: 1,
CardType: 2,
},
}
t.Run("failed to get projects user not found", func(t *testing.T) {
req := NewRequest(t, "GET", "/api/v1/users/user-not-found/projects").AddTokenAuth(token)
MakeRequest(t, req, http.StatusNotFound)
})
t.Run("get projects successfully", func(t *testing.T) {
req := NewRequest(t, "GET", "/api/v1/users/user2/projects").AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusOK)
var apiProjects []*api.Project
DecodeJSON(t, resp, &apiProjects)
assert.Equal(t, len(expectedProjects), len(apiProjects))
for i, expectedProject := range expectedProjects {
assert.Equal(t, expectedProject.Title, apiProjects[i].Title)
assert.Equal(t, expectedProject.OwnerID, apiProjects[i].OwnerID)
assert.Equal(t, expectedProject.IsClosed, apiProjects[i].IsClosed)
assert.Equal(t, expectedProject.CreatorID, apiProjects[i].CreatorID)
assert.Equal(t, expectedProject.TemplateType, apiProjects[i].TemplateType)
assert.Equal(t, expectedProject.CardType, apiProjects[i].CardType)
}
})
}