mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-06-01 12:22:11 +00:00
Kd/ci playwright go test (#20123)
* Add initial playwright config * Simplify Makefile * Simplify Makefile * Use correct config files * Update playwright settings * Fix package-lock file * Don't use test logger for e2e tests * fix frontend lint * Allow passing TEST_LOGGER variable * Init postgres database * use standard gitea env variables * Update playwright * update drone * Move empty env var to commands * Cleanup * Move integrations to subfolder * tests integrations to tests integraton * Run e2e tests with go test * Fix linting * install CI deps * Add files to ESlint * Fix drone typo * Don't log to console in CI * Use go test http server * Add build step before tests * Move shared init function to common package * fix drone * Clean up tests * Fix linting * Better mocking for page + version string * Cleanup test generation * Remove dependency on gitea binary * Fix linting * add initial support for running specific tests * Add ACCEPT_VISUAL variable * don't require git-lfs * Add initial documentation * Review feedback * Add logged in session test * Attempt fixing drone race * Cleanup and bump version * Bump deps * Review feedback * simplify installation * Fix ci * Update install docs
This commit is contained in:
parent
5710ff343c
commit
c8ded77680
644 changed files with 1857 additions and 1027 deletions
96
tests/integration/README.md
Normal file
96
tests/integration/README.md
Normal file
|
@ -0,0 +1,96 @@
|
|||
# Integration tests
|
||||
|
||||
Integration tests can be run with make commands for the
|
||||
appropriate backends, namely:
|
||||
```shell
|
||||
make test-sqlite
|
||||
make test-pgsql
|
||||
make test-mysql
|
||||
make test-mysql8
|
||||
make test-mssql
|
||||
```
|
||||
|
||||
Make sure to perform a clean build before running tests:
|
||||
```
|
||||
make clean build
|
||||
```
|
||||
|
||||
## Run all tests via local drone
|
||||
```
|
||||
drone exec --local --build-event "pull_request"
|
||||
```
|
||||
|
||||
## Run sqlite integration tests
|
||||
Start tests
|
||||
```
|
||||
make test-sqlite
|
||||
```
|
||||
|
||||
## Run MySQL integration tests
|
||||
Setup a MySQL database inside docker
|
||||
```
|
||||
docker run -e "MYSQL_DATABASE=test" -e "MYSQL_ALLOW_EMPTY_PASSWORD=yes" -p 3306:3306 --rm --name mysql mysql:latest #(just ctrl-c to stop db and clean the container)
|
||||
docker run -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" --rm --name elasticsearch elasticsearch:7.6.0 #(in a second terminal, just ctrl-c to stop db and clean the container)
|
||||
```
|
||||
Start tests based on the database container
|
||||
```
|
||||
TEST_MYSQL_HOST=localhost:3306 TEST_MYSQL_DBNAME=test TEST_MYSQL_USERNAME=root TEST_MYSQL_PASSWORD='' make test-mysql
|
||||
```
|
||||
|
||||
## Run pgsql integration tests
|
||||
Setup a pgsql database inside docker
|
||||
```
|
||||
docker run -e "POSTGRES_DB=test" -p 5432:5432 --rm --name pgsql postgres:latest #(just ctrl-c to stop db and clean the container)
|
||||
```
|
||||
Start tests based on the database container
|
||||
```
|
||||
TEST_PGSQL_HOST=localhost:5432 TEST_PGSQL_DBNAME=test TEST_PGSQL_USERNAME=postgres TEST_PGSQL_PASSWORD=postgres make test-pgsql
|
||||
```
|
||||
|
||||
## Run mssql integration tests
|
||||
Setup a mssql database inside docker
|
||||
```
|
||||
docker run -e "ACCEPT_EULA=Y" -e "MSSQL_PID=Standard" -e "SA_PASSWORD=MwantsaSecurePassword1" -p 1433:1433 --rm --name mssql microsoft/mssql-server-linux:latest #(just ctrl-c to stop db and clean the container)
|
||||
```
|
||||
Start tests based on the database container
|
||||
```
|
||||
TEST_MSSQL_HOST=localhost:1433 TEST_MSSQL_DBNAME=gitea_test TEST_MSSQL_USERNAME=sa TEST_MSSQL_PASSWORD=MwantsaSecurePassword1 make test-mssql
|
||||
```
|
||||
|
||||
## Running individual tests
|
||||
|
||||
Example command to run GPG test:
|
||||
|
||||
For SQLite:
|
||||
|
||||
```
|
||||
make test-sqlite#GPG
|
||||
```
|
||||
|
||||
For other databases(replace `mssql` to `mysql`, `mysql8` or `pgsql`):
|
||||
|
||||
```
|
||||
TEST_MSSQL_HOST=localhost:1433 TEST_MSSQL_DBNAME=test TEST_MSSQL_USERNAME=sa TEST_MSSQL_PASSWORD=MwantsaSecurePassword1 make test-mssql#GPG
|
||||
```
|
||||
|
||||
## Setting timeouts for declaring long-tests and long-flushes
|
||||
|
||||
We appreciate that some testing machines may not be very powerful and
|
||||
the default timeouts for declaring a slow test or a slow clean-up flush
|
||||
may not be appropriate.
|
||||
|
||||
You can either:
|
||||
|
||||
* Within the test ini file set the following section:
|
||||
|
||||
```ini
|
||||
[integration-tests]
|
||||
SLOW_TEST = 10s ; 10s is the default value
|
||||
SLOW_FLUSH = 5S ; 5s is the default value
|
||||
```
|
||||
|
||||
* Set the following environment variables:
|
||||
|
||||
```bash
|
||||
GITEA_SLOW_TEST_TIME="10s" GITEA_SLOW_FLUSH_TIME="5s" make test-sqlite
|
||||
```
|
71
tests/integration/README_ZH.md
Normal file
71
tests/integration/README_ZH.md
Normal file
|
@ -0,0 +1,71 @@
|
|||
# 关于集成测试
|
||||
|
||||
使用如下 make 命令可以运行指定的集成测试:
|
||||
```shell
|
||||
make test-mysql
|
||||
make test-pgsql
|
||||
make test-sqlite
|
||||
```
|
||||
|
||||
在执行集成测试命令前请确保清理了之前的构建环境,清理命令如下:
|
||||
```
|
||||
make clean build
|
||||
```
|
||||
|
||||
## 如何在本地 drone 服务器上运行所有测试
|
||||
```
|
||||
drone exec --local --build-event "pull_request"
|
||||
```
|
||||
|
||||
## 如何使用 sqlite 数据库进行集成测试
|
||||
使用该命令执行集成测试
|
||||
```
|
||||
make test-sqlite
|
||||
```
|
||||
|
||||
## 如何使用 mysql 数据库进行集成测试
|
||||
首先在docker容器里部署一个 mysql 数据库
|
||||
```
|
||||
docker run -e "MYSQL_DATABASE=test" -e "MYSQL_ALLOW_EMPTY_PASSWORD=yes" -p 3306:3306 --rm --name mysql mysql:8 #(just ctrl-c to stop db and clean the container)
|
||||
```
|
||||
之后便可以基于这个数据库进行集成测试
|
||||
```
|
||||
TEST_MYSQL_HOST=localhost:3306 TEST_MYSQL_DBNAME=test TEST_MYSQL_USERNAME=root TEST_MYSQL_PASSWORD='' make test-mysql
|
||||
```
|
||||
|
||||
## 如何使用 pgsql 数据库进行集成测试
|
||||
同上,首先在 docker 容器里部署一个 pgsql 数据库
|
||||
```
|
||||
docker run -e "POSTGRES_DB=test" -p 5432:5432 --rm --name pgsql postgres:14 #(just ctrl-c to stop db and clean the container)
|
||||
```
|
||||
之后便可以基于这个数据库进行集成测试
|
||||
```
|
||||
TEST_PGSQL_HOST=localhost:5432 TEST_PGSQL_DBNAME=test TEST_PGSQL_USERNAME=postgres TEST_PGSQL_PASSWORD=postgres make test-pgsql
|
||||
```
|
||||
|
||||
## Run mssql integration tests
|
||||
同上,首先在 docker 容器里部署一个 mssql 数据库
|
||||
```
|
||||
docker run -e "ACCEPT_EULA=Y" -e "MSSQL_PID=Standard" -e "SA_PASSWORD=MwantsaSecurePassword1" -p 1433:1433 --rm --name mssql microsoft/mssql-server-linux:latest #(just ctrl-c to stop db and clean the container)
|
||||
```
|
||||
之后便可以基于这个数据库进行集成测试
|
||||
```
|
||||
TEST_MSSQL_HOST=localhost:1433 TEST_MSSQL_DBNAME=gitea_test TEST_MSSQL_USERNAME=sa TEST_MSSQL_PASSWORD=MwantsaSecurePassword1 make test-mssql
|
||||
```
|
||||
|
||||
## 如何进行自定义的集成测试
|
||||
|
||||
下面的示例展示了怎样在集成测试中只进行 GPG 测试:
|
||||
|
||||
sqlite 数据库:
|
||||
|
||||
```
|
||||
make test-sqlite#GPG
|
||||
```
|
||||
|
||||
其它数据库(把 MSSQL 替换为 MYSQL, MYSQL8, PGSQL):
|
||||
|
||||
```
|
||||
TEST_MSSQL_HOST=localhost:1433 TEST_MSSQL_DBNAME=test TEST_MSSQL_USERNAME=sa TEST_MSSQL_PASSWORD=MwantsaSecurePassword1 make test-mssql#GPG
|
||||
```
|
||||
|
84
tests/integration/admin_user_test.go
Normal file
84
tests/integration/admin_user_test.go
Normal file
|
@ -0,0 +1,84 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAdminViewUsers(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
session := loginUser(t, "user1")
|
||||
req := NewRequest(t, "GET", "/admin/users")
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
session = loginUser(t, "user2")
|
||||
req = NewRequest(t, "GET", "/admin/users")
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
}
|
||||
|
||||
func TestAdminViewUser(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
session := loginUser(t, "user1")
|
||||
req := NewRequest(t, "GET", "/admin/users/1")
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
session = loginUser(t, "user2")
|
||||
req = NewRequest(t, "GET", "/admin/users/1")
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
}
|
||||
|
||||
func TestAdminEditUser(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
testSuccessfullEdit(t, user_model.User{ID: 2, Name: "newusername", LoginName: "otherlogin", Email: "new@e-mail.gitea"})
|
||||
}
|
||||
|
||||
func testSuccessfullEdit(t *testing.T, formData user_model.User) {
|
||||
makeRequest(t, formData, http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func makeRequest(t *testing.T, formData user_model.User, headerCode int) {
|
||||
session := loginUser(t, "user1")
|
||||
csrf := GetCSRF(t, session, "/admin/users/"+strconv.Itoa(int(formData.ID)))
|
||||
req := NewRequestWithValues(t, "POST", "/admin/users/"+strconv.Itoa(int(formData.ID)), map[string]string{
|
||||
"_csrf": csrf,
|
||||
"user_name": formData.Name,
|
||||
"login_name": formData.LoginName,
|
||||
"login_type": "0-0",
|
||||
"email": formData.Email,
|
||||
})
|
||||
|
||||
session.MakeRequest(t, req, headerCode)
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: formData.ID})
|
||||
assert.Equal(t, formData.Name, user.Name)
|
||||
assert.Equal(t, formData.LoginName, user.LoginName)
|
||||
assert.Equal(t, formData.Email, user.Email)
|
||||
}
|
||||
|
||||
func TestAdminDeleteUser(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
session := loginUser(t, "user1")
|
||||
|
||||
csrf := GetCSRF(t, session, "/admin/users/8")
|
||||
req := NewRequestWithValues(t, "POST", "/admin/users/8/delete", map[string]string{
|
||||
"_csrf": csrf,
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
||||
assertUserDeleted(t, 8)
|
||||
unittest.CheckConsistencyFor(t, &user_model.User{})
|
||||
}
|
113
tests/integration/api_activitypub_person_test.go
Normal file
113
tests/integration/api_activitypub_person_test.go
Normal file
|
@ -0,0 +1,113 @@
|
|||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/activitypub"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/routers"
|
||||
|
||||
ap "github.com/go-ap/activitypub"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestActivityPubPerson(t *testing.T) {
|
||||
setting.Federation.Enabled = true
|
||||
c = routers.NormalRoutes(context.TODO())
|
||||
defer func() {
|
||||
setting.Federation.Enabled = false
|
||||
c = routers.NormalRoutes(context.TODO())
|
||||
}()
|
||||
|
||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||
username := "user2"
|
||||
req := NewRequestf(t, "GET", fmt.Sprintf("/api/v1/activitypub/user/%s", username))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
body := resp.Body.Bytes()
|
||||
assert.Contains(t, string(body), "@context")
|
||||
|
||||
var person ap.Person
|
||||
err := person.UnmarshalJSON(body)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, ap.PersonType, person.Type)
|
||||
assert.Equal(t, username, person.PreferredUsername.String())
|
||||
keyID := person.GetID().String()
|
||||
assert.Regexp(t, fmt.Sprintf("activitypub/user/%s$", username), keyID)
|
||||
assert.Regexp(t, fmt.Sprintf("activitypub/user/%s/outbox$", username), person.Outbox.GetID().String())
|
||||
assert.Regexp(t, fmt.Sprintf("activitypub/user/%s/inbox$", username), person.Inbox.GetID().String())
|
||||
|
||||
pubKey := person.PublicKey
|
||||
assert.NotNil(t, pubKey)
|
||||
publicKeyID := keyID + "#main-key"
|
||||
assert.Equal(t, pubKey.ID.String(), publicKeyID)
|
||||
|
||||
pubKeyPem := pubKey.PublicKeyPem
|
||||
assert.NotNil(t, pubKeyPem)
|
||||
assert.Regexp(t, "^-----BEGIN PUBLIC KEY-----", pubKeyPem)
|
||||
})
|
||||
}
|
||||
|
||||
func TestActivityPubMissingPerson(t *testing.T) {
|
||||
setting.Federation.Enabled = true
|
||||
c = routers.NormalRoutes(context.TODO())
|
||||
defer func() {
|
||||
setting.Federation.Enabled = false
|
||||
c = routers.NormalRoutes(context.TODO())
|
||||
}()
|
||||
|
||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||
req := NewRequestf(t, "GET", "/api/v1/activitypub/user/nonexistentuser")
|
||||
resp := MakeRequest(t, req, http.StatusNotFound)
|
||||
assert.Contains(t, resp.Body.String(), "user redirect does not exist")
|
||||
})
|
||||
}
|
||||
|
||||
func TestActivityPubPersonInbox(t *testing.T) {
|
||||
setting.Federation.Enabled = true
|
||||
c = routers.NormalRoutes(context.TODO())
|
||||
defer func() {
|
||||
setting.Federation.Enabled = false
|
||||
c = routers.NormalRoutes(context.TODO())
|
||||
}()
|
||||
|
||||
srv := httptest.NewServer(c)
|
||||
defer srv.Close()
|
||||
|
||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||
appURL := setting.AppURL
|
||||
setting.AppURL = srv.URL
|
||||
defer func() {
|
||||
setting.Database.LogSQL = false
|
||||
setting.AppURL = appURL
|
||||
}()
|
||||
username1 := "user1"
|
||||
ctx := context.Background()
|
||||
user1, err := user_model.GetUserByName(ctx, username1)
|
||||
assert.NoError(t, err)
|
||||
user1url := fmt.Sprintf("%s/api/v1/activitypub/user/%s#main-key", srv.URL, username1)
|
||||
c, err := activitypub.NewClient(user1, user1url)
|
||||
assert.NoError(t, err)
|
||||
username2 := "user2"
|
||||
user2inboxurl := fmt.Sprintf("%s/api/v1/activitypub/user/%s/inbox", srv.URL, username2)
|
||||
|
||||
// Signed request succeeds
|
||||
resp, err := c.Post([]byte{}, user2inboxurl)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, http.StatusNoContent, resp.StatusCode)
|
||||
|
||||
// Unsigned request fails
|
||||
req := NewRequest(t, "POST", user2inboxurl)
|
||||
MakeRequest(t, req, http.StatusInternalServerError)
|
||||
})
|
||||
}
|
88
tests/integration/api_admin_org_test.go
Normal file
88
tests/integration/api_admin_org_test.go
Normal file
|
@ -0,0 +1,88 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"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 TestAPIAdminOrgCreate(t *testing.T) {
|
||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||
session := loginUser(t, "user1")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
org := api.CreateOrgOption{
|
||||
UserName: "user2_org",
|
||||
FullName: "User2's organization",
|
||||
Description: "This organization created by admin for user2",
|
||||
Website: "https://try.gitea.io",
|
||||
Location: "Shanghai",
|
||||
Visibility: "private",
|
||||
}
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/admin/users/user2/orgs?token="+token, &org)
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
var apiOrg api.Organization
|
||||
DecodeJSON(t, resp, &apiOrg)
|
||||
|
||||
assert.Equal(t, org.UserName, apiOrg.UserName)
|
||||
assert.Equal(t, org.FullName, apiOrg.FullName)
|
||||
assert.Equal(t, org.Description, apiOrg.Description)
|
||||
assert.Equal(t, org.Website, apiOrg.Website)
|
||||
assert.Equal(t, org.Location, apiOrg.Location)
|
||||
assert.Equal(t, org.Visibility, apiOrg.Visibility)
|
||||
|
||||
unittest.AssertExistsAndLoadBean(t, &user_model.User{
|
||||
Name: org.UserName,
|
||||
LowerName: strings.ToLower(org.UserName),
|
||||
FullName: org.FullName,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestAPIAdminOrgCreateBadVisibility(t *testing.T) {
|
||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||
session := loginUser(t, "user1")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
org := api.CreateOrgOption{
|
||||
UserName: "user2_org",
|
||||
FullName: "User2's organization",
|
||||
Description: "This organization created by admin for user2",
|
||||
Website: "https://try.gitea.io",
|
||||
Location: "Shanghai",
|
||||
Visibility: "notvalid",
|
||||
}
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/admin/users/user2/orgs?token="+token, &org)
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAPIAdminOrgCreateNotAdmin(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
nonAdminUsername := "user2"
|
||||
session := loginUser(t, nonAdminUsername)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
org := api.CreateOrgOption{
|
||||
UserName: "user2_org",
|
||||
FullName: "User2's organization",
|
||||
Description: "This organization created by admin for user2",
|
||||
Website: "https://try.gitea.io",
|
||||
Location: "Shanghai",
|
||||
Visibility: "public",
|
||||
}
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/admin/users/user2/orgs?token="+token, &org)
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
}
|
211
tests/integration/api_admin_test.go
Normal file
211
tests/integration/api_admin_test.go
Normal file
|
@ -0,0 +1,211 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIAdminCreateAndDeleteSSHKey(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
// user1 is an admin user
|
||||
session := loginUser(t, "user1")
|
||||
keyOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user2"})
|
||||
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys?token=%s", keyOwner.Name, token)
|
||||
req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
|
||||
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment\n",
|
||||
"title": "test-key",
|
||||
})
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
var newPublicKey api.PublicKey
|
||||
DecodeJSON(t, resp, &newPublicKey)
|
||||
unittest.AssertExistsAndLoadBean(t, &asymkey_model.PublicKey{
|
||||
ID: newPublicKey.ID,
|
||||
Name: newPublicKey.Title,
|
||||
Fingerprint: newPublicKey.Fingerprint,
|
||||
OwnerID: keyOwner.ID,
|
||||
})
|
||||
|
||||
req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d?token=%s",
|
||||
keyOwner.Name, newPublicKey.ID, token)
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
unittest.AssertNotExistsBean(t, &asymkey_model.PublicKey{ID: newPublicKey.ID})
|
||||
}
|
||||
|
||||
func TestAPIAdminDeleteMissingSSHKey(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
// user1 is an admin user
|
||||
session := loginUser(t, "user1")
|
||||
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "DELETE", "/api/v1/admin/users/user1/keys/%d?token=%s", unittest.NonexistentID, token)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
||||
|
||||
func TestAPIAdminDeleteUnauthorizedKey(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
adminUsername := "user1"
|
||||
normalUsername := "user2"
|
||||
session := loginUser(t, adminUsername)
|
||||
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys?token=%s", adminUsername, token)
|
||||
req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
|
||||
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment\n",
|
||||
"title": "test-key",
|
||||
})
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
var newPublicKey api.PublicKey
|
||||
DecodeJSON(t, resp, &newPublicKey)
|
||||
|
||||
session = loginUser(t, normalUsername)
|
||||
token = getTokenForLoggedInUser(t, session)
|
||||
req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d?token=%s",
|
||||
adminUsername, newPublicKey.ID, token)
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
}
|
||||
|
||||
func TestAPISudoUser(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
adminUsername := "user1"
|
||||
normalUsername := "user2"
|
||||
session := loginUser(t, adminUsername)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/user?sudo=%s&token=%s", normalUsername, token)
|
||||
req := NewRequest(t, "GET", urlStr)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var user api.User
|
||||
DecodeJSON(t, resp, &user)
|
||||
|
||||
assert.Equal(t, normalUsername, user.UserName)
|
||||
}
|
||||
|
||||
func TestAPISudoUserForbidden(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
adminUsername := "user1"
|
||||
normalUsername := "user2"
|
||||
|
||||
session := loginUser(t, normalUsername)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/user?sudo=%s&token=%s", adminUsername, token)
|
||||
req := NewRequest(t, "GET", urlStr)
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
}
|
||||
|
||||
func TestAPIListUsers(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
adminUsername := "user1"
|
||||
session := loginUser(t, adminUsername)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/admin/users?token=%s", token)
|
||||
req := NewRequest(t, "GET", urlStr)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var users []api.User
|
||||
DecodeJSON(t, resp, &users)
|
||||
|
||||
found := false
|
||||
for _, user := range users {
|
||||
if user.UserName == adminUsername {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
assert.True(t, found)
|
||||
numberOfUsers := unittest.GetCount(t, &user_model.User{}, "type = 0")
|
||||
assert.Equal(t, numberOfUsers, len(users))
|
||||
}
|
||||
|
||||
func TestAPIListUsersNotLoggedIn(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
req := NewRequest(t, "GET", "/api/v1/admin/users")
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
}
|
||||
|
||||
func TestAPIListUsersNonAdmin(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
nonAdminUsername := "user2"
|
||||
session := loginUser(t, nonAdminUsername)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "GET", "/api/v1/admin/users?token=%s", token)
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
}
|
||||
|
||||
func TestAPICreateUserInvalidEmail(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
adminUsername := "user1"
|
||||
session := loginUser(t, adminUsername)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/admin/users?token=%s", token)
|
||||
req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
|
||||
"email": "invalid_email@domain.com\r\n",
|
||||
"full_name": "invalid user",
|
||||
"login_name": "invalidUser",
|
||||
"must_change_password": "true",
|
||||
"password": "password",
|
||||
"send_notify": "true",
|
||||
"source_id": "0",
|
||||
"username": "invalidUser",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
}
|
||||
|
||||
func TestAPIEditUser(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
adminUsername := "user1"
|
||||
session := loginUser(t, adminUsername)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/admin/users/%s?token=%s", "user2", token)
|
||||
|
||||
req := NewRequestWithValues(t, "PATCH", urlStr, map[string]string{
|
||||
// required
|
||||
"login_name": "user2",
|
||||
"source_id": "0",
|
||||
// to change
|
||||
"full_name": "Full Name User 2",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
empty := ""
|
||||
req = NewRequestWithJSON(t, "PATCH", urlStr, api.EditUserOption{
|
||||
LoginName: "user2",
|
||||
SourceID: 0,
|
||||
Email: &empty,
|
||||
})
|
||||
resp := session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
|
||||
errMap := make(map[string]interface{})
|
||||
json.Unmarshal(resp.Body.Bytes(), &errMap)
|
||||
assert.EqualValues(t, "email is not allowed to be empty string", errMap["message"].(string))
|
||||
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{LoginName: "user2"})
|
||||
assert.False(t, user2.IsRestricted)
|
||||
bTrue := true
|
||||
req = NewRequestWithJSON(t, "PATCH", urlStr, api.EditUserOption{
|
||||
// required
|
||||
LoginName: "user2",
|
||||
SourceID: 0,
|
||||
// to change
|
||||
Restricted: &bTrue,
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
user2 = unittest.AssertExistsAndLoadBean(t, &user_model.User{LoginName: "user2"})
|
||||
assert.True(t, user2.IsRestricted)
|
||||
}
|
201
tests/integration/api_branch_test.go
Normal file
201
tests/integration/api_branch_test.go
Normal file
|
@ -0,0 +1,201 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func testAPIGetBranch(t *testing.T, branchName string, exists bool) {
|
||||
session := loginUser(t, "user2")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/branches/%s?token=%s", branchName, token)
|
||||
resp := session.MakeRequest(t, req, NoExpectedStatus)
|
||||
if !exists {
|
||||
assert.EqualValues(t, http.StatusNotFound, resp.Code)
|
||||
return
|
||||
}
|
||||
assert.EqualValues(t, http.StatusOK, resp.Code)
|
||||
var branch api.Branch
|
||||
DecodeJSON(t, resp, &branch)
|
||||
assert.EqualValues(t, branchName, branch.Name)
|
||||
assert.True(t, branch.UserCanPush)
|
||||
assert.True(t, branch.UserCanMerge)
|
||||
}
|
||||
|
||||
func testAPIGetBranchProtection(t *testing.T, branchName string, expectedHTTPStatus int) {
|
||||
session := loginUser(t, "user2")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/branch_protections/%s?token=%s", branchName, token)
|
||||
resp := session.MakeRequest(t, req, expectedHTTPStatus)
|
||||
|
||||
if resp.Code == http.StatusOK {
|
||||
var branchProtection api.BranchProtection
|
||||
DecodeJSON(t, resp, &branchProtection)
|
||||
assert.EqualValues(t, branchName, branchProtection.BranchName)
|
||||
}
|
||||
}
|
||||
|
||||
func testAPICreateBranchProtection(t *testing.T, branchName string, expectedHTTPStatus int) {
|
||||
session := loginUser(t, "user2")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/repos/user2/repo1/branch_protections?token="+token, &api.BranchProtection{
|
||||
BranchName: branchName,
|
||||
})
|
||||
resp := session.MakeRequest(t, req, expectedHTTPStatus)
|
||||
|
||||
if resp.Code == http.StatusCreated {
|
||||
var branchProtection api.BranchProtection
|
||||
DecodeJSON(t, resp, &branchProtection)
|
||||
assert.EqualValues(t, branchName, branchProtection.BranchName)
|
||||
}
|
||||
}
|
||||
|
||||
func testAPIEditBranchProtection(t *testing.T, branchName string, body *api.BranchProtection, expectedHTTPStatus int) {
|
||||
session := loginUser(t, "user2")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestWithJSON(t, "PATCH", "/api/v1/repos/user2/repo1/branch_protections/"+branchName+"?token="+token, body)
|
||||
resp := session.MakeRequest(t, req, expectedHTTPStatus)
|
||||
|
||||
if resp.Code == http.StatusOK {
|
||||
var branchProtection api.BranchProtection
|
||||
DecodeJSON(t, resp, &branchProtection)
|
||||
assert.EqualValues(t, branchName, branchProtection.BranchName)
|
||||
}
|
||||
}
|
||||
|
||||
func testAPIDeleteBranchProtection(t *testing.T, branchName string, expectedHTTPStatus int) {
|
||||
session := loginUser(t, "user2")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "DELETE", "/api/v1/repos/user2/repo1/branch_protections/%s?token=%s", branchName, token)
|
||||
session.MakeRequest(t, req, expectedHTTPStatus)
|
||||
}
|
||||
|
||||
func testAPIDeleteBranch(t *testing.T, branchName string, expectedHTTPStatus int) {
|
||||
session := loginUser(t, "user2")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "DELETE", "/api/v1/repos/user2/repo1/branches/%s?token=%s", branchName, token)
|
||||
session.MakeRequest(t, req, expectedHTTPStatus)
|
||||
}
|
||||
|
||||
func TestAPIGetBranch(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
for _, test := range []struct {
|
||||
BranchName string
|
||||
Exists bool
|
||||
}{
|
||||
{"master", true},
|
||||
{"master/doesnotexist", false},
|
||||
{"feature/1", true},
|
||||
{"feature/1/doesnotexist", false},
|
||||
} {
|
||||
testAPIGetBranch(t, test.BranchName, test.Exists)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPICreateBranch(t *testing.T) {
|
||||
onGiteaRun(t, testAPICreateBranches)
|
||||
}
|
||||
|
||||
func testAPICreateBranches(t *testing.T, giteaURL *url.URL) {
|
||||
username := "user2"
|
||||
ctx := NewAPITestContext(t, username, "my-noo-repo")
|
||||
giteaURL.Path = ctx.GitPath()
|
||||
|
||||
t.Run("CreateRepo", doAPICreateRepository(ctx, false))
|
||||
testCases := []struct {
|
||||
OldBranch string
|
||||
NewBranch string
|
||||
ExpectedHTTPStatus int
|
||||
}{
|
||||
// Creating branch from default branch
|
||||
{
|
||||
OldBranch: "",
|
||||
NewBranch: "new_branch_from_default_branch",
|
||||
ExpectedHTTPStatus: http.StatusCreated,
|
||||
},
|
||||
// Creating branch from master
|
||||
{
|
||||
OldBranch: "master",
|
||||
NewBranch: "new_branch_from_master_1",
|
||||
ExpectedHTTPStatus: http.StatusCreated,
|
||||
},
|
||||
// Trying to create from master but already exists
|
||||
{
|
||||
OldBranch: "master",
|
||||
NewBranch: "new_branch_from_master_1",
|
||||
ExpectedHTTPStatus: http.StatusConflict,
|
||||
},
|
||||
// Trying to create from other branch (not default branch)
|
||||
{
|
||||
OldBranch: "new_branch_from_master_1",
|
||||
NewBranch: "branch_2",
|
||||
ExpectedHTTPStatus: http.StatusCreated,
|
||||
},
|
||||
// Trying to create from a branch which does not exist
|
||||
{
|
||||
OldBranch: "does_not_exist",
|
||||
NewBranch: "new_branch_from_non_existent",
|
||||
ExpectedHTTPStatus: http.StatusNotFound,
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
defer tests.ResetFixtures(t)
|
||||
session := ctx.Session
|
||||
testAPICreateBranch(t, session, "user2", "my-noo-repo", test.OldBranch, test.NewBranch, test.ExpectedHTTPStatus)
|
||||
}
|
||||
}
|
||||
|
||||
func testAPICreateBranch(t testing.TB, session *TestSession, user, repo, oldBranch, newBranch string, status int) bool {
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/repos/"+user+"/"+repo+"/branches?token="+token, &api.CreateBranchRepoOption{
|
||||
BranchName: newBranch,
|
||||
OldBranchName: oldBranch,
|
||||
})
|
||||
resp := session.MakeRequest(t, req, status)
|
||||
|
||||
var branch api.Branch
|
||||
DecodeJSON(t, resp, &branch)
|
||||
|
||||
if status == http.StatusCreated {
|
||||
assert.EqualValues(t, newBranch, branch.Name)
|
||||
}
|
||||
|
||||
return resp.Result().StatusCode == status
|
||||
}
|
||||
|
||||
func TestAPIBranchProtection(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
// Branch protection only on branch that exist
|
||||
testAPICreateBranchProtection(t, "master/doesnotexist", http.StatusNotFound)
|
||||
// Get branch protection on branch that exist but not branch protection
|
||||
testAPIGetBranchProtection(t, "master", http.StatusNotFound)
|
||||
|
||||
testAPICreateBranchProtection(t, "master", http.StatusCreated)
|
||||
// Can only create once
|
||||
testAPICreateBranchProtection(t, "master", http.StatusForbidden)
|
||||
|
||||
// Can't delete a protected branch
|
||||
testAPIDeleteBranch(t, "master", http.StatusForbidden)
|
||||
|
||||
testAPIGetBranchProtection(t, "master", http.StatusOK)
|
||||
testAPIEditBranchProtection(t, "master", &api.BranchProtection{
|
||||
EnablePush: true,
|
||||
}, http.StatusOK)
|
||||
|
||||
testAPIDeleteBranchProtection(t, "master", http.StatusNoContent)
|
||||
|
||||
// Test branch deletion
|
||||
testAPIDeleteBranch(t, "master", http.StatusForbidden)
|
||||
testAPIDeleteBranch(t, "branch2", http.StatusNoContent)
|
||||
}
|
205
tests/integration/api_comment_test.go
Normal file
205
tests/integration/api_comment_test.go
Normal file
|
@ -0,0 +1,205 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
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/convert"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIListRepoComments(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{},
|
||||
unittest.Cond("type = ?", issues_model.CommentTypeComment))
|
||||
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
||||
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
|
||||
session := loginUser(t, repoOwner.Name)
|
||||
link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments", repoOwner.Name, repo.Name))
|
||||
req := NewRequest(t, "GET", link.String())
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var apiComments []*api.Comment
|
||||
DecodeJSON(t, resp, &apiComments)
|
||||
assert.Len(t, apiComments, 2)
|
||||
for _, apiComment := range apiComments {
|
||||
c := &issues_model.Comment{ID: apiComment.ID}
|
||||
unittest.AssertExistsAndLoadBean(t, c,
|
||||
unittest.Cond("type = ?", issues_model.CommentTypeComment))
|
||||
unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: c.IssueID, RepoID: repo.ID})
|
||||
}
|
||||
|
||||
// test before and since filters
|
||||
query := url.Values{}
|
||||
before := "2000-01-01T00:00:11+00:00" // unix: 946684811
|
||||
since := "2000-01-01T00:00:12+00:00" // unix: 946684812
|
||||
query.Add("before", before)
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiComments)
|
||||
assert.Len(t, apiComments, 1)
|
||||
assert.EqualValues(t, 2, apiComments[0].ID)
|
||||
|
||||
query.Del("before")
|
||||
query.Add("since", since)
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiComments)
|
||||
assert.Len(t, apiComments, 1)
|
||||
assert.EqualValues(t, 3, apiComments[0].ID)
|
||||
}
|
||||
|
||||
func TestAPIListIssueComments(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{},
|
||||
unittest.Cond("type = ?", issues_model.CommentTypeComment))
|
||||
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
||||
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
|
||||
session := loginUser(t, repoOwner.Name)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/%d/comments",
|
||||
repoOwner.Name, repo.Name, issue.Index)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var comments []*api.Comment
|
||||
DecodeJSON(t, resp, &comments)
|
||||
expectedCount := unittest.GetCount(t, &issues_model.Comment{IssueID: issue.ID},
|
||||
unittest.Cond("type = ?", issues_model.CommentTypeComment))
|
||||
assert.EqualValues(t, expectedCount, len(comments))
|
||||
}
|
||||
|
||||
func TestAPICreateComment(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
const commentBody = "Comment body"
|
||||
|
||||
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
||||
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
|
||||
session := loginUser(t, repoOwner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/comments?token=%s",
|
||||
repoOwner.Name, repo.Name, issue.Index, token)
|
||||
req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
|
||||
"body": commentBody,
|
||||
})
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
var updatedComment api.Comment
|
||||
DecodeJSON(t, resp, &updatedComment)
|
||||
assert.EqualValues(t, commentBody, updatedComment.Body)
|
||||
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: updatedComment.ID, IssueID: issue.ID, Content: commentBody})
|
||||
}
|
||||
|
||||
func TestAPIGetComment(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 2})
|
||||
assert.NoError(t, comment.LoadIssue())
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: comment.Issue.RepoID})
|
||||
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
|
||||
session := loginUser(t, repoOwner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/comments/%d", repoOwner.Name, repo.Name, comment.ID)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/comments/%d?token=%s", repoOwner.Name, repo.Name, comment.ID, token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var apiComment api.Comment
|
||||
DecodeJSON(t, resp, &apiComment)
|
||||
|
||||
assert.NoError(t, comment.LoadPoster())
|
||||
expect := convert.ToComment(comment)
|
||||
|
||||
assert.Equal(t, expect.ID, apiComment.ID)
|
||||
assert.Equal(t, expect.Poster.FullName, apiComment.Poster.FullName)
|
||||
assert.Equal(t, expect.Body, apiComment.Body)
|
||||
assert.Equal(t, expect.Created.Unix(), apiComment.Created.Unix())
|
||||
}
|
||||
|
||||
func TestAPIEditComment(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
const newCommentBody = "This is the new comment body"
|
||||
|
||||
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{},
|
||||
unittest.Cond("type = ?", issues_model.CommentTypeComment))
|
||||
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
||||
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
|
||||
session := loginUser(t, repoOwner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d?token=%s",
|
||||
repoOwner.Name, repo.Name, comment.ID, token)
|
||||
req := NewRequestWithValues(t, "PATCH", urlStr, map[string]string{
|
||||
"body": newCommentBody,
|
||||
})
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var updatedComment api.Comment
|
||||
DecodeJSON(t, resp, &updatedComment)
|
||||
assert.EqualValues(t, comment.ID, updatedComment.ID)
|
||||
assert.EqualValues(t, newCommentBody, updatedComment.Body)
|
||||
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: comment.ID, IssueID: issue.ID, Content: newCommentBody})
|
||||
}
|
||||
|
||||
func TestAPIDeleteComment(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{},
|
||||
unittest.Cond("type = ?", issues_model.CommentTypeComment))
|
||||
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
||||
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
|
||||
session := loginUser(t, repoOwner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/comments/%d?token=%s",
|
||||
repoOwner.Name, repo.Name, comment.ID, token)
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
unittest.AssertNotExistsBean(t, &issues_model.Comment{ID: comment.ID})
|
||||
}
|
||||
|
||||
func TestAPIListIssueTimeline(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
// load comment
|
||||
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
||||
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
|
||||
// make request
|
||||
session := loginUser(t, repoOwner.Name)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/%d/timeline",
|
||||
repoOwner.Name, repo.Name, issue.Index)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// check if lens of list returned by API and
|
||||
// lists extracted directly from DB are the same
|
||||
var comments []*api.TimelineComment
|
||||
DecodeJSON(t, resp, &comments)
|
||||
expectedCount := unittest.GetCount(t, &issues_model.Comment{IssueID: issue.ID})
|
||||
assert.EqualValues(t, expectedCount, len(comments))
|
||||
}
|
19
tests/integration/api_fork_test.go
Normal file
19
tests/integration/api_fork_test.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2017 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
)
|
||||
|
||||
func TestCreateForkNoLogin(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/repos/user2/repo1/forks", &api.CreateForkOption{})
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
}
|
264
tests/integration/api_gpg_keys_test.go
Normal file
264
tests/integration/api_gpg_keys_test.go
Normal file
|
@ -0,0 +1,264 @@
|
|||
// Copyright 2017 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type makeRequestFunc func(testing.TB, *http.Request, int) *httptest.ResponseRecorder
|
||||
|
||||
func TestGPGKeys(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
session := loginUser(t, "user2")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
tt := []struct {
|
||||
name string
|
||||
makeRequest makeRequestFunc
|
||||
token string
|
||||
results []int
|
||||
}{
|
||||
{
|
||||
name: "NoLogin", makeRequest: MakeRequest, token: "",
|
||||
results: []int{http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized},
|
||||
},
|
||||
{
|
||||
name: "LoggedAsUser2", makeRequest: session.MakeRequest, token: token,
|
||||
results: []int{http.StatusOK, http.StatusOK, http.StatusNotFound, http.StatusNoContent, http.StatusUnprocessableEntity, http.StatusNotFound, http.StatusCreated, http.StatusNotFound, http.StatusCreated},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tt {
|
||||
// Basic test on result code
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Run("ViewOwnGPGKeys", func(t *testing.T) {
|
||||
testViewOwnGPGKeys(t, tc.makeRequest, tc.token, tc.results[0])
|
||||
})
|
||||
t.Run("ViewGPGKeys", func(t *testing.T) {
|
||||
testViewGPGKeys(t, tc.makeRequest, tc.token, tc.results[1])
|
||||
})
|
||||
t.Run("GetGPGKey", func(t *testing.T) {
|
||||
testGetGPGKey(t, tc.makeRequest, tc.token, tc.results[2])
|
||||
})
|
||||
t.Run("DeleteGPGKey", func(t *testing.T) {
|
||||
testDeleteGPGKey(t, tc.makeRequest, tc.token, tc.results[3])
|
||||
})
|
||||
|
||||
t.Run("CreateInvalidGPGKey", func(t *testing.T) {
|
||||
testCreateInvalidGPGKey(t, tc.makeRequest, tc.token, tc.results[4])
|
||||
})
|
||||
t.Run("CreateNoneRegistredEmailGPGKey", func(t *testing.T) {
|
||||
testCreateNoneRegistredEmailGPGKey(t, tc.makeRequest, tc.token, tc.results[5])
|
||||
})
|
||||
t.Run("CreateValidGPGKey", func(t *testing.T) {
|
||||
testCreateValidGPGKey(t, tc.makeRequest, tc.token, tc.results[6])
|
||||
})
|
||||
t.Run("CreateValidSecondaryEmailGPGKeyNotActivated", func(t *testing.T) {
|
||||
testCreateValidSecondaryEmailGPGKey(t, tc.makeRequest, tc.token, tc.results[7])
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Check state after basic add
|
||||
t.Run("CheckState", func(t *testing.T) {
|
||||
var keys []*api.GPGKey
|
||||
|
||||
req := NewRequest(t, "GET", "/api/v1/user/gpg_keys?token="+token) // GET all keys
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &keys)
|
||||
assert.Len(t, keys, 1)
|
||||
|
||||
primaryKey1 := keys[0] // Primary key 1
|
||||
assert.EqualValues(t, "38EA3BCED732982C", primaryKey1.KeyID)
|
||||
assert.Len(t, primaryKey1.Emails, 1)
|
||||
assert.EqualValues(t, "user2@example.com", primaryKey1.Emails[0].Email)
|
||||
assert.True(t, primaryKey1.Emails[0].Verified)
|
||||
|
||||
subKey := primaryKey1.SubsKey[0] // Subkey of 38EA3BCED732982C
|
||||
assert.EqualValues(t, "70D7C694D17D03AD", subKey.KeyID)
|
||||
assert.Empty(t, subKey.Emails)
|
||||
|
||||
var key api.GPGKey
|
||||
req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(primaryKey1.ID, 10)+"?token="+token) // Primary key 1
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &key)
|
||||
assert.EqualValues(t, "38EA3BCED732982C", key.KeyID)
|
||||
assert.Len(t, key.Emails, 1)
|
||||
assert.EqualValues(t, "user2@example.com", key.Emails[0].Email)
|
||||
assert.True(t, key.Emails[0].Verified)
|
||||
|
||||
req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(subKey.ID, 10)+"?token="+token) // Subkey of 38EA3BCED732982C
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &key)
|
||||
assert.EqualValues(t, "70D7C694D17D03AD", key.KeyID)
|
||||
assert.Empty(t, key.Emails)
|
||||
})
|
||||
|
||||
// Check state after basic add
|
||||
t.Run("CheckCommits", func(t *testing.T) {
|
||||
t.Run("NotSigned", func(t *testing.T) {
|
||||
var branch api.Branch
|
||||
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/not-signed?token="+token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &branch)
|
||||
assert.False(t, branch.Commit.Verification.Verified)
|
||||
})
|
||||
|
||||
t.Run("SignedWithNotValidatedEmail", func(t *testing.T) {
|
||||
var branch api.Branch
|
||||
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/good-sign-not-yet-validated?token="+token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &branch)
|
||||
assert.False(t, branch.Commit.Verification.Verified)
|
||||
})
|
||||
|
||||
t.Run("SignedWithValidEmail", func(t *testing.T) {
|
||||
var branch api.Branch
|
||||
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/good-sign?token="+token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &branch)
|
||||
assert.True(t, branch.Commit.Verification.Verified)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func testViewOwnGPGKeys(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
req := NewRequest(t, "GET", "/api/v1/user/gpg_keys?token="+token)
|
||||
makeRequest(t, req, expected)
|
||||
}
|
||||
|
||||
func testViewGPGKeys(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
req := NewRequest(t, "GET", "/api/v1/users/user2/gpg_keys?token="+token)
|
||||
makeRequest(t, req, expected)
|
||||
}
|
||||
|
||||
func testGetGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
req := NewRequest(t, "GET", "/api/v1/user/gpg_keys/1?token="+token)
|
||||
makeRequest(t, req, expected)
|
||||
}
|
||||
|
||||
func testDeleteGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
req := NewRequest(t, "DELETE", "/api/v1/user/gpg_keys/1?token="+token)
|
||||
makeRequest(t, req, expected)
|
||||
}
|
||||
|
||||
func testCreateGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int, publicKey string) {
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/user/gpg_keys?token="+token, api.CreateGPGKeyOption{
|
||||
ArmoredKey: publicKey,
|
||||
})
|
||||
makeRequest(t, req, expected)
|
||||
}
|
||||
|
||||
func testCreateInvalidGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
testCreateGPGKey(t, makeRequest, token, expected, "invalid_key")
|
||||
}
|
||||
|
||||
func testCreateNoneRegistredEmailGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
testCreateGPGKey(t, makeRequest, token, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQENBFmGUygBCACjCNbKvMGgp0fd5vyFW9olE1CLCSyyF9gQN2hSuzmZLuAZF2Kh
|
||||
dCMCG2T1UwzUB/yWUFWJ2BtCwSjuaRv+cGohqEy6bhEBV90peGA33lHfjx7wP25O
|
||||
7moAphDOTZtDj1AZfCh/PTcJut8Lc0eRDMhNyp/bYtO7SHNT1Hr6rrCV/xEtSAvR
|
||||
3b148/tmIBiSadaLwc558KU3ucjnW5RVGins3AjBZ+TuT4XXVH/oeLSeXPSJ5rt1
|
||||
rHwaseslMqZ4AbvwFLx5qn1OC9rEQv/F548QsA8m0IntLjoPon+6wcubA9Gra21c
|
||||
Fp6aRYl9x7fiqXDLg8i3s2nKdV7+e6as6Tp9ABEBAAG0FG5vdGtub3duQGV4YW1w
|
||||
bGUuY29tiQEcBBABAgAGBQJZhlMoAAoJEC8+pvYULDtte/wH/2JNrhmHwDY+hMj0
|
||||
batIK4HICnkKxjIgbha80P2Ao08NkzSge58fsxiKDFYAQjHui+ZAw4dq79Ax9AOO
|
||||
Iv2GS9+DUfWhrb6RF+vNuJldFzcI0rTW/z2q+XGKrUCwN3khJY5XngHfQQrdBtMK
|
||||
qsoUXz/5B8g422RTbo/SdPsyYAV6HeLLeV3rdgjI1fpaW0seZKHeTXQb/HvNeuPg
|
||||
qz+XV1g6Gdqa1RjDOaX7A8elVKxrYq3LBtc93FW+grBde8n7JL0zPM3DY+vJ0IJZ
|
||||
INx/MmBfmtCq05FqNclvU+sj2R3N1JJOtBOjZrJHQbJhzoILou8AkxeX1A+q9OAz
|
||||
1geiY5E=
|
||||
=TkP3
|
||||
-----END PGP PUBLIC KEY BLOCK-----`)
|
||||
}
|
||||
|
||||
func testCreateValidGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
// User2 <user2@example.com> //primary & activated
|
||||
testCreateGPGKey(t, makeRequest, token, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQENBFmGVsMBCACuxgZ7W7rI9xN08Y4M7B8yx/6/I4Slm94+wXf8YNRvAyqj30dW
|
||||
VJhyBcnfNRDLKSQp5o/hhfDkCgdqBjLa1PnHlGS3PXJc0hP/FyYPD2BFvNMPpCYS
|
||||
eu3T1qKSNXm6X0XOWD2LIrdiDC8HaI9FqZVMI/srMK2CF8XCL2m67W1FuoPlWzod
|
||||
5ORy0IZB7spoF0xihmcgnEGElRmdo5w/vkGH8U7Zyn9Eb57UVFeafgeskf4wqB23
|
||||
BjbMdW2YaB+yzMRwYgOnD5lnBD4uqSmvjaV9C0kxn7x+oJkkiRV8/z1cNcO+BaeQ
|
||||
Akh/yTTeTzYGSc/ZOqCX1O+NOPgSeixVlqenABEBAAG0GVVzZXIyIDx1c2VyMkBl
|
||||
eGFtcGxlLmNvbT6JAVQEEwEIAD4WIQRXgbSh0TtGbgRd7XI46jvO1zKYLAUCWYZW
|
||||
wwIbAwUJA8JnAAULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgAAKCRA46jvO1zKYLF/e
|
||||
B/91wm2KLMIQBZBA9WA2/+9rQWTo9EqgYrXN60rEzX3cYJWXZiE4DrKR1oWDGNLi
|
||||
KXOCW62snvJldolBqq0ZqaKvPKzl0Y5TRqbYEc9AjUSqgRin1b+G2DevLGT4ibq+
|
||||
7ocQvz0XkASEUAgHahp0Ubiiib1521WwT/duL+AG8Gg0+DK09RfV3eX5/EOkQCKv
|
||||
8cutqgsd2Smz40A8wXuJkRcipZBtrB/GkUaZ/eJdwEeSYZjEA9GWF61LJT2stvRN
|
||||
HCk7C3z3pVEek1PluiFs/4VN8BG8yDzW4c0tLty4Fj3VwPqwIbB5AJbquVfhQCb4
|
||||
Eep2lm3Lc9b1OwO5N3coPJkouQENBFmGVsMBCADAGba2L6NCOE1i3WIP6CPzbdOo
|
||||
N3gdTfTgccAx9fNeon9jor+3tgEjlo9/6cXiRoksOV6W4wFab/ZwWgwN6JO4CGvZ
|
||||
Wi7EQwMMMp1E36YTojKQJrcA9UvMnTHulqQQ88F5E845DhzFQM3erv42QZZMBAX3
|
||||
kXCgy1GNFocl6tLUvJdEqs+VcJGGANMpmzE4WLa8KhSYnxipwuQ62JBy9R+cHyKT
|
||||
OARk8znRqSu5bT3LtlrZ/HXu+6Oy4+2uCdNzZIh5J5tPS7CPA6ptl88iGVBte/CJ
|
||||
7cjgJWSQqeYp2Y5QvsWAivkQ4Ww9plHbbwV0A2eaHsjjWzlUl3HoJ/snMOhBABEB
|
||||
AAGJATwEGAEIACYWIQRXgbSh0TtGbgRd7XI46jvO1zKYLAUCWYZWwwIbDAUJA8Jn
|
||||
AAAKCRA46jvO1zKYLBwLCACQOpeRVrwIKVaWcPMYjVHHJsGscaLKpgpARAUgbiG6
|
||||
Cbc2WI8Sm3fRwrY0VAfN+u9QwrtvxANcyB3vTgTzw7FimfhOimxiTSO8HQCfjDZF
|
||||
Xly8rq+Fua7+ClWUpy21IekW41VvZYjH2sL6EVP+UcEOaGAyN53XfhaRVZPhNtZN
|
||||
NKAE9N5EG3rbsZ33LzJj40rEKlzFSseAAPft8qA3IXjzFBx+PQXHMpNCagL79he6
|
||||
lqockTJ+oPmta4CF/J0U5LUr1tOZXheL3TP6m8d08gDrtn0YuGOPk87i9sJz+jR9
|
||||
uy6MA3VSB99SK9ducGmE1Jv8mcziREroz2TEGr0zPs6h
|
||||
=J59D
|
||||
-----END PGP PUBLIC KEY BLOCK-----`)
|
||||
}
|
||||
|
||||
func testCreateValidSecondaryEmailGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
// User2 <user2-2@example.com> //secondary and not activated
|
||||
testCreateGPGKey(t, makeRequest, token, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQGNBGC2K2cBDAC1+Xgk+8UfhASVgRngQi4rnQ8k0t+bWsBz4Czd26+cxVDRwlTT
|
||||
8PALdrbrY/e9iXjcVcZ8Npo4UYe7/LfnL57dc7tgbenRGYYrWyVoNNv58BVw4xCY
|
||||
RmgvdHWIIPGuz3aME0smHxbJ2KewYTqjTPuVKF/wrHTwCpVWdjYKC5KDo3yx0mro
|
||||
xf9vOJOnkWNMiEw7TiZfkrbUqxyA53BVsSNKRX5C3b4FJcVT7eiAq7sDAaFxjEHy
|
||||
ahZslmvg7XZxWzSVzxDNesR7f4xuop8HBjzaluJoVuwiyWculTvz1b6hyHVQr+ad
|
||||
h8JGjj1tySI65OTFsTuptsfHXjtjl/NR4P6BXkf+FVwweaTQaEzpHkv0m9b9pY43
|
||||
CY/8XtS4uNPermiLG/Z0BB1eOCdoOQVHpjOa55IXQWhxXB6NZVyowiUbrR7jLDQy
|
||||
5JP7D1HmErTR8JRm3VDqGbSaCgugRgFX+lb/fpgFp9k02OeK+JQudolZOt1mVk+T
|
||||
C4xmEWxfiH15/JMAEQEAAbQbdXNlcjIgPHVzZXIyLTJAZXhhbXBsZS5jb20+iQHU
|
||||
BBMBCAA+FiEEB/Y4DM3Ba2H9iXmlPO9G70C+/D4FAmC2K2cCGwMFCQPCZwAFCwkI
|
||||
BwIGFQoJCAsCBBYCAwECHgECF4AACgkQPO9G70C+/D59/Av/XZIhCH4X2FpxCO3d
|
||||
oCa+sbYkBL5xeUoPfAx5ThXzqL/tllO88TKTMEGZF3k5pocXWH0xmhqlvDTcdb0i
|
||||
W3O0CN8FLmuotU51c0JC1mt9zwJP9PeJNyqxrMm01Yzj55z/Dz3QHSTlDjrWTWjn
|
||||
YBqDf2HfdM177oydfSYmevZni1aDmBalWpFPRvqISCO7uFnvg1hJQ5mD/0qie663
|
||||
QJ8LAAANg32H9DyPnYi9wU62WX0DMUVTjKctT3cnYCbirjjJ7ZlCCm+cf61CRX1B
|
||||
E1Ng/Ef3ZcUfXWitZSjfET/pKEMSNjsQawFpZ/LPCBl+UPHzaTPAASeGJvcbZ3py
|
||||
wZQLQc1MCu2hmMBQ8zHQTdS2Pp0RISxCQLYvVQL6DrcJDNiSqn9p9RQt5c5r5Pjx
|
||||
80BIPcjj3glOVP7PYE2azQAkt6reEjhimwCfjeDpiPnkBTY7Av2jCcUFhhemDY/j
|
||||
TRXK1paLphhJ36zC22SeHGxNNakjjuUakqB85DEUeoWuVm6ouQGNBGC2K2cBDADx
|
||||
G2rIAgMjdPtofhkEZXwv6zdNwmYOlIIM+59bam9Ep/vFq8F5f+xldevm5dvM8SeR
|
||||
pNwDGSOUf5OKBWBdsJFhlYBl7+EcKd/Tent/XS6JoA9ffF33b+r04L543+ykiKON
|
||||
WYeYi0F4WwYTIQgqZHJze1sPVkYGR5F0bL8PAcLuwd5dzZVi/q2HakrGdg29N8oY
|
||||
b/XnoR7FflPrNYdzO6hawi5Inx7KS7aWa0ZkARb0F4HSct+/m6nAZVsoJINLudyQ
|
||||
ut2NWeU8rWIm1hqyIxQFvuQJy46umq++10J/sWA98bkg41Rx+72+eP7DM5v8IgUp
|
||||
clJsfljRXIBWbmRAVZvtNI7PX9fwMMhf4M7wHO7G2WV39o1exKps5xFFcn8PUQiX
|
||||
jCSR81M145CgCdmLUR1y0pdkN/WIqjXBhkPIvO2dxEcodMNHb1aUUuUOnww6+xIP
|
||||
8rGVw+a2DUiALc8Qr5RP21AYKRctfiwhSQh2KODveMtyLI3U9C/eLRPp+QM3XB8A
|
||||
EQEAAYkBvAQYAQgAJhYhBAf2OAzNwWth/Yl5pTzvRu9Avvw+BQJgtitnAhsMBQkD
|
||||
wmcAAAoJEDzvRu9Avvw+3FcMAJBwupyJ4zwQFxTJ5BkDlusG3U2FXEf3bDrXhvNd
|
||||
qi8eS8Vo/vRiH/w/my5JFpz1o2tJToryF71D+uF5DTItalKquhsQ9reAEmXggqOh
|
||||
9Jd9mWJIEEWcRORiLNDKENKvE8bouw4U4hRaSF0IaGzAe5mO+oOvwal8L97wFxrZ
|
||||
4leM1GzkopiuNfbkkBBw2KJcMjYBHzzXSCALnVwhjbgkBEWPIg38APT3cr9KfnMM
|
||||
q8+tvsGLj4piAl3Lww7+GhSsDOUXH8btR41BSAQDrbO5q6oi/h4nuxoNmQIDW/Ug
|
||||
s+dd5hnY2FtHRjb4FCR9kAjdTE6stc8wzohWfbg1N+12TTA2ylByAumICVXixavH
|
||||
RJ7l0OiWJk388qw9mqh3k8HcBxL7OfDlFC9oPmCS0iYiIwW/Yc80kBhoxcvl/Xa7
|
||||
mIMMn8taHIaQO7v9ln2EVQYTzbNCmwTw9ovTM0j/Pbkg2EftfP1TCoxQHvBnsCED
|
||||
6qgtsUdi5eviONRkBgeZtN3oxA==
|
||||
=MgDv
|
||||
-----END PGP PUBLIC KEY BLOCK-----`)
|
||||
}
|
464
tests/integration/api_helper_for_declarative_test.go
Normal file
464
tests/integration/api_helper_for_declarative_test.go
Normal file
|
@ -0,0 +1,464 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/queue"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/services/forms"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type APITestContext struct {
|
||||
Reponame string
|
||||
Session *TestSession
|
||||
Token string
|
||||
Username string
|
||||
ExpectedCode int
|
||||
}
|
||||
|
||||
func NewAPITestContext(t *testing.T, username, reponame string) APITestContext {
|
||||
session := loginUser(t, username)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
return APITestContext{
|
||||
Session: session,
|
||||
Token: token,
|
||||
Username: username,
|
||||
Reponame: reponame,
|
||||
}
|
||||
}
|
||||
|
||||
func (ctx APITestContext) GitPath() string {
|
||||
return fmt.Sprintf("%s/%s.git", ctx.Username, ctx.Reponame)
|
||||
}
|
||||
|
||||
func doAPICreateRepository(ctx APITestContext, empty bool, callback ...func(*testing.T, api.Repository)) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
createRepoOption := &api.CreateRepoOption{
|
||||
AutoInit: !empty,
|
||||
Description: "Temporary repo",
|
||||
Name: ctx.Reponame,
|
||||
Private: true,
|
||||
Template: true,
|
||||
Gitignores: "",
|
||||
License: "WTFPL",
|
||||
Readme: "Default",
|
||||
}
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos?token="+ctx.Token, createRepoOption)
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
resp := ctx.Session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
var repository api.Repository
|
||||
DecodeJSON(t, resp, &repository)
|
||||
if len(callback) > 0 {
|
||||
callback[0](t, repository)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func doAPIEditRepository(ctx APITestContext, editRepoOption *api.EditRepoOption, callback ...func(*testing.T, api.Repository)) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
req := NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame), ctx.Token), editRepoOption)
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
resp := ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var repository api.Repository
|
||||
DecodeJSON(t, resp, &repository)
|
||||
if len(callback) > 0 {
|
||||
callback[0](t, repository)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func doAPIAddCollaborator(ctx APITestContext, username string, mode perm.AccessMode) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
permission := "read"
|
||||
|
||||
if mode == perm.AccessModeAdmin {
|
||||
permission = "admin"
|
||||
} else if mode > perm.AccessModeRead {
|
||||
permission = "write"
|
||||
}
|
||||
addCollaboratorOption := &api.AddCollaboratorOption{
|
||||
Permission: &permission,
|
||||
}
|
||||
req := NewRequestWithJSON(t, "PUT", fmt.Sprintf("/api/v1/repos/%s/%s/collaborators/%s?token=%s", ctx.Username, ctx.Reponame, username, ctx.Token), addCollaboratorOption)
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
ctx.Session.MakeRequest(t, req, http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
|
||||
func doAPIForkRepository(ctx APITestContext, username string, callback ...func(*testing.T, api.Repository)) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
createForkOption := &api.CreateForkOption{}
|
||||
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/forks?token=%s", username, ctx.Reponame, ctx.Token), createForkOption)
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
resp := ctx.Session.MakeRequest(t, req, http.StatusAccepted)
|
||||
var repository api.Repository
|
||||
DecodeJSON(t, resp, &repository)
|
||||
if len(callback) > 0 {
|
||||
callback[0](t, repository)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func doAPIGetRepository(ctx APITestContext, callback ...func(*testing.T, api.Repository)) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", ctx.Username, ctx.Reponame, ctx.Token)
|
||||
|
||||
req := NewRequest(t, "GET", urlStr)
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
resp := ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var repository api.Repository
|
||||
DecodeJSON(t, resp, &repository)
|
||||
if len(callback) > 0 {
|
||||
callback[0](t, repository)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func doAPIDeleteRepository(ctx APITestContext) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", ctx.Username, ctx.Reponame, ctx.Token)
|
||||
|
||||
req := NewRequest(t, "DELETE", urlStr)
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
ctx.Session.MakeRequest(t, req, http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
|
||||
func doAPICreateUserKey(ctx APITestContext, keyname, keyFile string, callback ...func(*testing.T, api.PublicKey)) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
urlStr := fmt.Sprintf("/api/v1/user/keys?token=%s", ctx.Token)
|
||||
|
||||
dataPubKey, err := os.ReadFile(keyFile + ".pub")
|
||||
assert.NoError(t, err)
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateKeyOption{
|
||||
Title: keyname,
|
||||
Key: string(dataPubKey),
|
||||
})
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
resp := ctx.Session.MakeRequest(t, req, http.StatusCreated)
|
||||
var publicKey api.PublicKey
|
||||
DecodeJSON(t, resp, &publicKey)
|
||||
if len(callback) > 0 {
|
||||
callback[0](t, publicKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func doAPIDeleteUserKey(ctx APITestContext, keyID int64) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
urlStr := fmt.Sprintf("/api/v1/user/keys/%d?token=%s", keyID, ctx.Token)
|
||||
|
||||
req := NewRequest(t, "DELETE", urlStr)
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
ctx.Session.MakeRequest(t, req, http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
|
||||
func doAPICreateDeployKey(ctx APITestContext, keyname, keyFile string, readOnly bool) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/keys?token=%s", ctx.Username, ctx.Reponame, ctx.Token)
|
||||
|
||||
dataPubKey, err := os.ReadFile(keyFile + ".pub")
|
||||
assert.NoError(t, err)
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, api.CreateKeyOption{
|
||||
Title: keyname,
|
||||
Key: string(dataPubKey),
|
||||
ReadOnly: readOnly,
|
||||
})
|
||||
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
ctx.Session.MakeRequest(t, req, http.StatusCreated)
|
||||
}
|
||||
}
|
||||
|
||||
func doAPICreatePullRequest(ctx APITestContext, owner, repo, baseBranch, headBranch string) func(*testing.T) (api.PullRequest, error) {
|
||||
return func(t *testing.T) (api.PullRequest, error) {
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/pulls?token=%s",
|
||||
owner, repo, ctx.Token)
|
||||
req := NewRequestWithJSON(t, http.MethodPost, urlStr, &api.CreatePullRequestOption{
|
||||
Head: headBranch,
|
||||
Base: baseBranch,
|
||||
Title: fmt.Sprintf("create a pr from %s to %s", headBranch, baseBranch),
|
||||
})
|
||||
|
||||
expected := http.StatusCreated
|
||||
if ctx.ExpectedCode != 0 {
|
||||
expected = ctx.ExpectedCode
|
||||
}
|
||||
resp := ctx.Session.MakeRequest(t, req, expected)
|
||||
|
||||
decoder := json.NewDecoder(resp.Body)
|
||||
pr := api.PullRequest{}
|
||||
err := decoder.Decode(&pr)
|
||||
return pr, err
|
||||
}
|
||||
}
|
||||
|
||||
func doAPIGetPullRequest(ctx APITestContext, owner, repo string, index int64) func(*testing.T) (api.PullRequest, error) {
|
||||
return func(t *testing.T) (api.PullRequest, error) {
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d?token=%s",
|
||||
owner, repo, index, ctx.Token)
|
||||
req := NewRequest(t, http.MethodGet, urlStr)
|
||||
|
||||
expected := http.StatusOK
|
||||
if ctx.ExpectedCode != 0 {
|
||||
expected = ctx.ExpectedCode
|
||||
}
|
||||
resp := ctx.Session.MakeRequest(t, req, expected)
|
||||
|
||||
decoder := json.NewDecoder(resp.Body)
|
||||
pr := api.PullRequest{}
|
||||
err := decoder.Decode(&pr)
|
||||
return pr, err
|
||||
}
|
||||
}
|
||||
|
||||
func doAPIMergePullRequest(ctx APITestContext, owner, repo string, index int64) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/merge?token=%s",
|
||||
owner, repo, index, ctx.Token)
|
||||
|
||||
var req *http.Request
|
||||
var resp *httptest.ResponseRecorder
|
||||
|
||||
for i := 0; i < 6; i++ {
|
||||
req = NewRequestWithJSON(t, http.MethodPost, urlStr, &forms.MergePullRequestForm{
|
||||
MergeMessageField: "doAPIMergePullRequest Merge",
|
||||
Do: string(repo_model.MergeStyleMerge),
|
||||
})
|
||||
|
||||
resp = ctx.Session.MakeRequest(t, req, NoExpectedStatus)
|
||||
|
||||
if resp.Code != http.StatusMethodNotAllowed {
|
||||
break
|
||||
}
|
||||
err := api.APIError{}
|
||||
DecodeJSON(t, resp, &err)
|
||||
assert.EqualValues(t, "Please try again later", err.Message)
|
||||
queue.GetManager().FlushAll(context.Background(), 5*time.Second)
|
||||
<-time.After(1 * time.Second)
|
||||
}
|
||||
|
||||
expected := ctx.ExpectedCode
|
||||
if expected == 0 {
|
||||
expected = http.StatusOK
|
||||
}
|
||||
|
||||
if !assert.EqualValues(t, expected, resp.Code,
|
||||
"Request: %s %s", req.Method, req.URL.String()) {
|
||||
logUnexpectedResponse(t, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func doAPIManuallyMergePullRequest(ctx APITestContext, owner, repo, commitID string, index int64) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/merge?token=%s",
|
||||
owner, repo, index, ctx.Token)
|
||||
req := NewRequestWithJSON(t, http.MethodPost, urlStr, &forms.MergePullRequestForm{
|
||||
Do: string(repo_model.MergeStyleManuallyMerged),
|
||||
MergeCommitID: commitID,
|
||||
})
|
||||
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
func doAPIAutoMergePullRequest(ctx APITestContext, owner, repo string, index int64) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/merge?token=%s",
|
||||
owner, repo, index, ctx.Token)
|
||||
req := NewRequestWithJSON(t, http.MethodPost, urlStr, &forms.MergePullRequestForm{
|
||||
MergeMessageField: "doAPIMergePullRequest Merge",
|
||||
Do: string(repo_model.MergeStyleMerge),
|
||||
MergeWhenChecksSucceed: true,
|
||||
})
|
||||
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
ctx.Session.MakeRequest(t, req, 200)
|
||||
}
|
||||
}
|
||||
|
||||
func doAPICancelAutoMergePullRequest(ctx APITestContext, owner, repo string, index int64) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/merge?token=%s",
|
||||
owner, repo, index, ctx.Token)
|
||||
req := NewRequest(t, http.MethodDelete, urlStr)
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
ctx.Session.MakeRequest(t, req, 204)
|
||||
}
|
||||
}
|
||||
|
||||
func doAPIGetBranch(ctx APITestContext, branch string, callback ...func(*testing.T, api.Branch)) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/branches/%s?token=%s", ctx.Username, ctx.Reponame, branch, ctx.Token)
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
resp := ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var branch api.Branch
|
||||
DecodeJSON(t, resp, &branch)
|
||||
if len(callback) > 0 {
|
||||
callback[0](t, branch)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func doAPICreateFile(ctx APITestContext, treepath string, options *api.CreateFileOptions, callback ...func(*testing.T, api.FileResponse)) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
url := fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", ctx.Username, ctx.Reponame, treepath, ctx.Token)
|
||||
req := NewRequestWithJSON(t, "POST", url, &options)
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
resp := ctx.Session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
var contents api.FileResponse
|
||||
DecodeJSON(t, resp, &contents)
|
||||
if len(callback) > 0 {
|
||||
callback[0](t, contents)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func doAPICreateOrganization(ctx APITestContext, options *api.CreateOrgOption, callback ...func(*testing.T, api.Organization)) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
url := fmt.Sprintf("/api/v1/orgs?token=%s", ctx.Token)
|
||||
|
||||
req := NewRequestWithJSON(t, "POST", url, &options)
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
resp := ctx.Session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
var contents api.Organization
|
||||
DecodeJSON(t, resp, &contents)
|
||||
if len(callback) > 0 {
|
||||
callback[0](t, contents)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func doAPICreateOrganizationRepository(ctx APITestContext, orgName string, options *api.CreateRepoOption, callback ...func(*testing.T, api.Repository)) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
url := fmt.Sprintf("/api/v1/orgs/%s/repos?token=%s", orgName, ctx.Token)
|
||||
|
||||
req := NewRequestWithJSON(t, "POST", url, &options)
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
resp := ctx.Session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
var contents api.Repository
|
||||
DecodeJSON(t, resp, &contents)
|
||||
if len(callback) > 0 {
|
||||
callback[0](t, contents)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func doAPICreateOrganizationTeam(ctx APITestContext, orgName string, options *api.CreateTeamOption, callback ...func(*testing.T, api.Team)) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
url := fmt.Sprintf("/api/v1/orgs/%s/teams?token=%s", orgName, ctx.Token)
|
||||
|
||||
req := NewRequestWithJSON(t, "POST", url, &options)
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
resp := ctx.Session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
var contents api.Team
|
||||
DecodeJSON(t, resp, &contents)
|
||||
if len(callback) > 0 {
|
||||
callback[0](t, contents)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func doAPIAddUserToOrganizationTeam(ctx APITestContext, teamID int64, username string) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
url := fmt.Sprintf("/api/v1/teams/%d/members/%s?token=%s", teamID, username, ctx.Token)
|
||||
|
||||
req := NewRequest(t, "PUT", url)
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
ctx.Session.MakeRequest(t, req, http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
|
||||
func doAPIAddRepoToOrganizationTeam(ctx APITestContext, teamID int64, orgName, repoName string) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
url := fmt.Sprintf("/api/v1/teams/%d/repos/%s/%s?token=%s", teamID, orgName, repoName, ctx.Token)
|
||||
|
||||
req := NewRequest(t, "PUT", url)
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
ctx.Session.MakeRequest(t, req, http.StatusNoContent)
|
||||
}
|
||||
}
|
138
tests/integration/api_httpsig_test.go
Normal file
138
tests/integration/api_httpsig_test.go
Normal file
|
@ -0,0 +1,138 @@
|
|||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/go-fed/httpsig"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
const (
|
||||
httpsigPrivateKey = `-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
|
||||
NhAAAAAwEAAQAAAQEAqjmQeb5Eb1xV7qbNf9ErQ0XRvKZWzUsLFhJzZz+Ab7q8WtPs91vQ
|
||||
fBiypw4i8OTG6WzDcgZaV8Ndxn7iHnIstdA1k89MVG4stydymmwmk9+mrCMNsu5OmdIy9F
|
||||
AZ61RDcKuf5VG2WKkmeK0VO+OMJIYfE1C6czNeJ6UAmcIOmhGxvjMI83XUO9n0ftwTwayp
|
||||
+XU5prvKx/fTvlPjbraPNU4OzwPjVLqXBzpoXYhBquPaZYFRVyvfFZLObYsmy+BrsxcloM
|
||||
l+9w4P0ATJ9njB7dRDL+RrN4uhhYSihqOK4w4vaiOj1+aA0eC0zXunEfLXfGIVQ/FhWcCy
|
||||
5f72mMiKnQAAA9AxSmzFMUpsxQAAAAdzc2gtcnNhAAABAQCqOZB5vkRvXFXups1/0StDRd
|
||||
G8plbNSwsWEnNnP4Bvurxa0+z3W9B8GLKnDiLw5MbpbMNyBlpXw13GfuIeciy10DWTz0xU
|
||||
biy3J3KabCaT36asIw2y7k6Z0jL0UBnrVENwq5/lUbZYqSZ4rRU744wkhh8TULpzM14npQ
|
||||
CZwg6aEbG+MwjzddQ72fR+3BPBrKn5dTmmu8rH99O+U+Nuto81Tg7PA+NUupcHOmhdiEGq
|
||||
49plgVFXK98Vks5tiybL4GuzFyWgyX73Dg/QBMn2eMHt1EMv5Gs3i6GFhKKGo4rjDi9qI6
|
||||
PX5oDR4LTNe6cR8td8YhVD8WFZwLLl/vaYyIqdAAAAAwEAAQAAAQBz+nyBNi2SYir6SxPA
|
||||
flcnoq5gBkUl4ndPNosCUbXEakpi5/mQHzJRGtK+F1efIYCVEdGoIsPy/90onNKbQ9dKmO
|
||||
2oI5kx/U7iCzJ+HCm8nqkEp21x+AP9scWdx+Wg/OxmG8j5iU7f4X+gwOyyvTqCuA78Lgia
|
||||
7Oi9wiJCoIEqXr6dRYGJzfASwKA2dj995HzATexleLSD5fQCmZTF+Vh5OQ5WmE+c53JdZS
|
||||
T3Plie/P/smgSWBtf1fWr6JL2+EBsqQsIK1Jo7r/7rxsz+ILoVfnneNQY4QSa9W+t6ZAI+
|
||||
caSA0Guv7vC92ewjlMVlwKa3XaEjMJb5sFlg1r6TYMwBAAAAgQDQwXvgSXNaSHIeH53/Ab
|
||||
t4BlNibtxK8vY8CZFloAKXkjrivKSlDAmQCM0twXOweX2ScPjE+XlSMV4AUsv/J6XHGHci
|
||||
W3+PGIBfc/fQRBpiyhzkoXYDVrlkSKHffCnAqTUQlYkhr0s7NkZpEeqPE0doAUs4dK3Iqb
|
||||
zdtz8e5BPXZwAAAIEA4U/JskIu5Oge8Is2OLOhlol0EJGw5JGodpFyhbMC+QYK9nYqy7wI
|
||||
a6mZ2EfOjjwIZD/+wYyulw6cRve4zXwgzUEXLIKp8/H3sYvJK2UMeP7y68sQFqGxbm6Rnh
|
||||
tyBBSaJQnOXVOFf9gqZGCyO/J0Illg3AXTuC8KS/cxwasC38EAAACBAMFo/6XQoR6E3ynj
|
||||
VBaz2SilWqQBixUyvcNz8LY73IIDCecoccRMFSEKhWtvlJijxvFbF9M8g9oKAVPuub4V5r
|
||||
CGmwVPEd5yt4C2iyV0PhLp1PA2/i42FpCSnHaz/EXSz6ncTZcOMMuDqUbgUUpQg4VSUDl9
|
||||
fhTNAzWwZoQ91aHdAAAAFHUwMDIyMTQ2QGljdHMtcC1ueC03AQIDBAUG
|
||||
-----END OPENSSH PRIVATE KEY-----`
|
||||
httpsigCertificate = `ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgiR7SU8gmZLhopx4Y03nOXVuAb+4fyMcJYjMGcE1Z2oEAAAADAQABAAABAQCqOZB5vkRvXFXups1/0StDRdG8plbNSwsWEnNnP4Bvurxa0+z3W9B8GLKnDiLw5MbpbMNyBlpXw13GfuIeciy10DWTz0xUbiy3J3KabCaT36asIw2y7k6Z0jL0UBnrVENwq5/lUbZYqSZ4rRU744wkhh8TULpzM14npQCZwg6aEbG+MwjzddQ72fR+3BPBrKn5dTmmu8rH99O+U+Nuto81Tg7PA+NUupcHOmhdiEGq49plgVFXK98Vks5tiybL4GuzFyWgyX73Dg/QBMn2eMHt1EMv5Gs3i6GFhKKGo4rjDi9qI6PX5oDR4LTNe6cR8td8YhVD8WFZwLLl/vaYyIqdAAAAAAAAAAEAAAABAAAABXVzZXIxAAAACQAAAAV1c2VyMQAAAABimoIOAAAAAMCWkRMAAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAABlwAAAAdzc2gtcnNhAAAAAwEAAQAAAYEAm+AwtXTBZyeqV1qOxjMU3Ibc5iR2M3zerGfRQDxUeIozC3xpIvqJbzjDuRapdf8hpxn2xC0GtUusuLIUr4/+Svs1BUnJhF2H9xnK/O0aopS5MpNekUvnBzQdbvO8Ux2xE2mt58giXhkEaXeCEODSqG++OZsA2e40AR/AGRJ4OdDofMvH4vLJAQQc2mKdYpYL8xu+NC+7nsenx1etpsqtEl3gmvqCVI6t9uhVPMvlbGt9h/AN3u7ToF2T3bdk1TZbcdkvR9ljvETIuy32ksAETX8tc7vm30edK+nn/GMeWCgjM+MFm9Uh1NRkvNNJozo5SJy0DkWETTJUsEdfry5VQ3IjqhWqQ0m4/mDlTmsEdEdWqpUiqWZLd9w7jgT8fanuglZyIu2fj8fyqjPjiws5S2P0Uvi28UKQ1nH01UYj/kuakU3BNzN1IqDf3tARP9fjKV/dCBqb1ZAOtyC2GyhGuGzNwEi+woUwq+sTeV0/hqVSb3hSitXHzcfRMRyOK82BAAABlAAAAAxyc2Etc2hhMi01MTIAAAGAMBfgZFvz4BdxriGKYd6eRhMo6hf+I8S9uzNRsflJXHuA+HR9ExIm/Q9JjKmfThQzNyGGBOBILaDU205SAJuG+kk3SieSQDd75ZQd8YmNlCc+516AriOsTiyVCupnf3I2euTjMZqEZbJcBbkBljppTOWQVN7xxE8QakDfGhg0+RjJE9wYOTmkKpDBfII5Nw8V5DoOD7kNEpXYqHdy/8lVxpqUYNIP1J0dNP4f6qBcZcM1PDA12q8zwIGqSNNjf2UXY/Nr8nv9CnK4fB8NDOPKTBa4cm48BGbvM/X0l6dYKswuZ9Np8lw+y6+GxTgznGCrkzMmuEV4FzSq4xHp41H2L2MTwUkwYaeyG1VP6aWkvn6zPkSxaaJDfQX7CAFe17IhIGXR0UPLjKjh35nDLzMWb/W6/W1lK9YkZNHXSf7Z9m9MUAZN7yQgOggGsuYEW4imZxvZizMd+fdDu9mbhr0FDis89I7MSJDnyYRE9FXS7p3QpppBwGcss/9yV3JV3Bjc`
|
||||
)
|
||||
|
||||
func TestHTTPSigPubKey(t *testing.T) {
|
||||
// Add our public key to user1
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
session := loginUser(t, "user1")
|
||||
token := url.QueryEscape(getTokenForLoggedInUser(t, session))
|
||||
keysURL := fmt.Sprintf("/api/v1/user/keys?token=%s", token)
|
||||
keyType := "ssh-rsa"
|
||||
keyContent := "AAAAB3NzaC1yc2EAAAADAQABAAABAQCqOZB5vkRvXFXups1/0StDRdG8plbNSwsWEnNnP4Bvurxa0+z3W9B8GLKnDiLw5MbpbMNyBlpXw13GfuIeciy10DWTz0xUbiy3J3KabCaT36asIw2y7k6Z0jL0UBnrVENwq5/lUbZYqSZ4rRU744wkhh8TULpzM14npQCZwg6aEbG+MwjzddQ72fR+3BPBrKn5dTmmu8rH99O+U+Nuto81Tg7PA+NUupcHOmhdiEGq49plgVFXK98Vks5tiybL4GuzFyWgyX73Dg/QBMn2eMHt1EMv5Gs3i6GFhKKGo4rjDi9qI6PX5oDR4LTNe6cR8td8YhVD8WFZwLLl/vaYyIqd"
|
||||
rawKeyBody := api.CreateKeyOption{
|
||||
Title: "test-key",
|
||||
Key: keyType + " " + keyContent,
|
||||
}
|
||||
req := NewRequestWithJSON(t, "POST", keysURL, rawKeyBody)
|
||||
session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
// parse our private key and create the httpsig request
|
||||
sshSigner, _ := ssh.ParsePrivateKey([]byte(httpsigPrivateKey))
|
||||
keyID := ssh.FingerprintSHA256(sshSigner.PublicKey())
|
||||
|
||||
// create the request
|
||||
req = NewRequest(t, "GET", "/api/v1/admin/users")
|
||||
|
||||
signer, _, err := httpsig.NewSSHSigner(sshSigner, httpsig.DigestSha512, []string{httpsig.RequestTarget, "(created)", "(expires)"}, httpsig.Signature, 10)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// sign the request
|
||||
err = signer.SignRequest(keyID, req, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// make the request
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
|
||||
func TestHTTPSigCert(t *testing.T) {
|
||||
// Add our public key to user1
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
session := loginUser(t, "user1")
|
||||
|
||||
csrf := GetCSRF(t, session, "/user/settings/keys")
|
||||
req := NewRequestWithValues(t, "POST", "/user/settings/keys", map[string]string{
|
||||
"_csrf": csrf,
|
||||
"content": "user1",
|
||||
"title": "principal",
|
||||
"type": "principal",
|
||||
})
|
||||
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
pkcert, _, _, _, err := ssh.ParseAuthorizedKey([]byte(httpsigCertificate))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// parse our private key and create the httpsig request
|
||||
sshSigner, _ := ssh.ParsePrivateKey([]byte(httpsigPrivateKey))
|
||||
keyID := "gitea"
|
||||
|
||||
// create our certificate signer using the ssh signer and our certificate
|
||||
certSigner, err := ssh.NewCertSigner(pkcert.(*ssh.Certificate), sshSigner)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// create the request
|
||||
req = NewRequest(t, "GET", "/api/v1/admin/users")
|
||||
|
||||
// add our cert to the request
|
||||
certString := base64.RawStdEncoding.EncodeToString(pkcert.(*ssh.Certificate).Marshal())
|
||||
req.Header.Add("x-ssh-certificate", certString)
|
||||
|
||||
signer, _, err := httpsig.NewSSHSigner(certSigner, httpsig.DigestSha512, []string{httpsig.RequestTarget, "(created)", "(expires)", "x-ssh-certificate"}, httpsig.Signature, 10)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// sign the request
|
||||
err = signer.SignRequest(keyID, req, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// make the request
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
}
|
208
tests/integration/api_issue_label_test.go
Normal file
208
tests/integration/api_issue_label_test.go
Normal file
|
@ -0,0 +1,208 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
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"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIModifyLabels(t *testing.T) {
|
||||
assert.NoError(t, unittest.LoadFixtures())
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
session := loginUser(t, owner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/labels?token=%s", owner.Name, repo.Name, token)
|
||||
|
||||
// CreateLabel
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateLabelOption{
|
||||
Name: "TestL 1",
|
||||
Color: "abcdef",
|
||||
Description: "test label",
|
||||
})
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
apiLabel := new(api.Label)
|
||||
DecodeJSON(t, resp, &apiLabel)
|
||||
dbLabel := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: apiLabel.ID, RepoID: repo.ID})
|
||||
assert.EqualValues(t, dbLabel.Name, apiLabel.Name)
|
||||
assert.EqualValues(t, strings.TrimLeft(dbLabel.Color, "#"), apiLabel.Color)
|
||||
|
||||
req = NewRequestWithJSON(t, "POST", urlStr, &api.CreateLabelOption{
|
||||
Name: "TestL 2",
|
||||
Color: "#123456",
|
||||
Description: "jet another test label",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusCreated)
|
||||
req = NewRequestWithJSON(t, "POST", urlStr, &api.CreateLabelOption{
|
||||
Name: "WrongTestL",
|
||||
Color: "#12345g",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
|
||||
// ListLabels
|
||||
req = NewRequest(t, "GET", urlStr)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
var apiLabels []*api.Label
|
||||
DecodeJSON(t, resp, &apiLabels)
|
||||
assert.Len(t, apiLabels, 2)
|
||||
|
||||
// GetLabel
|
||||
singleURLStr := fmt.Sprintf("/api/v1/repos/%s/%s/labels/%d?token=%s", owner.Name, repo.Name, dbLabel.ID, token)
|
||||
req = NewRequest(t, "GET", singleURLStr)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiLabel)
|
||||
assert.EqualValues(t, strings.TrimLeft(dbLabel.Color, "#"), apiLabel.Color)
|
||||
|
||||
// EditLabel
|
||||
newName := "LabelNewName"
|
||||
newColor := "09876a"
|
||||
newColorWrong := "09g76a"
|
||||
req = NewRequestWithJSON(t, "PATCH", singleURLStr, &api.EditLabelOption{
|
||||
Name: &newName,
|
||||
Color: &newColor,
|
||||
})
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiLabel)
|
||||
assert.EqualValues(t, newColor, apiLabel.Color)
|
||||
req = NewRequestWithJSON(t, "PATCH", singleURLStr, &api.EditLabelOption{
|
||||
Color: &newColorWrong,
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
|
||||
// DeleteLabel
|
||||
req = NewRequest(t, "DELETE", singleURLStr)
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
}
|
||||
|
||||
func TestAPIAddIssueLabels(t *testing.T) {
|
||||
assert.NoError(t, unittest.LoadFixtures())
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: repo.ID})
|
||||
_ = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{RepoID: repo.ID, ID: 2})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
|
||||
session := loginUser(t, owner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels?token=%s",
|
||||
repo.OwnerName, repo.Name, issue.Index, token)
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.IssueLabelsOption{
|
||||
Labels: []int64{1, 2},
|
||||
})
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var apiLabels []*api.Label
|
||||
DecodeJSON(t, resp, &apiLabels)
|
||||
assert.Len(t, apiLabels, unittest.GetCount(t, &issues_model.IssueLabel{IssueID: issue.ID}))
|
||||
|
||||
unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: 2})
|
||||
}
|
||||
|
||||
func TestAPIReplaceIssueLabels(t *testing.T) {
|
||||
assert.NoError(t, unittest.LoadFixtures())
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: repo.ID})
|
||||
label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{RepoID: repo.ID})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
|
||||
session := loginUser(t, owner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels?token=%s",
|
||||
owner.Name, repo.Name, issue.Index, token)
|
||||
req := NewRequestWithJSON(t, "PUT", urlStr, &api.IssueLabelsOption{
|
||||
Labels: []int64{label.ID},
|
||||
})
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var apiLabels []*api.Label
|
||||
DecodeJSON(t, resp, &apiLabels)
|
||||
if assert.Len(t, apiLabels, 1) {
|
||||
assert.EqualValues(t, label.ID, apiLabels[0].ID)
|
||||
}
|
||||
|
||||
unittest.AssertCount(t, &issues_model.IssueLabel{IssueID: issue.ID}, 1)
|
||||
unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: label.ID})
|
||||
}
|
||||
|
||||
func TestAPIModifyOrgLabels(t *testing.T) {
|
||||
assert.NoError(t, unittest.LoadFixtures())
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
user := "user1"
|
||||
session := loginUser(t, user)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/orgs/%s/labels?token=%s", owner.Name, token)
|
||||
|
||||
// CreateLabel
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateLabelOption{
|
||||
Name: "TestL 1",
|
||||
Color: "abcdef",
|
||||
Description: "test label",
|
||||
})
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
apiLabel := new(api.Label)
|
||||
DecodeJSON(t, resp, &apiLabel)
|
||||
dbLabel := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: apiLabel.ID, OrgID: owner.ID})
|
||||
assert.EqualValues(t, dbLabel.Name, apiLabel.Name)
|
||||
assert.EqualValues(t, strings.TrimLeft(dbLabel.Color, "#"), apiLabel.Color)
|
||||
|
||||
req = NewRequestWithJSON(t, "POST", urlStr, &api.CreateLabelOption{
|
||||
Name: "TestL 2",
|
||||
Color: "#123456",
|
||||
Description: "jet another test label",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusCreated)
|
||||
req = NewRequestWithJSON(t, "POST", urlStr, &api.CreateLabelOption{
|
||||
Name: "WrongTestL",
|
||||
Color: "#12345g",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
|
||||
// ListLabels
|
||||
req = NewRequest(t, "GET", urlStr)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
var apiLabels []*api.Label
|
||||
DecodeJSON(t, resp, &apiLabels)
|
||||
assert.Len(t, apiLabels, 4)
|
||||
|
||||
// GetLabel
|
||||
singleURLStr := fmt.Sprintf("/api/v1/orgs/%s/labels/%d?token=%s", owner.Name, dbLabel.ID, token)
|
||||
req = NewRequest(t, "GET", singleURLStr)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiLabel)
|
||||
assert.EqualValues(t, strings.TrimLeft(dbLabel.Color, "#"), apiLabel.Color)
|
||||
|
||||
// EditLabel
|
||||
newName := "LabelNewName"
|
||||
newColor := "09876a"
|
||||
newColorWrong := "09g76a"
|
||||
req = NewRequestWithJSON(t, "PATCH", singleURLStr, &api.EditLabelOption{
|
||||
Name: &newName,
|
||||
Color: &newColor,
|
||||
})
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiLabel)
|
||||
assert.EqualValues(t, newColor, apiLabel.Color)
|
||||
req = NewRequestWithJSON(t, "PATCH", singleURLStr, &api.EditLabelOption{
|
||||
Color: &newColorWrong,
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
|
||||
// DeleteLabel
|
||||
req = NewRequest(t, "DELETE", singleURLStr)
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
}
|
81
tests/integration/api_issue_milestone_test.go
Normal file
81
tests/integration/api_issue_milestone_test.go
Normal file
|
@ -0,0 +1,81 @@
|
|||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
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/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIIssuesMilestone(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: milestone.RepoID})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
assert.Equal(t, int64(1), int64(milestone.NumIssues))
|
||||
assert.Equal(t, structs.StateOpen, milestone.State())
|
||||
|
||||
session := loginUser(t, owner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
// update values of issue
|
||||
milestoneState := "closed"
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/milestones/%d?token=%s", owner.Name, repo.Name, milestone.ID, token)
|
||||
req := NewRequestWithJSON(t, "PATCH", urlStr, structs.EditMilestoneOption{
|
||||
State: &milestoneState,
|
||||
})
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var apiMilestone structs.Milestone
|
||||
DecodeJSON(t, resp, &apiMilestone)
|
||||
assert.EqualValues(t, "closed", apiMilestone.State)
|
||||
|
||||
req = NewRequest(t, "GET", urlStr)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
var apiMilestone2 structs.Milestone
|
||||
DecodeJSON(t, resp, &apiMilestone2)
|
||||
assert.EqualValues(t, "closed", apiMilestone2.State)
|
||||
|
||||
req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/milestones?token=%s", owner.Name, repo.Name, token), structs.CreateMilestoneOption{
|
||||
Title: "wow",
|
||||
Description: "closed one",
|
||||
State: "closed",
|
||||
})
|
||||
resp = session.MakeRequest(t, req, http.StatusCreated)
|
||||
DecodeJSON(t, resp, &apiMilestone)
|
||||
assert.Equal(t, "wow", apiMilestone.Title)
|
||||
assert.Equal(t, structs.StateClosed, apiMilestone.State)
|
||||
|
||||
var apiMilestones []structs.Milestone
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/milestones?state=%s&token=%s", owner.Name, repo.Name, "all", token))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiMilestones)
|
||||
assert.Len(t, apiMilestones, 4)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/milestones/%s?token=%s", owner.Name, repo.Name, apiMilestones[2].Title, token))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiMilestone)
|
||||
assert.EqualValues(t, apiMilestones[2], apiMilestone)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/milestones?state=%s&name=%s&token=%s", owner.Name, repo.Name, "all", "milestone2", token))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiMilestones)
|
||||
assert.Len(t, apiMilestones, 1)
|
||||
assert.Equal(t, int64(2), apiMilestones[0].ID)
|
||||
|
||||
req = NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/repos/%s/%s/milestones/%d?token=%s", owner.Name, repo.Name, apiMilestone.ID, token))
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
}
|
144
tests/integration/api_issue_reaction_test.go
Normal file
144
tests/integration/api_issue_reaction_test.go
Normal file
|
@ -0,0 +1,144 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/convert"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIIssuesReactions(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
|
||||
_ = issue.LoadRepo(db.DefaultContext)
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID})
|
||||
|
||||
session := loginUser(t, owner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/reactions?token=%s",
|
||||
owner.Name, issue.Repo.Name, issue.Index, token)
|
||||
|
||||
// Try to add not allowed reaction
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.EditReactionOption{
|
||||
Reaction: "wrong",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
|
||||
// Delete not allowed reaction
|
||||
req = NewRequestWithJSON(t, "DELETE", urlStr, &api.EditReactionOption{
|
||||
Reaction: "zzz",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// Add allowed reaction
|
||||
req = NewRequestWithJSON(t, "POST", urlStr, &api.EditReactionOption{
|
||||
Reaction: "rocket",
|
||||
})
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
var apiNewReaction api.Reaction
|
||||
DecodeJSON(t, resp, &apiNewReaction)
|
||||
|
||||
// Add existing reaction
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
|
||||
// Get end result of reaction list of issue #1
|
||||
req = NewRequestf(t, "GET", urlStr)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
var apiReactions []*api.Reaction
|
||||
DecodeJSON(t, resp, &apiReactions)
|
||||
expectResponse := make(map[int]api.Reaction)
|
||||
expectResponse[0] = api.Reaction{
|
||||
User: convert.ToUser(user2, user2),
|
||||
Reaction: "eyes",
|
||||
Created: time.Unix(1573248003, 0),
|
||||
}
|
||||
expectResponse[1] = apiNewReaction
|
||||
assert.Len(t, apiReactions, 2)
|
||||
for i, r := range apiReactions {
|
||||
assert.Equal(t, expectResponse[i].Reaction, r.Reaction)
|
||||
assert.Equal(t, expectResponse[i].Created.Unix(), r.Created.Unix())
|
||||
assert.Equal(t, expectResponse[i].User.ID, r.User.ID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPICommentReactions(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 2})
|
||||
_ = comment.LoadIssue()
|
||||
issue := comment.Issue
|
||||
_ = issue.LoadRepo(db.DefaultContext)
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID})
|
||||
|
||||
session := loginUser(t, owner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d/reactions?token=%s",
|
||||
owner.Name, issue.Repo.Name, comment.ID, token)
|
||||
|
||||
// Try to add not allowed reaction
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.EditReactionOption{
|
||||
Reaction: "wrong",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
|
||||
// Delete none existing reaction
|
||||
req = NewRequestWithJSON(t, "DELETE", urlStr, &api.EditReactionOption{
|
||||
Reaction: "eyes",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// Add allowed reaction
|
||||
req = NewRequestWithJSON(t, "POST", urlStr, &api.EditReactionOption{
|
||||
Reaction: "+1",
|
||||
})
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
var apiNewReaction api.Reaction
|
||||
DecodeJSON(t, resp, &apiNewReaction)
|
||||
|
||||
// Add existing reaction
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
|
||||
// Get end result of reaction list of issue #1
|
||||
req = NewRequestf(t, "GET", urlStr)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
var apiReactions []*api.Reaction
|
||||
DecodeJSON(t, resp, &apiReactions)
|
||||
expectResponse := make(map[int]api.Reaction)
|
||||
expectResponse[0] = api.Reaction{
|
||||
User: convert.ToUser(user2, user2),
|
||||
Reaction: "laugh",
|
||||
Created: time.Unix(1573248004, 0),
|
||||
}
|
||||
expectResponse[1] = api.Reaction{
|
||||
User: convert.ToUser(user1, user1),
|
||||
Reaction: "laugh",
|
||||
Created: time.Unix(1573248005, 0),
|
||||
}
|
||||
expectResponse[2] = apiNewReaction
|
||||
assert.Len(t, apiReactions, 3)
|
||||
for i, r := range apiReactions {
|
||||
assert.Equal(t, expectResponse[i].Reaction, r.Reaction)
|
||||
assert.Equal(t, expectResponse[i].Created.Unix(), r.Created.Unix())
|
||||
assert.Equal(t, expectResponse[i].User.ID, r.User.ID)
|
||||
}
|
||||
}
|
92
tests/integration/api_issue_stopwatch_test.go
Normal file
92
tests/integration/api_issue_stopwatch_test.go
Normal file
|
@ -0,0 +1,92 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
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"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIListStopWatches(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(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)
|
||||
req := NewRequestf(t, "GET", "/api/v1/user/stopwatches?token=%s", token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var apiWatches []*api.StopWatch
|
||||
DecodeJSON(t, resp, &apiWatches)
|
||||
stopwatch := unittest.AssertExistsAndLoadBean(t, &issues_model.Stopwatch{UserID: owner.ID})
|
||||
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: stopwatch.IssueID})
|
||||
if assert.Len(t, apiWatches, 1) {
|
||||
assert.EqualValues(t, stopwatch.CreatedUnix.AsTime().Unix(), apiWatches[0].Created.Unix())
|
||||
assert.EqualValues(t, issue.Index, apiWatches[0].IssueIndex)
|
||||
assert.EqualValues(t, issue.Title, apiWatches[0].IssueTitle)
|
||||
assert.EqualValues(t, repo.Name, apiWatches[0].RepoName)
|
||||
assert.EqualValues(t, repo.OwnerName, apiWatches[0].RepoOwnerName)
|
||||
assert.Greater(t, apiWatches[0].Seconds, int64(0))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIStopStopWatches(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
|
||||
_ = issue.LoadRepo(db.DefaultContext)
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID})
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
req := NewRequestf(t, "POST", "/api/v1/repos/%s/%s/issues/%d/stopwatch/stop?token=%s", owner.Name, issue.Repo.Name, issue.Index, token)
|
||||
session.MakeRequest(t, req, http.StatusCreated)
|
||||
session.MakeRequest(t, req, http.StatusConflict)
|
||||
}
|
||||
|
||||
func TestAPICancelStopWatches(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
|
||||
_ = issue.LoadRepo(db.DefaultContext)
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID})
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/%d/stopwatch/delete?token=%s", owner.Name, issue.Repo.Name, issue.Index, token)
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
session.MakeRequest(t, req, http.StatusConflict)
|
||||
}
|
||||
|
||||
func TestAPIStartStopWatches(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 3})
|
||||
_ = issue.LoadRepo(db.DefaultContext)
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID})
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
req := NewRequestf(t, "POST", "/api/v1/repos/%s/%s/issues/%d/stopwatch/start?token=%s", owner.Name, issue.Repo.Name, issue.Index, token)
|
||||
session.MakeRequest(t, req, http.StatusCreated)
|
||||
session.MakeRequest(t, req, http.StatusConflict)
|
||||
}
|
77
tests/integration/api_issue_subscription_test.go
Normal file
77
tests/integration/api_issue_subscription_test.go
Normal file
|
@ -0,0 +1,77 @@
|
|||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
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"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIIssueSubscriptions(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
issue1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
|
||||
issue2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
|
||||
issue3 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 3})
|
||||
issue4 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4})
|
||||
issue5 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 8})
|
||||
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue1.PosterID})
|
||||
|
||||
session := loginUser(t, owner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
testSubscription := func(issue *issues_model.Issue, isWatching bool) {
|
||||
issueRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/subscriptions/check?token=%s", issueRepo.OwnerName, issueRepo.Name, issue.Index, token)
|
||||
req := NewRequest(t, "GET", urlStr)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
wi := new(api.WatchInfo)
|
||||
DecodeJSON(t, resp, wi)
|
||||
|
||||
assert.EqualValues(t, isWatching, wi.Subscribed)
|
||||
assert.EqualValues(t, !isWatching, wi.Ignored)
|
||||
assert.EqualValues(t, issue.APIURL()+"/subscriptions", wi.URL)
|
||||
assert.EqualValues(t, issue.CreatedUnix, wi.CreatedAt.Unix())
|
||||
assert.EqualValues(t, issueRepo.APIURL(), wi.RepositoryURL)
|
||||
}
|
||||
|
||||
testSubscription(issue1, true)
|
||||
testSubscription(issue2, true)
|
||||
testSubscription(issue3, true)
|
||||
testSubscription(issue4, false)
|
||||
testSubscription(issue5, false)
|
||||
|
||||
issue1Repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue1.RepoID})
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/subscriptions/%s?token=%s", issue1Repo.OwnerName, issue1Repo.Name, issue1.Index, owner.Name, token)
|
||||
req := NewRequest(t, "DELETE", urlStr)
|
||||
session.MakeRequest(t, req, http.StatusCreated)
|
||||
testSubscription(issue1, false)
|
||||
|
||||
req = NewRequest(t, "DELETE", urlStr)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
testSubscription(issue1, false)
|
||||
|
||||
issue5Repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue5.RepoID})
|
||||
urlStr = fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/subscriptions/%s?token=%s", issue5Repo.OwnerName, issue5Repo.Name, issue5.Index, owner.Name, token)
|
||||
req = NewRequest(t, "PUT", urlStr)
|
||||
session.MakeRequest(t, req, http.StatusCreated)
|
||||
testSubscription(issue5, true)
|
||||
|
||||
req = NewRequest(t, "PUT", urlStr)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
testSubscription(issue5, true)
|
||||
}
|
329
tests/integration/api_issue_test.go
Normal file
329
tests/integration/api_issue_test.go
Normal file
|
@ -0,0 +1,329 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
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/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIListIssues(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(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)
|
||||
link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/issues", owner.Name, repo.Name))
|
||||
|
||||
link.RawQuery = url.Values{"token": {token}, "state": {"all"}}.Encode()
|
||||
resp := session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||
var apiIssues []*api.Issue
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
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})
|
||||
}
|
||||
|
||||
// test milestone filter
|
||||
link.RawQuery = url.Values{"token": {token}, "state": {"all"}, "type": {"all"}, "milestones": {"ignore,milestone1,3,4"}}.Encode()
|
||||
resp = session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
if assert.Len(t, apiIssues, 2) {
|
||||
assert.EqualValues(t, 3, apiIssues[0].Milestone.ID)
|
||||
assert.EqualValues(t, 1, apiIssues[1].Milestone.ID)
|
||||
}
|
||||
|
||||
link.RawQuery = url.Values{"token": {token}, "state": {"all"}, "created_by": {"user2"}}.Encode()
|
||||
resp = session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
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 = session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
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 = session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
if assert.Len(t, apiIssues, 1) {
|
||||
assert.EqualValues(t, 1, apiIssues[0].ID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPICreateIssue(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
const body, title = "apiTestBody", "apiTestTitle"
|
||||
|
||||
repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID})
|
||||
|
||||
session := loginUser(t, owner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues?state=all&token=%s", owner.Name, repoBefore.Name, token)
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateIssueOption{
|
||||
Body: body,
|
||||
Title: title,
|
||||
Assignee: owner.Name,
|
||||
})
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
var apiIssue api.Issue
|
||||
DecodeJSON(t, resp, &apiIssue)
|
||||
assert.Equal(t, body, apiIssue.Body)
|
||||
assert.Equal(t, title, apiIssue.Title)
|
||||
|
||||
unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{
|
||||
RepoID: repoBefore.ID,
|
||||
AssigneeID: owner.ID,
|
||||
Content: body,
|
||||
Title: title,
|
||||
})
|
||||
|
||||
repoAfter := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
assert.Equal(t, repoBefore.NumIssues+1, repoAfter.NumIssues)
|
||||
assert.Equal(t, repoBefore.NumClosedIssues, repoAfter.NumClosedIssues)
|
||||
}
|
||||
|
||||
func TestAPIEditIssue(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
issueBefore := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10})
|
||||
repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID})
|
||||
assert.NoError(t, issueBefore.LoadAttributes(db.DefaultContext))
|
||||
assert.Equal(t, int64(1019307200), int64(issueBefore.DeadlineUnix))
|
||||
assert.Equal(t, api.StateOpen, issueBefore.State())
|
||||
|
||||
session := loginUser(t, owner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
// update values of issue
|
||||
issueState := "closed"
|
||||
removeDeadline := true
|
||||
milestone := int64(4)
|
||||
body := "new content!"
|
||||
title := "new title from api set"
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d?token=%s", owner.Name, repoBefore.Name, issueBefore.Index, token)
|
||||
req := NewRequestWithJSON(t, "PATCH", urlStr, api.EditIssueOption{
|
||||
State: &issueState,
|
||||
RemoveDeadline: &removeDeadline,
|
||||
Milestone: &milestone,
|
||||
Body: &body,
|
||||
Title: title,
|
||||
|
||||
// ToDo change more
|
||||
})
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
var apiIssue api.Issue
|
||||
DecodeJSON(t, resp, &apiIssue)
|
||||
|
||||
issueAfter := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10})
|
||||
repoAfter := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID})
|
||||
|
||||
// check deleted user
|
||||
assert.Equal(t, int64(500), issueAfter.PosterID)
|
||||
assert.NoError(t, issueAfter.LoadAttributes(db.DefaultContext))
|
||||
assert.Equal(t, int64(-1), issueAfter.PosterID)
|
||||
assert.Equal(t, int64(-1), issueBefore.PosterID)
|
||||
assert.Equal(t, int64(-1), apiIssue.Poster.ID)
|
||||
|
||||
// check repo change
|
||||
assert.Equal(t, repoBefore.NumClosedIssues+1, repoAfter.NumClosedIssues)
|
||||
|
||||
// API response
|
||||
assert.Equal(t, api.StateClosed, apiIssue.State)
|
||||
assert.Equal(t, milestone, apiIssue.Milestone.ID)
|
||||
assert.Equal(t, body, apiIssue.Body)
|
||||
assert.True(t, apiIssue.Deadline == nil)
|
||||
assert.Equal(t, title, apiIssue.Title)
|
||||
|
||||
// in database
|
||||
assert.Equal(t, api.StateClosed, issueAfter.State())
|
||||
assert.Equal(t, milestone, issueAfter.MilestoneID)
|
||||
assert.Equal(t, int64(0), int64(issueAfter.DeadlineUnix))
|
||||
assert.Equal(t, body, issueAfter.Content)
|
||||
assert.Equal(t, title, issueAfter.Title)
|
||||
}
|
||||
|
||||
func TestAPISearchIssues(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
token := getUserToken(t, "user2")
|
||||
|
||||
// as this API was used in the frontend, it uses UI page size
|
||||
expectedIssueCount := 15 // from the fixtures
|
||||
if expectedIssueCount > setting.UI.IssuePagingNum {
|
||||
expectedIssueCount = setting.UI.IssuePagingNum
|
||||
}
|
||||
|
||||
link, _ := url.Parse("/api/v1/repos/issues/search")
|
||||
query := url.Values{"token": {getUserToken(t, "user1")}}
|
||||
var apiIssues []*api.Issue
|
||||
|
||||
link.RawQuery = query.Encode()
|
||||
req := NewRequest(t, "GET", link.String())
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, expectedIssueCount)
|
||||
|
||||
since := "2000-01-01T00%3A50%3A01%2B00%3A00" // 946687801
|
||||
before := time.Unix(999307200, 0).Format(time.RFC3339)
|
||||
query.Add("since", since)
|
||||
query.Add("before", before)
|
||||
query.Add("token", token)
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 8)
|
||||
query.Del("since")
|
||||
query.Del("before")
|
||||
|
||||
query.Add("state", "closed")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
query.Set("state", "all")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.EqualValues(t, "17", resp.Header().Get("X-Total-Count"))
|
||||
assert.Len(t, apiIssues, 17)
|
||||
|
||||
query.Add("limit", "10")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.EqualValues(t, "17", resp.Header().Get("X-Total-Count"))
|
||||
assert.Len(t, apiIssues, 10)
|
||||
|
||||
query = url.Values{"assigned": {"true"}, "state": {"all"}, "token": {token}}
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
query = url.Values{"milestones": {"milestone1"}, "state": {"all"}, "token": {token}}
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 1)
|
||||
|
||||
query = url.Values{"milestones": {"milestone1,milestone3"}, "state": {"all"}, "token": {token}}
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
query = url.Values{"owner": {"user2"}, "token": {token}} // user
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 6)
|
||||
|
||||
query = url.Values{"owner": {"user3"}, "token": {token}} // organization
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 5)
|
||||
|
||||
query = url.Values{"owner": {"user3"}, "team": {"team1"}, "token": {token}} // organization + team
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
}
|
||||
|
||||
func TestAPISearchIssuesWithLabels(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
// as this API was used in the frontend, it uses UI page size
|
||||
expectedIssueCount := 15 // from the fixtures
|
||||
if expectedIssueCount > setting.UI.IssuePagingNum {
|
||||
expectedIssueCount = setting.UI.IssuePagingNum
|
||||
}
|
||||
|
||||
link, _ := url.Parse("/api/v1/repos/issues/search")
|
||||
query := url.Values{"token": {getUserToken(t, "user1")}}
|
||||
var apiIssues []*api.Issue
|
||||
|
||||
link.RawQuery = query.Encode()
|
||||
req := NewRequest(t, "GET", link.String())
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, expectedIssueCount)
|
||||
|
||||
query.Add("labels", "label1")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
// multiple labels
|
||||
query.Set("labels", "label1,label2")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
// an org label
|
||||
query.Set("labels", "orglabel4")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 1)
|
||||
|
||||
// org and repo label
|
||||
query.Set("labels", "label2,orglabel4")
|
||||
query.Add("state", "all")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
|
||||
// org and repo label which share the same issue
|
||||
query.Set("labels", "label1,orglabel4")
|
||||
link.RawQuery = query.Encode()
|
||||
req = NewRequest(t, "GET", link.String())
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
assert.Len(t, apiIssues, 2)
|
||||
}
|
125
tests/integration/api_issue_tracked_time_test.go
Normal file
125
tests/integration/api_issue_tracked_time_test.go
Normal file
|
@ -0,0 +1,125 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"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 TestAPIGetTrackedTimes(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
issue2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
|
||||
assert.NoError(t, issue2.LoadRepo(db.DefaultContext))
|
||||
|
||||
session := loginUser(t, user2.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/%d/times?token=%s", user2.Name, issue2.Repo.Name, issue2.Index, token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var apiTimes api.TrackedTimeList
|
||||
DecodeJSON(t, resp, &apiTimes)
|
||||
expect, err := issues_model.GetTrackedTimes(db.DefaultContext, &issues_model.FindTrackedTimesOptions{IssueID: issue2.ID})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, apiTimes, 3)
|
||||
|
||||
for i, time := range expect {
|
||||
assert.Equal(t, time.ID, apiTimes[i].ID)
|
||||
assert.EqualValues(t, issue2.Title, apiTimes[i].Issue.Title)
|
||||
assert.EqualValues(t, issue2.ID, apiTimes[i].IssueID)
|
||||
assert.Equal(t, time.Created.Unix(), apiTimes[i].Created.Unix())
|
||||
assert.Equal(t, time.Time, apiTimes[i].Time)
|
||||
user, err := user_model.GetUserByID(time.UserID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, user.Name, apiTimes[i].UserName)
|
||||
}
|
||||
|
||||
// test filter
|
||||
since := "2000-01-01T00%3A00%3A02%2B00%3A00" // 946684802
|
||||
before := "2000-01-01T00%3A00%3A12%2B00%3A00" // 946684812
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/%d/times?since=%s&before=%s&token=%s", user2.Name, issue2.Repo.Name, issue2.Index, since, before, token)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
var filterAPITimes api.TrackedTimeList
|
||||
DecodeJSON(t, resp, &filterAPITimes)
|
||||
assert.Len(t, filterAPITimes, 2)
|
||||
assert.Equal(t, int64(3), filterAPITimes[0].ID)
|
||||
assert.Equal(t, int64(6), filterAPITimes[1].ID)
|
||||
}
|
||||
|
||||
func TestAPIDeleteTrackedTime(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
time6 := unittest.AssertExistsAndLoadBean(t, &issues_model.TrackedTime{ID: 6})
|
||||
issue2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
|
||||
assert.NoError(t, issue2.LoadRepo(db.DefaultContext))
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
session := loginUser(t, user2.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
// Deletion not allowed
|
||||
req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/%d/times/%d?token=%s", user2.Name, issue2.Repo.Name, issue2.Index, time6.ID, token)
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
|
||||
time3 := unittest.AssertExistsAndLoadBean(t, &issues_model.TrackedTime{ID: 3})
|
||||
req = NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/%d/times/%d?token=%s", user2.Name, issue2.Repo.Name, issue2.Index, time3.ID, token)
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
// Delete non existing time
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Reset time of user 2 on issue 2
|
||||
trackedSeconds, err := issues_model.GetTrackedSeconds(db.DefaultContext, issues_model.FindTrackedTimesOptions{IssueID: 2, UserID: 2})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(3661), trackedSeconds)
|
||||
|
||||
req = NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/%d/times?token=%s", user2.Name, issue2.Repo.Name, issue2.Index, token)
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
trackedSeconds, err = issues_model.GetTrackedSeconds(db.DefaultContext, issues_model.FindTrackedTimesOptions{IssueID: 2, UserID: 2})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(0), trackedSeconds)
|
||||
}
|
||||
|
||||
func TestAPIAddTrackedTimes(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
issue2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
|
||||
assert.NoError(t, issue2.LoadRepo(db.DefaultContext))
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||
|
||||
session := loginUser(t, admin.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/times?token=%s", user2.Name, issue2.Repo.Name, issue2.Index, token)
|
||||
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.AddTimeOption{
|
||||
Time: 33,
|
||||
User: user2.Name,
|
||||
Created: time.Unix(947688818, 0),
|
||||
})
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var apiNewTime api.TrackedTime
|
||||
DecodeJSON(t, resp, &apiNewTime)
|
||||
|
||||
assert.EqualValues(t, 33, apiNewTime.Time)
|
||||
assert.EqualValues(t, user2.ID, apiNewTime.UserID)
|
||||
assert.EqualValues(t, 947688818, apiNewTime.Created.Unix())
|
||||
}
|
201
tests/integration/api_keys_test.go
Normal file
201
tests/integration/api_keys_test.go
Normal file
|
@ -0,0 +1,201 @@
|
|||
// Copyright 2017 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
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"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestViewDeployKeysNoLogin(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo1/keys")
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
}
|
||||
|
||||
func TestCreateDeployKeyNoLogin(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/repos/user2/repo1/keys", api.CreateKeyOption{
|
||||
Title: "title",
|
||||
Key: "key",
|
||||
})
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
}
|
||||
|
||||
func TestGetDeployKeyNoLogin(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo1/keys/1")
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
}
|
||||
|
||||
func TestDeleteDeployKeyNoLogin(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
req := NewRequest(t, "DELETE", "/api/v1/repos/user2/repo1/keys/1")
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
}
|
||||
|
||||
func TestCreateReadOnlyDeployKey(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: "repo1"})
|
||||
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
|
||||
session := loginUser(t, repoOwner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
keysURL := fmt.Sprintf("/api/v1/repos/%s/%s/keys?token=%s", repoOwner.Name, repo.Name, token)
|
||||
rawKeyBody := api.CreateKeyOption{
|
||||
Title: "read-only",
|
||||
Key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment\n",
|
||||
ReadOnly: true,
|
||||
}
|
||||
req := NewRequestWithJSON(t, "POST", keysURL, rawKeyBody)
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
var newDeployKey api.DeployKey
|
||||
DecodeJSON(t, resp, &newDeployKey)
|
||||
unittest.AssertExistsAndLoadBean(t, &asymkey_model.DeployKey{
|
||||
ID: newDeployKey.ID,
|
||||
Name: rawKeyBody.Title,
|
||||
Content: rawKeyBody.Key,
|
||||
Mode: perm.AccessModeRead,
|
||||
})
|
||||
}
|
||||
|
||||
func TestCreateReadWriteDeployKey(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: "repo1"})
|
||||
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
|
||||
session := loginUser(t, repoOwner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
keysURL := fmt.Sprintf("/api/v1/repos/%s/%s/keys?token=%s", repoOwner.Name, repo.Name, token)
|
||||
rawKeyBody := api.CreateKeyOption{
|
||||
Title: "read-write",
|
||||
Key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment\n",
|
||||
}
|
||||
req := NewRequestWithJSON(t, "POST", keysURL, rawKeyBody)
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
var newDeployKey api.DeployKey
|
||||
DecodeJSON(t, resp, &newDeployKey)
|
||||
unittest.AssertExistsAndLoadBean(t, &asymkey_model.DeployKey{
|
||||
ID: newDeployKey.ID,
|
||||
Name: rawKeyBody.Title,
|
||||
Content: rawKeyBody.Key,
|
||||
Mode: perm.AccessModeWrite,
|
||||
})
|
||||
}
|
||||
|
||||
func TestCreateUserKey(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user1"})
|
||||
|
||||
session := loginUser(t, "user1")
|
||||
token := url.QueryEscape(getTokenForLoggedInUser(t, session))
|
||||
keysURL := fmt.Sprintf("/api/v1/user/keys?token=%s", token)
|
||||
keyType := "ssh-rsa"
|
||||
keyContent := "AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM="
|
||||
rawKeyBody := api.CreateKeyOption{
|
||||
Title: "test-key",
|
||||
Key: keyType + " " + keyContent,
|
||||
}
|
||||
req := NewRequestWithJSON(t, "POST", keysURL, rawKeyBody)
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
var newPublicKey api.PublicKey
|
||||
DecodeJSON(t, resp, &newPublicKey)
|
||||
fingerprint, err := asymkey_model.CalcFingerprint(rawKeyBody.Key)
|
||||
assert.NoError(t, err)
|
||||
unittest.AssertExistsAndLoadBean(t, &asymkey_model.PublicKey{
|
||||
ID: newPublicKey.ID,
|
||||
OwnerID: user.ID,
|
||||
Name: rawKeyBody.Title,
|
||||
Fingerprint: fingerprint,
|
||||
Mode: perm.AccessModeWrite,
|
||||
})
|
||||
|
||||
// Search by fingerprint
|
||||
fingerprintURL := fmt.Sprintf("/api/v1/user/keys?token=%s&fingerprint=%s", token, newPublicKey.Fingerprint)
|
||||
|
||||
req = NewRequest(t, "GET", fingerprintURL)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var fingerprintPublicKeys []api.PublicKey
|
||||
DecodeJSON(t, resp, &fingerprintPublicKeys)
|
||||
assert.Equal(t, newPublicKey.Fingerprint, fingerprintPublicKeys[0].Fingerprint)
|
||||
assert.Equal(t, newPublicKey.ID, fingerprintPublicKeys[0].ID)
|
||||
assert.Equal(t, user.ID, fingerprintPublicKeys[0].Owner.ID)
|
||||
|
||||
fingerprintURL = fmt.Sprintf("/api/v1/users/%s/keys?token=%s&fingerprint=%s", user.Name, token, newPublicKey.Fingerprint)
|
||||
|
||||
req = NewRequest(t, "GET", fingerprintURL)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
DecodeJSON(t, resp, &fingerprintPublicKeys)
|
||||
assert.Equal(t, newPublicKey.Fingerprint, fingerprintPublicKeys[0].Fingerprint)
|
||||
assert.Equal(t, newPublicKey.ID, fingerprintPublicKeys[0].ID)
|
||||
assert.Equal(t, user.ID, fingerprintPublicKeys[0].Owner.ID)
|
||||
|
||||
// Fail search by fingerprint
|
||||
fingerprintURL = fmt.Sprintf("/api/v1/user/keys?token=%s&fingerprint=%sA", token, newPublicKey.Fingerprint)
|
||||
|
||||
req = NewRequest(t, "GET", fingerprintURL)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
DecodeJSON(t, resp, &fingerprintPublicKeys)
|
||||
assert.Len(t, fingerprintPublicKeys, 0)
|
||||
|
||||
// Fail searching for wrong users key
|
||||
fingerprintURL = fmt.Sprintf("/api/v1/users/%s/keys?token=%s&fingerprint=%s", "user2", token, newPublicKey.Fingerprint)
|
||||
req = NewRequest(t, "GET", fingerprintURL)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
DecodeJSON(t, resp, &fingerprintPublicKeys)
|
||||
assert.Len(t, fingerprintPublicKeys, 0)
|
||||
|
||||
// Now login as user 2
|
||||
session2 := loginUser(t, "user2")
|
||||
token2 := url.QueryEscape(getTokenForLoggedInUser(t, session2))
|
||||
|
||||
// Should find key even though not ours, but we shouldn't know whose it is
|
||||
fingerprintURL = fmt.Sprintf("/api/v1/user/keys?token=%s&fingerprint=%s", token2, newPublicKey.Fingerprint)
|
||||
req = NewRequest(t, "GET", fingerprintURL)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
DecodeJSON(t, resp, &fingerprintPublicKeys)
|
||||
assert.Equal(t, newPublicKey.Fingerprint, fingerprintPublicKeys[0].Fingerprint)
|
||||
assert.Equal(t, newPublicKey.ID, fingerprintPublicKeys[0].ID)
|
||||
assert.Nil(t, fingerprintPublicKeys[0].Owner)
|
||||
|
||||
// Should find key even though not ours, but we shouldn't know whose it is
|
||||
fingerprintURL = fmt.Sprintf("/api/v1/users/%s/keys?token=%s&fingerprint=%s", user.Name, token2, newPublicKey.Fingerprint)
|
||||
|
||||
req = NewRequest(t, "GET", fingerprintURL)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
DecodeJSON(t, resp, &fingerprintPublicKeys)
|
||||
assert.Equal(t, newPublicKey.Fingerprint, fingerprintPublicKeys[0].Fingerprint)
|
||||
assert.Equal(t, newPublicKey.ID, fingerprintPublicKeys[0].ID)
|
||||
assert.Nil(t, fingerprintPublicKeys[0].Owner)
|
||||
|
||||
// Fail when searching for key if it is not ours
|
||||
fingerprintURL = fmt.Sprintf("/api/v1/users/%s/keys?token=%s&fingerprint=%s", "user2", token2, newPublicKey.Fingerprint)
|
||||
req = NewRequest(t, "GET", fingerprintURL)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
DecodeJSON(t, resp, &fingerprintPublicKeys)
|
||||
assert.Len(t, fingerprintPublicKeys, 0)
|
||||
}
|
39
tests/integration/api_nodeinfo_test.go
Normal file
39
tests/integration/api_nodeinfo_test.go
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/routers"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNodeinfo(t *testing.T) {
|
||||
setting.Federation.Enabled = true
|
||||
c = routers.NormalRoutes(context.TODO())
|
||||
defer func() {
|
||||
setting.Federation.Enabled = false
|
||||
c = routers.NormalRoutes(context.TODO())
|
||||
}()
|
||||
|
||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||
req := NewRequestf(t, "GET", "/api/v1/nodeinfo")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
var nodeinfo api.NodeInfo
|
||||
DecodeJSON(t, resp, &nodeinfo)
|
||||
assert.True(t, nodeinfo.OpenRegistrations)
|
||||
assert.Equal(t, "gitea", nodeinfo.Software.Name)
|
||||
assert.Equal(t, 23, nodeinfo.Usage.Users.Total)
|
||||
assert.Equal(t, 17, nodeinfo.Usage.LocalPosts)
|
||||
assert.Equal(t, 2, nodeinfo.Usage.LocalComments)
|
||||
})
|
||||
}
|
193
tests/integration/api_notification_test.go
Normal file
193
tests/integration/api_notification_test.go
Normal file
|
@ -0,0 +1,193 @@
|
|||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
activities_model "code.gitea.io/gitea/models/activities"
|
||||
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"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPINotification(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
thread5 := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{ID: 5})
|
||||
assert.NoError(t, thread5.LoadAttributes())
|
||||
session := loginUser(t, user2.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
// -- GET /notifications --
|
||||
// test filter
|
||||
since := "2000-01-01T00%3A50%3A01%2B00%3A00" // 946687801
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?since=%s&token=%s", since, token))
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var apiNL []api.NotificationThread
|
||||
DecodeJSON(t, resp, &apiNL)
|
||||
|
||||
assert.Len(t, apiNL, 1)
|
||||
assert.EqualValues(t, 5, apiNL[0].ID)
|
||||
|
||||
// test filter
|
||||
before := "2000-01-01T01%3A06%3A59%2B00%3A00" // 946688819
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?all=%s&before=%s&token=%s", "true", before, token))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiNL)
|
||||
|
||||
assert.Len(t, apiNL, 3)
|
||||
assert.EqualValues(t, 4, apiNL[0].ID)
|
||||
assert.True(t, apiNL[0].Unread)
|
||||
assert.False(t, apiNL[0].Pinned)
|
||||
assert.EqualValues(t, 3, apiNL[1].ID)
|
||||
assert.False(t, apiNL[1].Unread)
|
||||
assert.True(t, apiNL[1].Pinned)
|
||||
assert.EqualValues(t, 2, apiNL[2].ID)
|
||||
assert.False(t, apiNL[2].Unread)
|
||||
assert.False(t, apiNL[2].Pinned)
|
||||
|
||||
// -- GET /repos/{owner}/{repo}/notifications --
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/notifications?status-types=unread&token=%s", user2.Name, repo1.Name, token))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiNL)
|
||||
|
||||
assert.Len(t, apiNL, 1)
|
||||
assert.EqualValues(t, 4, apiNL[0].ID)
|
||||
|
||||
// -- GET /repos/{owner}/{repo}/notifications -- multiple status-types
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/notifications?status-types=unread&status-types=pinned&token=%s", user2.Name, repo1.Name, token))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiNL)
|
||||
|
||||
assert.Len(t, apiNL, 2)
|
||||
assert.EqualValues(t, 4, apiNL[0].ID)
|
||||
assert.True(t, apiNL[0].Unread)
|
||||
assert.False(t, apiNL[0].Pinned)
|
||||
assert.EqualValues(t, 3, apiNL[1].ID)
|
||||
assert.False(t, apiNL[1].Unread)
|
||||
assert.True(t, apiNL[1].Pinned)
|
||||
|
||||
// -- GET /notifications/threads/{id} --
|
||||
// get forbidden
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications/threads/%d?token=%s", 1, token))
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
|
||||
// get own
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications/threads/%d?token=%s", thread5.ID, token))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
var apiN api.NotificationThread
|
||||
DecodeJSON(t, resp, &apiN)
|
||||
|
||||
assert.EqualValues(t, 5, apiN.ID)
|
||||
assert.False(t, apiN.Pinned)
|
||||
assert.True(t, apiN.Unread)
|
||||
assert.EqualValues(t, "issue4", apiN.Subject.Title)
|
||||
assert.EqualValues(t, "Issue", apiN.Subject.Type)
|
||||
assert.EqualValues(t, thread5.Issue.APIURL(), apiN.Subject.URL)
|
||||
assert.EqualValues(t, thread5.Repository.HTMLURL(), apiN.Repository.HTMLURL)
|
||||
|
||||
new := struct {
|
||||
New int64 `json:"new"`
|
||||
}{}
|
||||
|
||||
// -- check notifications --
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications/new?token=%s", token))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &new)
|
||||
assert.True(t, new.New > 0)
|
||||
|
||||
// -- mark notifications as read --
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?status-types=unread&token=%s", token))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiNL)
|
||||
assert.Len(t, apiNL, 2)
|
||||
|
||||
lastReadAt := "2000-01-01T00%3A50%3A01%2B00%3A00" // 946687801 <- only Notification 4 is in this filter ...
|
||||
req = NewRequest(t, "PUT", fmt.Sprintf("/api/v1/repos/%s/%s/notifications?last_read_at=%s&token=%s", user2.Name, repo1.Name, lastReadAt, token))
|
||||
session.MakeRequest(t, req, http.StatusResetContent)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?status-types=unread&token=%s", token))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiNL)
|
||||
assert.Len(t, apiNL, 1)
|
||||
|
||||
// -- PATCH /notifications/threads/{id} --
|
||||
req = NewRequest(t, "PATCH", fmt.Sprintf("/api/v1/notifications/threads/%d?token=%s", thread5.ID, token))
|
||||
session.MakeRequest(t, req, http.StatusResetContent)
|
||||
|
||||
assert.Equal(t, activities_model.NotificationStatusUnread, thread5.Status)
|
||||
thread5 = unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{ID: 5})
|
||||
assert.Equal(t, activities_model.NotificationStatusRead, thread5.Status)
|
||||
|
||||
// -- check notifications --
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications/new?token=%s", token))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &new)
|
||||
assert.True(t, new.New == 0)
|
||||
}
|
||||
|
||||
func TestAPINotificationPUT(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
thread5 := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{ID: 5})
|
||||
assert.NoError(t, thread5.LoadAttributes())
|
||||
session := loginUser(t, user2.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
// Check notifications are as expected
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?all=true&token=%s", token))
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var apiNL []api.NotificationThread
|
||||
DecodeJSON(t, resp, &apiNL)
|
||||
|
||||
assert.Len(t, apiNL, 4)
|
||||
assert.EqualValues(t, 5, apiNL[0].ID)
|
||||
assert.True(t, apiNL[0].Unread)
|
||||
assert.False(t, apiNL[0].Pinned)
|
||||
assert.EqualValues(t, 4, apiNL[1].ID)
|
||||
assert.True(t, apiNL[1].Unread)
|
||||
assert.False(t, apiNL[1].Pinned)
|
||||
assert.EqualValues(t, 3, apiNL[2].ID)
|
||||
assert.False(t, apiNL[2].Unread)
|
||||
assert.True(t, apiNL[2].Pinned)
|
||||
assert.EqualValues(t, 2, apiNL[3].ID)
|
||||
assert.False(t, apiNL[3].Unread)
|
||||
assert.False(t, apiNL[3].Pinned)
|
||||
|
||||
//
|
||||
// Notification ID 2 is the only one with status-type read & pinned
|
||||
// change it to unread.
|
||||
//
|
||||
req = NewRequest(t, "PUT", fmt.Sprintf("/api/v1/notifications?status-types=read&status-type=pinned&to-status=unread&token=%s", token))
|
||||
resp = session.MakeRequest(t, req, http.StatusResetContent)
|
||||
DecodeJSON(t, resp, &apiNL)
|
||||
assert.Len(t, apiNL, 1)
|
||||
assert.EqualValues(t, 2, apiNL[0].ID)
|
||||
assert.True(t, apiNL[0].Unread)
|
||||
assert.False(t, apiNL[0].Pinned)
|
||||
|
||||
//
|
||||
// Now nofication ID 2 is the first in the list and is unread.
|
||||
//
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?all=true&token=%s", token))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiNL)
|
||||
|
||||
assert.Len(t, apiNL, 4)
|
||||
assert.EqualValues(t, 2, apiNL[0].ID)
|
||||
assert.True(t, apiNL[0].Unread)
|
||||
assert.False(t, apiNL[0].Pinned)
|
||||
}
|
166
tests/integration/api_oauth2_apps_test.go
Normal file
166
tests/integration/api_oauth2_apps_test.go
Normal file
|
@ -0,0 +1,166 @@
|
|||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.package models
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"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 TestOAuth2Application(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
testAPICreateOAuth2Application(t)
|
||||
testAPIListOAuth2Applications(t)
|
||||
testAPIGetOAuth2Application(t)
|
||||
testAPIUpdateOAuth2Application(t)
|
||||
testAPIDeleteOAuth2Application(t)
|
||||
}
|
||||
|
||||
func testAPICreateOAuth2Application(t *testing.T) {
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
appBody := api.CreateOAuth2ApplicationOptions{
|
||||
Name: "test-app-1",
|
||||
RedirectURIs: []string{
|
||||
"http://www.google.com",
|
||||
},
|
||||
}
|
||||
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/user/applications/oauth2", &appBody)
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
var createdApp *api.OAuth2Application
|
||||
DecodeJSON(t, resp, &createdApp)
|
||||
|
||||
assert.EqualValues(t, appBody.Name, createdApp.Name)
|
||||
assert.Len(t, createdApp.ClientSecret, 56)
|
||||
assert.Len(t, createdApp.ClientID, 36)
|
||||
assert.NotEmpty(t, createdApp.Created)
|
||||
assert.EqualValues(t, appBody.RedirectURIs[0], createdApp.RedirectURIs[0])
|
||||
unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{UID: user.ID, Name: createdApp.Name})
|
||||
}
|
||||
|
||||
func testAPIListOAuth2Applications(t *testing.T) {
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
existApp := unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{
|
||||
UID: user.ID,
|
||||
Name: "test-app-1",
|
||||
RedirectURIs: []string{
|
||||
"http://www.google.com",
|
||||
},
|
||||
})
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/user/applications/oauth2?token=%s", token)
|
||||
req := NewRequest(t, "GET", urlStr)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var appList api.OAuth2ApplicationList
|
||||
DecodeJSON(t, resp, &appList)
|
||||
expectedApp := appList[0]
|
||||
|
||||
assert.EqualValues(t, existApp.Name, expectedApp.Name)
|
||||
assert.EqualValues(t, existApp.ClientID, expectedApp.ClientID)
|
||||
assert.Len(t, expectedApp.ClientID, 36)
|
||||
assert.Empty(t, expectedApp.ClientSecret)
|
||||
assert.EqualValues(t, existApp.RedirectURIs[0], expectedApp.RedirectURIs[0])
|
||||
unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{ID: expectedApp.ID, Name: expectedApp.Name})
|
||||
}
|
||||
|
||||
func testAPIDeleteOAuth2Application(t *testing.T) {
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
oldApp := unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{
|
||||
UID: user.ID,
|
||||
Name: "test-app-1",
|
||||
})
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/user/applications/oauth2/%d?token=%s", oldApp.ID, token)
|
||||
req := NewRequest(t, "DELETE", urlStr)
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
unittest.AssertNotExistsBean(t, &auth.OAuth2Application{UID: oldApp.UID, Name: oldApp.Name})
|
||||
|
||||
// Delete again will return not found
|
||||
req = NewRequest(t, "DELETE", urlStr)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
||||
|
||||
func testAPIGetOAuth2Application(t *testing.T) {
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
existApp := unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{
|
||||
UID: user.ID,
|
||||
Name: "test-app-1",
|
||||
RedirectURIs: []string{
|
||||
"http://www.google.com",
|
||||
},
|
||||
})
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/user/applications/oauth2/%d?token=%s", existApp.ID, token)
|
||||
req := NewRequest(t, "GET", urlStr)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var app api.OAuth2Application
|
||||
DecodeJSON(t, resp, &app)
|
||||
expectedApp := app
|
||||
|
||||
assert.EqualValues(t, existApp.Name, expectedApp.Name)
|
||||
assert.EqualValues(t, existApp.ClientID, expectedApp.ClientID)
|
||||
assert.Len(t, expectedApp.ClientID, 36)
|
||||
assert.Empty(t, expectedApp.ClientSecret)
|
||||
assert.Len(t, expectedApp.RedirectURIs, 1)
|
||||
assert.EqualValues(t, existApp.RedirectURIs[0], expectedApp.RedirectURIs[0])
|
||||
unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{ID: expectedApp.ID, Name: expectedApp.Name})
|
||||
}
|
||||
|
||||
func testAPIUpdateOAuth2Application(t *testing.T) {
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
existApp := unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{
|
||||
UID: user.ID,
|
||||
Name: "test-app-1",
|
||||
RedirectURIs: []string{
|
||||
"http://www.google.com",
|
||||
},
|
||||
})
|
||||
|
||||
appBody := api.CreateOAuth2ApplicationOptions{
|
||||
Name: "test-app-1",
|
||||
RedirectURIs: []string{
|
||||
"http://www.google.com/",
|
||||
"http://www.github.com/",
|
||||
},
|
||||
}
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/user/applications/oauth2/%d", existApp.ID)
|
||||
req := NewRequestWithJSON(t, "PATCH", urlStr, &appBody)
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var app api.OAuth2Application
|
||||
DecodeJSON(t, resp, &app)
|
||||
expectedApp := app
|
||||
|
||||
assert.Len(t, expectedApp.RedirectURIs, 2)
|
||||
assert.EqualValues(t, expectedApp.RedirectURIs[0], appBody.RedirectURIs[0])
|
||||
assert.EqualValues(t, expectedApp.RedirectURIs[1], appBody.RedirectURIs[1])
|
||||
unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{ID: expectedApp.ID, Name: expectedApp.Name})
|
||||
}
|
153
tests/integration/api_org_test.go
Normal file
153
tests/integration/api_org_test.go
Normal file
|
@ -0,0 +1,153 @@
|
|||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"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/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIOrgCreate(t *testing.T) {
|
||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||
token := getUserToken(t, "user1")
|
||||
|
||||
org := api.CreateOrgOption{
|
||||
UserName: "user1_org",
|
||||
FullName: "User1's organization",
|
||||
Description: "This organization created by user1",
|
||||
Website: "https://try.gitea.io",
|
||||
Location: "Shanghai",
|
||||
Visibility: "limited",
|
||||
}
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/orgs?token="+token, &org)
|
||||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
var apiOrg api.Organization
|
||||
DecodeJSON(t, resp, &apiOrg)
|
||||
|
||||
assert.Equal(t, org.UserName, apiOrg.UserName)
|
||||
assert.Equal(t, org.FullName, apiOrg.FullName)
|
||||
assert.Equal(t, org.Description, apiOrg.Description)
|
||||
assert.Equal(t, org.Website, apiOrg.Website)
|
||||
assert.Equal(t, org.Location, apiOrg.Location)
|
||||
assert.Equal(t, org.Visibility, apiOrg.Visibility)
|
||||
|
||||
unittest.AssertExistsAndLoadBean(t, &user_model.User{
|
||||
Name: org.UserName,
|
||||
LowerName: strings.ToLower(org.UserName),
|
||||
FullName: org.FullName,
|
||||
})
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s?token=%s", org.UserName, token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiOrg)
|
||||
assert.EqualValues(t, org.UserName, apiOrg.UserName)
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/repos?token=%s", org.UserName, token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var repos []*api.Repository
|
||||
DecodeJSON(t, resp, &repos)
|
||||
for _, repo := range repos {
|
||||
assert.False(t, repo.Private)
|
||||
}
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/members?token=%s", org.UserName, token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// user1 on this org is public
|
||||
var users []*api.User
|
||||
DecodeJSON(t, resp, &users)
|
||||
assert.Len(t, users, 1)
|
||||
assert.EqualValues(t, "user1", users[0].UserName)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAPIOrgEdit(t *testing.T) {
|
||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||
session := loginUser(t, "user1")
|
||||
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
org := api.EditOrgOption{
|
||||
FullName: "User3 organization new full name",
|
||||
Description: "A new description",
|
||||
Website: "https://try.gitea.io/new",
|
||||
Location: "Beijing",
|
||||
Visibility: "private",
|
||||
}
|
||||
req := NewRequestWithJSON(t, "PATCH", "/api/v1/orgs/user3?token="+token, &org)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var apiOrg api.Organization
|
||||
DecodeJSON(t, resp, &apiOrg)
|
||||
|
||||
assert.Equal(t, "user3", apiOrg.UserName)
|
||||
assert.Equal(t, org.FullName, apiOrg.FullName)
|
||||
assert.Equal(t, org.Description, apiOrg.Description)
|
||||
assert.Equal(t, org.Website, apiOrg.Website)
|
||||
assert.Equal(t, org.Location, apiOrg.Location)
|
||||
assert.Equal(t, org.Visibility, apiOrg.Visibility)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAPIOrgEditBadVisibility(t *testing.T) {
|
||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||
session := loginUser(t, "user1")
|
||||
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
org := api.EditOrgOption{
|
||||
FullName: "User3 organization new full name",
|
||||
Description: "A new description",
|
||||
Website: "https://try.gitea.io/new",
|
||||
Location: "Beijing",
|
||||
Visibility: "badvisibility",
|
||||
}
|
||||
req := NewRequestWithJSON(t, "PATCH", "/api/v1/orgs/user3?token="+token, &org)
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAPIOrgDeny(t *testing.T) {
|
||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||
setting.Service.RequireSignInView = true
|
||||
defer func() {
|
||||
setting.Service.RequireSignInView = false
|
||||
}()
|
||||
|
||||
orgName := "user1_org"
|
||||
req := NewRequestf(t, "GET", "/api/v1/orgs/%s", orgName)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/repos", orgName)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/members", orgName)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAPIGetAll(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
req := NewRequestf(t, "GET", "/api/v1/orgs")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var apiOrgList []*api.Organization
|
||||
DecodeJSON(t, resp, &apiOrgList)
|
||||
|
||||
assert.Len(t, apiOrgList, 7)
|
||||
assert.Equal(t, "org25", apiOrgList[0].FullName)
|
||||
assert.Equal(t, "public", apiOrgList[0].Visibility)
|
||||
}
|
215
tests/integration/api_packages_composer_test.go
Normal file
215
tests/integration/api_packages_composer_test.go
Normal file
|
@ -0,0 +1,215 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
neturl "net/url"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
composer_module "code.gitea.io/gitea/modules/packages/composer"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/routers/api/packages/composer"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPackageComposer(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
vendorName := "gitea"
|
||||
projectName := "composer-package"
|
||||
packageName := vendorName + "/" + projectName
|
||||
packageVersion := "1.0.3"
|
||||
packageDescription := "Package Description"
|
||||
packageType := "composer-plugin"
|
||||
packageAuthor := "Gitea Authors"
|
||||
packageLicense := "MIT"
|
||||
|
||||
var buf bytes.Buffer
|
||||
archive := zip.NewWriter(&buf)
|
||||
w, _ := archive.Create("composer.json")
|
||||
w.Write([]byte(`{
|
||||
"name": "` + packageName + `",
|
||||
"description": "` + packageDescription + `",
|
||||
"type": "` + packageType + `",
|
||||
"license": "` + packageLicense + `",
|
||||
"authors": [
|
||||
{
|
||||
"name": "` + packageAuthor + `"
|
||||
}
|
||||
]
|
||||
}`))
|
||||
archive.Close()
|
||||
content := buf.Bytes()
|
||||
|
||||
url := fmt.Sprintf("%sapi/packages/%s/composer", setting.AppURL, user.Name)
|
||||
|
||||
t.Run("ServiceIndex", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/packages.json", url))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result composer.ServiceIndexResponse
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Equal(t, url+"/search.json?q=%query%&type=%type%", result.SearchTemplate)
|
||||
assert.Equal(t, url+"/p2/%package%.json", result.MetadataTemplate)
|
||||
assert.Equal(t, url+"/list.json", result.PackageList)
|
||||
})
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
t.Run("MissingVersion", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", url, bytes.NewReader(content))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusBadRequest)
|
||||
})
|
||||
|
||||
t.Run("Valid", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
uploadURL := url + "?version=" + packageVersion
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", uploadURL, bytes.NewReader(content))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeComposer)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, pd.SemVer)
|
||||
assert.IsType(t, &composer_module.Metadata{}, pd.Metadata)
|
||||
assert.Equal(t, packageName, pd.Package.Name)
|
||||
assert.Equal(t, packageVersion, pd.Version.Version)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 1)
|
||||
assert.Equal(t, fmt.Sprintf("%s-%s.%s.zip", vendorName, projectName, packageVersion), pfs[0].Name)
|
||||
assert.True(t, pfs[0].IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(len(content)), pb.Size)
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", uploadURL, bytes.NewReader(content))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusBadRequest)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Download", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeComposer)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
assert.Equal(t, int64(0), pvs[0].DownloadCount)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 1)
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/files/%s/%s/%s", url, neturl.PathEscape(packageName), neturl.PathEscape(pvs[0].LowerVersion), neturl.PathEscape(pfs[0].LowerName)))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, content, resp.Body.Bytes())
|
||||
|
||||
pvs, err = packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeComposer)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
assert.Equal(t, int64(1), pvs[0].DownloadCount)
|
||||
})
|
||||
|
||||
t.Run("SearchService", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
cases := []struct {
|
||||
Query string
|
||||
Type string
|
||||
Page int
|
||||
PerPage int
|
||||
ExpectedTotal int64
|
||||
ExpectedResults int
|
||||
}{
|
||||
{"", "", 0, 0, 1, 1},
|
||||
{"", "", 1, 1, 1, 1},
|
||||
{"test", "", 1, 0, 0, 0},
|
||||
{"gitea", "", 1, 1, 1, 1},
|
||||
{"gitea", "", 2, 1, 1, 0},
|
||||
{"", packageType, 1, 1, 1, 1},
|
||||
{"gitea", packageType, 1, 1, 1, 1},
|
||||
{"gitea", "dummy", 1, 1, 0, 0},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/search.json?q=%s&type=%s&page=%d&per_page=%d", url, c.Query, c.Type, c.Page, c.PerPage))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result composer.SearchResultResponse
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Equal(t, c.ExpectedTotal, result.Total, "case %d: unexpected total hits", i)
|
||||
assert.Len(t, result.Results, c.ExpectedResults, "case %d: unexpected result count", i)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("EnumeratePackages", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", url+"/list.json")
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result map[string][]string
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Contains(t, result, "packageNames")
|
||||
names := result["packageNames"]
|
||||
assert.Len(t, names, 1)
|
||||
assert.Equal(t, packageName, names[0])
|
||||
})
|
||||
|
||||
t.Run("PackageMetadata", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/p2/%s/%s.json", url, vendorName, projectName))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result composer.PackageMetadataResponse
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Contains(t, result.Packages, packageName)
|
||||
pkgs := result.Packages[packageName]
|
||||
assert.Len(t, pkgs, 1)
|
||||
assert.Equal(t, packageName, pkgs[0].Name)
|
||||
assert.Equal(t, packageVersion, pkgs[0].Version)
|
||||
assert.Equal(t, packageType, pkgs[0].Type)
|
||||
assert.Equal(t, packageDescription, pkgs[0].Description)
|
||||
assert.Len(t, pkgs[0].Authors, 1)
|
||||
assert.Equal(t, packageAuthor, pkgs[0].Authors[0].Name)
|
||||
assert.Equal(t, "zip", pkgs[0].Dist.Type)
|
||||
assert.Equal(t, "7b40bfd6da811b2b78deec1e944f156dbb2c747b", pkgs[0].Dist.Checksum)
|
||||
})
|
||||
}
|
725
tests/integration/api_packages_conan_test.go
Normal file
725
tests/integration/api_packages_conan_test.go
Normal file
|
@ -0,0 +1,725 @@
|
|||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
stdurl "net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
conan_model "code.gitea.io/gitea/models/packages/conan"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
conan_module "code.gitea.io/gitea/modules/packages/conan"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
conan_router "code.gitea.io/gitea/routers/api/packages/conan"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const (
|
||||
conanfileName = "conanfile.py"
|
||||
conaninfoName = "conaninfo.txt"
|
||||
|
||||
conanLicense = "MIT"
|
||||
conanAuthor = "Gitea <info@gitea.io>"
|
||||
conanHomepage = "https://gitea.io/"
|
||||
conanURL = "https://gitea.com/"
|
||||
conanDescription = "Description of ConanPackage"
|
||||
conanTopic = "gitea"
|
||||
|
||||
conanPackageReference = "dummyreference"
|
||||
|
||||
contentConaninfo = `[settings]
|
||||
arch=x84_64
|
||||
|
||||
[requires]
|
||||
fmt/7.1.3
|
||||
|
||||
[options]
|
||||
shared=False
|
||||
|
||||
[full_settings]
|
||||
arch=x84_64
|
||||
|
||||
[full_requires]
|
||||
fmt/7.1.3
|
||||
|
||||
[full_options]
|
||||
shared=False
|
||||
|
||||
[recipe_hash]
|
||||
74714915a51073acb548ca1ce29afbac
|
||||
|
||||
[env]
|
||||
CC=gcc-10`
|
||||
)
|
||||
|
||||
func addTokenAuthHeader(request *http.Request, token string) *http.Request {
|
||||
request.Header.Set("Authorization", token)
|
||||
return request
|
||||
}
|
||||
|
||||
func buildConanfileContent(name, version string) string {
|
||||
return `from conans import ConanFile, CMake, tools
|
||||
|
||||
class ConanPackageConan(ConanFile):
|
||||
name = "` + name + `"
|
||||
version = "` + version + `"
|
||||
license = "` + conanLicense + `"
|
||||
author = "` + conanAuthor + `"
|
||||
homepage = "` + conanHomepage + `"
|
||||
url = "` + conanURL + `"
|
||||
description = "` + conanDescription + `"
|
||||
topics = ("` + conanTopic + `")
|
||||
settings = "os", "compiler", "build_type", "arch"
|
||||
options = {"shared": [True, False], "fPIC": [True, False]}
|
||||
default_options = {"shared": False, "fPIC": True}
|
||||
generators = "cmake"`
|
||||
}
|
||||
|
||||
func uploadConanPackageV1(t *testing.T, baseURL, token, name, version, user, channel string) {
|
||||
contentConanfile := buildConanfileContent(name, version)
|
||||
|
||||
recipeURL := fmt.Sprintf("%s/v1/conans/%s/%s/%s/%s", baseURL, name, version, user, channel)
|
||||
|
||||
req := NewRequest(t, "GET", recipeURL)
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/digest", recipeURL))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/download_urls", recipeURL))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "POST", fmt.Sprintf("%s/upload_urls", recipeURL))
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
|
||||
req = NewRequestWithJSON(t, "POST", fmt.Sprintf("%s/upload_urls", recipeURL), map[string]int64{
|
||||
conanfileName: int64(len(contentConanfile)),
|
||||
"removed.txt": 0,
|
||||
})
|
||||
req = addTokenAuthHeader(req, token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
uploadURLs := make(map[string]string)
|
||||
DecodeJSON(t, resp, &uploadURLs)
|
||||
|
||||
assert.Contains(t, uploadURLs, conanfileName)
|
||||
assert.NotContains(t, uploadURLs, "removed.txt")
|
||||
|
||||
uploadURL := uploadURLs[conanfileName]
|
||||
assert.NotEmpty(t, uploadURL)
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", uploadURL, strings.NewReader(contentConanfile))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
packageURL := fmt.Sprintf("%s/packages/%s", recipeURL, conanPackageReference)
|
||||
|
||||
req = NewRequest(t, "GET", packageURL)
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/digest", packageURL))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/download_urls", packageURL))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "POST", fmt.Sprintf("%s/upload_urls", packageURL))
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
|
||||
req = NewRequestWithJSON(t, "POST", fmt.Sprintf("%s/upload_urls", packageURL), map[string]int64{
|
||||
conaninfoName: int64(len(contentConaninfo)),
|
||||
"removed.txt": 0,
|
||||
})
|
||||
req = addTokenAuthHeader(req, token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
uploadURLs = make(map[string]string)
|
||||
DecodeJSON(t, resp, &uploadURLs)
|
||||
|
||||
assert.Contains(t, uploadURLs, conaninfoName)
|
||||
assert.NotContains(t, uploadURLs, "removed.txt")
|
||||
|
||||
uploadURL = uploadURLs[conaninfoName]
|
||||
assert.NotEmpty(t, uploadURL)
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", uploadURL, strings.NewReader(contentConaninfo))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
}
|
||||
|
||||
func uploadConanPackageV2(t *testing.T, baseURL, token, name, version, user, channel, recipeRevision, packageRevision string) {
|
||||
contentConanfile := buildConanfileContent(name, version)
|
||||
|
||||
recipeURL := fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/revisions/%s", baseURL, name, version, user, channel, recipeRevision)
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/files/%s", recipeURL, conanfileName), strings.NewReader(contentConanfile))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/files", recipeURL))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var list *struct {
|
||||
Files map[string]interface{} `json:"files"`
|
||||
}
|
||||
DecodeJSON(t, resp, &list)
|
||||
assert.Len(t, list.Files, 1)
|
||||
assert.Contains(t, list.Files, conanfileName)
|
||||
|
||||
packageURL := fmt.Sprintf("%s/packages/%s/revisions/%s", recipeURL, conanPackageReference, packageRevision)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/files", packageURL))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/files/%s", packageURL, conaninfoName), strings.NewReader(contentConaninfo))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/files", packageURL))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
list = nil
|
||||
DecodeJSON(t, resp, &list)
|
||||
assert.Len(t, list.Files, 1)
|
||||
assert.Contains(t, list.Files, conaninfoName)
|
||||
}
|
||||
|
||||
func TestPackageConan(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
name := "ConanPackage"
|
||||
version1 := "1.2"
|
||||
version2 := "1.3"
|
||||
user1 := "dummy"
|
||||
user2 := "gitea"
|
||||
channel1 := "test"
|
||||
channel2 := "final"
|
||||
revision1 := "rev1"
|
||||
revision2 := "rev2"
|
||||
|
||||
url := fmt.Sprintf("%sapi/packages/%s/conan", setting.AppURL, user.Name)
|
||||
|
||||
t.Run("v1", func(t *testing.T) {
|
||||
t.Run("Ping", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/v1/ping", url))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, "revisions", resp.Header().Get("X-Conan-Server-Capabilities"))
|
||||
})
|
||||
|
||||
token := ""
|
||||
|
||||
t.Run("Authenticate", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/v1/users/authenticate", url))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
body := resp.Body.String()
|
||||
assert.NotEmpty(t, body)
|
||||
|
||||
token = fmt.Sprintf("Bearer %s", body)
|
||||
})
|
||||
|
||||
t.Run("CheckCredentials", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/v1/users/check_credentials", url))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
})
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
uploadConanPackageV1(t, url, token, name, version1, user1, channel1)
|
||||
|
||||
t.Run("Validate", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeConan)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, pd.SemVer)
|
||||
assert.Equal(t, name, pd.Package.Name)
|
||||
assert.Equal(t, version1, pd.Version.Version)
|
||||
assert.IsType(t, &conan_module.Metadata{}, pd.Metadata)
|
||||
metadata := pd.Metadata.(*conan_module.Metadata)
|
||||
assert.Equal(t, conanLicense, metadata.License)
|
||||
assert.Equal(t, conanAuthor, metadata.Author)
|
||||
assert.Equal(t, conanHomepage, metadata.ProjectURL)
|
||||
assert.Equal(t, conanURL, metadata.RepositoryURL)
|
||||
assert.Equal(t, conanDescription, metadata.Description)
|
||||
assert.Equal(t, []string{conanTopic}, metadata.Keywords)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 2)
|
||||
|
||||
for _, pf := range pfs {
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pf.BlobID)
|
||||
assert.NoError(t, err)
|
||||
|
||||
if pf.Name == conanfileName {
|
||||
assert.True(t, pf.IsLead)
|
||||
|
||||
assert.Equal(t, int64(len(buildConanfileContent(name, version1))), pb.Size)
|
||||
} else if pf.Name == conaninfoName {
|
||||
assert.False(t, pf.IsLead)
|
||||
|
||||
assert.Equal(t, int64(len(contentConaninfo)), pb.Size)
|
||||
} else {
|
||||
assert.Fail(t, "unknown file: %s", pf.Name)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Download", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
recipeURL := fmt.Sprintf("%s/v1/conans/%s/%s/%s/%s", url, name, version1, user1, channel1)
|
||||
|
||||
req := NewRequest(t, "GET", recipeURL)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
fileHashes := make(map[string]string)
|
||||
DecodeJSON(t, resp, &fileHashes)
|
||||
assert.Len(t, fileHashes, 1)
|
||||
assert.Contains(t, fileHashes, conanfileName)
|
||||
assert.Equal(t, "7abc52241c22090782c54731371847a8", fileHashes[conanfileName])
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/digest", recipeURL))
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
downloadURLs := make(map[string]string)
|
||||
DecodeJSON(t, resp, &downloadURLs)
|
||||
assert.Contains(t, downloadURLs, conanfileName)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/download_urls", recipeURL))
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
DecodeJSON(t, resp, &downloadURLs)
|
||||
assert.Contains(t, downloadURLs, conanfileName)
|
||||
|
||||
req = NewRequest(t, "GET", downloadURLs[conanfileName])
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, buildConanfileContent(name, version1), resp.Body.String())
|
||||
|
||||
packageURL := fmt.Sprintf("%s/packages/%s", recipeURL, conanPackageReference)
|
||||
|
||||
req = NewRequest(t, "GET", packageURL)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
fileHashes = make(map[string]string)
|
||||
DecodeJSON(t, resp, &fileHashes)
|
||||
assert.Len(t, fileHashes, 1)
|
||||
assert.Contains(t, fileHashes, conaninfoName)
|
||||
assert.Equal(t, "7628bfcc5b17f1470c468621a78df394", fileHashes[conaninfoName])
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/digest", packageURL))
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
downloadURLs = make(map[string]string)
|
||||
DecodeJSON(t, resp, &downloadURLs)
|
||||
assert.Contains(t, downloadURLs, conaninfoName)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/download_urls", packageURL))
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
DecodeJSON(t, resp, &downloadURLs)
|
||||
assert.Contains(t, downloadURLs, conaninfoName)
|
||||
|
||||
req = NewRequest(t, "GET", downloadURLs[conaninfoName])
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, contentConaninfo, resp.Body.String())
|
||||
})
|
||||
|
||||
t.Run("Search", func(t *testing.T) {
|
||||
uploadConanPackageV1(t, url, token, name, version2, user1, channel1)
|
||||
uploadConanPackageV1(t, url, token, name, version1, user1, channel2)
|
||||
uploadConanPackageV1(t, url, token, name, version1, user2, channel1)
|
||||
uploadConanPackageV1(t, url, token, name, version1, user2, channel2)
|
||||
|
||||
t.Run("Recipe", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
cases := []struct {
|
||||
Query string
|
||||
Expected []string
|
||||
}{
|
||||
{"ConanPackage", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1.2", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1.1", []string{}},
|
||||
{"Conan*", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/*", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1*", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/*2", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1*2", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1.2@", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1.2@du*", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@dummy/final"}},
|
||||
{"ConanPackage/1.2@du*/", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@dummy/final"}},
|
||||
{"ConanPackage/1.2@du*/*test", []string{"ConanPackage/1.2@dummy/test"}},
|
||||
{"ConanPackage/1.2@du*/*st", []string{"ConanPackage/1.2@dummy/test"}},
|
||||
{"ConanPackage/1.2@gitea/*", []string{"ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"*/*@dummy", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@dummy/final"}},
|
||||
{"*/*@*/final", []string{"ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/final"}},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/v1/conans/search?q=%s", url, stdurl.QueryEscape(c.Query)))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result *conan_router.SearchResult
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.ElementsMatch(t, c.Expected, result.Results, "case %d: unexpected result", i)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Package", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/v1/conans/%s/%s/%s/%s/search", url, name, version1, user1, channel2))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result map[string]*conan_module.Conaninfo
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Contains(t, result, conanPackageReference)
|
||||
info := result[conanPackageReference]
|
||||
assert.NotEmpty(t, info.Settings)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Delete", func(t *testing.T) {
|
||||
t.Run("Package", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
cases := []struct {
|
||||
Channel string
|
||||
References []string
|
||||
}{
|
||||
{channel1, []string{conanPackageReference}},
|
||||
{channel2, []string{}},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
rref, _ := conan_module.NewRecipeReference(name, version1, user1, c.Channel, conan_module.DefaultRevision)
|
||||
references, err := conan_model.GetPackageReferences(db.DefaultContext, user.ID, rref)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, references)
|
||||
|
||||
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("%s/v1/conans/%s/%s/%s/%s/packages/delete", url, name, version1, user1, c.Channel), map[string][]string{
|
||||
"package_ids": c.References,
|
||||
})
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
references, err = conan_model.GetPackageReferences(db.DefaultContext, user.ID, rref)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, references, "case %d: should be empty", i)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Recipe", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
cases := []struct {
|
||||
Channel string
|
||||
}{
|
||||
{channel1},
|
||||
{channel2},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
rref, _ := conan_module.NewRecipeReference(name, version1, user1, c.Channel, conan_module.DefaultRevision)
|
||||
revisions, err := conan_model.GetRecipeRevisions(db.DefaultContext, user.ID, rref)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, revisions)
|
||||
|
||||
req := NewRequest(t, "DELETE", fmt.Sprintf("%s/v1/conans/%s/%s/%s/%s", url, name, version1, user1, c.Channel))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
revisions, err = conan_model.GetRecipeRevisions(db.DefaultContext, user.ID, rref)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, revisions, "case %d: should be empty", i)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("v2", func(t *testing.T) {
|
||||
t.Run("Ping", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/v2/ping", url))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, "revisions", resp.Header().Get("X-Conan-Server-Capabilities"))
|
||||
})
|
||||
|
||||
token := ""
|
||||
|
||||
t.Run("Authenticate", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/v2/users/authenticate", url))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
body := resp.Body.String()
|
||||
assert.NotEmpty(t, body)
|
||||
|
||||
token = fmt.Sprintf("Bearer %s", body)
|
||||
})
|
||||
|
||||
t.Run("CheckCredentials", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/v2/users/check_credentials", url))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
})
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
uploadConanPackageV2(t, url, token, name, version1, user1, channel1, revision1, revision1)
|
||||
|
||||
t.Run("Validate", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeConan)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 2)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Latest", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
recipeURL := fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s", url, name, version1, user1, channel1)
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/latest", recipeURL))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
obj := make(map[string]string)
|
||||
DecodeJSON(t, resp, &obj)
|
||||
assert.Contains(t, obj, "revision")
|
||||
assert.Equal(t, revision1, obj["revision"])
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/revisions/%s/packages/%s/latest", recipeURL, revision1, conanPackageReference))
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
obj = make(map[string]string)
|
||||
DecodeJSON(t, resp, &obj)
|
||||
assert.Contains(t, obj, "revision")
|
||||
assert.Equal(t, revision1, obj["revision"])
|
||||
})
|
||||
|
||||
t.Run("ListRevisions", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
uploadConanPackageV2(t, url, token, name, version1, user1, channel1, revision1, revision2)
|
||||
uploadConanPackageV2(t, url, token, name, version1, user1, channel1, revision2, revision1)
|
||||
uploadConanPackageV2(t, url, token, name, version1, user1, channel1, revision2, revision2)
|
||||
|
||||
recipeURL := fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/revisions", url, name, version1, user1, channel1)
|
||||
|
||||
req := NewRequest(t, "GET", recipeURL)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
type RevisionInfo struct {
|
||||
Revision string `json:"revision"`
|
||||
Time time.Time `json:"time"`
|
||||
}
|
||||
|
||||
type RevisionList struct {
|
||||
Revisions []*RevisionInfo `json:"revisions"`
|
||||
}
|
||||
|
||||
var list *RevisionList
|
||||
DecodeJSON(t, resp, &list)
|
||||
assert.Len(t, list.Revisions, 2)
|
||||
revs := make([]string, 0, len(list.Revisions))
|
||||
for _, rev := range list.Revisions {
|
||||
revs = append(revs, rev.Revision)
|
||||
}
|
||||
assert.ElementsMatch(t, []string{revision1, revision2}, revs)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/%s/packages/%s/revisions", recipeURL, revision1, conanPackageReference))
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
DecodeJSON(t, resp, &list)
|
||||
assert.Len(t, list.Revisions, 2)
|
||||
revs = make([]string, 0, len(list.Revisions))
|
||||
for _, rev := range list.Revisions {
|
||||
revs = append(revs, rev.Revision)
|
||||
}
|
||||
assert.ElementsMatch(t, []string{revision1, revision2}, revs)
|
||||
})
|
||||
|
||||
t.Run("Search", func(t *testing.T) {
|
||||
t.Run("Recipe", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
cases := []struct {
|
||||
Query string
|
||||
Expected []string
|
||||
}{
|
||||
{"ConanPackage", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1.2", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1.1", []string{}},
|
||||
{"Conan*", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/*", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1*", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/*2", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1*2", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1.2@", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"ConanPackage/1.2@du*", []string{"ConanPackage/1.2@dummy/test"}},
|
||||
{"ConanPackage/1.2@du*/", []string{"ConanPackage/1.2@dummy/test"}},
|
||||
{"ConanPackage/1.2@du*/*test", []string{"ConanPackage/1.2@dummy/test"}},
|
||||
{"ConanPackage/1.2@du*/*st", []string{"ConanPackage/1.2@dummy/test"}},
|
||||
{"ConanPackage/1.2@gitea/*", []string{"ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
|
||||
{"*/*@dummy", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test"}},
|
||||
{"*/*@*/final", []string{"ConanPackage/1.2@gitea/final"}},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/v2/conans/search?q=%s", url, stdurl.QueryEscape(c.Query)))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result *conan_router.SearchResult
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.ElementsMatch(t, c.Expected, result.Results, "case %d: unexpected result", i)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Package", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/search", url, name, version1, user1, channel1))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result map[string]*conan_module.Conaninfo
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Contains(t, result, conanPackageReference)
|
||||
info := result[conanPackageReference]
|
||||
assert.NotEmpty(t, info.Settings)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/revisions/%s/search", url, name, version1, user1, channel1, revision1))
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
result = make(map[string]*conan_module.Conaninfo)
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Contains(t, result, conanPackageReference)
|
||||
info = result[conanPackageReference]
|
||||
assert.NotEmpty(t, info.Settings)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Delete", func(t *testing.T) {
|
||||
t.Run("Package", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
rref, _ := conan_module.NewRecipeReference(name, version1, user1, channel1, revision1)
|
||||
pref, _ := conan_module.NewPackageReference(rref, conanPackageReference, conan_module.DefaultRevision)
|
||||
|
||||
checkPackageRevisionCount := func(count int) {
|
||||
revisions, err := conan_model.GetPackageRevisions(db.DefaultContext, user.ID, pref)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, revisions, count)
|
||||
}
|
||||
checkPackageReferenceCount := func(count int) {
|
||||
references, err := conan_model.GetPackageReferences(db.DefaultContext, user.ID, rref)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, references, count)
|
||||
}
|
||||
|
||||
checkPackageRevisionCount(2)
|
||||
|
||||
req := NewRequest(t, "DELETE", fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/revisions/%s/packages/%s/revisions/%s", url, name, version1, user1, channel1, revision1, conanPackageReference, revision1))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
checkPackageRevisionCount(1)
|
||||
|
||||
req = NewRequest(t, "DELETE", fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/revisions/%s/packages/%s", url, name, version1, user1, channel1, revision1, conanPackageReference))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
checkPackageRevisionCount(0)
|
||||
|
||||
rref = rref.WithRevision(revision2)
|
||||
|
||||
checkPackageReferenceCount(1)
|
||||
|
||||
req = NewRequest(t, "DELETE", fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/revisions/%s/packages", url, name, version1, user1, channel1, revision2))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
checkPackageReferenceCount(0)
|
||||
})
|
||||
|
||||
t.Run("Recipe", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
rref, _ := conan_module.NewRecipeReference(name, version1, user1, channel1, conan_module.DefaultRevision)
|
||||
|
||||
checkRecipeRevisionCount := func(count int) {
|
||||
revisions, err := conan_model.GetRecipeRevisions(db.DefaultContext, user.ID, rref)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, revisions, count)
|
||||
}
|
||||
|
||||
checkRecipeRevisionCount(2)
|
||||
|
||||
req := NewRequest(t, "DELETE", fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/revisions/%s", url, name, version1, user1, channel1, revision1))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
checkRecipeRevisionCount(1)
|
||||
|
||||
req = NewRequest(t, "DELETE", fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s", url, name, version1, user1, channel1))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
checkRecipeRevisionCount(0)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
608
tests/integration/api_packages_container_test.go
Normal file
608
tests/integration/api_packages_container_test.go
Normal file
|
@ -0,0 +1,608 @@
|
|||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
packages_model "code.gitea.io/gitea/models/packages"
|
||||
container_model "code.gitea.io/gitea/models/packages/container"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
container_module "code.gitea.io/gitea/modules/packages/container"
|
||||
"code.gitea.io/gitea/modules/packages/container/oci"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPackageContainer(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
has := func(l packages_model.PackagePropertyList, name string) bool {
|
||||
for _, pp := range l {
|
||||
if pp.Name == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
getAllByName := func(l packages_model.PackagePropertyList, name string) []string {
|
||||
values := make([]string, 0, len(l))
|
||||
for _, pp := range l {
|
||||
if pp.Name == name {
|
||||
values = append(values, pp.Value)
|
||||
}
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
images := []string{"test", "te/st"}
|
||||
tags := []string{"latest", "main"}
|
||||
multiTag := "multi"
|
||||
|
||||
unknownDigest := "sha256:0000000000000000000000000000000000000000000000000000000000000000"
|
||||
|
||||
blobDigest := "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"
|
||||
blobContent, _ := base64.StdEncoding.DecodeString(`H4sIAAAJbogA/2IYBaNgFIxYAAgAAP//Lq+17wAEAAA=`)
|
||||
|
||||
configDigest := "sha256:4607e093bec406eaadb6f3a340f63400c9d3a7038680744c406903766b938f0d"
|
||||
configContent := `{"architecture":"amd64","config":{"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/true"],"ArgsEscaped":true,"Image":"sha256:9bd8b88dc68b80cffe126cc820e4b52c6e558eb3b37680bfee8e5f3ed7b8c257"},"container":"b89fe92a887d55c0961f02bdfbfd8ac3ddf66167db374770d2d9e9fab3311510","container_config":{"Hostname":"b89fe92a887d","Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/true\"]"],"ArgsEscaped":true,"Image":"sha256:9bd8b88dc68b80cffe126cc820e4b52c6e558eb3b37680bfee8e5f3ed7b8c257"},"created":"2022-01-01T00:00:00.000000000Z","docker_version":"20.10.12","history":[{"created":"2022-01-01T00:00:00.000000000Z","created_by":"/bin/sh -c #(nop) COPY file:0e7589b0c800daaf6fa460d2677101e4676dd9491980210cb345480e513f3602 in /true "},{"created":"2022-01-01T00:00:00.000000001Z","created_by":"/bin/sh -c #(nop) CMD [\"/true\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:0ff3b91bdf21ecdf2f2f3d4372c2098a14dbe06cd678e8f0a85fd4902d00e2e2"]}}`
|
||||
|
||||
manifestDigest := "sha256:4f10484d1c1bb13e3956b4de1cd42db8e0f14a75be1617b60f2de3cd59c803c6"
|
||||
manifestContent := `{"schemaVersion":2,"mediaType":"` + oci.MediaTypeDockerManifest + `","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:4607e093bec406eaadb6f3a340f63400c9d3a7038680744c406903766b938f0d","size":1069},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4","size":32}]}`
|
||||
|
||||
untaggedManifestDigest := "sha256:4305f5f5572b9a426b88909b036e52ee3cf3d7b9c1b01fac840e90747f56623d"
|
||||
untaggedManifestContent := `{"schemaVersion":2,"mediaType":"` + oci.MediaTypeImageManifest + `","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:4607e093bec406eaadb6f3a340f63400c9d3a7038680744c406903766b938f0d","size":1069},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4","size":32}]}`
|
||||
|
||||
indexManifestDigest := "sha256:bab112d6efb9e7f221995caaaa880352feb5bd8b1faf52fae8d12c113aa123ec"
|
||||
indexManifestContent := `{"schemaVersion":2,"mediaType":"` + oci.MediaTypeImageIndex + `","manifests":[{"mediaType":"` + oci.MediaTypeDockerManifest + `","digest":"` + manifestDigest + `","platform":{"os":"linux","architecture":"arm","variant":"v7"}},{"mediaType":"` + oci.MediaTypeImageManifest + `","digest":"` + untaggedManifestDigest + `","platform":{"os":"linux","architecture":"arm64","variant":"v8"}}]}`
|
||||
|
||||
anonymousToken := ""
|
||||
userToken := ""
|
||||
|
||||
t.Run("Authenticate", func(t *testing.T) {
|
||||
type TokenResponse struct {
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
authenticate := []string{`Bearer realm="` + setting.AppURL + `v2/token",service="container_registry",scope="*"`}
|
||||
|
||||
t.Run("Anonymous", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%sv2", setting.AppURL))
|
||||
resp := MakeRequest(t, req, http.StatusUnauthorized)
|
||||
|
||||
assert.ElementsMatch(t, authenticate, resp.Header().Values("WWW-Authenticate"))
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%sv2/token", setting.AppURL))
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
tokenResponse := &TokenResponse{}
|
||||
DecodeJSON(t, resp, &tokenResponse)
|
||||
|
||||
assert.NotEmpty(t, tokenResponse.Token)
|
||||
|
||||
anonymousToken = fmt.Sprintf("Bearer %s", tokenResponse.Token)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%sv2", setting.AppURL))
|
||||
addTokenAuthHeader(req, anonymousToken)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
})
|
||||
|
||||
t.Run("User", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%sv2", setting.AppURL))
|
||||
resp := MakeRequest(t, req, http.StatusUnauthorized)
|
||||
|
||||
assert.ElementsMatch(t, authenticate, resp.Header().Values("WWW-Authenticate"))
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%sv2/token", setting.AppURL))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
tokenResponse := &TokenResponse{}
|
||||
DecodeJSON(t, resp, &tokenResponse)
|
||||
|
||||
assert.NotEmpty(t, tokenResponse.Token)
|
||||
|
||||
userToken = fmt.Sprintf("Bearer %s", tokenResponse.Token)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%sv2", setting.AppURL))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("DetermineSupport", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%sv2", setting.AppURL))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, "registry/2.0", resp.Header().Get("Docker-Distribution-Api-Version"))
|
||||
})
|
||||
|
||||
for _, image := range images {
|
||||
t.Run(fmt.Sprintf("[Image:%s]", image), func(t *testing.T) {
|
||||
url := fmt.Sprintf("%sv2/%s/%s", setting.AppURL, user.Name, image)
|
||||
|
||||
t.Run("UploadBlob/Monolithic", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "POST", fmt.Sprintf("%s/blobs/uploads", url))
|
||||
addTokenAuthHeader(req, anonymousToken)
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
|
||||
req = NewRequestWithBody(t, "POST", fmt.Sprintf("%s/blobs/uploads?digest=%s", url, unknownDigest), bytes.NewReader(blobContent))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusBadRequest)
|
||||
|
||||
req = NewRequestWithBody(t, "POST", fmt.Sprintf("%s/blobs/uploads?digest=%s", url, blobDigest), bytes.NewReader(blobContent))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
assert.Equal(t, fmt.Sprintf("/v2/%s/%s/blobs/%s", user.Name, image, blobDigest), resp.Header().Get("Location"))
|
||||
assert.Equal(t, blobDigest, resp.Header().Get("Docker-Content-Digest"))
|
||||
|
||||
pv, err := packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, image, container_model.UploadVersion)
|
||||
assert.NoError(t, err)
|
||||
|
||||
pfs, err := packages_model.GetFilesByVersionID(db.DefaultContext, pv.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 1)
|
||||
|
||||
pb, err := packages_model.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, len(blobContent), pb.Size)
|
||||
})
|
||||
|
||||
t.Run("UploadBlob/Chunked", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "POST", fmt.Sprintf("%s/blobs/uploads", url))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp := MakeRequest(t, req, http.StatusAccepted)
|
||||
|
||||
uuid := resp.Header().Get("Docker-Upload-Uuid")
|
||||
assert.NotEmpty(t, uuid)
|
||||
|
||||
pbu, err := packages_model.GetBlobUploadByID(db.DefaultContext, uuid)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 0, pbu.BytesReceived)
|
||||
|
||||
uploadURL := resp.Header().Get("Location")
|
||||
assert.NotEmpty(t, uploadURL)
|
||||
|
||||
req = NewRequestWithBody(t, "PATCH", setting.AppURL+uploadURL[1:]+"000", bytes.NewReader(blobContent))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequestWithBody(t, "PATCH", setting.AppURL+uploadURL[1:], bytes.NewReader(blobContent))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
|
||||
req.Header.Set("Content-Range", "1-10")
|
||||
MakeRequest(t, req, http.StatusRequestedRangeNotSatisfiable)
|
||||
|
||||
contentRange := fmt.Sprintf("0-%d", len(blobContent)-1)
|
||||
req.Header.Set("Content-Range", contentRange)
|
||||
resp = MakeRequest(t, req, http.StatusAccepted)
|
||||
|
||||
assert.Equal(t, uuid, resp.Header().Get("Docker-Upload-Uuid"))
|
||||
assert.Equal(t, contentRange, resp.Header().Get("Range"))
|
||||
|
||||
pbu, err = packages_model.GetBlobUploadByID(db.DefaultContext, uuid)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, len(blobContent), pbu.BytesReceived)
|
||||
|
||||
uploadURL = resp.Header().Get("Location")
|
||||
|
||||
req = NewRequest(t, "PUT", fmt.Sprintf("%s?digest=%s", setting.AppURL+uploadURL[1:], blobDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp = MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
assert.Equal(t, fmt.Sprintf("/v2/%s/%s/blobs/%s", user.Name, image, blobDigest), resp.Header().Get("Location"))
|
||||
assert.Equal(t, blobDigest, resp.Header().Get("Docker-Content-Digest"))
|
||||
})
|
||||
|
||||
for _, tag := range tags {
|
||||
t.Run(fmt.Sprintf("[Tag:%s]", tag), func(t *testing.T) {
|
||||
t.Run("UploadManifest", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithBody(t, "POST", fmt.Sprintf("%s/blobs/uploads?digest=%s", url, configDigest), strings.NewReader(configContent))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/manifests/%s", url, tag), strings.NewReader(manifestContent))
|
||||
addTokenAuthHeader(req, anonymousToken)
|
||||
req.Header.Set("Content-Type", oci.MediaTypeDockerManifest)
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/manifests/%s", url, tag), strings.NewReader(manifestContent))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
req.Header.Set("Content-Type", oci.MediaTypeDockerManifest)
|
||||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
assert.Equal(t, manifestDigest, resp.Header().Get("Docker-Content-Digest"))
|
||||
|
||||
pv, err := packages_model.GetVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, image, tag)
|
||||
assert.NoError(t, err)
|
||||
|
||||
pd, err := packages_model.GetPackageDescriptor(db.DefaultContext, pv)
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, pd.SemVer)
|
||||
assert.Equal(t, image, pd.Package.Name)
|
||||
assert.Equal(t, tag, pd.Version.Version)
|
||||
assert.ElementsMatch(t, []string{strings.ToLower(user.LowerName + "/" + image)}, getAllByName(pd.PackageProperties, container_module.PropertyRepository))
|
||||
assert.True(t, has(pd.VersionProperties, container_module.PropertyManifestTagged))
|
||||
|
||||
assert.IsType(t, &container_module.Metadata{}, pd.Metadata)
|
||||
metadata := pd.Metadata.(*container_module.Metadata)
|
||||
assert.Equal(t, container_module.TypeOCI, metadata.Type)
|
||||
assert.Len(t, metadata.ImageLayers, 2)
|
||||
assert.Empty(t, metadata.MultiArch)
|
||||
|
||||
assert.Len(t, pd.Files, 3)
|
||||
for _, pfd := range pd.Files {
|
||||
switch pfd.File.Name {
|
||||
case container_model.ManifestFilename:
|
||||
assert.True(t, pfd.File.IsLead)
|
||||
assert.Equal(t, oci.MediaTypeDockerManifest, pfd.Properties.GetByName(container_module.PropertyMediaType))
|
||||
assert.Equal(t, manifestDigest, pfd.Properties.GetByName(container_module.PropertyDigest))
|
||||
case strings.Replace(configDigest, ":", "_", 1):
|
||||
assert.False(t, pfd.File.IsLead)
|
||||
assert.Equal(t, "application/vnd.docker.container.image.v1+json", pfd.Properties.GetByName(container_module.PropertyMediaType))
|
||||
assert.Equal(t, configDigest, pfd.Properties.GetByName(container_module.PropertyDigest))
|
||||
case strings.Replace(blobDigest, ":", "_", 1):
|
||||
assert.False(t, pfd.File.IsLead)
|
||||
assert.Equal(t, "application/vnd.docker.image.rootfs.diff.tar.gzip", pfd.Properties.GetByName(container_module.PropertyMediaType))
|
||||
assert.Equal(t, blobDigest, pfd.Properties.GetByName(container_module.PropertyDigest))
|
||||
default:
|
||||
assert.Fail(t, "unknown file: %s", pfd.File.Name)
|
||||
}
|
||||
}
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/manifests/%s", url, tag))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
pv, err = packages_model.GetVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, image, tag)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, pv.DownloadCount)
|
||||
|
||||
// Overwrite existing tag should keep the download count
|
||||
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/manifests/%s", url, tag), strings.NewReader(manifestContent))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
req.Header.Set("Content-Type", oci.MediaTypeDockerManifest)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
pv, err = packages_model.GetVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, image, tag)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, pv.DownloadCount)
|
||||
})
|
||||
|
||||
t.Run("HeadManifest", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "HEAD", fmt.Sprintf("%s/manifests/unknown-tag", url))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "HEAD", fmt.Sprintf("%s/manifests/%s", url, tag))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, fmt.Sprintf("%d", len(manifestContent)), resp.Header().Get("Content-Length"))
|
||||
assert.Equal(t, manifestDigest, resp.Header().Get("Docker-Content-Digest"))
|
||||
})
|
||||
|
||||
t.Run("GetManifest", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/manifests/unknown-tag", url))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/manifests/%s", url, tag))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, fmt.Sprintf("%d", len(manifestContent)), resp.Header().Get("Content-Length"))
|
||||
assert.Equal(t, oci.MediaTypeDockerManifest, resp.Header().Get("Content-Type"))
|
||||
assert.Equal(t, manifestDigest, resp.Header().Get("Docker-Content-Digest"))
|
||||
assert.Equal(t, manifestContent, resp.Body.String())
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("UploadUntaggedManifest", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/manifests/%s", url, untaggedManifestDigest), strings.NewReader(untaggedManifestContent))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
req.Header.Set("Content-Type", oci.MediaTypeImageManifest)
|
||||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
assert.Equal(t, untaggedManifestDigest, resp.Header().Get("Docker-Content-Digest"))
|
||||
|
||||
req = NewRequest(t, "HEAD", fmt.Sprintf("%s/manifests/%s", url, untaggedManifestDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, fmt.Sprintf("%d", len(untaggedManifestContent)), resp.Header().Get("Content-Length"))
|
||||
assert.Equal(t, untaggedManifestDigest, resp.Header().Get("Docker-Content-Digest"))
|
||||
|
||||
pv, err := packages_model.GetVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, image, untaggedManifestDigest)
|
||||
assert.NoError(t, err)
|
||||
|
||||
pd, err := packages_model.GetPackageDescriptor(db.DefaultContext, pv)
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, pd.SemVer)
|
||||
assert.Equal(t, image, pd.Package.Name)
|
||||
assert.Equal(t, untaggedManifestDigest, pd.Version.Version)
|
||||
assert.ElementsMatch(t, []string{strings.ToLower(user.LowerName + "/" + image)}, getAllByName(pd.PackageProperties, container_module.PropertyRepository))
|
||||
assert.False(t, has(pd.VersionProperties, container_module.PropertyManifestTagged))
|
||||
|
||||
assert.IsType(t, &container_module.Metadata{}, pd.Metadata)
|
||||
|
||||
assert.Len(t, pd.Files, 3)
|
||||
for _, pfd := range pd.Files {
|
||||
if pfd.File.Name == container_model.ManifestFilename {
|
||||
assert.True(t, pfd.File.IsLead)
|
||||
assert.Equal(t, oci.MediaTypeImageManifest, pfd.Properties.GetByName(container_module.PropertyMediaType))
|
||||
assert.Equal(t, untaggedManifestDigest, pfd.Properties.GetByName(container_module.PropertyDigest))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("UploadIndexManifest", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/manifests/%s", url, multiTag), strings.NewReader(indexManifestContent))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
req.Header.Set("Content-Type", oci.MediaTypeImageIndex)
|
||||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
assert.Equal(t, indexManifestDigest, resp.Header().Get("Docker-Content-Digest"))
|
||||
|
||||
pv, err := packages_model.GetVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, image, multiTag)
|
||||
assert.NoError(t, err)
|
||||
|
||||
pd, err := packages_model.GetPackageDescriptor(db.DefaultContext, pv)
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, pd.SemVer)
|
||||
assert.Equal(t, image, pd.Package.Name)
|
||||
assert.Equal(t, multiTag, pd.Version.Version)
|
||||
assert.ElementsMatch(t, []string{strings.ToLower(user.LowerName + "/" + image)}, getAllByName(pd.PackageProperties, container_module.PropertyRepository))
|
||||
assert.True(t, has(pd.VersionProperties, container_module.PropertyManifestTagged))
|
||||
|
||||
assert.ElementsMatch(t, []string{manifestDigest, untaggedManifestDigest}, getAllByName(pd.VersionProperties, container_module.PropertyManifestReference))
|
||||
|
||||
assert.IsType(t, &container_module.Metadata{}, pd.Metadata)
|
||||
metadata := pd.Metadata.(*container_module.Metadata)
|
||||
assert.Equal(t, container_module.TypeOCI, metadata.Type)
|
||||
assert.Contains(t, metadata.MultiArch, "linux/arm/v7")
|
||||
assert.Equal(t, manifestDigest, metadata.MultiArch["linux/arm/v7"])
|
||||
assert.Contains(t, metadata.MultiArch, "linux/arm64/v8")
|
||||
assert.Equal(t, untaggedManifestDigest, metadata.MultiArch["linux/arm64/v8"])
|
||||
|
||||
assert.Len(t, pd.Files, 1)
|
||||
assert.True(t, pd.Files[0].File.IsLead)
|
||||
assert.Equal(t, oci.MediaTypeImageIndex, pd.Files[0].Properties.GetByName(container_module.PropertyMediaType))
|
||||
assert.Equal(t, indexManifestDigest, pd.Files[0].Properties.GetByName(container_module.PropertyDigest))
|
||||
})
|
||||
|
||||
t.Run("UploadBlob/Mount", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "POST", fmt.Sprintf("%s/blobs/uploads?mount=%s", url, unknownDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusAccepted)
|
||||
|
||||
req = NewRequest(t, "POST", fmt.Sprintf("%s/blobs/uploads?mount=%s", url, blobDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
assert.Equal(t, fmt.Sprintf("/v2/%s/%s/blobs/%s", user.Name, image, blobDigest), resp.Header().Get("Location"))
|
||||
assert.Equal(t, blobDigest, resp.Header().Get("Docker-Content-Digest"))
|
||||
})
|
||||
|
||||
t.Run("HeadBlob", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "HEAD", fmt.Sprintf("%s/blobs/%s", url, unknownDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "HEAD", fmt.Sprintf("%s/blobs/%s", url, blobDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, fmt.Sprintf("%d", len(blobContent)), resp.Header().Get("Content-Length"))
|
||||
assert.Equal(t, blobDigest, resp.Header().Get("Docker-Content-Digest"))
|
||||
})
|
||||
|
||||
t.Run("GetBlob", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/blobs/%s", url, unknownDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/blobs/%s", url, blobDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, fmt.Sprintf("%d", len(blobContent)), resp.Header().Get("Content-Length"))
|
||||
assert.Equal(t, blobDigest, resp.Header().Get("Docker-Content-Digest"))
|
||||
assert.Equal(t, blobContent, resp.Body.Bytes())
|
||||
})
|
||||
|
||||
t.Run("GetTagList", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
cases := []struct {
|
||||
URL string
|
||||
ExpectedTags []string
|
||||
ExpectedLink string
|
||||
}{
|
||||
{
|
||||
URL: fmt.Sprintf("%s/tags/list", url),
|
||||
ExpectedTags: []string{"latest", "main", "multi"},
|
||||
ExpectedLink: fmt.Sprintf(`</v2/%s/%s/tags/list?last=multi>; rel="next"`, user.Name, image),
|
||||
},
|
||||
{
|
||||
URL: fmt.Sprintf("%s/tags/list?n=0", url),
|
||||
ExpectedTags: []string{},
|
||||
ExpectedLink: "",
|
||||
},
|
||||
{
|
||||
URL: fmt.Sprintf("%s/tags/list?n=2", url),
|
||||
ExpectedTags: []string{"latest", "main"},
|
||||
ExpectedLink: fmt.Sprintf(`</v2/%s/%s/tags/list?last=main&n=2>; rel="next"`, user.Name, image),
|
||||
},
|
||||
{
|
||||
URL: fmt.Sprintf("%s/tags/list?last=main", url),
|
||||
ExpectedTags: []string{"multi"},
|
||||
ExpectedLink: fmt.Sprintf(`</v2/%s/%s/tags/list?last=multi>; rel="next"`, user.Name, image),
|
||||
},
|
||||
{
|
||||
URL: fmt.Sprintf("%s/tags/list?n=1&last=latest", url),
|
||||
ExpectedTags: []string{"main"},
|
||||
ExpectedLink: fmt.Sprintf(`</v2/%s/%s/tags/list?last=main&n=1>; rel="next"`, user.Name, image),
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
req := NewRequest(t, "GET", c.URL)
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
type TagList struct {
|
||||
Name string `json:"name"`
|
||||
Tags []string `json:"tags"`
|
||||
}
|
||||
|
||||
tagList := &TagList{}
|
||||
DecodeJSON(t, resp, &tagList)
|
||||
|
||||
assert.Equal(t, user.Name+"/"+image, tagList.Name)
|
||||
assert.Equal(t, c.ExpectedTags, tagList.Tags)
|
||||
assert.Equal(t, c.ExpectedLink, resp.Header().Get("Link"))
|
||||
}
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s?type=container&q=%s", user.Name, image))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var apiPackages []*api.Package
|
||||
DecodeJSON(t, resp, &apiPackages)
|
||||
assert.Len(t, apiPackages, 4) // "latest", "main", "multi", "sha256:..."
|
||||
})
|
||||
|
||||
t.Run("Delete", func(t *testing.T) {
|
||||
t.Run("Blob", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "DELETE", fmt.Sprintf("%s/blobs/%s", url, blobDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusAccepted)
|
||||
|
||||
req = NewRequest(t, "HEAD", fmt.Sprintf("%s/blobs/%s", url, blobDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
|
||||
t.Run("ManifestByDigest", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "DELETE", fmt.Sprintf("%s/manifests/%s", url, untaggedManifestDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusAccepted)
|
||||
|
||||
req = NewRequest(t, "HEAD", fmt.Sprintf("%s/manifests/%s", url, untaggedManifestDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
|
||||
t.Run("ManifestByTag", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "DELETE", fmt.Sprintf("%s/manifests/%s", url, multiTag))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusAccepted)
|
||||
|
||||
req = NewRequest(t, "HEAD", fmt.Sprintf("%s/manifests/%s", url, multiTag))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("OwnerNameChange", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
checkCatalog := func(owner string) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%sv2/_catalog", setting.AppURL))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
type RepositoryList struct {
|
||||
Repositories []string `json:"repositories"`
|
||||
}
|
||||
|
||||
repoList := &RepositoryList{}
|
||||
DecodeJSON(t, resp, &repoList)
|
||||
|
||||
assert.Len(t, repoList.Repositories, len(images))
|
||||
names := make([]string, 0, len(images))
|
||||
for _, image := range images {
|
||||
names = append(names, strings.ToLower(owner+"/"+image))
|
||||
}
|
||||
assert.ElementsMatch(t, names, repoList.Repositories)
|
||||
}
|
||||
}
|
||||
|
||||
t.Run(fmt.Sprintf("Catalog[%s]", user.LowerName), checkCatalog(user.LowerName))
|
||||
|
||||
session := loginUser(t, user.Name)
|
||||
|
||||
newOwnerName := "newUsername"
|
||||
|
||||
req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{
|
||||
"_csrf": GetCSRF(t, session, "/user/settings"),
|
||||
"name": newOwnerName,
|
||||
"email": "user2@example.com",
|
||||
"language": "en-US",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
||||
t.Run(fmt.Sprintf("Catalog[%s]", newOwnerName), checkCatalog(newOwnerName))
|
||||
|
||||
req = NewRequestWithValues(t, "POST", "/user/settings", map[string]string{
|
||||
"_csrf": GetCSRF(t, session, "/user/settings"),
|
||||
"name": user.Name,
|
||||
"email": "user2@example.com",
|
||||
"language": "en-US",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
})
|
||||
}
|
194
tests/integration/api_packages_generic_test.go
Normal file
194
tests/integration/api_packages_generic_test.go
Normal file
|
@ -0,0 +1,194 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPackageGeneric(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
packageName := "te-st_pac.kage"
|
||||
packageVersion := "1.0.3-te st"
|
||||
filename := "fi-le_na.me"
|
||||
content := []byte{1, 2, 3}
|
||||
|
||||
url := fmt.Sprintf("/api/packages/%s/generic/%s/%s", user.Name, packageName, packageVersion)
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", url+"/"+filename, bytes.NewReader(content))
|
||||
AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, pd.Metadata)
|
||||
assert.Equal(t, packageName, pd.Package.Name)
|
||||
assert.Equal(t, packageVersion, pd.Version.Version)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 1)
|
||||
assert.Equal(t, filename, pfs[0].Name)
|
||||
assert.True(t, pfs[0].IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(len(content)), pb.Size)
|
||||
|
||||
t.Run("Exists", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", url+"/"+filename, bytes.NewReader(content))
|
||||
AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusConflict)
|
||||
})
|
||||
|
||||
t.Run("Additional", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", url+"/dummy.bin", bytes.NewReader(content))
|
||||
AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
// Check deduplication
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 2)
|
||||
assert.Equal(t, pfs[0].BlobID, pfs[1].BlobID)
|
||||
})
|
||||
|
||||
t.Run("InvalidParameter", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, "invalid+package name", packageVersion, filename), bytes.NewReader(content))
|
||||
AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusBadRequest)
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, packageName, "%20test ", filename), bytes.NewReader(content))
|
||||
AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusBadRequest)
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, packageName, packageVersion, "inval+id.na me"), bytes.NewReader(content))
|
||||
AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusBadRequest)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Download", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
checkDownloadCount := func(count int64) {
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
assert.Equal(t, count, pvs[0].DownloadCount)
|
||||
}
|
||||
|
||||
checkDownloadCount(0)
|
||||
|
||||
req := NewRequest(t, "GET", url+"/"+filename)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, content, resp.Body.Bytes())
|
||||
|
||||
checkDownloadCount(1)
|
||||
|
||||
req = NewRequest(t, "GET", url+"/dummy.bin")
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
checkDownloadCount(2)
|
||||
|
||||
t.Run("NotExists", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", url+"/not.found")
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Delete", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
t.Run("File", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "DELETE", url+"/"+filename)
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
|
||||
req = NewRequest(t, "DELETE", url+"/"+filename)
|
||||
AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
req = NewRequest(t, "GET", url+"/"+filename)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "DELETE", url+"/"+filename)
|
||||
AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
t.Run("RemovesVersion", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req = NewRequest(t, "DELETE", url+"/dummy.bin")
|
||||
AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, pvs)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Version", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", url+"/"+filename, bytes.NewReader(content))
|
||||
AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
req = NewRequest(t, "DELETE", url)
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
|
||||
req = NewRequest(t, "DELETE", url)
|
||||
AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, pvs)
|
||||
|
||||
req = NewRequest(t, "GET", url+"/"+filename)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "DELETE", url)
|
||||
AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
})
|
||||
}
|
167
tests/integration/api_packages_helm_test.go
Normal file
167
tests/integration/api_packages_helm_test.go
Normal file
|
@ -0,0 +1,167 @@
|
|||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
helm_module "code.gitea.io/gitea/modules/packages/helm"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
func TestPackageHelm(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
packageName := "test-chart"
|
||||
packageVersion := "1.0.3"
|
||||
packageAuthor := "KN4CK3R"
|
||||
packageDescription := "Gitea Test Package"
|
||||
|
||||
filename := fmt.Sprintf("%s-%s.tgz", packageName, packageVersion)
|
||||
|
||||
chartContent := `apiVersion: v2
|
||||
description: ` + packageDescription + `
|
||||
name: ` + packageName + `
|
||||
type: application
|
||||
version: ` + packageVersion + `
|
||||
maintainers:
|
||||
- name: ` + packageAuthor + `
|
||||
dependencies:
|
||||
- name: dep1
|
||||
repository: https://example.com/
|
||||
version: 1.0.0`
|
||||
|
||||
var buf bytes.Buffer
|
||||
zw := gzip.NewWriter(&buf)
|
||||
archive := tar.NewWriter(zw)
|
||||
archive.WriteHeader(&tar.Header{
|
||||
Name: fmt.Sprintf("%s/Chart.yaml", packageName),
|
||||
Mode: 0o600,
|
||||
Size: int64(len(chartContent)),
|
||||
})
|
||||
archive.Write([]byte(chartContent))
|
||||
archive.Close()
|
||||
zw.Close()
|
||||
content := buf.Bytes()
|
||||
|
||||
url := fmt.Sprintf("/api/packages/%s/helm", user.Name)
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
uploadURL := url + "/api/charts"
|
||||
|
||||
req := NewRequestWithBody(t, "POST", uploadURL, bytes.NewReader(content))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeHelm)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, pd.SemVer)
|
||||
assert.IsType(t, &helm_module.Metadata{}, pd.Metadata)
|
||||
assert.Equal(t, packageName, pd.Package.Name)
|
||||
assert.Equal(t, packageVersion, pd.Version.Version)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 1)
|
||||
assert.Equal(t, filename, pfs[0].Name)
|
||||
assert.True(t, pfs[0].IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(len(content)), pb.Size)
|
||||
|
||||
req = NewRequestWithBody(t, "POST", uploadURL, bytes.NewReader(content))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
})
|
||||
|
||||
t.Run("Download", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
checkDownloadCount := func(count int64) {
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeHelm)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
assert.Equal(t, count, pvs[0].DownloadCount)
|
||||
}
|
||||
|
||||
checkDownloadCount(0)
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/%s", url, filename))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, content, resp.Body.Bytes())
|
||||
|
||||
checkDownloadCount(1)
|
||||
})
|
||||
|
||||
t.Run("Index", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/index.yaml", url))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
type ChartVersion struct {
|
||||
helm_module.Metadata `yaml:",inline"`
|
||||
URLs []string `yaml:"urls"`
|
||||
Created time.Time `yaml:"created,omitempty"`
|
||||
Removed bool `yaml:"removed,omitempty"`
|
||||
Digest string `yaml:"digest,omitempty"`
|
||||
}
|
||||
|
||||
type ServerInfo struct {
|
||||
ContextPath string `yaml:"contextPath,omitempty"`
|
||||
}
|
||||
|
||||
type Index struct {
|
||||
APIVersion string `yaml:"apiVersion"`
|
||||
Entries map[string][]*ChartVersion `yaml:"entries"`
|
||||
Generated time.Time `yaml:"generated,omitempty"`
|
||||
ServerInfo *ServerInfo `yaml:"serverInfo,omitempty"`
|
||||
}
|
||||
|
||||
var result Index
|
||||
assert.NoError(t, yaml.NewDecoder(resp.Body).Decode(&result))
|
||||
assert.NotEmpty(t, result.Entries)
|
||||
assert.Contains(t, result.Entries, packageName)
|
||||
|
||||
cvs := result.Entries[packageName]
|
||||
assert.Len(t, cvs, 1)
|
||||
|
||||
cv := cvs[0]
|
||||
assert.Equal(t, packageName, cv.Name)
|
||||
assert.Equal(t, packageVersion, cv.Version)
|
||||
assert.Equal(t, packageDescription, cv.Description)
|
||||
assert.Len(t, cv.Maintainers, 1)
|
||||
assert.Equal(t, packageAuthor, cv.Maintainers[0].Name)
|
||||
assert.Len(t, cv.Dependencies, 1)
|
||||
assert.ElementsMatch(t, []string{fmt.Sprintf("%s%s/%s", setting.AppURL, url[1:], filename)}, cv.URLs)
|
||||
|
||||
assert.Equal(t, url, result.ServerInfo.ContextPath)
|
||||
})
|
||||
}
|
218
tests/integration/api_packages_maven_test.go
Normal file
218
tests/integration/api_packages_maven_test.go
Normal file
|
@ -0,0 +1,218 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/packages/maven"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPackageMaven(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
groupID := "com.gitea"
|
||||
artifactID := "test-project"
|
||||
packageName := groupID + "-" + artifactID
|
||||
packageVersion := "1.0.1"
|
||||
packageDescription := "Test Description"
|
||||
|
||||
root := fmt.Sprintf("/api/packages/%s/maven/%s/%s", user.Name, strings.ReplaceAll(groupID, ".", "/"), artifactID)
|
||||
filename := fmt.Sprintf("%s-%s.jar", packageName, packageVersion)
|
||||
|
||||
putFile := func(t *testing.T, path, content string, expectedStatus int) {
|
||||
req := NewRequestWithBody(t, "PUT", root+path, strings.NewReader(content))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, expectedStatus)
|
||||
}
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
putFile(t, fmt.Sprintf("/%s/%s", packageVersion, filename), "test", http.StatusCreated)
|
||||
putFile(t, fmt.Sprintf("/%s/%s", packageVersion, filename), "test", http.StatusBadRequest)
|
||||
putFile(t, "/maven-metadata.xml", "test", http.StatusOK)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, pd.SemVer)
|
||||
assert.Nil(t, pd.Metadata)
|
||||
assert.Equal(t, packageName, pd.Package.Name)
|
||||
assert.Equal(t, packageVersion, pd.Version.Version)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 1)
|
||||
assert.Equal(t, filename, pfs[0].Name)
|
||||
assert.False(t, pfs[0].IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(4), pb.Size)
|
||||
})
|
||||
|
||||
t.Run("UploadExists", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
putFile(t, fmt.Sprintf("/%s/%s", packageVersion, filename), "test", http.StatusBadRequest)
|
||||
})
|
||||
|
||||
t.Run("Download", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s", root, packageVersion, filename))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, []byte("test"), resp.Body.Bytes())
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
assert.Equal(t, int64(0), pvs[0].DownloadCount)
|
||||
})
|
||||
|
||||
t.Run("UploadVerifySHA1", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
t.Run("Missmatch", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
putFile(t, fmt.Sprintf("/%s/%s.sha1", packageVersion, filename), "test", http.StatusBadRequest)
|
||||
})
|
||||
t.Run("Valid", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
putFile(t, fmt.Sprintf("/%s/%s.sha1", packageVersion, filename), "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", http.StatusOK)
|
||||
})
|
||||
})
|
||||
|
||||
pomContent := `<?xml version="1.0"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<groupId>` + groupID + `</groupId>
|
||||
<artifactId>` + artifactID + `</artifactId>
|
||||
<version>` + packageVersion + `</version>
|
||||
<description>` + packageDescription + `</description>
|
||||
</project>`
|
||||
|
||||
t.Run("UploadPOM", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, pd.Metadata)
|
||||
|
||||
putFile(t, fmt.Sprintf("/%s/%s.pom", packageVersion, filename), pomContent, http.StatusCreated)
|
||||
|
||||
pvs, err = packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err = packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.IsType(t, &maven.Metadata{}, pd.Metadata)
|
||||
assert.Equal(t, packageDescription, pd.Metadata.(*maven.Metadata).Description)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 2)
|
||||
for _, pf := range pfs {
|
||||
if strings.HasSuffix(pf.Name, ".pom") {
|
||||
assert.Equal(t, filename+".pom", pf.Name)
|
||||
assert.True(t, pf.IsLead)
|
||||
} else {
|
||||
assert.False(t, pf.IsLead)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("DownloadPOM", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s.pom", root, packageVersion, filename))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, []byte(pomContent), resp.Body.Bytes())
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
assert.Equal(t, int64(1), pvs[0].DownloadCount)
|
||||
})
|
||||
|
||||
t.Run("DownloadChecksums", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/1.2.3/%s", root, filename))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
for key, checksum := range map[string]string{
|
||||
"md5": "098f6bcd4621d373cade4e832627b4f6",
|
||||
"sha1": "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3",
|
||||
"sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
|
||||
"sha512": "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff",
|
||||
} {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s.%s", root, packageVersion, filename, key))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, checksum, resp.Body.String())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("DownloadMetadata", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", root+"/maven-metadata.xml")
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
expectedMetadata := `<?xml version="1.0" encoding="UTF-8"?>` + "\n<metadata><groupId>com.gitea</groupId><artifactId>test-project</artifactId><versioning><release>1.0.1</release><latest>1.0.1</latest><versions><version>1.0.1</version></versions></versioning></metadata>"
|
||||
assert.Equal(t, expectedMetadata, resp.Body.String())
|
||||
|
||||
for key, checksum := range map[string]string{
|
||||
"md5": "6bee0cebaaa686d658adf3e7e16371a0",
|
||||
"sha1": "8696abce499fe84d9ea93e5492abe7147e195b6c",
|
||||
"sha256": "3f48322f81c4b2c3bb8649ae1e5c9801476162b520e1c2734ac06b2c06143208",
|
||||
"sha512": "cb075aa2e2ef1a83cdc14dd1e08c505b72d633399b39e73a21f00f0deecb39a3e2c79f157c1163f8a3854828750706e0dec3a0f5e4778e91f8ec2cf351a855f2",
|
||||
} {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/maven-metadata.xml.%s", root, key))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, checksum, resp.Body.String())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("UploadSnapshot", func(t *testing.T) {
|
||||
snapshotVersion := packageVersion + "-SNAPSHOT"
|
||||
|
||||
putFile(t, fmt.Sprintf("/%s/%s", snapshotVersion, filename), "test", http.StatusCreated)
|
||||
putFile(t, "/maven-metadata.xml", "test", http.StatusOK)
|
||||
putFile(t, fmt.Sprintf("/%s/maven-metadata.xml", snapshotVersion), "test", http.StatusCreated)
|
||||
putFile(t, fmt.Sprintf("/%s/maven-metadata.xml", snapshotVersion), "test-overwrite", http.StatusCreated)
|
||||
})
|
||||
}
|
279
tests/integration/api_packages_npm_test.go
Normal file
279
tests/integration/api_packages_npm_test.go
Normal file
|
@ -0,0 +1,279 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/packages/npm"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPackageNpm(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
token := fmt.Sprintf("Bearer %s", getTokenForLoggedInUser(t, loginUser(t, user.Name)))
|
||||
|
||||
packageName := "@scope/test-package"
|
||||
packageVersion := "1.0.1-pre"
|
||||
packageTag := "latest"
|
||||
packageTag2 := "release"
|
||||
packageAuthor := "KN4CK3R"
|
||||
packageDescription := "Test Description"
|
||||
|
||||
data := "H4sIAAAAAAAA/ytITM5OTE/VL4DQelnF+XkMVAYGBgZmJiYK2MRBwNDcSIHB2NTMwNDQzMwAqA7IMDUxA9LUdgg2UFpcklgEdAql5kD8ogCnhwio5lJQUMpLzE1VslJQcihOzi9I1S9JLS7RhSYIJR2QgrLUouLM/DyQGkM9Az1D3YIiqExKanFyUWZBCVQ2BKhVwQVJDKwosbQkI78IJO/tZ+LsbRykxFXLNdA+HwWjYBSMgpENACgAbtAACAAA"
|
||||
|
||||
buildUpload := func(version string) string {
|
||||
return `{
|
||||
"_id": "` + packageName + `",
|
||||
"name": "` + packageName + `",
|
||||
"description": "` + packageDescription + `",
|
||||
"dist-tags": {
|
||||
"` + packageTag + `": "` + version + `"
|
||||
},
|
||||
"versions": {
|
||||
"` + version + `": {
|
||||
"name": "` + packageName + `",
|
||||
"version": "` + version + `",
|
||||
"description": "` + packageDescription + `",
|
||||
"author": {
|
||||
"name": "` + packageAuthor + `"
|
||||
},
|
||||
"dist": {
|
||||
"integrity": "sha512-yA4FJsVhetynGfOC1jFf79BuS+jrHbm0fhh+aHzCQkOaOBXKf9oBnC4a6DnLLnEsHQDRLYd00cwj8sCXpC+wIg==",
|
||||
"shasum": "aaa7eaf852a948b0aa05afeda35b1badca155d90"
|
||||
}
|
||||
}
|
||||
},
|
||||
"_attachments": {
|
||||
"` + packageName + `-` + version + `.tgz": {
|
||||
"data": "` + data + `"
|
||||
}
|
||||
}
|
||||
}`
|
||||
}
|
||||
|
||||
root := fmt.Sprintf("/api/packages/%s/npm/%s", user.Name, url.QueryEscape(packageName))
|
||||
tagsRoot := fmt.Sprintf("/api/packages/%s/npm/-/package/%s/dist-tags", user.Name, url.QueryEscape(packageName))
|
||||
filename := fmt.Sprintf("%s-%s.tgz", strings.Split(packageName, "/")[1], packageVersion)
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", root, strings.NewReader(buildUpload(packageVersion)))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNpm)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, pd.SemVer)
|
||||
assert.IsType(t, &npm.Metadata{}, pd.Metadata)
|
||||
assert.Equal(t, packageName, pd.Package.Name)
|
||||
assert.Equal(t, packageVersion, pd.Version.Version)
|
||||
assert.Len(t, pd.VersionProperties, 1)
|
||||
assert.Equal(t, npm.TagProperty, pd.VersionProperties[0].Name)
|
||||
assert.Equal(t, packageTag, pd.VersionProperties[0].Value)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 1)
|
||||
assert.Equal(t, filename, pfs[0].Name)
|
||||
assert.True(t, pfs[0].IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(192), pb.Size)
|
||||
})
|
||||
|
||||
t.Run("UploadExists", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", root, strings.NewReader(buildUpload(packageVersion)))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusBadRequest)
|
||||
})
|
||||
|
||||
t.Run("Download", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/-/%s/%s", root, packageVersion, filename))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
b, _ := base64.StdEncoding.DecodeString(data)
|
||||
assert.Equal(t, b, resp.Body.Bytes())
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNpm)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
assert.Equal(t, int64(1), pvs[0].DownloadCount)
|
||||
})
|
||||
|
||||
t.Run("PackageMetadata", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/api/packages/%s/npm/%s", user.Name, "does-not-exist"))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", root)
|
||||
req = addTokenAuthHeader(req, token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result npm.PackageMetadata
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Equal(t, packageName, result.ID)
|
||||
assert.Equal(t, packageName, result.Name)
|
||||
assert.Equal(t, packageDescription, result.Description)
|
||||
assert.Contains(t, result.DistTags, packageTag)
|
||||
assert.Equal(t, packageVersion, result.DistTags[packageTag])
|
||||
assert.Equal(t, packageAuthor, result.Author.Name)
|
||||
assert.Contains(t, result.Versions, packageVersion)
|
||||
pmv := result.Versions[packageVersion]
|
||||
assert.Equal(t, fmt.Sprintf("%s@%s", packageName, packageVersion), pmv.ID)
|
||||
assert.Equal(t, packageName, pmv.Name)
|
||||
assert.Equal(t, packageDescription, pmv.Description)
|
||||
assert.Equal(t, packageAuthor, pmv.Author.Name)
|
||||
assert.Equal(t, "sha512-yA4FJsVhetynGfOC1jFf79BuS+jrHbm0fhh+aHzCQkOaOBXKf9oBnC4a6DnLLnEsHQDRLYd00cwj8sCXpC+wIg==", pmv.Dist.Integrity)
|
||||
assert.Equal(t, "aaa7eaf852a948b0aa05afeda35b1badca155d90", pmv.Dist.Shasum)
|
||||
assert.Equal(t, fmt.Sprintf("%s%s/-/%s/%s", setting.AppURL, root[1:], packageVersion, filename), pmv.Dist.Tarball)
|
||||
})
|
||||
|
||||
t.Run("AddTag", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
test := func(t *testing.T, status int, tag, version string) {
|
||||
req := NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/%s", tagsRoot, tag), strings.NewReader(`"`+version+`"`))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, status)
|
||||
}
|
||||
|
||||
test(t, http.StatusBadRequest, "1.0", packageVersion)
|
||||
test(t, http.StatusBadRequest, "v1.0", packageVersion)
|
||||
test(t, http.StatusNotFound, packageTag2, "1.2")
|
||||
test(t, http.StatusOK, packageTag, packageVersion)
|
||||
test(t, http.StatusOK, packageTag2, packageVersion)
|
||||
})
|
||||
|
||||
t.Run("ListTags", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", tagsRoot)
|
||||
req = addTokenAuthHeader(req, token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result map[string]string
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Len(t, result, 2)
|
||||
assert.Contains(t, result, packageTag)
|
||||
assert.Equal(t, packageVersion, result[packageTag])
|
||||
assert.Contains(t, result, packageTag2)
|
||||
assert.Equal(t, packageVersion, result[packageTag2])
|
||||
})
|
||||
|
||||
t.Run("PackageMetadataDistTags", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", root)
|
||||
req = addTokenAuthHeader(req, token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result npm.PackageMetadata
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Len(t, result.DistTags, 2)
|
||||
assert.Contains(t, result.DistTags, packageTag)
|
||||
assert.Equal(t, packageVersion, result.DistTags[packageTag])
|
||||
assert.Contains(t, result.DistTags, packageTag2)
|
||||
assert.Equal(t, packageVersion, result.DistTags[packageTag2])
|
||||
})
|
||||
|
||||
t.Run("DeleteTag", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
test := func(t *testing.T, status int, tag string) {
|
||||
req := NewRequest(t, "DELETE", fmt.Sprintf("%s/%s", tagsRoot, tag))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, status)
|
||||
}
|
||||
|
||||
test(t, http.StatusBadRequest, "v1.0")
|
||||
test(t, http.StatusBadRequest, "1.0")
|
||||
test(t, http.StatusOK, "dummy")
|
||||
test(t, http.StatusOK, packageTag2)
|
||||
})
|
||||
|
||||
t.Run("Delete", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", root, strings.NewReader(buildUpload(packageVersion+"-dummy")))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
req = NewRequest(t, "PUT", root+"/-rev/dummy")
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
|
||||
req = NewRequest(t, "PUT", root+"/-rev/dummy")
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
t.Run("Version", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNpm)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 2)
|
||||
|
||||
req := NewRequest(t, "DELETE", fmt.Sprintf("%s/-/%s/%s/-rev/dummy", root, packageVersion, filename))
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
|
||||
req = NewRequest(t, "DELETE", fmt.Sprintf("%s/-/%s/%s/-rev/dummy", root, packageVersion, filename))
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
pvs, err = packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNpm)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
})
|
||||
|
||||
t.Run("Full", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNpm)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
req := NewRequest(t, "DELETE", root+"/-rev/dummy")
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
|
||||
req = NewRequest(t, "DELETE", root+"/-rev/dummy")
|
||||
req = addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
pvs, err = packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNpm)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 0)
|
||||
})
|
||||
})
|
||||
}
|
393
tests/integration/api_packages_nuget_test.go
Normal file
393
tests/integration/api_packages_nuget_test.go
Normal file
|
@ -0,0 +1,393 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
nuget_module "code.gitea.io/gitea/modules/packages/nuget"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/routers/api/packages/nuget"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func addNuGetAPIKeyHeader(request *http.Request, token string) *http.Request {
|
||||
request.Header.Set("X-NuGet-ApiKey", token)
|
||||
return request
|
||||
}
|
||||
|
||||
func TestPackageNuGet(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
token := getUserToken(t, user.Name)
|
||||
|
||||
packageName := "test.package"
|
||||
packageVersion := "1.0.3"
|
||||
packageAuthors := "KN4CK3R"
|
||||
packageDescription := "Gitea Test Package"
|
||||
symbolFilename := "test.pdb"
|
||||
symbolID := "d910bb6948bd4c6cb40155bcf52c3c94"
|
||||
|
||||
var buf bytes.Buffer
|
||||
archive := zip.NewWriter(&buf)
|
||||
w, _ := archive.Create("package.nuspec")
|
||||
w.Write([]byte(`<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>` + packageName + `</id>
|
||||
<version>` + packageVersion + `</version>
|
||||
<authors>` + packageAuthors + `</authors>
|
||||
<description>` + packageDescription + `</description>
|
||||
<group targetFramework=".NETStandard2.0">
|
||||
<dependency id="Microsoft.CSharp" version="4.5.0" />
|
||||
</group>
|
||||
</metadata>
|
||||
</package>`))
|
||||
archive.Close()
|
||||
content := buf.Bytes()
|
||||
|
||||
url := fmt.Sprintf("/api/packages/%s/nuget", user.Name)
|
||||
|
||||
t.Run("ServiceIndex", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/index.json", url))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/index.json", url))
|
||||
req = addNuGetAPIKeyHeader(req, token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result nuget.ServiceIndexResponse
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Equal(t, "3.0.0", result.Version)
|
||||
assert.NotEmpty(t, result.Resources)
|
||||
|
||||
root := setting.AppURL + url[1:]
|
||||
for _, r := range result.Resources {
|
||||
switch r.Type {
|
||||
case "SearchQueryService":
|
||||
fallthrough
|
||||
case "SearchQueryService/3.0.0-beta":
|
||||
fallthrough
|
||||
case "SearchQueryService/3.0.0-rc":
|
||||
assert.Equal(t, root+"/query", r.ID)
|
||||
case "RegistrationsBaseUrl":
|
||||
fallthrough
|
||||
case "RegistrationsBaseUrl/3.0.0-beta":
|
||||
fallthrough
|
||||
case "RegistrationsBaseUrl/3.0.0-rc":
|
||||
assert.Equal(t, root+"/registration", r.ID)
|
||||
case "PackageBaseAddress/3.0.0":
|
||||
assert.Equal(t, root+"/package", r.ID)
|
||||
case "PackagePublish/2.0.0":
|
||||
assert.Equal(t, root, r.ID)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
t.Run("DependencyPackage", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", url, bytes.NewReader(content))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNuGet)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, pd.SemVer)
|
||||
assert.IsType(t, &nuget_module.Metadata{}, pd.Metadata)
|
||||
assert.Equal(t, packageName, pd.Package.Name)
|
||||
assert.Equal(t, packageVersion, pd.Version.Version)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 1)
|
||||
assert.Equal(t, fmt.Sprintf("%s.%s.nupkg", packageName, packageVersion), pfs[0].Name)
|
||||
assert.True(t, pfs[0].IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(len(content)), pb.Size)
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", url, bytes.NewReader(content))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusConflict)
|
||||
})
|
||||
|
||||
t.Run("SymbolPackage", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
createPackage := func(id, packageType string) io.Reader {
|
||||
var buf bytes.Buffer
|
||||
archive := zip.NewWriter(&buf)
|
||||
|
||||
w, _ := archive.Create("package.nuspec")
|
||||
w.Write([]byte(`<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>` + id + `</id>
|
||||
<version>` + packageVersion + `</version>
|
||||
<authors>` + packageAuthors + `</authors>
|
||||
<description>` + packageDescription + `</description>
|
||||
<packageTypes><packageType name="` + packageType + `" /></packageTypes>
|
||||
</metadata>
|
||||
</package>`))
|
||||
|
||||
w, _ = archive.Create(symbolFilename)
|
||||
b, _ := base64.StdEncoding.DecodeString(`QlNKQgEAAQAAAAAADAAAAFBEQiB2MS4wAAAAAAAABgB8AAAAWAAAACNQZGIAAAAA1AAAAAgBAAAj
|
||||
fgAA3AEAAAQAAAAjU3RyaW5ncwAAAADgAQAABAAAACNVUwDkAQAAMAAAACNHVUlEAAAAFAIAACgB
|
||||
AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
|
||||
w.Write(b)
|
||||
|
||||
archive.Close()
|
||||
return &buf
|
||||
}
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/symbolpackage", url), createPackage("unknown-package", "SymbolsPackage"))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/symbolpackage", url), createPackage(packageName, "DummyPackage"))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusBadRequest)
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/symbolpackage", url), createPackage(packageName, "SymbolsPackage"))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNuGet)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, pd.SemVer)
|
||||
assert.IsType(t, &nuget_module.Metadata{}, pd.Metadata)
|
||||
assert.Equal(t, packageName, pd.Package.Name)
|
||||
assert.Equal(t, packageVersion, pd.Version.Version)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 3)
|
||||
for _, pf := range pfs {
|
||||
switch pf.Name {
|
||||
case fmt.Sprintf("%s.%s.nupkg", packageName, packageVersion):
|
||||
case fmt.Sprintf("%s.%s.snupkg", packageName, packageVersion):
|
||||
assert.False(t, pf.IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pf.BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(616), pb.Size)
|
||||
case symbolFilename:
|
||||
assert.False(t, pf.IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pf.BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(160), pb.Size)
|
||||
|
||||
pps, err := packages.GetProperties(db.DefaultContext, packages.PropertyTypeFile, pf.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pps, 1)
|
||||
assert.Equal(t, nuget_module.PropertySymbolID, pps[0].Name)
|
||||
assert.Equal(t, symbolID, pps[0].Value)
|
||||
default:
|
||||
assert.Fail(t, "unexpected file: %v", pf.Name)
|
||||
}
|
||||
}
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/symbolpackage", url), createPackage(packageName, "SymbolsPackage"))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusConflict)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Download", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
checkDownloadCount := func(count int64) {
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNuGet)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
assert.Equal(t, count, pvs[0].DownloadCount)
|
||||
}
|
||||
|
||||
checkDownloadCount(0)
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s.%s.nupkg", url, packageName, packageVersion, packageName, packageVersion))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, content, resp.Body.Bytes())
|
||||
|
||||
checkDownloadCount(1)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s.%s.snupkg", url, packageName, packageVersion, packageName, packageVersion))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
checkDownloadCount(1)
|
||||
|
||||
t.Run("Symbol", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/symbols/%s/%sFFFFFFFF/gitea.pdb", url, symbolFilename, symbolID))
|
||||
MakeRequest(t, req, http.StatusBadRequest)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/symbols/%s/%sFFFFFFFF/%s", url, symbolFilename, "00000000000000000000000000000000", symbolFilename))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/symbols/%s/%sFFFFFFFF/%s", url, symbolFilename, symbolID, symbolFilename))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
checkDownloadCount(1)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("SearchService", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
cases := []struct {
|
||||
Query string
|
||||
Skip int
|
||||
Take int
|
||||
ExpectedTotal int64
|
||||
ExpectedResults int
|
||||
}{
|
||||
{"", 0, 0, 1, 1},
|
||||
{"", 0, 10, 1, 1},
|
||||
{"gitea", 0, 10, 0, 0},
|
||||
{"test", 0, 10, 1, 1},
|
||||
{"test", 1, 10, 1, 0},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/query?q=%s&skip=%d&take=%d", url, c.Query, c.Skip, c.Take))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result nuget.SearchResultResponse
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Equal(t, c.ExpectedTotal, result.TotalHits, "case %d: unexpected total hits", i)
|
||||
assert.Len(t, result.Data, c.ExpectedResults, "case %d: unexpected result count", i)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("RegistrationService", func(t *testing.T) {
|
||||
indexURL := fmt.Sprintf("%s%s/registration/%s/index.json", setting.AppURL, url[1:], packageName)
|
||||
leafURL := fmt.Sprintf("%s%s/registration/%s/%s.json", setting.AppURL, url[1:], packageName, packageVersion)
|
||||
contentURL := fmt.Sprintf("%s%s/package/%s/%s/%s.%s.nupkg", setting.AppURL, url[1:], packageName, packageVersion, packageName, packageVersion)
|
||||
|
||||
t.Run("RegistrationIndex", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/registration/%s/index.json", url, packageName))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result nuget.RegistrationIndexResponse
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Equal(t, indexURL, result.RegistrationIndexURL)
|
||||
assert.Equal(t, 1, result.Count)
|
||||
assert.Len(t, result.Pages, 1)
|
||||
assert.Equal(t, indexURL, result.Pages[0].RegistrationPageURL)
|
||||
assert.Equal(t, packageVersion, result.Pages[0].Lower)
|
||||
assert.Equal(t, packageVersion, result.Pages[0].Upper)
|
||||
assert.Equal(t, 1, result.Pages[0].Count)
|
||||
assert.Len(t, result.Pages[0].Items, 1)
|
||||
assert.Equal(t, packageName, result.Pages[0].Items[0].CatalogEntry.ID)
|
||||
assert.Equal(t, packageVersion, result.Pages[0].Items[0].CatalogEntry.Version)
|
||||
assert.Equal(t, packageAuthors, result.Pages[0].Items[0].CatalogEntry.Authors)
|
||||
assert.Equal(t, packageDescription, result.Pages[0].Items[0].CatalogEntry.Description)
|
||||
assert.Equal(t, leafURL, result.Pages[0].Items[0].CatalogEntry.CatalogLeafURL)
|
||||
assert.Equal(t, contentURL, result.Pages[0].Items[0].CatalogEntry.PackageContentURL)
|
||||
})
|
||||
|
||||
t.Run("RegistrationLeaf", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/registration/%s/%s.json", url, packageName, packageVersion))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result nuget.RegistrationLeafResponse
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Equal(t, leafURL, result.RegistrationLeafURL)
|
||||
assert.Equal(t, contentURL, result.PackageContentURL)
|
||||
assert.Equal(t, indexURL, result.RegistrationIndexURL)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("PackageService", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/index.json", url, packageName))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result nuget.PackageVersionsResponse
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Len(t, result.Versions, 1)
|
||||
assert.Equal(t, packageVersion, result.Versions[0])
|
||||
})
|
||||
|
||||
t.Run("Delete", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "DELETE", fmt.Sprintf("%s/%s/%s", url, packageName, packageVersion))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNuGet)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, pvs)
|
||||
})
|
||||
|
||||
t.Run("DownloadNotExists", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s.%s.nupkg", url, packageName, packageVersion, packageName, packageVersion))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s.%s.snupkg", url, packageName, packageVersion, packageName, packageVersion))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
|
||||
t.Run("DeleteNotExists", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "DELETE", fmt.Sprintf("%s/package/%s/%s", url, packageName, packageVersion))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
}
|
180
tests/integration/api_packages_pub_test.go
Normal file
180
tests/integration/api_packages_pub_test.go
Normal file
|
@ -0,0 +1,180 @@
|
|||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
pub_module "code.gitea.io/gitea/modules/packages/pub"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPackagePub(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
token := "Bearer " + getUserToken(t, user.Name)
|
||||
|
||||
packageName := "test_package"
|
||||
packageVersion := "1.0.1"
|
||||
packageDescription := "Test Description"
|
||||
|
||||
filename := fmt.Sprintf("%s.tar.gz", packageVersion)
|
||||
|
||||
pubspecContent := `name: ` + packageName + `
|
||||
version: ` + packageVersion + `
|
||||
description: ` + packageDescription
|
||||
|
||||
var buf bytes.Buffer
|
||||
zw := gzip.NewWriter(&buf)
|
||||
archive := tar.NewWriter(zw)
|
||||
archive.WriteHeader(&tar.Header{
|
||||
Name: "pubspec.yaml",
|
||||
Mode: 0o600,
|
||||
Size: int64(len(pubspecContent)),
|
||||
})
|
||||
archive.Write([]byte(pubspecContent))
|
||||
archive.Close()
|
||||
zw.Close()
|
||||
content := buf.Bytes()
|
||||
|
||||
root := fmt.Sprintf("/api/packages/%s/pub", user.Name)
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
uploadURL := root + "/api/packages/versions/new"
|
||||
|
||||
req := NewRequest(t, "GET", uploadURL)
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
|
||||
req = NewRequest(t, "GET", uploadURL)
|
||||
addTokenAuthHeader(req, token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
type UploadRequest struct {
|
||||
URL string `json:"url"`
|
||||
Fields map[string]string `json:"fields"`
|
||||
}
|
||||
|
||||
var result UploadRequest
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Empty(t, result.Fields)
|
||||
|
||||
uploadFile := func(t *testing.T, url string, content []byte, expectedStatus int) *httptest.ResponseRecorder {
|
||||
body := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(body)
|
||||
part, _ := writer.CreateFormFile("file", "dummy.tar.gz")
|
||||
_, _ = io.Copy(part, bytes.NewReader(content))
|
||||
|
||||
_ = writer.Close()
|
||||
|
||||
req := NewRequestWithBody(t, "POST", url, body)
|
||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||
addTokenAuthHeader(req, token)
|
||||
return MakeRequest(t, req, expectedStatus)
|
||||
}
|
||||
|
||||
resp = uploadFile(t, result.URL, content, http.StatusNoContent)
|
||||
|
||||
req = NewRequest(t, "GET", resp.Header().Get("Location"))
|
||||
addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypePub)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, pd.SemVer)
|
||||
assert.IsType(t, &pub_module.Metadata{}, pd.Metadata)
|
||||
assert.Equal(t, packageName, pd.Package.Name)
|
||||
assert.Equal(t, packageVersion, pd.Version.Version)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 1)
|
||||
assert.Equal(t, filename, pfs[0].Name)
|
||||
assert.True(t, pfs[0].IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(len(content)), pb.Size)
|
||||
|
||||
resp = uploadFile(t, result.URL, content, http.StatusBadRequest)
|
||||
})
|
||||
|
||||
t.Run("Download", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/api/packages/%s/%s", root, packageName, packageVersion))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
type VersionMetadata struct {
|
||||
Version string `json:"version"`
|
||||
ArchiveURL string `json:"archive_url"`
|
||||
Published time.Time `json:"published"`
|
||||
Pubspec interface{} `json:"pubspec,omitempty"`
|
||||
}
|
||||
|
||||
var result VersionMetadata
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Equal(t, packageVersion, result.Version)
|
||||
assert.NotNil(t, result.Pubspec)
|
||||
|
||||
req = NewRequest(t, "GET", result.ArchiveURL)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, content, resp.Body.Bytes())
|
||||
})
|
||||
|
||||
t.Run("EnumeratePackageVersions", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/api/packages/%s", root, packageName))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
type VersionMetadata struct {
|
||||
Version string `json:"version"`
|
||||
ArchiveURL string `json:"archive_url"`
|
||||
Published time.Time `json:"published"`
|
||||
Pubspec interface{} `json:"pubspec,omitempty"`
|
||||
}
|
||||
|
||||
type PackageVersions struct {
|
||||
Name string `json:"name"`
|
||||
Latest *VersionMetadata `json:"latest"`
|
||||
Versions []*VersionMetadata `json:"versions"`
|
||||
}
|
||||
|
||||
var result PackageVersions
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Equal(t, packageName, result.Name)
|
||||
assert.NotNil(t, result.Latest)
|
||||
assert.Len(t, result.Versions, 1)
|
||||
assert.Equal(t, result.Latest.Version, result.Versions[0].Version)
|
||||
assert.Equal(t, packageVersion, result.Latest.Version)
|
||||
assert.NotNil(t, result.Latest.Pubspec)
|
||||
})
|
||||
}
|
182
tests/integration/api_packages_pypi_test.go
Normal file
182
tests/integration/api_packages_pypi_test.go
Normal file
|
@ -0,0 +1,182 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/packages/pypi"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPackagePyPI(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
packageName := "test-package"
|
||||
packageVersion := "1.0.1"
|
||||
packageAuthor := "KN4CK3R"
|
||||
packageDescription := "Test Description"
|
||||
|
||||
content := "test"
|
||||
hashSHA256 := "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
|
||||
|
||||
root := fmt.Sprintf("/api/packages/%s/pypi", user.Name)
|
||||
|
||||
uploadFile := func(t *testing.T, filename, content string, expectedStatus int) {
|
||||
body := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(body)
|
||||
part, _ := writer.CreateFormFile("content", filename)
|
||||
_, _ = io.Copy(part, strings.NewReader(content))
|
||||
|
||||
writer.WriteField("name", packageName)
|
||||
writer.WriteField("version", packageVersion)
|
||||
writer.WriteField("author", packageAuthor)
|
||||
writer.WriteField("summary", packageDescription)
|
||||
writer.WriteField("description", packageDescription)
|
||||
writer.WriteField("sha256_digest", hashSHA256)
|
||||
writer.WriteField("requires_python", "3.6")
|
||||
|
||||
_ = writer.Close()
|
||||
|
||||
req := NewRequestWithBody(t, "POST", root, body)
|
||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, expectedStatus)
|
||||
}
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
filename := "test.whl"
|
||||
uploadFile(t, filename, content, http.StatusCreated)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypePyPI)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, pd.SemVer)
|
||||
assert.IsType(t, &pypi.Metadata{}, pd.Metadata)
|
||||
assert.Equal(t, packageName, pd.Package.Name)
|
||||
assert.Equal(t, packageVersion, pd.Version.Version)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 1)
|
||||
assert.Equal(t, filename, pfs[0].Name)
|
||||
assert.True(t, pfs[0].IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(4), pb.Size)
|
||||
})
|
||||
|
||||
t.Run("UploadAddFile", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
filename := "test.tar.gz"
|
||||
uploadFile(t, filename, content, http.StatusCreated)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypePyPI)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, pd.SemVer)
|
||||
assert.IsType(t, &pypi.Metadata{}, pd.Metadata)
|
||||
assert.Equal(t, packageName, pd.Package.Name)
|
||||
assert.Equal(t, packageVersion, pd.Version.Version)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 2)
|
||||
|
||||
pf, err := packages.GetFileForVersionByName(db.DefaultContext, pvs[0].ID, filename, packages.EmptyFileKey)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, filename, pf.Name)
|
||||
assert.True(t, pf.IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pf.BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(4), pb.Size)
|
||||
})
|
||||
|
||||
t.Run("UploadHashMismatch", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
filename := "test2.whl"
|
||||
uploadFile(t, filename, "dummy", http.StatusBadRequest)
|
||||
})
|
||||
|
||||
t.Run("UploadExists", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
uploadFile(t, "test.whl", content, http.StatusBadRequest)
|
||||
uploadFile(t, "test.tar.gz", content, http.StatusBadRequest)
|
||||
})
|
||||
|
||||
t.Run("Download", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
downloadFile := func(filename string) {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/files/%s/%s/%s", root, packageName, packageVersion, filename))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, []byte(content), resp.Body.Bytes())
|
||||
}
|
||||
|
||||
downloadFile("test.whl")
|
||||
downloadFile("test.tar.gz")
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypePyPI)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
assert.Equal(t, int64(2), pvs[0].DownloadCount)
|
||||
})
|
||||
|
||||
t.Run("PackageMetadata", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/simple/%s", root, packageName))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
nodes := htmlDoc.doc.Find("a").Nodes
|
||||
assert.Len(t, nodes, 2)
|
||||
|
||||
hrefMatcher := regexp.MustCompile(fmt.Sprintf(`%s/files/%s/%s/test\..+#sha256-%s`, root, packageName, packageVersion, hashSHA256))
|
||||
|
||||
for _, a := range nodes {
|
||||
for _, att := range a.Attr {
|
||||
switch att.Key {
|
||||
case "href":
|
||||
assert.Regexp(t, hrefMatcher, att.Val)
|
||||
case "data-requires-python":
|
||||
assert.Equal(t, "3.6", att.Val)
|
||||
default:
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
227
tests/integration/api_packages_rubygems_test.go
Normal file
227
tests/integration/api_packages_rubygems_test.go
Normal file
|
@ -0,0 +1,227 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/packages/rubygems"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPackageRubyGems(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
packageName := "gitea"
|
||||
packageVersion := "1.0.5"
|
||||
packageFilename := "gitea-1.0.5.gem"
|
||||
|
||||
gemContent, _ := base64.StdEncoding.DecodeString(`bWV0YWRhdGEuZ3oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwMDA0NDQAMDAwMDAw
|
||||
MAAwMDAwMDAwADAwMDAwMDAxMDQxADE0MTEwNzcyMzY2ADAxMzQ0MQAgMAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB1c3RhcgAwMHdoZWVsAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAd2hlZWwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAwMDAwADAwMDAw
|
||||
MDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf
|
||||
iwgA9vQjYQID1VVNb9QwEL37V5he9pRsmlJAFlQckCoOXAriQIUix5nNmsYf2JOqKwS/nYmz2d3Q
|
||||
qqCCKpFdadfjmfdm5nmcLMv4k9DXm6Wrv4BCcQ5GiPcelF5pJVE7y6w0IHirESS7hhDJJu4I+jhu
|
||||
Mc53Tsd5kZ8y30lcuWAEH2KY7HHtQhQs4+cJkwwuwNdeB6JhtbaNDoLTL1MQsFJrqQnr8jNrJJJH
|
||||
WZTHWfEiK094UYj0zYvp4Z9YAx5sA1ZpSCS3M30zeWwo2bG60FvUBjIKJts2GwMW76r0Yr9NzjN3
|
||||
YhwsGX2Ozl4dpcWwvK9d43PQtDIv9igvHwSyIIwFmXHjqTqxLY8MPkCADmQk80p2EfZ6VbM6/ue6
|
||||
/1D0Bq7/qeA/zh6W82leHmhFWUHn/JbsEfT6q7QbiCpoj8l0QcEUFLmX6kq2wBEiMjBSd+Pwt7T5
|
||||
Ot0kuXYMbkD1KOuOBnWYb7hBsAP4bhlkFRqnqpWefMZ/pHCn6+WIFGq2dgY8EQq+RvRRLJcTyZJ1
|
||||
WhHqGPTu7QdmACXdJFLwb9+ZdxErbSPKrqsMxJhAWCJ1qaqRdtu6yktcT/STsamG0qp7rsa5EL/K
|
||||
MBua30uw4ynzExqYWRJDfx8/kQWN3PwsDh2jYLr1W+pZcAmCs9splvnz/Flesqhbq21bXcGG/OLh
|
||||
+2fv/JTF3hgZyCW9OaZjxoZjdnBGfgKpxZyJ1QYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZGF0
|
||||
YS50YXIuZ3oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwMDA0NDQAMDAwMDAwMAAw
|
||||
MDAwMDAwADAwMDAwMDAwMjQyADE0MTEwNzcyMzY2ADAxMzM2MQAgMAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB1c3RhcgAwMHdoZWVsAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAd2hlZWwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAwMDAwADAwMDAwMDAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfiwgA
|
||||
9vQjYQID7M/NCsMgDABgz32KrA/QxersK/Q17ExXIcyhlr7+HLv1sJ02KPhBCPk5JOyn881nsl2c
|
||||
xI+gRDRaC3zbZ8RBCamlxGHolTFlX11kLwDFH6wp21hO2RYi/rD3bb5/7iCubFOCMbBtABzNkIjn
|
||||
bvGlAnisOUE7EnOALUR2p7b06e6aV4iqqqrquJ4AAAD//wMA+sA/NQAIAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGNoZWNr
|
||||
c3Vtcy55YW1sLmd6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAwNDQ0ADAwMDAwMDAAMDAw
|
||||
MDAwMAAwMDAwMDAwMDQ1MAAxNDExMDc3MjM2NgAwMTQ2MTIAIDAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdXN0YXIAMDB3aGVlbAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAHdoZWVsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAwMDAwMAAwMDAwMDAwAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH4sIAPb0
|
||||
I2ECA2WQOa4UQAxE8znFXGCQ21vbPyMj5wRuL0Qk6EecnmZCyKyy9FSvXq/X4/u3ryj68Xg+f/Zn
|
||||
VHzGlx+/P57qvU4XxWalBKftSXOgCjNYkdRycrC5Axem+W4HqS12PNEv7836jF9vnlHxwSyxKY+y
|
||||
go0cPblyHzkrZ4HF1GSVhe7mOOoasXNk2fnbUxb+19Pp9tobD/QlJKMX7y204PREh6nQ5hG9Alw6
|
||||
x4TnmtA+aekGfm6wAseog2LSgpR4Q7cYnAH3K4qAQa6A6JCC1gpuY7P+9YxE5SZ+j0eVGbaBTwBQ
|
||||
iIqRUyyzLCoFCBdYNWxniapTavD97blXTzFvgoVoAsKBAtlU48cdaOmeZDpwV01OtcGwjscfeUrY
|
||||
B9QBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA`)
|
||||
|
||||
root := fmt.Sprintf("/api/packages/%s/rubygems", user.Name)
|
||||
|
||||
uploadFile := func(t *testing.T, expectedStatus int) {
|
||||
req := NewRequestWithBody(t, "POST", fmt.Sprintf("%s/api/v1/gems", root), bytes.NewReader(gemContent))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, expectedStatus)
|
||||
}
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
uploadFile(t, http.StatusCreated)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeRubyGems)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, pd.SemVer)
|
||||
assert.IsType(t, &rubygems.Metadata{}, pd.Metadata)
|
||||
assert.Equal(t, packageName, pd.Package.Name)
|
||||
assert.Equal(t, packageVersion, pd.Version.Version)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 1)
|
||||
assert.Equal(t, packageFilename, pfs[0].Name)
|
||||
assert.True(t, pfs[0].IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(4608), pb.Size)
|
||||
})
|
||||
|
||||
t.Run("UploadExists", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
uploadFile(t, http.StatusBadRequest)
|
||||
})
|
||||
|
||||
t.Run("Download", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/gems/%s", root, packageFilename))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, gemContent, resp.Body.Bytes())
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeRubyGems)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
assert.Equal(t, int64(1), pvs[0].DownloadCount)
|
||||
})
|
||||
|
||||
t.Run("DownloadGemspec", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/quick/Marshal.4.8/%sspec.rz", root, packageFilename))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
b, _ := base64.StdEncoding.DecodeString(`eJxi4Si1EndPzbWyCi5ITc5My0xOLMnMz2M8zMIRLeGpxGWsZ6RnzGbF5hqSyempxJWeWZKayGbN
|
||||
EBJqJQjWFZZaVJyZnxfN5qnEZahnoGcKkjTwVBJyB6lUKEhMzk5MTwULGngqcRaVJlWCONEMBp5K
|
||||
DGAWSKc7zFhPJamg0qRK99TcYphehZLU4hKInFhGSUlBsZW+PtgZepn5+iDxECRzDUDGcfh6hoA4
|
||||
gAAAAP//MS06Gw==`)
|
||||
assert.Equal(t, b, resp.Body.Bytes())
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeRubyGems)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
assert.Equal(t, int64(1), pvs[0].DownloadCount)
|
||||
})
|
||||
|
||||
t.Run("EnumeratePackages", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
enumeratePackages := func(t *testing.T, endpoint string, expectedContent []byte) {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/%s", root, endpoint))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, expectedContent, resp.Body.Bytes())
|
||||
}
|
||||
|
||||
b, _ := base64.StdEncoding.DecodeString(`H4sICAAAAAAA/3NwZWNzLjQuOABi4Yhmi+bwVOJKzyxJTWSzYnMNCbUSdE/NtbIKSy0qzszPi2bzVOIy1DPQM2WzZgjxVOIsKk2qBDEBAQAA///xOEYKOwAAAA==`)
|
||||
enumeratePackages(t, "specs.4.8.gz", b)
|
||||
b, _ = base64.StdEncoding.DecodeString(`H4sICAAAAAAA/2xhdGVzdF9zcGVjcy40LjgAYuGIZovm8FTiSs8sSU1ks2JzDQm1EnRPzbWyCkstKs7Mz4tm81TiMtQz0DNls2YI8VTiLCpNqgQxAQEAAP//8ThGCjsAAAA=`)
|
||||
enumeratePackages(t, "latest_specs.4.8.gz", b)
|
||||
b, _ = base64.StdEncoding.DecodeString(`H4sICAAAAAAA/3ByZXJlbGVhc2Vfc3BlY3MuNC44AGLhiGYABAAA//9snXr5BAAAAA==`)
|
||||
enumeratePackages(t, "prerelease_specs.4.8.gz", b)
|
||||
})
|
||||
|
||||
t.Run("Delete", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
body := bytes.Buffer{}
|
||||
writer := multipart.NewWriter(&body)
|
||||
writer.WriteField("gem_name", packageName)
|
||||
writer.WriteField("version", packageVersion)
|
||||
writer.Close()
|
||||
|
||||
req := NewRequestWithBody(t, "DELETE", fmt.Sprintf("%s/api/v1/gems/yank", root), &body)
|
||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeRubyGems)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, pvs)
|
||||
})
|
||||
}
|
168
tests/integration/api_packages_test.go
Normal file
168
tests/integration/api_packages_test.go
Normal file
|
@ -0,0 +1,168 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
packages_model "code.gitea.io/gitea/models/packages"
|
||||
container_model "code.gitea.io/gitea/models/packages/container"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
packages_service "code.gitea.io/gitea/services/packages"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPackageAPI(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)
|
||||
|
||||
packageName := "test-package"
|
||||
packageVersion := "1.0.3"
|
||||
filename := "file.bin"
|
||||
|
||||
url := fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, packageName, packageVersion, filename)
|
||||
req := NewRequestWithBody(t, "PUT", url, bytes.NewReader([]byte{}))
|
||||
AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
t.Run("ListPackages", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s?token=%s", user.Name, token))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var apiPackages []*api.Package
|
||||
DecodeJSON(t, resp, &apiPackages)
|
||||
|
||||
assert.Len(t, apiPackages, 1)
|
||||
assert.Equal(t, string(packages_model.TypeGeneric), apiPackages[0].Type)
|
||||
assert.Equal(t, packageName, apiPackages[0].Name)
|
||||
assert.Equal(t, packageVersion, apiPackages[0].Version)
|
||||
assert.NotNil(t, apiPackages[0].Creator)
|
||||
assert.Equal(t, user.Name, apiPackages[0].Creator.UserName)
|
||||
})
|
||||
|
||||
t.Run("GetPackage", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/dummy/%s/%s?token=%s", user.Name, packageName, packageVersion, token))
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/generic/%s/%s?token=%s", user.Name, packageName, packageVersion, token))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var p *api.Package
|
||||
DecodeJSON(t, resp, &p)
|
||||
|
||||
assert.Equal(t, string(packages_model.TypeGeneric), p.Type)
|
||||
assert.Equal(t, packageName, p.Name)
|
||||
assert.Equal(t, packageVersion, p.Version)
|
||||
assert.NotNil(t, p.Creator)
|
||||
assert.Equal(t, user.Name, p.Creator.UserName)
|
||||
|
||||
t.Run("RepositoryLink", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
p, err := packages_model.GetPackageByName(db.DefaultContext, user.ID, packages_model.TypeGeneric, packageName)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// no repository link
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/generic/%s/%s?token=%s", user.Name, packageName, packageVersion, token))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var ap1 *api.Package
|
||||
DecodeJSON(t, resp, &ap1)
|
||||
assert.Nil(t, ap1.Repository)
|
||||
|
||||
// link to public repository
|
||||
assert.NoError(t, packages_model.SetRepositoryLink(db.DefaultContext, p.ID, 1))
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/generic/%s/%s?token=%s", user.Name, packageName, packageVersion, token))
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var ap2 *api.Package
|
||||
DecodeJSON(t, resp, &ap2)
|
||||
assert.NotNil(t, ap2.Repository)
|
||||
assert.EqualValues(t, 1, ap2.Repository.ID)
|
||||
|
||||
// link to private repository
|
||||
assert.NoError(t, packages_model.SetRepositoryLink(db.DefaultContext, p.ID, 2))
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/generic/%s/%s?token=%s", user.Name, packageName, packageVersion, token))
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var ap3 *api.Package
|
||||
DecodeJSON(t, resp, &ap3)
|
||||
assert.Nil(t, ap3.Repository)
|
||||
|
||||
assert.NoError(t, packages_model.UnlinkRepositoryFromAllPackages(db.DefaultContext, 2))
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("ListPackageFiles", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/dummy/%s/%s/files?token=%s", user.Name, packageName, packageVersion, token))
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/generic/%s/%s/files?token=%s", user.Name, packageName, packageVersion, token))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var files []*api.PackageFile
|
||||
DecodeJSON(t, resp, &files)
|
||||
|
||||
assert.Len(t, files, 1)
|
||||
assert.Equal(t, int64(0), files[0].Size)
|
||||
assert.Equal(t, filename, files[0].Name)
|
||||
assert.Equal(t, "d41d8cd98f00b204e9800998ecf8427e", files[0].HashMD5)
|
||||
assert.Equal(t, "da39a3ee5e6b4b0d3255bfef95601890afd80709", files[0].HashSHA1)
|
||||
assert.Equal(t, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", files[0].HashSHA256)
|
||||
assert.Equal(t, "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", files[0].HashSHA512)
|
||||
})
|
||||
|
||||
t.Run("DeletePackage", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/packages/%s/dummy/%s/%s?token=%s", user.Name, packageName, packageVersion, token))
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/packages/%s/generic/%s/%s?token=%s", user.Name, packageName, packageVersion, token))
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPackageCleanup(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
pbs, err := packages_model.FindExpiredUnreferencedBlobs(db.DefaultContext, time.Duration(0))
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, pbs)
|
||||
|
||||
_, err = packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, 2, packages_model.TypeContainer, "test", container_model.UploadVersion)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = packages_service.Cleanup(nil, time.Duration(0))
|
||||
assert.NoError(t, err)
|
||||
|
||||
pbs, err = packages_model.FindExpiredUnreferencedBlobs(db.DefaultContext, time.Duration(0))
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, pbs)
|
||||
|
||||
_, err = packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, 2, packages_model.TypeContainer, "test", container_model.UploadVersion)
|
||||
assert.ErrorIs(t, err, packages_model.ErrPackageNotExist)
|
||||
}
|
171
tests/integration/api_packages_vagrant_test.go
Normal file
171
tests/integration/api_packages_vagrant_test.go
Normal file
|
@ -0,0 +1,171 @@
|
|||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
vagrant_module "code.gitea.io/gitea/modules/packages/vagrant"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPackageVagrant(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
token := "Bearer " + getUserToken(t, user.Name)
|
||||
|
||||
packageName := "test_package"
|
||||
packageVersion := "1.0.1"
|
||||
packageDescription := "Test Description"
|
||||
packageProvider := "virtualbox"
|
||||
|
||||
filename := fmt.Sprintf("%s.box", packageProvider)
|
||||
|
||||
infoContent, _ := json.Marshal(map[string]string{
|
||||
"description": packageDescription,
|
||||
})
|
||||
|
||||
var buf bytes.Buffer
|
||||
zw := gzip.NewWriter(&buf)
|
||||
archive := tar.NewWriter(zw)
|
||||
archive.WriteHeader(&tar.Header{
|
||||
Name: "info.json",
|
||||
Mode: 0o600,
|
||||
Size: int64(len(infoContent)),
|
||||
})
|
||||
archive.Write(infoContent)
|
||||
archive.Close()
|
||||
zw.Close()
|
||||
content := buf.Bytes()
|
||||
|
||||
root := fmt.Sprintf("/api/packages/%s/vagrant", user.Name)
|
||||
|
||||
t.Run("Authenticate", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
authenticateURL := fmt.Sprintf("%s/authenticate", root)
|
||||
|
||||
req := NewRequest(t, "GET", authenticateURL)
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
|
||||
req = NewRequest(t, "GET", authenticateURL)
|
||||
addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
})
|
||||
|
||||
boxURL := fmt.Sprintf("%s/%s", root, packageName)
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "HEAD", boxURL)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
uploadURL := fmt.Sprintf("%s/%s/%s", boxURL, packageVersion, filename)
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", uploadURL, bytes.NewReader(content))
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", uploadURL, bytes.NewReader(content))
|
||||
addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
req = NewRequest(t, "HEAD", boxURL)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
assert.True(t, strings.HasPrefix(resp.HeaderMap.Get("Content-Type"), "application/json"))
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeVagrant)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pvs, 1)
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, pd.SemVer)
|
||||
assert.IsType(t, &vagrant_module.Metadata{}, pd.Metadata)
|
||||
assert.Equal(t, packageName, pd.Package.Name)
|
||||
assert.Equal(t, packageVersion, pd.Version.Version)
|
||||
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 1)
|
||||
assert.Equal(t, filename, pfs[0].Name)
|
||||
assert.True(t, pfs[0].IsLead)
|
||||
|
||||
pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(len(content)), pb.Size)
|
||||
|
||||
req = NewRequestWithBody(t, "PUT", uploadURL, bytes.NewReader(content))
|
||||
addTokenAuthHeader(req, token)
|
||||
MakeRequest(t, req, http.StatusConflict)
|
||||
})
|
||||
|
||||
t.Run("Download", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s", boxURL, packageVersion, filename))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, content, resp.Body.Bytes())
|
||||
})
|
||||
|
||||
t.Run("EnumeratePackageVersions", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", boxURL)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
type providerData struct {
|
||||
Name string `json:"name"`
|
||||
URL string `json:"url"`
|
||||
Checksum string `json:"checksum"`
|
||||
ChecksumType string `json:"checksum_type"`
|
||||
}
|
||||
|
||||
type versionMetadata struct {
|
||||
Version string `json:"version"`
|
||||
Status string `json:"status"`
|
||||
DescriptionHTML string `json:"description_html,omitempty"`
|
||||
DescriptionMarkdown string `json:"description_markdown,omitempty"`
|
||||
Providers []*providerData `json:"providers"`
|
||||
}
|
||||
|
||||
type packageMetadata struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description,omitempty"`
|
||||
ShortDescription string `json:"short_description,omitempty"`
|
||||
Versions []*versionMetadata `json:"versions"`
|
||||
}
|
||||
|
||||
var result packageMetadata
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Equal(t, packageName, result.Name)
|
||||
assert.Equal(t, packageDescription, result.Description)
|
||||
assert.Len(t, result.Versions, 1)
|
||||
version := result.Versions[0]
|
||||
assert.Equal(t, packageVersion, version.Version)
|
||||
assert.Equal(t, "active", version.Status)
|
||||
assert.Len(t, version.Providers, 1)
|
||||
provider := version.Providers[0]
|
||||
assert.Equal(t, packageProvider, provider.Name)
|
||||
assert.Equal(t, "sha512", provider.ChecksumType)
|
||||
assert.Equal(t, "259bebd6160acad695016d22a45812e26f187aaf78e71a4c23ee3201528346293f991af3468a8c6c5d2a21d7d9e1bdc1bf79b87110b2fddfcc5a0d45963c7c30", provider.Checksum)
|
||||
})
|
||||
}
|
154
tests/integration/api_private_serv_test.go
Normal file
154
tests/integration/api_private_serv_test.go
Normal file
|
@ -0,0 +1,154 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
"code.gitea.io/gitea/modules/private"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIPrivateNoServ(t *testing.T) {
|
||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
key, user, err := private.ServNoCommand(ctx, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(2), user.ID)
|
||||
assert.Equal(t, "user2", user.Name)
|
||||
assert.Equal(t, int64(1), key.ID)
|
||||
assert.Equal(t, "user2@localhost", key.Name)
|
||||
|
||||
deployKey, err := asymkey_model.AddDeployKey(1, "test-deploy", "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBGXEEzWmm1dxb+57RoK5KVCL0w2eNv9cqJX2AGGVlkFsVDhOXHzsadS3LTK4VlEbbrDMJdoti9yM8vclA8IeRacAAAAEc3NoOg== nocomment", false)
|
||||
assert.NoError(t, err)
|
||||
|
||||
key, user, err = private.ServNoCommand(ctx, deployKey.KeyID)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, user)
|
||||
assert.Equal(t, deployKey.KeyID, key.ID)
|
||||
assert.Equal(t, "test-deploy", key.Name)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAPIPrivateServ(t *testing.T) {
|
||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// Can push to a repo we own
|
||||
results, err := private.ServCommand(ctx, 1, "user2", "repo1", perm.AccessModeWrite, "git-upload-pack", "")
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, results.IsWiki)
|
||||
assert.Zero(t, results.DeployKeyID)
|
||||
assert.Equal(t, int64(1), results.KeyID)
|
||||
assert.Equal(t, "user2@localhost", results.KeyName)
|
||||
assert.Equal(t, "user2", results.UserName)
|
||||
assert.Equal(t, int64(2), results.UserID)
|
||||
assert.Equal(t, "user2", results.OwnerName)
|
||||
assert.Equal(t, "repo1", results.RepoName)
|
||||
assert.Equal(t, int64(1), results.RepoID)
|
||||
|
||||
// Cannot push to a private repo we're not associated with
|
||||
results, err = private.ServCommand(ctx, 1, "user15", "big_test_private_1", perm.AccessModeWrite, "git-upload-pack", "")
|
||||
assert.Error(t, err)
|
||||
assert.Empty(t, results)
|
||||
|
||||
// Cannot pull from a private repo we're not associated with
|
||||
results, err = private.ServCommand(ctx, 1, "user15", "big_test_private_1", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.Error(t, err)
|
||||
assert.Empty(t, results)
|
||||
|
||||
// Can pull from a public repo we're not associated with
|
||||
results, err = private.ServCommand(ctx, 1, "user15", "big_test_public_1", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, results.IsWiki)
|
||||
assert.Zero(t, results.DeployKeyID)
|
||||
assert.Equal(t, int64(1), results.KeyID)
|
||||
assert.Equal(t, "user2@localhost", results.KeyName)
|
||||
assert.Equal(t, "user2", results.UserName)
|
||||
assert.Equal(t, int64(2), results.UserID)
|
||||
assert.Equal(t, "user15", results.OwnerName)
|
||||
assert.Equal(t, "big_test_public_1", results.RepoName)
|
||||
assert.Equal(t, int64(17), results.RepoID)
|
||||
|
||||
// Cannot push to a public repo we're not associated with
|
||||
results, err = private.ServCommand(ctx, 1, "user15", "big_test_public_1", perm.AccessModeWrite, "git-upload-pack", "")
|
||||
assert.Error(t, err)
|
||||
assert.Empty(t, results)
|
||||
|
||||
// Add reading deploy key
|
||||
deployKey, err := asymkey_model.AddDeployKey(19, "test-deploy", "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBGXEEzWmm1dxb+57RoK5KVCL0w2eNv9cqJX2AGGVlkFsVDhOXHzsadS3LTK4VlEbbrDMJdoti9yM8vclA8IeRacAAAAEc3NoOg== nocomment", true)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Can pull from repo we're a deploy key for
|
||||
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, results.IsWiki)
|
||||
assert.NotZero(t, results.DeployKeyID)
|
||||
assert.Equal(t, deployKey.KeyID, results.KeyID)
|
||||
assert.Equal(t, "test-deploy", results.KeyName)
|
||||
assert.Equal(t, "user15", results.UserName)
|
||||
assert.Equal(t, int64(15), results.UserID)
|
||||
assert.Equal(t, "user15", results.OwnerName)
|
||||
assert.Equal(t, "big_test_private_1", results.RepoName)
|
||||
assert.Equal(t, int64(19), results.RepoID)
|
||||
|
||||
// Cannot push to a private repo with reading key
|
||||
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeWrite, "git-upload-pack", "")
|
||||
assert.Error(t, err)
|
||||
assert.Empty(t, results)
|
||||
|
||||
// Cannot pull from a private repo we're not associated with
|
||||
results, err = private.ServCommand(ctx, deployKey.ID, "user15", "big_test_private_2", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.Error(t, err)
|
||||
assert.Empty(t, results)
|
||||
|
||||
// Cannot pull from a public repo we're not associated with
|
||||
results, err = private.ServCommand(ctx, deployKey.ID, "user15", "big_test_public_1", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.Error(t, err)
|
||||
assert.Empty(t, results)
|
||||
|
||||
// Add writing deploy key
|
||||
deployKey, err = asymkey_model.AddDeployKey(20, "test-deploy", "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBGXEEzWmm1dxb+57RoK5KVCL0w2eNv9cqJX2AGGVlkFsVDhOXHzsadS3LTK4VlEbbrDMJdoti9yM8vclA8IeRacAAAAEc3NoOg== nocomment", false)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Cannot push to a private repo with reading key
|
||||
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeWrite, "git-upload-pack", "")
|
||||
assert.Error(t, err)
|
||||
assert.Empty(t, results)
|
||||
|
||||
// Can pull from repo we're a writing deploy key for
|
||||
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, results.IsWiki)
|
||||
assert.NotZero(t, results.DeployKeyID)
|
||||
assert.Equal(t, deployKey.KeyID, results.KeyID)
|
||||
assert.Equal(t, "test-deploy", results.KeyName)
|
||||
assert.Equal(t, "user15", results.UserName)
|
||||
assert.Equal(t, int64(15), results.UserID)
|
||||
assert.Equal(t, "user15", results.OwnerName)
|
||||
assert.Equal(t, "big_test_private_2", results.RepoName)
|
||||
assert.Equal(t, int64(20), results.RepoID)
|
||||
|
||||
// Can push to repo we're a writing deploy key for
|
||||
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeWrite, "git-upload-pack", "")
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, results.IsWiki)
|
||||
assert.NotZero(t, results.DeployKeyID)
|
||||
assert.Equal(t, deployKey.KeyID, results.KeyID)
|
||||
assert.Equal(t, "test-deploy", results.KeyName)
|
||||
assert.Equal(t, "user15", results.UserName)
|
||||
assert.Equal(t, int64(15), results.UserID)
|
||||
assert.Equal(t, "user15", results.OwnerName)
|
||||
assert.Equal(t, "big_test_private_2", results.RepoName)
|
||||
assert.Equal(t, int64(20), results.RepoID)
|
||||
})
|
||||
}
|
41
tests/integration/api_pull_commits_test.go
Normal file
41
tests/integration/api_pull_commits_test.go
Normal file
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIPullCommits(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
pullIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2})
|
||||
assert.NoError(t, pullIssue.LoadIssue())
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue.HeadRepoID})
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
req := NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/%s/pulls/%d/commits", repo.OwnerName, repo.Name, pullIssue.Index)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var commits []*api.Commit
|
||||
DecodeJSON(t, resp, &commits)
|
||||
|
||||
if !assert.Len(t, commits, 2) {
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, "5f22f7d0d95d614d25a5b68592adb345a4b5c7fd", commits[0].SHA)
|
||||
assert.Equal(t, "4a357436d925b5c974181ff12a994538ddc5a269", commits[1].SHA)
|
||||
}
|
||||
|
||||
// TODO add tests for already merged PR and closed PR
|
307
tests/integration/api_pull_review_test.go
Normal file
307
tests/integration/api_pull_review_test.go
Normal file
|
@ -0,0 +1,307 @@
|
|||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIPullReview(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})
|
||||
|
||||
// test ListPullReviews
|
||||
session := loginUser(t, "user2")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/%s/pulls/%d/reviews?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var reviews []*api.PullReview
|
||||
DecodeJSON(t, resp, &reviews)
|
||||
if !assert.Len(t, reviews, 6) {
|
||||
return
|
||||
}
|
||||
for _, r := range reviews {
|
||||
assert.EqualValues(t, pullIssue.HTMLURL(), r.HTMLPullURL)
|
||||
}
|
||||
assert.EqualValues(t, 8, reviews[3].ID)
|
||||
assert.EqualValues(t, "APPROVED", reviews[3].State)
|
||||
assert.EqualValues(t, 0, reviews[3].CodeCommentsCount)
|
||||
assert.True(t, reviews[3].Stale)
|
||||
assert.False(t, reviews[3].Official)
|
||||
|
||||
assert.EqualValues(t, 10, reviews[5].ID)
|
||||
assert.EqualValues(t, "REQUEST_CHANGES", reviews[5].State)
|
||||
assert.EqualValues(t, 1, reviews[5].CodeCommentsCount)
|
||||
assert.EqualValues(t, -1, reviews[5].Reviewer.ID) // ghost user
|
||||
assert.False(t, reviews[5].Stale)
|
||||
assert.True(t, reviews[5].Official)
|
||||
|
||||
// test GetPullReview
|
||||
req = NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/%s/pulls/%d/reviews/%d?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, reviews[3].ID, token)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
var review api.PullReview
|
||||
DecodeJSON(t, resp, &review)
|
||||
assert.EqualValues(t, *reviews[3], review)
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/pulls/%d/reviews/%d?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, reviews[5].ID, token)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &review)
|
||||
assert.EqualValues(t, *reviews[5], review)
|
||||
|
||||
// test GetPullReviewComments
|
||||
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 7})
|
||||
req = NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/%s/pulls/%d/reviews/%d/comments?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, 10, token)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
var reviewComments []*api.PullReviewComment
|
||||
DecodeJSON(t, resp, &reviewComments)
|
||||
assert.Len(t, reviewComments, 1)
|
||||
assert.EqualValues(t, "Ghost", reviewComments[0].Poster.UserName)
|
||||
assert.EqualValues(t, "a review from a deleted user", reviewComments[0].Body)
|
||||
assert.EqualValues(t, comment.ID, reviewComments[0].ID)
|
||||
assert.EqualValues(t, comment.UpdatedUnix, reviewComments[0].Updated.Unix())
|
||||
assert.EqualValues(t, comment.HTMLURL(), reviewComments[0].HTMLURL)
|
||||
|
||||
// test CreatePullReview
|
||||
req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/reviews?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, token), &api.CreatePullReviewOptions{
|
||||
Body: "body1",
|
||||
// Event: "" # will result in PENDING
|
||||
Comments: []api.CreatePullReviewComment{
|
||||
{
|
||||
Path: "README.md",
|
||||
Body: "first new line",
|
||||
OldLineNum: 0,
|
||||
NewLineNum: 1,
|
||||
}, {
|
||||
Path: "README.md",
|
||||
Body: "first old line",
|
||||
OldLineNum: 1,
|
||||
NewLineNum: 0,
|
||||
}, {
|
||||
Path: "iso-8859-1.txt",
|
||||
Body: "this line contains a non-utf-8 character",
|
||||
OldLineNum: 0,
|
||||
NewLineNum: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &review)
|
||||
assert.EqualValues(t, 6, review.ID)
|
||||
assert.EqualValues(t, "PENDING", review.State)
|
||||
assert.EqualValues(t, 3, review.CodeCommentsCount)
|
||||
|
||||
// test SubmitPullReview
|
||||
req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/reviews/%d?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, review.ID, token), &api.SubmitPullReviewOptions{
|
||||
Event: "APPROVED",
|
||||
Body: "just two nits",
|
||||
})
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &review)
|
||||
assert.EqualValues(t, 6, review.ID)
|
||||
assert.EqualValues(t, "APPROVED", review.State)
|
||||
assert.EqualValues(t, 3, review.CodeCommentsCount)
|
||||
|
||||
// test dismiss review
|
||||
req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/reviews/%d/dismissals?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, review.ID, token), &api.DismissPullReviewOptions{
|
||||
Message: "test",
|
||||
})
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &review)
|
||||
assert.EqualValues(t, 6, review.ID)
|
||||
assert.True(t, review.Dismissed)
|
||||
|
||||
// test dismiss review
|
||||
req = NewRequest(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/reviews/%d/undismissals?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, review.ID, token))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &review)
|
||||
assert.EqualValues(t, 6, review.ID)
|
||||
assert.False(t, review.Dismissed)
|
||||
|
||||
// test DeletePullReview
|
||||
req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/reviews?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, token), &api.CreatePullReviewOptions{
|
||||
Body: "just a comment",
|
||||
Event: "COMMENT",
|
||||
})
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &review)
|
||||
assert.EqualValues(t, "COMMENT", review.State)
|
||||
assert.EqualValues(t, 0, review.CodeCommentsCount)
|
||||
req = NewRequestf(t, http.MethodDelete, "/api/v1/repos/%s/%s/pulls/%d/reviews/%d?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, review.ID, token)
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
// test CreatePullReview Comment without body but with comments
|
||||
req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/reviews?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, token), &api.CreatePullReviewOptions{
|
||||
// Body: "",
|
||||
Event: "COMMENT",
|
||||
Comments: []api.CreatePullReviewComment{
|
||||
{
|
||||
Path: "README.md",
|
||||
Body: "first new line",
|
||||
OldLineNum: 0,
|
||||
NewLineNum: 1,
|
||||
}, {
|
||||
Path: "README.md",
|
||||
Body: "first old line",
|
||||
OldLineNum: 1,
|
||||
NewLineNum: 0,
|
||||
},
|
||||
},
|
||||
})
|
||||
var commentReview api.PullReview
|
||||
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &commentReview)
|
||||
assert.EqualValues(t, "COMMENT", commentReview.State)
|
||||
assert.EqualValues(t, 2, commentReview.CodeCommentsCount)
|
||||
assert.EqualValues(t, "", commentReview.Body)
|
||||
assert.EqualValues(t, false, commentReview.Dismissed)
|
||||
|
||||
// test CreatePullReview Comment with body but without comments
|
||||
commentBody := "This is a body of the comment."
|
||||
req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/reviews?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, token), &api.CreatePullReviewOptions{
|
||||
Body: commentBody,
|
||||
Event: "COMMENT",
|
||||
Comments: []api.CreatePullReviewComment{},
|
||||
})
|
||||
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &commentReview)
|
||||
assert.EqualValues(t, "COMMENT", commentReview.State)
|
||||
assert.EqualValues(t, 0, commentReview.CodeCommentsCount)
|
||||
assert.EqualValues(t, commentBody, commentReview.Body)
|
||||
assert.EqualValues(t, false, commentReview.Dismissed)
|
||||
|
||||
// test CreatePullReview Comment without body and no comments
|
||||
req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/reviews?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, token), &api.CreatePullReviewOptions{
|
||||
Body: "",
|
||||
Event: "COMMENT",
|
||||
Comments: []api.CreatePullReviewComment{},
|
||||
})
|
||||
resp = session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
errMap := make(map[string]interface{})
|
||||
json.Unmarshal(resp.Body.Bytes(), &errMap)
|
||||
assert.EqualValues(t, "review event COMMENT requires a body or a comment", errMap["message"].(string))
|
||||
|
||||
// test get review requests
|
||||
// to make it simple, use same api with get review
|
||||
pullIssue12 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 12})
|
||||
assert.NoError(t, pullIssue12.LoadAttributes(db.DefaultContext))
|
||||
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue12.RepoID})
|
||||
|
||||
req = NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/%s/pulls/%d/reviews?token=%s", repo3.OwnerName, repo3.Name, pullIssue12.Index, token)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &reviews)
|
||||
assert.EqualValues(t, 11, reviews[0].ID)
|
||||
assert.EqualValues(t, "REQUEST_REVIEW", reviews[0].State)
|
||||
assert.EqualValues(t, 0, reviews[0].CodeCommentsCount)
|
||||
assert.False(t, reviews[0].Stale)
|
||||
assert.True(t, reviews[0].Official)
|
||||
assert.EqualValues(t, "test_team", reviews[0].ReviewerTeam.Name)
|
||||
|
||||
assert.EqualValues(t, 12, reviews[1].ID)
|
||||
assert.EqualValues(t, "REQUEST_REVIEW", reviews[1].State)
|
||||
assert.EqualValues(t, 0, reviews[0].CodeCommentsCount)
|
||||
assert.False(t, reviews[1].Stale)
|
||||
assert.True(t, reviews[1].Official)
|
||||
assert.EqualValues(t, 1, reviews[1].Reviewer.ID)
|
||||
}
|
||||
|
||||
func TestAPIPullReviewRequest(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})
|
||||
|
||||
// Test add Review Request
|
||||
session := loginUser(t, "user2")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/requested_reviewers?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, token), &api.PullReviewRequestOptions{
|
||||
Reviewers: []string{"user4@example.com", "user8"},
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
// poster of pr can't be reviewer
|
||||
req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/requested_reviewers?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, token), &api.PullReviewRequestOptions{
|
||||
Reviewers: []string{"user1"},
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
|
||||
// test user not exist
|
||||
req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/requested_reviewers?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, token), &api.PullReviewRequestOptions{
|
||||
Reviewers: []string{"testOther"},
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Test Remove Review Request
|
||||
session2 := loginUser(t, "user4")
|
||||
token2 := getTokenForLoggedInUser(t, session2)
|
||||
|
||||
req = NewRequestWithJSON(t, http.MethodDelete, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/requested_reviewers?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, token2), &api.PullReviewRequestOptions{
|
||||
Reviewers: []string{"user4"},
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
// doer is not admin
|
||||
req = NewRequestWithJSON(t, http.MethodDelete, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/requested_reviewers?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, token2), &api.PullReviewRequestOptions{
|
||||
Reviewers: []string{"user8"},
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
|
||||
req = NewRequestWithJSON(t, http.MethodDelete, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/requested_reviewers?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, token), &api.PullReviewRequestOptions{
|
||||
Reviewers: []string{"user8"},
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
// Test team review request
|
||||
pullIssue12 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 12})
|
||||
assert.NoError(t, pullIssue12.LoadAttributes(db.DefaultContext))
|
||||
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue12.RepoID})
|
||||
|
||||
// Test add Team Review Request
|
||||
req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/requested_reviewers?token=%s", repo3.OwnerName, repo3.Name, pullIssue12.Index, token), &api.PullReviewRequestOptions{
|
||||
TeamReviewers: []string{"team1", "owners"},
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
// Test add Team Review Request to not allowned
|
||||
req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/requested_reviewers?token=%s", repo3.OwnerName, repo3.Name, pullIssue12.Index, token), &api.PullReviewRequestOptions{
|
||||
TeamReviewers: []string{"test_team"},
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
|
||||
// Test add Team Review Request to not exist
|
||||
req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/requested_reviewers?token=%s", repo3.OwnerName, repo3.Name, pullIssue12.Index, token), &api.PullReviewRequestOptions{
|
||||
TeamReviewers: []string{"not_exist_team"},
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Test Remove team Review Request
|
||||
req = NewRequestWithJSON(t, http.MethodDelete, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/requested_reviewers?token=%s", repo3.OwnerName, repo3.Name, pullIssue12.Index, token), &api.PullReviewRequestOptions{
|
||||
TeamReviewers: []string{"team1"},
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
// empty request test
|
||||
req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/requested_reviewers?token=%s", repo3.OwnerName, repo3.Name, pullIssue12.Index, token), &api.PullReviewRequestOptions{})
|
||||
session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
req = NewRequestWithJSON(t, http.MethodDelete, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/requested_reviewers?token=%s", repo3.OwnerName, repo3.Name, pullIssue12.Index, token), &api.PullReviewRequestOptions{})
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
}
|
185
tests/integration/api_pull_test.go
Normal file
185
tests/integration/api_pull_test.go
Normal file
|
@ -0,0 +1,185 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
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/services/forms"
|
||||
issue_service "code.gitea.io/gitea/services/issue"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIViewPulls(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/pulls?state=all&token="+token, owner.Name, repo.Name)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var pulls []*api.PullRequest
|
||||
DecodeJSON(t, resp, &pulls)
|
||||
expectedLen := unittest.GetCount(t, &issues_model.Issue{RepoID: repo.ID}, unittest.Cond("is_pull = ?", true))
|
||||
assert.Len(t, pulls, expectedLen)
|
||||
}
|
||||
|
||||
// TestAPIMergePullWIP ensures that we can't merge a WIP pull request
|
||||
func TestAPIMergePullWIP(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{Status: issues_model.PullRequestStatusMergeable}, unittest.Cond("has_merged = ?", false))
|
||||
pr.LoadIssue()
|
||||
issue_service.ChangeTitle(pr.Issue, owner, setting.Repository.PullRequest.WorkInProgressPrefixes[0]+" "+pr.Issue.Title)
|
||||
|
||||
// force reload
|
||||
pr.LoadAttributes()
|
||||
|
||||
assert.Contains(t, pr.Issue.Title, setting.Repository.PullRequest.WorkInProgressPrefixes[0])
|
||||
|
||||
session := loginUser(t, owner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/merge?token=%s", owner.Name, repo.Name, pr.Index, token), &forms.MergePullRequestForm{
|
||||
MergeMessageField: pr.Issue.Title,
|
||||
Do: string(repo_model.MergeStyleMerge),
|
||||
})
|
||||
|
||||
session.MakeRequest(t, req, http.StatusMethodNotAllowed)
|
||||
}
|
||||
|
||||
func TestAPICreatePullSuccess(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
repo10 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10})
|
||||
// repo10 have code, pulls units.
|
||||
repo11 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 11})
|
||||
// repo11 only have code unit but should still create pulls
|
||||
owner10 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo10.OwnerID})
|
||||
owner11 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo11.OwnerID})
|
||||
|
||||
session := loginUser(t, owner11.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls?token=%s", owner10.Name, repo10.Name, token), &api.CreatePullRequestOption{
|
||||
Head: fmt.Sprintf("%s:master", owner11.Name),
|
||||
Base: "master",
|
||||
Title: "create a failure pr",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusCreated)
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity) // second request should fail
|
||||
}
|
||||
|
||||
func TestAPICreatePullWithFieldsSuccess(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
// repo10 have code, pulls units.
|
||||
repo10 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10})
|
||||
owner10 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo10.OwnerID})
|
||||
// repo11 only have code unit but should still create pulls
|
||||
repo11 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 11})
|
||||
owner11 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo11.OwnerID})
|
||||
|
||||
session := loginUser(t, owner11.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
opts := &api.CreatePullRequestOption{
|
||||
Head: fmt.Sprintf("%s:master", owner11.Name),
|
||||
Base: "master",
|
||||
Title: "create a failure pr",
|
||||
Body: "foobaaar",
|
||||
Milestone: 5,
|
||||
Assignees: []string{owner10.Name},
|
||||
Labels: []int64{5},
|
||||
}
|
||||
|
||||
req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls?token=%s", owner10.Name, repo10.Name, token), opts)
|
||||
|
||||
res := session.MakeRequest(t, req, http.StatusCreated)
|
||||
pull := new(api.PullRequest)
|
||||
DecodeJSON(t, res, pull)
|
||||
|
||||
assert.NotNil(t, pull.Milestone)
|
||||
assert.EqualValues(t, opts.Milestone, pull.Milestone.ID)
|
||||
if assert.Len(t, pull.Assignees, 1) {
|
||||
assert.EqualValues(t, opts.Assignees[0], owner10.Name)
|
||||
}
|
||||
assert.NotNil(t, pull.Labels)
|
||||
assert.EqualValues(t, opts.Labels[0], pull.Labels[0].ID)
|
||||
}
|
||||
|
||||
func TestAPICreatePullWithFieldsFailure(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
// repo10 have code, pulls units.
|
||||
repo10 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10})
|
||||
owner10 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo10.OwnerID})
|
||||
// repo11 only have code unit but should still create pulls
|
||||
repo11 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 11})
|
||||
owner11 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo11.OwnerID})
|
||||
|
||||
session := loginUser(t, owner11.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
opts := &api.CreatePullRequestOption{
|
||||
Head: fmt.Sprintf("%s:master", owner11.Name),
|
||||
Base: "master",
|
||||
}
|
||||
|
||||
req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls?token=%s", owner10.Name, repo10.Name, token), opts)
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
opts.Title = "is required"
|
||||
|
||||
opts.Milestone = 666
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
opts.Milestone = 5
|
||||
|
||||
opts.Assignees = []string{"qweruqweroiuyqweoiruywqer"}
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
opts.Assignees = []string{owner10.LoginName}
|
||||
|
||||
opts.Labels = []int64{55555}
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
opts.Labels = []int64{5}
|
||||
}
|
||||
|
||||
func TestAPIEditPull(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
repo10 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10})
|
||||
owner10 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo10.OwnerID})
|
||||
|
||||
session := loginUser(t, owner10.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls?token=%s", owner10.Name, repo10.Name, token), &api.CreatePullRequestOption{
|
||||
Head: "develop",
|
||||
Base: "master",
|
||||
Title: "create a success pr",
|
||||
})
|
||||
pull := new(api.PullRequest)
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
DecodeJSON(t, resp, pull)
|
||||
assert.EqualValues(t, "master", pull.Base.Name)
|
||||
|
||||
req = NewRequestWithJSON(t, http.MethodPatch, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d?token=%s", owner10.Name, repo10.Name, pull.Index, token), &api.EditPullRequestOption{
|
||||
Base: "feature/1",
|
||||
Title: "edit a this pr",
|
||||
})
|
||||
resp = session.MakeRequest(t, req, http.StatusCreated)
|
||||
DecodeJSON(t, resp, pull)
|
||||
assert.EqualValues(t, "feature/1", pull.Base.Name)
|
||||
|
||||
req = NewRequestWithJSON(t, http.MethodPatch, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d?token=%s", owner10.Name, repo10.Name, pull.Index, token), &api.EditPullRequestOption{
|
||||
Base: "not-exist",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
233
tests/integration/api_releases_test.go
Normal file
233
tests/integration/api_releases_test.go
Normal file
|
@ -0,0 +1,233 @@
|
|||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
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 TestAPIListReleases(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
token := getUserToken(t, user2.LowerName)
|
||||
|
||||
link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/releases", user2.Name, repo.Name))
|
||||
link.RawQuery = url.Values{"token": {token}}.Encode()
|
||||
resp := MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||
var apiReleases []*api.Release
|
||||
DecodeJSON(t, resp, &apiReleases)
|
||||
if assert.Len(t, apiReleases, 3) {
|
||||
for _, release := range apiReleases {
|
||||
switch release.ID {
|
||||
case 1:
|
||||
assert.False(t, release.IsDraft)
|
||||
assert.False(t, release.IsPrerelease)
|
||||
case 4:
|
||||
assert.True(t, release.IsDraft)
|
||||
assert.False(t, release.IsPrerelease)
|
||||
case 5:
|
||||
assert.False(t, release.IsDraft)
|
||||
assert.True(t, release.IsPrerelease)
|
||||
default:
|
||||
assert.NoError(t, fmt.Errorf("unexpected release: %v", release))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// test filter
|
||||
testFilterByLen := func(auth bool, query url.Values, expectedLength int, msgAndArgs ...string) {
|
||||
if auth {
|
||||
query.Set("token", token)
|
||||
}
|
||||
link.RawQuery = query.Encode()
|
||||
resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiReleases)
|
||||
assert.Len(t, apiReleases, expectedLength, msgAndArgs)
|
||||
}
|
||||
|
||||
testFilterByLen(false, url.Values{"draft": {"true"}}, 0, "anon should not see drafts")
|
||||
testFilterByLen(true, url.Values{"draft": {"true"}}, 1, "repo owner should see drafts")
|
||||
testFilterByLen(true, url.Values{"draft": {"false"}}, 2, "exclude drafts")
|
||||
testFilterByLen(true, url.Values{"draft": {"false"}, "pre-release": {"false"}}, 1, "exclude drafts and pre-releases")
|
||||
testFilterByLen(true, url.Values{"pre-release": {"true"}}, 1, "only get pre-release")
|
||||
testFilterByLen(true, url.Values{"draft": {"true"}, "pre-release": {"true"}}, 0, "there is no pre-release draft")
|
||||
}
|
||||
|
||||
func createNewReleaseUsingAPI(t *testing.T, session *TestSession, token string, owner *user_model.User, repo *repo_model.Repository, name, target, title, desc string) *api.Release {
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases?token=%s",
|
||||
owner.Name, repo.Name, token)
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateReleaseOption{
|
||||
TagName: name,
|
||||
Title: title,
|
||||
Note: desc,
|
||||
IsDraft: false,
|
||||
IsPrerelease: false,
|
||||
Target: target,
|
||||
})
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
var newRelease api.Release
|
||||
DecodeJSON(t, resp, &newRelease)
|
||||
rel := &repo_model.Release{
|
||||
ID: newRelease.ID,
|
||||
TagName: newRelease.TagName,
|
||||
Title: newRelease.Title,
|
||||
}
|
||||
unittest.AssertExistsAndLoadBean(t, rel)
|
||||
assert.EqualValues(t, newRelease.Note, rel.Note)
|
||||
|
||||
return &newRelease
|
||||
}
|
||||
|
||||
func TestAPICreateAndUpdateRelease(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
session := loginUser(t, owner.LowerName)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
gitRepo, err := git.OpenRepository(git.DefaultContext, repo.RepoPath())
|
||||
assert.NoError(t, err)
|
||||
defer gitRepo.Close()
|
||||
|
||||
err = gitRepo.CreateTag("v0.0.1", "master")
|
||||
assert.NoError(t, err)
|
||||
|
||||
target, err := gitRepo.GetTagCommitID("v0.0.1")
|
||||
assert.NoError(t, err)
|
||||
|
||||
newRelease := createNewReleaseUsingAPI(t, session, token, owner, repo, "v0.0.1", target, "v0.0.1", "test")
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases/%d?token=%s",
|
||||
owner.Name, repo.Name, newRelease.ID, token)
|
||||
req := NewRequest(t, "GET", urlStr)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var release api.Release
|
||||
DecodeJSON(t, resp, &release)
|
||||
|
||||
assert.Equal(t, newRelease.TagName, release.TagName)
|
||||
assert.Equal(t, newRelease.Title, release.Title)
|
||||
assert.Equal(t, newRelease.Note, release.Note)
|
||||
|
||||
req = NewRequestWithJSON(t, "PATCH", urlStr, &api.EditReleaseOption{
|
||||
TagName: release.TagName,
|
||||
Title: release.Title,
|
||||
Note: "updated",
|
||||
IsDraft: &release.IsDraft,
|
||||
IsPrerelease: &release.IsPrerelease,
|
||||
Target: release.Target,
|
||||
})
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
DecodeJSON(t, resp, &newRelease)
|
||||
rel := &repo_model.Release{
|
||||
ID: newRelease.ID,
|
||||
TagName: newRelease.TagName,
|
||||
Title: newRelease.Title,
|
||||
}
|
||||
unittest.AssertExistsAndLoadBean(t, rel)
|
||||
assert.EqualValues(t, rel.Note, newRelease.Note)
|
||||
}
|
||||
|
||||
func TestAPICreateReleaseToDefaultBranch(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
session := loginUser(t, owner.LowerName)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
createNewReleaseUsingAPI(t, session, token, owner, repo, "v0.0.1", "", "v0.0.1", "test")
|
||||
}
|
||||
|
||||
func TestAPICreateReleaseToDefaultBranchOnExistingTag(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
session := loginUser(t, owner.LowerName)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
gitRepo, err := git.OpenRepository(git.DefaultContext, repo.RepoPath())
|
||||
assert.NoError(t, err)
|
||||
defer gitRepo.Close()
|
||||
|
||||
err = gitRepo.CreateTag("v0.0.1", "master")
|
||||
assert.NoError(t, err)
|
||||
|
||||
createNewReleaseUsingAPI(t, session, token, owner, repo, "v0.0.1", "", "v0.0.1", "test")
|
||||
}
|
||||
|
||||
func TestAPIGetReleaseByTag(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
session := loginUser(t, owner.LowerName)
|
||||
|
||||
tag := "v1.1"
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases/tags/%s",
|
||||
owner.Name, repo.Name, tag)
|
||||
|
||||
req := NewRequestf(t, "GET", urlStr)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var release *api.Release
|
||||
DecodeJSON(t, resp, &release)
|
||||
|
||||
assert.Equal(t, "testing-release", release.Title)
|
||||
|
||||
nonexistingtag := "nonexistingtag"
|
||||
|
||||
urlStr = fmt.Sprintf("/api/v1/repos/%s/%s/releases/tags/%s",
|
||||
owner.Name, repo.Name, nonexistingtag)
|
||||
|
||||
req = NewRequestf(t, "GET", urlStr)
|
||||
resp = session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
var err *api.APIError
|
||||
DecodeJSON(t, resp, &err)
|
||||
assert.NotEmpty(t, err.Message)
|
||||
}
|
||||
|
||||
func TestAPIDeleteReleaseByTagName(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
session := loginUser(t, owner.LowerName)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
createNewReleaseUsingAPI(t, session, token, owner, repo, "release-tag", "", "Release Tag", "test")
|
||||
|
||||
// delete release
|
||||
req := NewRequestf(t, http.MethodDelete, fmt.Sprintf("/api/v1/repos/%s/%s/releases/tags/release-tag?token=%s", owner.Name, repo.Name, token))
|
||||
_ = session.MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
// make sure release is deleted
|
||||
req = NewRequestf(t, http.MethodDelete, fmt.Sprintf("/api/v1/repos/%s/%s/releases/tags/release-tag?token=%s", owner.Name, repo.Name, token))
|
||||
_ = session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// delete release tag too
|
||||
req = NewRequestf(t, http.MethodDelete, fmt.Sprintf("/api/v1/repos/%s/%s/tags/release-tag?token=%s", owner.Name, repo.Name, token))
|
||||
_ = session.MakeRequest(t, req, http.StatusNoContent)
|
||||
}
|
54
tests/integration/api_repo_archive_test.go
Normal file
54
tests/integration/api_repo_archive_test.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
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/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIDownloadArchive(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
session := loginUser(t, user2.LowerName)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/archive/master.zip", user2.Name, repo.Name))
|
||||
link.RawQuery = url.Values{"token": {token}}.Encode()
|
||||
resp := MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||
bs, err := io.ReadAll(resp.Body)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 320, len(bs))
|
||||
|
||||
link, _ = url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/archive/master.tar.gz", user2.Name, repo.Name))
|
||||
link.RawQuery = url.Values{"token": {token}}.Encode()
|
||||
resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||
bs, err = io.ReadAll(resp.Body)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 266, len(bs))
|
||||
|
||||
link, _ = url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/archive/master.bundle", user2.Name, repo.Name))
|
||||
link.RawQuery = url.Values{"token": {token}}.Encode()
|
||||
resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||
bs, err = io.ReadAll(resp.Body)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 382, len(bs))
|
||||
|
||||
link, _ = url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/archive/master", user2.Name, repo.Name))
|
||||
link.RawQuery = url.Values{"token": {token}}.Encode()
|
||||
MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusBadRequest)
|
||||
}
|
131
tests/integration/api_repo_collaborator_test.go
Normal file
131
tests/integration/api_repo_collaborator_test.go
Normal file
|
@ -0,0 +1,131 @@
|
|||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
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"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIRepoCollaboratorPermission(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
|
||||
repo2Owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo2.OwnerID})
|
||||
|
||||
user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
|
||||
user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
|
||||
user10 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 10})
|
||||
user11 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 11})
|
||||
|
||||
session := loginUser(t, repo2Owner.Name)
|
||||
testCtx := NewAPITestContext(t, repo2Owner.Name, repo2.Name)
|
||||
|
||||
t.Run("RepoOwnerShouldBeOwner", func(t *testing.T) {
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission?token=%s", repo2Owner.Name, repo2.Name, repo2Owner.Name, testCtx.Token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var repoPermission api.RepoCollaboratorPermission
|
||||
DecodeJSON(t, resp, &repoPermission)
|
||||
|
||||
assert.Equal(t, "owner", repoPermission.Permission)
|
||||
})
|
||||
|
||||
t.Run("CollaboratorWithReadAccess", func(t *testing.T) {
|
||||
t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user4.Name, perm.AccessModeRead))
|
||||
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission?token=%s", repo2Owner.Name, repo2.Name, user4.Name, testCtx.Token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var repoPermission api.RepoCollaboratorPermission
|
||||
DecodeJSON(t, resp, &repoPermission)
|
||||
|
||||
assert.Equal(t, "read", repoPermission.Permission)
|
||||
})
|
||||
|
||||
t.Run("CollaboratorWithWriteAccess", func(t *testing.T) {
|
||||
t.Run("AddUserAsCollaboratorWithWriteAccess", doAPIAddCollaborator(testCtx, user4.Name, perm.AccessModeWrite))
|
||||
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission?token=%s", repo2Owner.Name, repo2.Name, user4.Name, testCtx.Token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var repoPermission api.RepoCollaboratorPermission
|
||||
DecodeJSON(t, resp, &repoPermission)
|
||||
|
||||
assert.Equal(t, "write", repoPermission.Permission)
|
||||
})
|
||||
|
||||
t.Run("CollaboratorWithAdminAccess", func(t *testing.T) {
|
||||
t.Run("AddUserAsCollaboratorWithAdminAccess", doAPIAddCollaborator(testCtx, user4.Name, perm.AccessModeAdmin))
|
||||
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission?token=%s", repo2Owner.Name, repo2.Name, user4.Name, testCtx.Token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var repoPermission api.RepoCollaboratorPermission
|
||||
DecodeJSON(t, resp, &repoPermission)
|
||||
|
||||
assert.Equal(t, "admin", repoPermission.Permission)
|
||||
})
|
||||
|
||||
t.Run("CollaboratorNotFound", func(t *testing.T) {
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission?token=%s", repo2Owner.Name, repo2.Name, "non-existent-user", testCtx.Token)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
|
||||
t.Run("CollaboratorCanQueryItsPermissions", func(t *testing.T) {
|
||||
t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user5.Name, perm.AccessModeRead))
|
||||
|
||||
_session := loginUser(t, user5.Name)
|
||||
_testCtx := NewAPITestContext(t, user5.Name, repo2.Name)
|
||||
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission?token=%s", repo2Owner.Name, repo2.Name, user5.Name, _testCtx.Token)
|
||||
resp := _session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var repoPermission api.RepoCollaboratorPermission
|
||||
DecodeJSON(t, resp, &repoPermission)
|
||||
|
||||
assert.Equal(t, "read", repoPermission.Permission)
|
||||
})
|
||||
|
||||
t.Run("CollaboratorCanQueryItsPermissions", func(t *testing.T) {
|
||||
t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user5.Name, perm.AccessModeRead))
|
||||
|
||||
_session := loginUser(t, user5.Name)
|
||||
_testCtx := NewAPITestContext(t, user5.Name, repo2.Name)
|
||||
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission?token=%s", repo2Owner.Name, repo2.Name, user5.Name, _testCtx.Token)
|
||||
resp := _session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var repoPermission api.RepoCollaboratorPermission
|
||||
DecodeJSON(t, resp, &repoPermission)
|
||||
|
||||
assert.Equal(t, "read", repoPermission.Permission)
|
||||
})
|
||||
|
||||
t.Run("RepoAdminCanQueryACollaboratorsPermissions", func(t *testing.T) {
|
||||
t.Run("AddUserAsCollaboratorWithAdminAccess", doAPIAddCollaborator(testCtx, user10.Name, perm.AccessModeAdmin))
|
||||
t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user11.Name, perm.AccessModeRead))
|
||||
|
||||
_session := loginUser(t, user10.Name)
|
||||
_testCtx := NewAPITestContext(t, user10.Name, repo2.Name)
|
||||
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission?token=%s", repo2Owner.Name, repo2.Name, user11.Name, _testCtx.Token)
|
||||
resp := _session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var repoPermission api.RepoCollaboratorPermission
|
||||
DecodeJSON(t, resp, &repoPermission)
|
||||
|
||||
assert.Equal(t, "read", repoPermission.Permission)
|
||||
})
|
||||
})
|
||||
}
|
346
tests/integration/api_repo_edit_test.go
Normal file
346
tests/integration/api_repo_edit_test.go
Normal file
|
@ -0,0 +1,346 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
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"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// getRepoEditOptionFromRepo gets the options for an existing repo exactly as is
|
||||
func getRepoEditOptionFromRepo(repo *repo_model.Repository) *api.EditRepoOption {
|
||||
name := repo.Name
|
||||
description := repo.Description
|
||||
website := repo.Website
|
||||
private := repo.IsPrivate
|
||||
hasIssues := false
|
||||
var internalTracker *api.InternalTracker
|
||||
var externalTracker *api.ExternalTracker
|
||||
if unit, err := repo.GetUnit(unit_model.TypeIssues); err == nil {
|
||||
config := unit.IssuesConfig()
|
||||
hasIssues = true
|
||||
internalTracker = &api.InternalTracker{
|
||||
EnableTimeTracker: config.EnableTimetracker,
|
||||
AllowOnlyContributorsToTrackTime: config.AllowOnlyContributorsToTrackTime,
|
||||
EnableIssueDependencies: config.EnableDependencies,
|
||||
}
|
||||
} else if unit, err := repo.GetUnit(unit_model.TypeExternalTracker); err == nil {
|
||||
config := unit.ExternalTrackerConfig()
|
||||
hasIssues = true
|
||||
externalTracker = &api.ExternalTracker{
|
||||
ExternalTrackerURL: config.ExternalTrackerURL,
|
||||
ExternalTrackerFormat: config.ExternalTrackerFormat,
|
||||
ExternalTrackerStyle: config.ExternalTrackerStyle,
|
||||
}
|
||||
}
|
||||
hasWiki := false
|
||||
var externalWiki *api.ExternalWiki
|
||||
if _, err := repo.GetUnit(unit_model.TypeWiki); err == nil {
|
||||
hasWiki = true
|
||||
} else if unit, err := repo.GetUnit(unit_model.TypeExternalWiki); err == nil {
|
||||
hasWiki = true
|
||||
config := unit.ExternalWikiConfig()
|
||||
externalWiki = &api.ExternalWiki{
|
||||
ExternalWikiURL: config.ExternalWikiURL,
|
||||
}
|
||||
}
|
||||
defaultBranch := repo.DefaultBranch
|
||||
hasPullRequests := false
|
||||
ignoreWhitespaceConflicts := false
|
||||
allowMerge := false
|
||||
allowRebase := false
|
||||
allowRebaseMerge := false
|
||||
allowSquash := false
|
||||
if unit, err := repo.GetUnit(unit_model.TypePullRequests); err == nil {
|
||||
config := unit.PullRequestsConfig()
|
||||
hasPullRequests = true
|
||||
ignoreWhitespaceConflicts = config.IgnoreWhitespaceConflicts
|
||||
allowMerge = config.AllowMerge
|
||||
allowRebase = config.AllowRebase
|
||||
allowRebaseMerge = config.AllowRebaseMerge
|
||||
allowSquash = config.AllowSquash
|
||||
}
|
||||
archived := repo.IsArchived
|
||||
return &api.EditRepoOption{
|
||||
Name: &name,
|
||||
Description: &description,
|
||||
Website: &website,
|
||||
Private: &private,
|
||||
HasIssues: &hasIssues,
|
||||
ExternalTracker: externalTracker,
|
||||
InternalTracker: internalTracker,
|
||||
HasWiki: &hasWiki,
|
||||
ExternalWiki: externalWiki,
|
||||
DefaultBranch: &defaultBranch,
|
||||
HasPullRequests: &hasPullRequests,
|
||||
IgnoreWhitespaceConflicts: &ignoreWhitespaceConflicts,
|
||||
AllowMerge: &allowMerge,
|
||||
AllowRebase: &allowRebase,
|
||||
AllowRebaseMerge: &allowRebaseMerge,
|
||||
AllowSquash: &allowSquash,
|
||||
Archived: &archived,
|
||||
}
|
||||
}
|
||||
|
||||
// getNewRepoEditOption Gets the options to change everything about an existing repo by adding to strings or changing
|
||||
// the boolean
|
||||
func getNewRepoEditOption(opts *api.EditRepoOption) *api.EditRepoOption {
|
||||
// Gives a new property to everything
|
||||
name := *opts.Name + "renamed"
|
||||
description := "new description"
|
||||
website := "http://wwww.newwebsite.com"
|
||||
private := !*opts.Private
|
||||
hasIssues := !*opts.HasIssues
|
||||
hasWiki := !*opts.HasWiki
|
||||
defaultBranch := "master"
|
||||
hasPullRequests := !*opts.HasPullRequests
|
||||
ignoreWhitespaceConflicts := !*opts.IgnoreWhitespaceConflicts
|
||||
allowMerge := !*opts.AllowMerge
|
||||
allowRebase := !*opts.AllowRebase
|
||||
allowRebaseMerge := !*opts.AllowRebaseMerge
|
||||
allowSquash := !*opts.AllowSquash
|
||||
archived := !*opts.Archived
|
||||
|
||||
return &api.EditRepoOption{
|
||||
Name: &name,
|
||||
Description: &description,
|
||||
Website: &website,
|
||||
Private: &private,
|
||||
DefaultBranch: &defaultBranch,
|
||||
HasIssues: &hasIssues,
|
||||
HasWiki: &hasWiki,
|
||||
HasPullRequests: &hasPullRequests,
|
||||
IgnoreWhitespaceConflicts: &ignoreWhitespaceConflicts,
|
||||
AllowMerge: &allowMerge,
|
||||
AllowRebase: &allowRebase,
|
||||
AllowRebaseMerge: &allowRebaseMerge,
|
||||
AllowSquash: &allowSquash,
|
||||
Archived: &archived,
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIRepoEdit(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
bFalse, bTrue := false, true
|
||||
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo1 & repo16
|
||||
user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of the repo3, is an org
|
||||
user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // owner of neither repos
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo
|
||||
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // public repo
|
||||
repo15 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 15}) // empty repo
|
||||
repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) // private repo
|
||||
|
||||
// Get user2's token
|
||||
session := loginUser(t, user2.Name)
|
||||
token2 := getTokenForLoggedInUser(t, session)
|
||||
// Get user4's token
|
||||
session = loginUser(t, user4.Name)
|
||||
token4 := getTokenForLoggedInUser(t, session)
|
||||
session = emptyTestSession(t)
|
||||
|
||||
// Test editing a repo1 which user2 owns, changing name and many properties
|
||||
origRepoEditOption := getRepoEditOptionFromRepo(repo1)
|
||||
repoEditOption := getNewRepoEditOption(origRepoEditOption)
|
||||
url := fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, repo1.Name, token2)
|
||||
req := NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var repo api.Repository
|
||||
DecodeJSON(t, resp, &repo)
|
||||
assert.NotNil(t, repo)
|
||||
// check response
|
||||
assert.Equal(t, *repoEditOption.Name, repo.Name)
|
||||
assert.Equal(t, *repoEditOption.Description, repo.Description)
|
||||
assert.Equal(t, *repoEditOption.Website, repo.Website)
|
||||
assert.Equal(t, *repoEditOption.Archived, repo.Archived)
|
||||
// check repo1 from database
|
||||
repo1edited := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
repo1editedOption := getRepoEditOptionFromRepo(repo1edited)
|
||||
assert.Equal(t, *repoEditOption.Name, *repo1editedOption.Name)
|
||||
assert.Equal(t, *repoEditOption.Description, *repo1editedOption.Description)
|
||||
assert.Equal(t, *repoEditOption.Website, *repo1editedOption.Website)
|
||||
assert.Equal(t, *repoEditOption.Archived, *repo1editedOption.Archived)
|
||||
assert.Equal(t, *repoEditOption.Private, *repo1editedOption.Private)
|
||||
assert.Equal(t, *repoEditOption.HasWiki, *repo1editedOption.HasWiki)
|
||||
|
||||
// Test editing repo1 to use internal issue and wiki (default)
|
||||
*repoEditOption.HasIssues = true
|
||||
repoEditOption.ExternalTracker = nil
|
||||
repoEditOption.InternalTracker = &api.InternalTracker{
|
||||
EnableTimeTracker: false,
|
||||
AllowOnlyContributorsToTrackTime: false,
|
||||
EnableIssueDependencies: false,
|
||||
}
|
||||
*repoEditOption.HasWiki = true
|
||||
repoEditOption.ExternalWiki = nil
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, *repoEditOption.Name, token2)
|
||||
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &repo)
|
||||
assert.NotNil(t, repo)
|
||||
// check repo1 was written to database
|
||||
repo1edited = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
repo1editedOption = getRepoEditOptionFromRepo(repo1edited)
|
||||
assert.Equal(t, *repo1editedOption.HasIssues, true)
|
||||
assert.Nil(t, repo1editedOption.ExternalTracker)
|
||||
assert.Equal(t, *repo1editedOption.InternalTracker, *repoEditOption.InternalTracker)
|
||||
assert.Equal(t, *repo1editedOption.HasWiki, true)
|
||||
assert.Nil(t, repo1editedOption.ExternalWiki)
|
||||
|
||||
// Test editing repo1 to use external issue and wiki
|
||||
repoEditOption.ExternalTracker = &api.ExternalTracker{
|
||||
ExternalTrackerURL: "http://www.somewebsite.com",
|
||||
ExternalTrackerFormat: "http://www.somewebsite.com/{user}/{repo}?issue={index}",
|
||||
ExternalTrackerStyle: "alphanumeric",
|
||||
}
|
||||
repoEditOption.ExternalWiki = &api.ExternalWiki{
|
||||
ExternalWikiURL: "http://www.somewebsite.com",
|
||||
}
|
||||
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &repo)
|
||||
assert.NotNil(t, repo)
|
||||
// check repo1 was written to database
|
||||
repo1edited = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
repo1editedOption = getRepoEditOptionFromRepo(repo1edited)
|
||||
assert.Equal(t, *repo1editedOption.HasIssues, true)
|
||||
assert.Equal(t, *repo1editedOption.ExternalTracker, *repoEditOption.ExternalTracker)
|
||||
assert.Equal(t, *repo1editedOption.HasWiki, true)
|
||||
assert.Equal(t, *repo1editedOption.ExternalWiki, *repoEditOption.ExternalWiki)
|
||||
|
||||
// Do some tests with invalid URL for external tracker and wiki
|
||||
repoEditOption.ExternalTracker.ExternalTrackerURL = "htp://www.somewebsite.com"
|
||||
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
repoEditOption.ExternalTracker.ExternalTrackerURL = "http://www.somewebsite.com"
|
||||
repoEditOption.ExternalTracker.ExternalTrackerFormat = "http://www.somewebsite.com/{user/{repo}?issue={index}"
|
||||
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
repoEditOption.ExternalTracker.ExternalTrackerFormat = "http://www.somewebsite.com/{user}/{repo}?issue={index}"
|
||||
repoEditOption.ExternalWiki.ExternalWikiURL = "htp://www.somewebsite.com"
|
||||
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
|
||||
// Test small repo change through API with issue and wiki option not set; They shall not be touched.
|
||||
*repoEditOption.Description = "small change"
|
||||
repoEditOption.HasIssues = nil
|
||||
repoEditOption.ExternalTracker = nil
|
||||
repoEditOption.HasWiki = nil
|
||||
repoEditOption.ExternalWiki = nil
|
||||
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &repo)
|
||||
assert.NotNil(t, repo)
|
||||
// check repo1 was written to database
|
||||
repo1edited = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
repo1editedOption = getRepoEditOptionFromRepo(repo1edited)
|
||||
assert.Equal(t, *repo1editedOption.Description, *repoEditOption.Description)
|
||||
assert.Equal(t, *repo1editedOption.HasIssues, true)
|
||||
assert.NotNil(t, *repo1editedOption.ExternalTracker)
|
||||
assert.Equal(t, *repo1editedOption.HasWiki, true)
|
||||
assert.NotNil(t, *repo1editedOption.ExternalWiki)
|
||||
|
||||
// reset repo in db
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, *repoEditOption.Name, token2)
|
||||
req = NewRequestWithJSON(t, "PATCH", url, &origRepoEditOption)
|
||||
_ = session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// Test editing a non-existing repo
|
||||
name := "repodoesnotexist"
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, name, token2)
|
||||
req = NewRequestWithJSON(t, "PATCH", url, &api.EditRepoOption{Name: &name})
|
||||
_ = session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Test editing repo16 by user4 who does not have write access
|
||||
origRepoEditOption = getRepoEditOptionFromRepo(repo16)
|
||||
repoEditOption = getNewRepoEditOption(origRepoEditOption)
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, repo16.Name, token4)
|
||||
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Tests a repo with no token given so will fail
|
||||
origRepoEditOption = getRepoEditOptionFromRepo(repo16)
|
||||
repoEditOption = getNewRepoEditOption(origRepoEditOption)
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s", user2.Name, repo16.Name)
|
||||
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
|
||||
_ = session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Test using access token for a private repo that the user of the token owns
|
||||
origRepoEditOption = getRepoEditOptionFromRepo(repo16)
|
||||
repoEditOption = getNewRepoEditOption(origRepoEditOption)
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, repo16.Name, token2)
|
||||
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
|
||||
_ = session.MakeRequest(t, req, http.StatusOK)
|
||||
// reset repo in db
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, *repoEditOption.Name, token2)
|
||||
req = NewRequestWithJSON(t, "PATCH", url, &origRepoEditOption)
|
||||
_ = session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// Test making a repo public that is private
|
||||
repo16 = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16})
|
||||
assert.True(t, repo16.IsPrivate)
|
||||
repoEditOption = &api.EditRepoOption{
|
||||
Private: &bFalse,
|
||||
}
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, repo16.Name, token2)
|
||||
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
|
||||
_ = session.MakeRequest(t, req, http.StatusOK)
|
||||
repo16 = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16})
|
||||
assert.False(t, repo16.IsPrivate)
|
||||
// Make it private again
|
||||
repoEditOption.Private = &bTrue
|
||||
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
|
||||
_ = session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// Test to change empty repo
|
||||
assert.False(t, repo15.IsArchived)
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, repo15.Name, token2)
|
||||
req = NewRequestWithJSON(t, "PATCH", url, &api.EditRepoOption{
|
||||
Archived: &bTrue,
|
||||
})
|
||||
_ = session.MakeRequest(t, req, http.StatusOK)
|
||||
repo15 = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 15})
|
||||
assert.True(t, repo15.IsArchived)
|
||||
req = NewRequestWithJSON(t, "PATCH", url, &api.EditRepoOption{
|
||||
Archived: &bFalse,
|
||||
})
|
||||
_ = session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// Test using org repo "user3/repo3" where user2 is a collaborator
|
||||
origRepoEditOption = getRepoEditOptionFromRepo(repo3)
|
||||
repoEditOption = getNewRepoEditOption(origRepoEditOption)
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user3.Name, repo3.Name, token2)
|
||||
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
// reset repo in db
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user3.Name, *repoEditOption.Name, token2)
|
||||
req = NewRequestWithJSON(t, "PATCH", url, &origRepoEditOption)
|
||||
_ = session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// Test using org repo "user3/repo3" with no user token
|
||||
origRepoEditOption = getRepoEditOptionFromRepo(repo3)
|
||||
repoEditOption = getNewRepoEditOption(origRepoEditOption)
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s", user3.Name, repo3.Name)
|
||||
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Test using repo "user2/repo1" where user4 is a NOT collaborator
|
||||
origRepoEditOption = getRepoEditOptionFromRepo(repo1)
|
||||
repoEditOption = getNewRepoEditOption(origRepoEditOption)
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, repo1.Name, token4)
|
||||
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
})
|
||||
}
|
308
tests/integration/api_repo_file_create_test.go
Normal file
308
tests/integration/api_repo_file_create_test.go
Normal file
|
@ -0,0 +1,308 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
stdCtx "context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
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/context"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func getCreateFileOptions() api.CreateFileOptions {
|
||||
content := "This is new text"
|
||||
contentEncoded := base64.StdEncoding.EncodeToString([]byte(content))
|
||||
return api.CreateFileOptions{
|
||||
FileOptions: api.FileOptions{
|
||||
BranchName: "master",
|
||||
NewBranchName: "master",
|
||||
Message: "Making this new file new/file.txt",
|
||||
Author: api.Identity{
|
||||
Name: "Anne Doe",
|
||||
Email: "annedoe@example.com",
|
||||
},
|
||||
Committer: api.Identity{
|
||||
Name: "John Doe",
|
||||
Email: "johndoe@example.com",
|
||||
},
|
||||
Dates: api.CommitDateOptions{
|
||||
Author: time.Unix(946684810, 0),
|
||||
Committer: time.Unix(978307190, 0),
|
||||
},
|
||||
},
|
||||
Content: contentEncoded,
|
||||
}
|
||||
}
|
||||
|
||||
func getExpectedFileResponseForCreate(repoFullName, commitID, treePath, latestCommitSHA string) *api.FileResponse {
|
||||
sha := "a635aa942442ddfdba07468cf9661c08fbdf0ebf"
|
||||
encoding := "base64"
|
||||
content := "VGhpcyBpcyBuZXcgdGV4dA=="
|
||||
selfURL := setting.AppURL + "api/v1/repos/" + repoFullName + "/contents/" + treePath + "?ref=master"
|
||||
htmlURL := setting.AppURL + repoFullName + "/src/branch/master/" + treePath
|
||||
gitURL := setting.AppURL + "api/v1/repos/" + repoFullName + "/git/blobs/" + sha
|
||||
downloadURL := setting.AppURL + repoFullName + "/raw/branch/master/" + treePath
|
||||
return &api.FileResponse{
|
||||
Content: &api.ContentsResponse{
|
||||
Name: filepath.Base(treePath),
|
||||
Path: treePath,
|
||||
SHA: sha,
|
||||
LastCommitSHA: latestCommitSHA,
|
||||
Size: 16,
|
||||
Type: "file",
|
||||
Encoding: &encoding,
|
||||
Content: &content,
|
||||
URL: &selfURL,
|
||||
HTMLURL: &htmlURL,
|
||||
GitURL: &gitURL,
|
||||
DownloadURL: &downloadURL,
|
||||
Links: &api.FileLinksResponse{
|
||||
Self: &selfURL,
|
||||
GitURL: &gitURL,
|
||||
HTMLURL: &htmlURL,
|
||||
},
|
||||
},
|
||||
Commit: &api.FileCommitResponse{
|
||||
CommitMeta: api.CommitMeta{
|
||||
URL: setting.AppURL + "api/v1/repos/" + repoFullName + "/git/commits/" + commitID,
|
||||
SHA: commitID,
|
||||
},
|
||||
HTMLURL: setting.AppURL + repoFullName + "/commit/" + commitID,
|
||||
Author: &api.CommitUser{
|
||||
Identity: api.Identity{
|
||||
Name: "Anne Doe",
|
||||
Email: "annedoe@example.com",
|
||||
},
|
||||
Date: "2000-01-01T00:00:10Z",
|
||||
},
|
||||
Committer: &api.CommitUser{
|
||||
Identity: api.Identity{
|
||||
Name: "John Doe",
|
||||
Email: "johndoe@example.com",
|
||||
},
|
||||
Date: "2000-12-31T23:59:50Z",
|
||||
},
|
||||
Message: "Updates README.md\n",
|
||||
},
|
||||
Verification: &api.PayloadCommitVerification{
|
||||
Verified: false,
|
||||
Reason: "gpg.error.not_signed_commit",
|
||||
Signature: "",
|
||||
Payload: "",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAPICreateFileSmall(b *testing.B) {
|
||||
onGiteaRunTB(b, func(t testing.TB, u *url.URL) {
|
||||
b := t.(*testing.B)
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo1 & repo16
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo
|
||||
|
||||
for n := 0; n < b.N; n++ {
|
||||
treePath := fmt.Sprintf("update/file%d.txt", n)
|
||||
createFileInBranch(user2, repo1, treePath, repo1.DefaultBranch, treePath)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkAPICreateFileMedium(b *testing.B) {
|
||||
data := make([]byte, 10*1024*1024)
|
||||
|
||||
onGiteaRunTB(b, func(t testing.TB, u *url.URL) {
|
||||
b := t.(*testing.B)
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo1 & repo16
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo
|
||||
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
treePath := fmt.Sprintf("update/file%d.txt", n)
|
||||
copy(data, treePath)
|
||||
createFileInBranch(user2, repo1, treePath, repo1.DefaultBranch, treePath)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestAPICreateFile(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo1 & repo16
|
||||
user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of the repo3, is an org
|
||||
user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // owner of neither repos
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo
|
||||
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // public repo
|
||||
repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) // private repo
|
||||
fileID := 0
|
||||
|
||||
// Get user2's token
|
||||
session := loginUser(t, user2.Name)
|
||||
token2 := getTokenForLoggedInUser(t, session)
|
||||
// Get user4's token
|
||||
session = loginUser(t, user4.Name)
|
||||
token4 := getTokenForLoggedInUser(t, session)
|
||||
session = emptyTestSession(t)
|
||||
|
||||
// Test creating a file in repo1 which user2 owns, try both with branch and empty branch
|
||||
for _, branch := range [...]string{
|
||||
"master", // Branch
|
||||
"", // Empty branch
|
||||
} {
|
||||
createFileOptions := getCreateFileOptions()
|
||||
createFileOptions.BranchName = branch
|
||||
fileID++
|
||||
treePath := fmt.Sprintf("new/file%d.txt", fileID)
|
||||
url := fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
|
||||
req := NewRequestWithJSON(t, "POST", url, &createFileOptions)
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
gitRepo, _ := git.OpenRepository(stdCtx.Background(), repo1.RepoPath())
|
||||
commitID, _ := gitRepo.GetBranchCommitID(createFileOptions.NewBranchName)
|
||||
latestCommit, _ := gitRepo.GetCommitByPath(treePath)
|
||||
expectedFileResponse := getExpectedFileResponseForCreate("user2/repo1", commitID, treePath, latestCommit.ID.String())
|
||||
var fileResponse api.FileResponse
|
||||
DecodeJSON(t, resp, &fileResponse)
|
||||
assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
|
||||
assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
|
||||
assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
|
||||
assert.EqualValues(t, expectedFileResponse.Commit.Author.Email, fileResponse.Commit.Author.Email)
|
||||
assert.EqualValues(t, expectedFileResponse.Commit.Author.Name, fileResponse.Commit.Author.Name)
|
||||
assert.EqualValues(t, expectedFileResponse.Commit.Author.Date, fileResponse.Commit.Author.Date)
|
||||
assert.EqualValues(t, expectedFileResponse.Commit.Committer.Email, fileResponse.Commit.Committer.Email)
|
||||
assert.EqualValues(t, expectedFileResponse.Commit.Committer.Name, fileResponse.Commit.Committer.Name)
|
||||
assert.EqualValues(t, expectedFileResponse.Commit.Committer.Date, fileResponse.Commit.Committer.Date)
|
||||
gitRepo.Close()
|
||||
}
|
||||
|
||||
// Test creating a file in a new branch
|
||||
createFileOptions := getCreateFileOptions()
|
||||
createFileOptions.BranchName = repo1.DefaultBranch
|
||||
createFileOptions.NewBranchName = "new_branch"
|
||||
fileID++
|
||||
treePath := fmt.Sprintf("new/file%d.txt", fileID)
|
||||
url := fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
|
||||
req := NewRequestWithJSON(t, "POST", url, &createFileOptions)
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
var fileResponse api.FileResponse
|
||||
DecodeJSON(t, resp, &fileResponse)
|
||||
expectedSHA := "a635aa942442ddfdba07468cf9661c08fbdf0ebf"
|
||||
expectedHTMLURL := fmt.Sprintf(setting.AppURL+"user2/repo1/src/branch/new_branch/new/file%d.txt", fileID)
|
||||
expectedDownloadURL := fmt.Sprintf(setting.AppURL+"user2/repo1/raw/branch/new_branch/new/file%d.txt", fileID)
|
||||
assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA)
|
||||
assert.EqualValues(t, expectedHTMLURL, *fileResponse.Content.HTMLURL)
|
||||
assert.EqualValues(t, expectedDownloadURL, *fileResponse.Content.DownloadURL)
|
||||
assert.EqualValues(t, createFileOptions.Message+"\n", fileResponse.Commit.Message)
|
||||
|
||||
// Test creating a file without a message
|
||||
createFileOptions = getCreateFileOptions()
|
||||
createFileOptions.Message = ""
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("new/file%d.txt", fileID)
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
|
||||
req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
|
||||
resp = session.MakeRequest(t, req, http.StatusCreated)
|
||||
DecodeJSON(t, resp, &fileResponse)
|
||||
expectedMessage := "Add '" + treePath + "'\n"
|
||||
assert.EqualValues(t, expectedMessage, fileResponse.Commit.Message)
|
||||
|
||||
// Test trying to create a file that already exists, should fail
|
||||
createFileOptions = getCreateFileOptions()
|
||||
treePath = "README.md"
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
|
||||
req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
|
||||
resp = session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
expectedAPIError := context.APIError{
|
||||
Message: "repository file already exists [path: " + treePath + "]",
|
||||
URL: setting.API.SwaggerURL,
|
||||
}
|
||||
var apiError context.APIError
|
||||
DecodeJSON(t, resp, &apiError)
|
||||
assert.Equal(t, expectedAPIError, apiError)
|
||||
|
||||
// Test creating a file in repo1 by user4 who does not have write access
|
||||
createFileOptions = getCreateFileOptions()
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("new/file%d.txt", fileID)
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token4)
|
||||
req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Tests a repo with no token given so will fail
|
||||
createFileOptions = getCreateFileOptions()
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("new/file%d.txt", fileID)
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user2.Name, repo16.Name, treePath)
|
||||
req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Test using access token for a private repo that the user of the token owns
|
||||
createFileOptions = getCreateFileOptions()
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("new/file%d.txt", fileID)
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token2)
|
||||
req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
|
||||
session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
// Test using org repo "user3/repo3" where user2 is a collaborator
|
||||
createFileOptions = getCreateFileOptions()
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("new/file%d.txt", fileID)
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user3.Name, repo3.Name, treePath, token2)
|
||||
req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
|
||||
session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
// Test using org repo "user3/repo3" with no user token
|
||||
createFileOptions = getCreateFileOptions()
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("new/file%d.txt", fileID)
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user3.Name, repo3.Name, treePath)
|
||||
req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Test using repo "user2/repo1" where user4 is a NOT collaborator
|
||||
createFileOptions = getCreateFileOptions()
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("new/file%d.txt", fileID)
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token4)
|
||||
req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
|
||||
// Test creating a file in an empty repository
|
||||
doAPICreateRepository(NewAPITestContext(t, "user2", "empty-repo"), true)(t)
|
||||
createFileOptions = getCreateFileOptions()
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("new/file%d.txt", fileID)
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, "empty-repo", treePath, token2)
|
||||
req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
|
||||
resp = session.MakeRequest(t, req, http.StatusCreated)
|
||||
emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "empty-repo"}) // public repo
|
||||
gitRepo, _ := git.OpenRepository(stdCtx.Background(), emptyRepo.RepoPath())
|
||||
commitID, _ := gitRepo.GetBranchCommitID(createFileOptions.NewBranchName)
|
||||
latestCommit, _ := gitRepo.GetCommitByPath(treePath)
|
||||
expectedFileResponse := getExpectedFileResponseForCreate("user2/empty-repo", commitID, treePath, latestCommit.ID.String())
|
||||
DecodeJSON(t, resp, &fileResponse)
|
||||
assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
|
||||
assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
|
||||
assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
|
||||
assert.EqualValues(t, expectedFileResponse.Commit.Author.Email, fileResponse.Commit.Author.Email)
|
||||
assert.EqualValues(t, expectedFileResponse.Commit.Author.Name, fileResponse.Commit.Author.Name)
|
||||
assert.EqualValues(t, expectedFileResponse.Commit.Author.Date, fileResponse.Commit.Author.Date)
|
||||
assert.EqualValues(t, expectedFileResponse.Commit.Committer.Email, fileResponse.Commit.Committer.Email)
|
||||
assert.EqualValues(t, expectedFileResponse.Commit.Committer.Name, fileResponse.Commit.Committer.Name)
|
||||
assert.EqualValues(t, expectedFileResponse.Commit.Committer.Date, fileResponse.Commit.Committer.Date)
|
||||
gitRepo.Close()
|
||||
})
|
||||
}
|
170
tests/integration/api_repo_file_delete_test.go
Normal file
170
tests/integration/api_repo_file_delete_test.go
Normal file
|
@ -0,0 +1,170 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
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"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func getDeleteFileOptions() *api.DeleteFileOptions {
|
||||
return &api.DeleteFileOptions{
|
||||
FileOptions: api.FileOptions{
|
||||
BranchName: "master",
|
||||
NewBranchName: "master",
|
||||
Message: "Removing the file new/file.txt",
|
||||
Author: api.Identity{
|
||||
Name: "John Doe",
|
||||
Email: "johndoe@example.com",
|
||||
},
|
||||
Committer: api.Identity{
|
||||
Name: "Jane Doe",
|
||||
Email: "janedoe@example.com",
|
||||
},
|
||||
},
|
||||
SHA: "103ff9234cefeee5ec5361d22b49fbb04d385885",
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIDeleteFile(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo1 & repo16
|
||||
user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of the repo3, is an org
|
||||
user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // owner of neither repos
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo
|
||||
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // public repo
|
||||
repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) // private repo
|
||||
fileID := 0
|
||||
|
||||
// Get user2's token
|
||||
session := loginUser(t, user2.Name)
|
||||
token2 := getTokenForLoggedInUser(t, session)
|
||||
// Get user4's token
|
||||
session = loginUser(t, user4.Name)
|
||||
token4 := getTokenForLoggedInUser(t, session)
|
||||
session = emptyTestSession(t)
|
||||
|
||||
// Test deleting a file in repo1 which user2 owns, try both with branch and empty branch
|
||||
for _, branch := range [...]string{
|
||||
"master", // Branch
|
||||
"", // Empty branch
|
||||
} {
|
||||
fileID++
|
||||
treePath := fmt.Sprintf("delete/file%d.txt", fileID)
|
||||
createFile(user2, repo1, treePath)
|
||||
deleteFileOptions := getDeleteFileOptions()
|
||||
deleteFileOptions.BranchName = branch
|
||||
url := fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
|
||||
req := NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var fileResponse api.FileResponse
|
||||
DecodeJSON(t, resp, &fileResponse)
|
||||
assert.NotNil(t, fileResponse)
|
||||
assert.Nil(t, fileResponse.Content)
|
||||
}
|
||||
|
||||
// Test deleting file and making the delete in a new branch
|
||||
fileID++
|
||||
treePath := fmt.Sprintf("delete/file%d.txt", fileID)
|
||||
createFile(user2, repo1, treePath)
|
||||
deleteFileOptions := getDeleteFileOptions()
|
||||
deleteFileOptions.BranchName = repo1.DefaultBranch
|
||||
deleteFileOptions.NewBranchName = "new_branch"
|
||||
url := fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
|
||||
req := NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var fileResponse api.FileResponse
|
||||
DecodeJSON(t, resp, &fileResponse)
|
||||
assert.NotNil(t, fileResponse)
|
||||
assert.Nil(t, fileResponse.Content)
|
||||
assert.EqualValues(t, deleteFileOptions.Message+"\n", fileResponse.Commit.Message)
|
||||
|
||||
// Test deleting file without a message
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("delete/file%d.txt", fileID)
|
||||
createFile(user2, repo1, treePath)
|
||||
deleteFileOptions = getDeleteFileOptions()
|
||||
deleteFileOptions.Message = ""
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
|
||||
req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &fileResponse)
|
||||
expectedMessage := "Delete '" + treePath + "'\n"
|
||||
assert.EqualValues(t, expectedMessage, fileResponse.Commit.Message)
|
||||
|
||||
// Test deleting a file with the wrong SHA
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("delete/file%d.txt", fileID)
|
||||
createFile(user2, repo1, treePath)
|
||||
deleteFileOptions = getDeleteFileOptions()
|
||||
deleteFileOptions.SHA = "badsha"
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
|
||||
req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
|
||||
session.MakeRequest(t, req, http.StatusBadRequest)
|
||||
|
||||
// Test creating a file in repo16 by user4 who does not have write access
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("delete/file%d.txt", fileID)
|
||||
createFile(user2, repo16, treePath)
|
||||
deleteFileOptions = getDeleteFileOptions()
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token4)
|
||||
req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Tests a repo with no token given so will fail
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("delete/file%d.txt", fileID)
|
||||
createFile(user2, repo16, treePath)
|
||||
deleteFileOptions = getDeleteFileOptions()
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user2.Name, repo16.Name, treePath)
|
||||
req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Test using access token for a private repo that the user of the token owns
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("delete/file%d.txt", fileID)
|
||||
createFile(user2, repo16, treePath)
|
||||
deleteFileOptions = getDeleteFileOptions()
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token2)
|
||||
req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// Test using org repo "user3/repo3" where user2 is a collaborator
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("delete/file%d.txt", fileID)
|
||||
createFile(user3, repo3, treePath)
|
||||
deleteFileOptions = getDeleteFileOptions()
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user3.Name, repo3.Name, treePath, token2)
|
||||
req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// Test using org repo "user3/repo3" with no user token
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("delete/file%d.txt", fileID)
|
||||
createFile(user3, repo3, treePath)
|
||||
deleteFileOptions = getDeleteFileOptions()
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user3.Name, repo3.Name, treePath)
|
||||
req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Test using repo "user2/repo1" where user4 is a NOT collaborator
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("delete/file%d.txt", fileID)
|
||||
createFile(user2, repo1, treePath)
|
||||
deleteFileOptions = getDeleteFileOptions()
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token4)
|
||||
req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
})
|
||||
}
|
57
tests/integration/api_repo_file_get_test.go
Normal file
57
tests/integration/api_repo_file_get_test.go
Normal file
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIGetRawFileOrLFS(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
// Test with raw file
|
||||
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo1/media/README.md")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, "# repo1\n\nDescription for repo1", resp.Body.String())
|
||||
|
||||
// Test with LFS
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
httpContext := NewAPITestContext(t, "user2", "repo-lfs-test")
|
||||
doAPICreateRepository(httpContext, false, func(t *testing.T, repository api.Repository) {
|
||||
u.Path = httpContext.GitPath()
|
||||
dstPath, err := os.MkdirTemp("", httpContext.Reponame)
|
||||
assert.NoError(t, err)
|
||||
defer util.RemoveAll(dstPath)
|
||||
|
||||
u.Path = httpContext.GitPath()
|
||||
u.User = url.UserPassword("user2", userPassword)
|
||||
|
||||
t.Run("Clone", doGitClone(dstPath, u))
|
||||
|
||||
dstPath2, err := os.MkdirTemp("", httpContext.Reponame)
|
||||
assert.NoError(t, err)
|
||||
defer util.RemoveAll(dstPath2)
|
||||
|
||||
t.Run("Partial Clone", doPartialGitClone(dstPath2, u))
|
||||
|
||||
lfs, _ := lfsCommitAndPushTest(t, dstPath)
|
||||
|
||||
reqLFS := NewRequest(t, "GET", "/api/v1/repos/user2/repo1/media/"+lfs)
|
||||
respLFS := MakeRequestNilResponseRecorder(t, reqLFS, http.StatusOK)
|
||||
assert.Equal(t, littleSize, respLFS.Length)
|
||||
|
||||
doAPIDeleteRepository(httpContext)
|
||||
})
|
||||
})
|
||||
}
|
29
tests/integration/api_repo_file_helpers.go
Normal file
29
tests/integration/api_repo_file_helpers.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
files_service "code.gitea.io/gitea/services/repository/files"
|
||||
)
|
||||
|
||||
func createFileInBranch(user *user_model.User, repo *repo_model.Repository, treePath, branchName, content string) (*api.FileResponse, error) {
|
||||
opts := &files_service.UpdateRepoFileOptions{
|
||||
OldBranch: branchName,
|
||||
TreePath: treePath,
|
||||
Content: content,
|
||||
IsNewFile: true,
|
||||
Author: nil,
|
||||
Committer: nil,
|
||||
}
|
||||
return files_service.CreateOrUpdateRepoFile(git.DefaultContext, repo, user, opts)
|
||||
}
|
||||
|
||||
func createFile(user *user_model.User, repo *repo_model.Repository, treePath string) (*api.FileResponse, error) {
|
||||
return createFileInBranch(user, repo, treePath, repo.DefaultBranch, "This is a NEW file")
|
||||
}
|
278
tests/integration/api_repo_file_update_test.go
Normal file
278
tests/integration/api_repo_file_update_test.go
Normal file
|
@ -0,0 +1,278 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
stdCtx "context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
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/context"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func getUpdateFileOptions() *api.UpdateFileOptions {
|
||||
content := "This is updated text"
|
||||
contentEncoded := base64.StdEncoding.EncodeToString([]byte(content))
|
||||
return &api.UpdateFileOptions{
|
||||
DeleteFileOptions: api.DeleteFileOptions{
|
||||
FileOptions: api.FileOptions{
|
||||
BranchName: "master",
|
||||
NewBranchName: "master",
|
||||
Message: "My update of new/file.txt",
|
||||
Author: api.Identity{
|
||||
Name: "John Doe",
|
||||
Email: "johndoe@example.com",
|
||||
},
|
||||
Committer: api.Identity{
|
||||
Name: "Anne Doe",
|
||||
Email: "annedoe@example.com",
|
||||
},
|
||||
},
|
||||
SHA: "103ff9234cefeee5ec5361d22b49fbb04d385885",
|
||||
},
|
||||
Content: contentEncoded,
|
||||
}
|
||||
}
|
||||
|
||||
func getExpectedFileResponseForUpdate(commitID, treePath, lastCommitSHA string) *api.FileResponse {
|
||||
sha := "08bd14b2e2852529157324de9c226b3364e76136"
|
||||
encoding := "base64"
|
||||
content := "VGhpcyBpcyB1cGRhdGVkIHRleHQ="
|
||||
selfURL := setting.AppURL + "api/v1/repos/user2/repo1/contents/" + treePath + "?ref=master"
|
||||
htmlURL := setting.AppURL + "user2/repo1/src/branch/master/" + treePath
|
||||
gitURL := setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/" + sha
|
||||
downloadURL := setting.AppURL + "user2/repo1/raw/branch/master/" + treePath
|
||||
return &api.FileResponse{
|
||||
Content: &api.ContentsResponse{
|
||||
Name: filepath.Base(treePath),
|
||||
Path: treePath,
|
||||
SHA: sha,
|
||||
LastCommitSHA: lastCommitSHA,
|
||||
Type: "file",
|
||||
Size: 20,
|
||||
Encoding: &encoding,
|
||||
Content: &content,
|
||||
URL: &selfURL,
|
||||
HTMLURL: &htmlURL,
|
||||
GitURL: &gitURL,
|
||||
DownloadURL: &downloadURL,
|
||||
Links: &api.FileLinksResponse{
|
||||
Self: &selfURL,
|
||||
GitURL: &gitURL,
|
||||
HTMLURL: &htmlURL,
|
||||
},
|
||||
},
|
||||
Commit: &api.FileCommitResponse{
|
||||
CommitMeta: api.CommitMeta{
|
||||
URL: setting.AppURL + "api/v1/repos/user2/repo1/git/commits/" + commitID,
|
||||
SHA: commitID,
|
||||
},
|
||||
HTMLURL: setting.AppURL + "user2/repo1/commit/" + commitID,
|
||||
Author: &api.CommitUser{
|
||||
Identity: api.Identity{
|
||||
Name: "John Doe",
|
||||
Email: "johndoe@example.com",
|
||||
},
|
||||
},
|
||||
Committer: &api.CommitUser{
|
||||
Identity: api.Identity{
|
||||
Name: "Anne Doe",
|
||||
Email: "annedoe@example.com",
|
||||
},
|
||||
},
|
||||
Message: "My update of README.md\n",
|
||||
},
|
||||
Verification: &api.PayloadCommitVerification{
|
||||
Verified: false,
|
||||
Reason: "gpg.error.not_signed_commit",
|
||||
Signature: "",
|
||||
Payload: "",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIUpdateFile(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo1 & repo16
|
||||
user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of the repo3, is an org
|
||||
user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // owner of neither repos
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo
|
||||
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // public repo
|
||||
repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) // private repo
|
||||
fileID := 0
|
||||
|
||||
// Get user2's token
|
||||
session := loginUser(t, user2.Name)
|
||||
token2 := getTokenForLoggedInUser(t, session)
|
||||
// Get user4's token
|
||||
session = loginUser(t, user4.Name)
|
||||
token4 := getTokenForLoggedInUser(t, session)
|
||||
session = emptyTestSession(t)
|
||||
|
||||
// Test updating a file in repo1 which user2 owns, try both with branch and empty branch
|
||||
for _, branch := range [...]string{
|
||||
"master", // Branch
|
||||
"", // Empty branch
|
||||
} {
|
||||
fileID++
|
||||
treePath := fmt.Sprintf("update/file%d.txt", fileID)
|
||||
createFile(user2, repo1, treePath)
|
||||
updateFileOptions := getUpdateFileOptions()
|
||||
updateFileOptions.BranchName = branch
|
||||
url := fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
|
||||
req := NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
gitRepo, _ := git.OpenRepository(stdCtx.Background(), repo1.RepoPath())
|
||||
commitID, _ := gitRepo.GetBranchCommitID(updateFileOptions.NewBranchName)
|
||||
lasCommit, _ := gitRepo.GetCommitByPath(treePath)
|
||||
expectedFileResponse := getExpectedFileResponseForUpdate(commitID, treePath, lasCommit.ID.String())
|
||||
var fileResponse api.FileResponse
|
||||
DecodeJSON(t, resp, &fileResponse)
|
||||
assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
|
||||
assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
|
||||
assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
|
||||
assert.EqualValues(t, expectedFileResponse.Commit.Author.Email, fileResponse.Commit.Author.Email)
|
||||
assert.EqualValues(t, expectedFileResponse.Commit.Author.Name, fileResponse.Commit.Author.Name)
|
||||
gitRepo.Close()
|
||||
}
|
||||
|
||||
// Test updating a file in a new branch
|
||||
updateFileOptions := getUpdateFileOptions()
|
||||
updateFileOptions.BranchName = repo1.DefaultBranch
|
||||
updateFileOptions.NewBranchName = "new_branch"
|
||||
fileID++
|
||||
treePath := fmt.Sprintf("update/file%d.txt", fileID)
|
||||
createFile(user2, repo1, treePath)
|
||||
url := fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
|
||||
req := NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var fileResponse api.FileResponse
|
||||
DecodeJSON(t, resp, &fileResponse)
|
||||
expectedSHA := "08bd14b2e2852529157324de9c226b3364e76136"
|
||||
expectedHTMLURL := fmt.Sprintf(setting.AppURL+"user2/repo1/src/branch/new_branch/update/file%d.txt", fileID)
|
||||
expectedDownloadURL := fmt.Sprintf(setting.AppURL+"user2/repo1/raw/branch/new_branch/update/file%d.txt", fileID)
|
||||
assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA)
|
||||
assert.EqualValues(t, expectedHTMLURL, *fileResponse.Content.HTMLURL)
|
||||
assert.EqualValues(t, expectedDownloadURL, *fileResponse.Content.DownloadURL)
|
||||
assert.EqualValues(t, updateFileOptions.Message+"\n", fileResponse.Commit.Message)
|
||||
|
||||
// Test updating a file and renaming it
|
||||
updateFileOptions = getUpdateFileOptions()
|
||||
updateFileOptions.BranchName = repo1.DefaultBranch
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("update/file%d.txt", fileID)
|
||||
createFile(user2, repo1, treePath)
|
||||
updateFileOptions.FromPath = treePath
|
||||
treePath = "rename/" + treePath
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
|
||||
req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &fileResponse)
|
||||
expectedSHA = "08bd14b2e2852529157324de9c226b3364e76136"
|
||||
expectedHTMLURL = fmt.Sprintf(setting.AppURL+"user2/repo1/src/branch/master/rename/update/file%d.txt", fileID)
|
||||
expectedDownloadURL = fmt.Sprintf(setting.AppURL+"user2/repo1/raw/branch/master/rename/update/file%d.txt", fileID)
|
||||
assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA)
|
||||
assert.EqualValues(t, expectedHTMLURL, *fileResponse.Content.HTMLURL)
|
||||
assert.EqualValues(t, expectedDownloadURL, *fileResponse.Content.DownloadURL)
|
||||
|
||||
// Test updating a file without a message
|
||||
updateFileOptions = getUpdateFileOptions()
|
||||
updateFileOptions.Message = ""
|
||||
updateFileOptions.BranchName = repo1.DefaultBranch
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("update/file%d.txt", fileID)
|
||||
createFile(user2, repo1, treePath)
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
|
||||
req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &fileResponse)
|
||||
expectedMessage := "Update '" + treePath + "'\n"
|
||||
assert.EqualValues(t, expectedMessage, fileResponse.Commit.Message)
|
||||
|
||||
// Test updating a file with the wrong SHA
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("update/file%d.txt", fileID)
|
||||
createFile(user2, repo1, treePath)
|
||||
updateFileOptions = getUpdateFileOptions()
|
||||
correctSHA := updateFileOptions.SHA
|
||||
updateFileOptions.SHA = "badsha"
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
|
||||
req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
|
||||
resp = session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
expectedAPIError := context.APIError{
|
||||
Message: "sha does not match [given: " + updateFileOptions.SHA + ", expected: " + correctSHA + "]",
|
||||
URL: setting.API.SwaggerURL,
|
||||
}
|
||||
var apiError context.APIError
|
||||
DecodeJSON(t, resp, &apiError)
|
||||
assert.Equal(t, expectedAPIError, apiError)
|
||||
|
||||
// Test creating a file in repo1 by user4 who does not have write access
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("update/file%d.txt", fileID)
|
||||
createFile(user2, repo16, treePath)
|
||||
updateFileOptions = getUpdateFileOptions()
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token4)
|
||||
req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Tests a repo with no token given so will fail
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("update/file%d.txt", fileID)
|
||||
createFile(user2, repo16, treePath)
|
||||
updateFileOptions = getUpdateFileOptions()
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user2.Name, repo16.Name, treePath)
|
||||
req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Test using access token for a private repo that the user of the token owns
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("update/file%d.txt", fileID)
|
||||
createFile(user2, repo16, treePath)
|
||||
updateFileOptions = getUpdateFileOptions()
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token2)
|
||||
req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// Test using org repo "user3/repo3" where user2 is a collaborator
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("update/file%d.txt", fileID)
|
||||
createFile(user3, repo3, treePath)
|
||||
updateFileOptions = getUpdateFileOptions()
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user3.Name, repo3.Name, treePath, token2)
|
||||
req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// Test using org repo "user3/repo3" with no user token
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("update/file%d.txt", fileID)
|
||||
createFile(user3, repo3, treePath)
|
||||
updateFileOptions = getUpdateFileOptions()
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user3.Name, repo3.Name, treePath)
|
||||
req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Test using repo "user2/repo1" where user4 is a NOT collaborator
|
||||
fileID++
|
||||
treePath = fmt.Sprintf("update/file%d.txt", fileID)
|
||||
createFile(user2, repo1, treePath)
|
||||
updateFileOptions = getUpdateFileOptions()
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token4)
|
||||
req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
})
|
||||
}
|
167
tests/integration/api_repo_get_contents_list_test.go
Normal file
167
tests/integration/api_repo_get_contents_list_test.go
Normal file
|
@ -0,0 +1,167 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
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/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func getExpectedContentsListResponseForContents(ref, refType, lastCommitSHA string) []*api.ContentsResponse {
|
||||
treePath := "README.md"
|
||||
sha := "4b4851ad51df6a7d9f25c979345979eaeb5b349f"
|
||||
selfURL := setting.AppURL + "api/v1/repos/user2/repo1/contents/" + treePath + "?ref=" + ref
|
||||
htmlURL := setting.AppURL + "user2/repo1/src/" + refType + "/" + ref + "/" + treePath
|
||||
gitURL := setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/" + sha
|
||||
downloadURL := setting.AppURL + "user2/repo1/raw/" + refType + "/" + ref + "/" + treePath
|
||||
return []*api.ContentsResponse{
|
||||
{
|
||||
Name: filepath.Base(treePath),
|
||||
Path: treePath,
|
||||
SHA: sha,
|
||||
LastCommitSHA: lastCommitSHA,
|
||||
Type: "file",
|
||||
Size: 30,
|
||||
URL: &selfURL,
|
||||
HTMLURL: &htmlURL,
|
||||
GitURL: &gitURL,
|
||||
DownloadURL: &downloadURL,
|
||||
Links: &api.FileLinksResponse{
|
||||
Self: &selfURL,
|
||||
GitURL: &gitURL,
|
||||
HTMLURL: &htmlURL,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIGetContentsList(t *testing.T) {
|
||||
onGiteaRun(t, testAPIGetContentsList)
|
||||
}
|
||||
|
||||
func testAPIGetContentsList(t *testing.T, u *url.URL) {
|
||||
/*** SETUP ***/
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo1 & repo16
|
||||
user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of the repo3, is an org
|
||||
user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // owner of neither repos
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo
|
||||
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // public repo
|
||||
repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) // private repo
|
||||
treePath := "" // root dir
|
||||
|
||||
// Get user2's token
|
||||
session := loginUser(t, user2.Name)
|
||||
token2 := getTokenForLoggedInUser(t, session)
|
||||
// Get user4's token
|
||||
session = loginUser(t, user4.Name)
|
||||
token4 := getTokenForLoggedInUser(t, session)
|
||||
session = emptyTestSession(t)
|
||||
|
||||
// Make a new branch in repo1
|
||||
newBranch := "test_branch"
|
||||
err := repo_service.CreateNewBranch(git.DefaultContext, user2, repo1, repo1.DefaultBranch, newBranch)
|
||||
assert.NoError(t, err)
|
||||
// Get the commit ID of the default branch
|
||||
gitRepo, err := git.OpenRepository(git.DefaultContext, repo1.RepoPath())
|
||||
assert.NoError(t, err)
|
||||
defer gitRepo.Close()
|
||||
|
||||
commitID, _ := gitRepo.GetBranchCommitID(repo1.DefaultBranch)
|
||||
// Make a new tag in repo1
|
||||
newTag := "test_tag"
|
||||
err = gitRepo.CreateTag(newTag, commitID)
|
||||
assert.NoError(t, err)
|
||||
/*** END SETUP ***/
|
||||
|
||||
// ref is default ref
|
||||
ref := repo1.DefaultBranch
|
||||
refType := "branch"
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var contentsListResponse []*api.ContentsResponse
|
||||
DecodeJSON(t, resp, &contentsListResponse)
|
||||
assert.NotNil(t, contentsListResponse)
|
||||
lastCommit, err := gitRepo.GetCommitByPath("README.md")
|
||||
assert.NoError(t, err)
|
||||
expectedContentsListResponse := getExpectedContentsListResponseForContents(ref, refType, lastCommit.ID.String())
|
||||
assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
|
||||
|
||||
// No ref
|
||||
refType = "branch"
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s", user2.Name, repo1.Name, treePath)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &contentsListResponse)
|
||||
assert.NotNil(t, contentsListResponse)
|
||||
|
||||
expectedContentsListResponse = getExpectedContentsListResponseForContents(repo1.DefaultBranch, refType, lastCommit.ID.String())
|
||||
assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
|
||||
|
||||
// ref is the branch we created above in setup
|
||||
ref = newBranch
|
||||
refType = "branch"
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &contentsListResponse)
|
||||
assert.NotNil(t, contentsListResponse)
|
||||
branchCommit, err := gitRepo.GetBranchCommit(ref)
|
||||
assert.NoError(t, err)
|
||||
lastCommit, err = branchCommit.GetCommitByPath("README.md")
|
||||
assert.NoError(t, err)
|
||||
expectedContentsListResponse = getExpectedContentsListResponseForContents(ref, refType, lastCommit.ID.String())
|
||||
assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
|
||||
|
||||
// ref is the new tag we created above in setup
|
||||
ref = newTag
|
||||
refType = "tag"
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &contentsListResponse)
|
||||
assert.NotNil(t, contentsListResponse)
|
||||
tagCommit, err := gitRepo.GetTagCommit(ref)
|
||||
assert.NoError(t, err)
|
||||
lastCommit, err = tagCommit.GetCommitByPath("README.md")
|
||||
assert.NoError(t, err)
|
||||
expectedContentsListResponse = getExpectedContentsListResponseForContents(ref, refType, lastCommit.ID.String())
|
||||
assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
|
||||
|
||||
// ref is a commit
|
||||
ref = commitID
|
||||
refType = "commit"
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &contentsListResponse)
|
||||
assert.NotNil(t, contentsListResponse)
|
||||
expectedContentsListResponse = getExpectedContentsListResponseForContents(ref, refType, commitID)
|
||||
assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
|
||||
|
||||
// Test file contents a file with a bad ref
|
||||
ref = "badref"
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Test accessing private ref with user token that does not have access - should fail
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token4)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Test access private ref of owner of token
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/readme.md?token=%s", user2.Name, repo16.Name, token2)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// Test access of org user3 private repo file by owner user2
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?token=%s", user3.Name, repo3.Name, treePath, token2)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
}
|
163
tests/integration/api_repo_get_contents_test.go
Normal file
163
tests/integration/api_repo_get_contents_test.go
Normal file
|
@ -0,0 +1,163 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
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/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func getExpectedContentsResponseForContents(ref, refType, lastCommitSHA string) *api.ContentsResponse {
|
||||
treePath := "README.md"
|
||||
sha := "4b4851ad51df6a7d9f25c979345979eaeb5b349f"
|
||||
encoding := "base64"
|
||||
content := "IyByZXBvMQoKRGVzY3JpcHRpb24gZm9yIHJlcG8x"
|
||||
selfURL := setting.AppURL + "api/v1/repos/user2/repo1/contents/" + treePath + "?ref=" + ref
|
||||
htmlURL := setting.AppURL + "user2/repo1/src/" + refType + "/" + ref + "/" + treePath
|
||||
gitURL := setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/" + sha
|
||||
downloadURL := setting.AppURL + "user2/repo1/raw/" + refType + "/" + ref + "/" + treePath
|
||||
return &api.ContentsResponse{
|
||||
Name: treePath,
|
||||
Path: treePath,
|
||||
SHA: sha,
|
||||
LastCommitSHA: lastCommitSHA,
|
||||
Type: "file",
|
||||
Size: 30,
|
||||
Encoding: &encoding,
|
||||
Content: &content,
|
||||
URL: &selfURL,
|
||||
HTMLURL: &htmlURL,
|
||||
GitURL: &gitURL,
|
||||
DownloadURL: &downloadURL,
|
||||
Links: &api.FileLinksResponse{
|
||||
Self: &selfURL,
|
||||
GitURL: &gitURL,
|
||||
HTMLURL: &htmlURL,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIGetContents(t *testing.T) {
|
||||
onGiteaRun(t, testAPIGetContents)
|
||||
}
|
||||
|
||||
func testAPIGetContents(t *testing.T, u *url.URL) {
|
||||
/*** SETUP ***/
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo1 & repo16
|
||||
user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of the repo3, is an org
|
||||
user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // owner of neither repos
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo
|
||||
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // public repo
|
||||
repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) // private repo
|
||||
treePath := "README.md"
|
||||
|
||||
// Get user2's token
|
||||
session := loginUser(t, user2.Name)
|
||||
token2 := getTokenForLoggedInUser(t, session)
|
||||
// Get user4's token
|
||||
session = loginUser(t, user4.Name)
|
||||
token4 := getTokenForLoggedInUser(t, session)
|
||||
session = emptyTestSession(t)
|
||||
|
||||
// Make a new branch in repo1
|
||||
newBranch := "test_branch"
|
||||
err := repo_service.CreateNewBranch(git.DefaultContext, user2, repo1, repo1.DefaultBranch, newBranch)
|
||||
assert.NoError(t, err)
|
||||
// Get the commit ID of the default branch
|
||||
gitRepo, err := git.OpenRepository(git.DefaultContext, repo1.RepoPath())
|
||||
assert.NoError(t, err)
|
||||
defer gitRepo.Close()
|
||||
|
||||
commitID, err := gitRepo.GetBranchCommitID(repo1.DefaultBranch)
|
||||
assert.NoError(t, err)
|
||||
// Make a new tag in repo1
|
||||
newTag := "test_tag"
|
||||
err = gitRepo.CreateTag(newTag, commitID)
|
||||
assert.NoError(t, err)
|
||||
/*** END SETUP ***/
|
||||
|
||||
// ref is default ref
|
||||
ref := repo1.DefaultBranch
|
||||
refType := "branch"
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var contentsResponse api.ContentsResponse
|
||||
DecodeJSON(t, resp, &contentsResponse)
|
||||
assert.NotNil(t, contentsResponse)
|
||||
lastCommit, _ := gitRepo.GetCommitByPath("README.md")
|
||||
expectedContentsResponse := getExpectedContentsResponseForContents(ref, refType, lastCommit.ID.String())
|
||||
assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
|
||||
|
||||
// No ref
|
||||
refType = "branch"
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s", user2.Name, repo1.Name, treePath)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &contentsResponse)
|
||||
assert.NotNil(t, contentsResponse)
|
||||
expectedContentsResponse = getExpectedContentsResponseForContents(repo1.DefaultBranch, refType, lastCommit.ID.String())
|
||||
assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
|
||||
|
||||
// ref is the branch we created above in setup
|
||||
ref = newBranch
|
||||
refType = "branch"
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &contentsResponse)
|
||||
assert.NotNil(t, contentsResponse)
|
||||
branchCommit, _ := gitRepo.GetBranchCommit(ref)
|
||||
lastCommit, _ = branchCommit.GetCommitByPath("README.md")
|
||||
expectedContentsResponse = getExpectedContentsResponseForContents(ref, refType, lastCommit.ID.String())
|
||||
assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
|
||||
|
||||
// ref is the new tag we created above in setup
|
||||
ref = newTag
|
||||
refType = "tag"
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &contentsResponse)
|
||||
assert.NotNil(t, contentsResponse)
|
||||
tagCommit, _ := gitRepo.GetTagCommit(ref)
|
||||
lastCommit, _ = tagCommit.GetCommitByPath("README.md")
|
||||
expectedContentsResponse = getExpectedContentsResponseForContents(ref, refType, lastCommit.ID.String())
|
||||
assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
|
||||
|
||||
// ref is a commit
|
||||
ref = commitID
|
||||
refType = "commit"
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &contentsResponse)
|
||||
assert.NotNil(t, contentsResponse)
|
||||
expectedContentsResponse = getExpectedContentsResponseForContents(ref, refType, commitID)
|
||||
assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
|
||||
|
||||
// Test file contents a file with a bad ref
|
||||
ref = "badref"
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Test accessing private ref with user token that does not have access - should fail
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token4)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Test access private ref of owner of token
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/readme.md?token=%s", user2.Name, repo16.Name, token2)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// Test access of org user3 private repo file by owner user2
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?token=%s", user3.Name, repo3.Name, treePath, token2)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
}
|
79
tests/integration/api_repo_git_blobs_test.go
Normal file
79
tests/integration/api_repo_git_blobs_test.go
Normal file
|
@ -0,0 +1,79 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
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"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIReposGitBlobs(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo1 & repo16
|
||||
user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of the repo3
|
||||
user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // owner of neither repos
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo
|
||||
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // public repo
|
||||
repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) // private repo
|
||||
repo1ReadmeSHA := "65f1bf27bc3bf70f64657658635e66094edbcb4d"
|
||||
repo3ReadmeSHA := "d56a3073c1dbb7b15963110a049d50cdb5db99fc"
|
||||
repo16ReadmeSHA := "f90451c72ef61a7645293d17b47be7a8e983da57"
|
||||
badSHA := "0000000000000000000000000000000000000000"
|
||||
|
||||
// Login as User2.
|
||||
session := loginUser(t, user2.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
session = emptyTestSession(t) // don't want anyone logged in for this
|
||||
|
||||
// Test a public repo that anyone can GET the blob of
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/blobs/%s", user2.Name, repo1.Name, repo1ReadmeSHA)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var gitBlobResponse api.GitBlobResponse
|
||||
DecodeJSON(t, resp, &gitBlobResponse)
|
||||
assert.NotNil(t, gitBlobResponse)
|
||||
expectedContent := "dHJlZSAyYTJmMWQ0NjcwNzI4YTJlMTAwNDllMzQ1YmQ3YTI3NjQ2OGJlYWI2CmF1dGhvciB1c2VyMSA8YWRkcmVzczFAZXhhbXBsZS5jb20+IDE0ODk5NTY0NzkgLTA0MDAKY29tbWl0dGVyIEV0aGFuIEtvZW5pZyA8ZXRoYW50a29lbmlnQGdtYWlsLmNvbT4gMTQ4OTk1NjQ3OSAtMDQwMAoKSW5pdGlhbCBjb21taXQK"
|
||||
assert.Equal(t, expectedContent, gitBlobResponse.Content)
|
||||
|
||||
// Tests a private repo with no token so will fail
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/blobs/%s", user2.Name, repo16.Name, repo16ReadmeSHA)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Test using access token for a private repo that the user of the token owns
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/blobs/%s?token=%s", user2.Name, repo16.Name, repo16ReadmeSHA, token)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// Test using bad sha
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/blobs/%s", user2.Name, repo1.Name, badSHA)
|
||||
session.MakeRequest(t, req, http.StatusBadRequest)
|
||||
|
||||
// Test using org repo "user3/repo3" where user2 is a collaborator
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/blobs/%s?token=%s", user3.Name, repo3.Name, repo3ReadmeSHA, token)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// Test using org repo "user3/repo3" where user2 is a collaborator
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/blobs/%s?token=%s", user3.Name, repo3.Name, repo3ReadmeSHA, token)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// Test using org repo "user3/repo3" with no user token
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/blobs/%s", user3.Name, repo3ReadmeSHA, repo3.Name)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Login as User4.
|
||||
session = loginUser(t, user4.Name)
|
||||
token4 := getTokenForLoggedInUser(t, session)
|
||||
session = emptyTestSession(t) // don't want anyone logged in for this
|
||||
|
||||
// Test using org repo "user3/repo3" where user4 is a NOT collaborator
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/blobs/d56a3073c1dbb7b15963110a049d50cdb5db99fc?access=%s", user3.Name, repo3.Name, token4)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
152
tests/integration/api_repo_git_commits_test.go
Normal file
152
tests/integration/api_repo_git_commits_test.go
Normal file
|
@ -0,0 +1,152 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"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 compareCommitFiles(t *testing.T, expect []string, files []*api.CommitAffectedFiles) {
|
||||
var actual []string
|
||||
for i := range files {
|
||||
actual = append(actual, files[i].Filename)
|
||||
}
|
||||
assert.ElementsMatch(t, expect, actual)
|
||||
}
|
||||
|
||||
func TestAPIReposGitCommits(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
// Login as User2.
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
// check invalid requests
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/git/commits/12345?token="+token, user.Name)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/git/commits/..?token="+token, user.Name)
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/git/commits/branch-not-exist?token="+token, user.Name)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
for _, ref := range [...]string{
|
||||
"master", // Branch
|
||||
"v1.1", // Tag
|
||||
"65f1", // short sha
|
||||
"65f1bf27bc3bf70f64657658635e66094edbcb4d", // full sha
|
||||
} {
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/git/commits/%s?token="+token, user.Name, ref)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIReposGitCommitList(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
// Login as User2.
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
// Test getting commits (Page 1)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo16/commits?token="+token, user.Name)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var apiData []api.Commit
|
||||
DecodeJSON(t, resp, &apiData)
|
||||
|
||||
assert.Len(t, apiData, 3)
|
||||
assert.EqualValues(t, "69554a64c1e6030f051e5c3f94bfbd773cd6a324", apiData[0].CommitMeta.SHA)
|
||||
compareCommitFiles(t, []string{"readme.md"}, apiData[0].Files)
|
||||
assert.EqualValues(t, "27566bd5738fc8b4e3fef3c5e72cce608537bd95", apiData[1].CommitMeta.SHA)
|
||||
compareCommitFiles(t, []string{"readme.md"}, apiData[1].Files)
|
||||
assert.EqualValues(t, "5099b81332712fe655e34e8dd63574f503f61811", apiData[2].CommitMeta.SHA)
|
||||
compareCommitFiles(t, []string{"readme.md"}, apiData[2].Files)
|
||||
}
|
||||
|
||||
func TestAPIReposGitCommitListPage2Empty(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
// Login as User2.
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
// Test getting commits (Page=2)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo16/commits?token="+token+"&page=2", user.Name)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var apiData []api.Commit
|
||||
DecodeJSON(t, resp, &apiData)
|
||||
|
||||
assert.Len(t, apiData, 0)
|
||||
}
|
||||
|
||||
func TestAPIReposGitCommitListDifferentBranch(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
// Login as User2.
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
// Test getting commits (Page=1, Branch=good-sign)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo16/commits?token="+token+"&sha=good-sign", user.Name)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var apiData []api.Commit
|
||||
DecodeJSON(t, resp, &apiData)
|
||||
|
||||
assert.Len(t, apiData, 1)
|
||||
assert.Equal(t, "f27c2b2b03dcab38beaf89b0ab4ff61f6de63441", apiData[0].CommitMeta.SHA)
|
||||
compareCommitFiles(t, []string{"readme.md"}, apiData[0].Files)
|
||||
}
|
||||
|
||||
func TestDownloadCommitDiffOrPatch(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
// Login as User2.
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
// Test getting diff
|
||||
reqDiff := NewRequestf(t, "GET", "/api/v1/repos/%s/repo16/git/commits/f27c2b2b03dcab38beaf89b0ab4ff61f6de63441.diff?token="+token, user.Name)
|
||||
resp := session.MakeRequest(t, reqDiff, http.StatusOK)
|
||||
assert.EqualValues(t,
|
||||
"commit f27c2b2b03dcab38beaf89b0ab4ff61f6de63441\nAuthor: User2 <user2@example.com>\nDate: Sun Aug 6 19:55:01 2017 +0200\n\n good signed commit\n\ndiff --git a/readme.md b/readme.md\nnew file mode 100644\nindex 0000000..458121c\n--- /dev/null\n+++ b/readme.md\n@@ -0,0 +1 @@\n+good sign\n",
|
||||
resp.Body.String())
|
||||
|
||||
// Test getting patch
|
||||
reqPatch := NewRequestf(t, "GET", "/api/v1/repos/%s/repo16/git/commits/f27c2b2b03dcab38beaf89b0ab4ff61f6de63441.patch?token="+token, user.Name)
|
||||
resp = session.MakeRequest(t, reqPatch, http.StatusOK)
|
||||
assert.EqualValues(t,
|
||||
"From f27c2b2b03dcab38beaf89b0ab4ff61f6de63441 Mon Sep 17 00:00:00 2001\nFrom: User2 <user2@example.com>\nDate: Sun, 6 Aug 2017 19:55:01 +0200\nSubject: [PATCH] good signed commit\n\n---\n readme.md | 1 +\n 1 file changed, 1 insertion(+)\n create mode 100644 readme.md\n\ndiff --git a/readme.md b/readme.md\nnew file mode 100644\nindex 0000000..458121c\n--- /dev/null\n+++ b/readme.md\n@@ -0,0 +1 @@\n+good sign\n",
|
||||
resp.Body.String())
|
||||
}
|
||||
|
||||
func TestGetFileHistory(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
// Login as User2.
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo16/commits?path=readme.md&token="+token+"&sha=good-sign", user.Name)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var apiData []api.Commit
|
||||
DecodeJSON(t, resp, &apiData)
|
||||
|
||||
assert.Len(t, apiData, 1)
|
||||
assert.Equal(t, "f27c2b2b03dcab38beaf89b0ab4ff61f6de63441", apiData[0].CommitMeta.SHA)
|
||||
compareCommitFiles(t, []string{"readme.md"}, apiData[0].Files)
|
||||
}
|
197
tests/integration/api_repo_git_hook_test.go
Normal file
197
tests/integration/api_repo_git_hook_test.go
Normal file
|
@ -0,0 +1,197 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
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"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const testHookContent = `#!/bin/bash
|
||||
|
||||
echo Hello, World!
|
||||
`
|
||||
|
||||
func TestAPIListGitHooks(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 37})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
|
||||
// user1 is an admin user
|
||||
session := loginUser(t, "user1")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/hooks/git?token=%s",
|
||||
owner.Name, repo.Name, token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
var apiGitHooks []*api.GitHook
|
||||
DecodeJSON(t, resp, &apiGitHooks)
|
||||
assert.Len(t, apiGitHooks, 3)
|
||||
for _, apiGitHook := range apiGitHooks {
|
||||
if apiGitHook.Name == "pre-receive" {
|
||||
assert.True(t, apiGitHook.IsActive)
|
||||
assert.Equal(t, testHookContent, apiGitHook.Content)
|
||||
} else {
|
||||
assert.False(t, apiGitHook.IsActive)
|
||||
assert.Empty(t, apiGitHook.Content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIListGitHooksNoHooks(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
|
||||
// user1 is an admin user
|
||||
session := loginUser(t, "user1")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/hooks/git?token=%s",
|
||||
owner.Name, repo.Name, token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
var apiGitHooks []*api.GitHook
|
||||
DecodeJSON(t, resp, &apiGitHooks)
|
||||
assert.Len(t, apiGitHooks, 3)
|
||||
for _, apiGitHook := range apiGitHooks {
|
||||
assert.False(t, apiGitHook.IsActive)
|
||||
assert.Empty(t, apiGitHook.Content)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIListGitHooksNoAccess(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(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)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/hooks/git?token=%s",
|
||||
owner.Name, repo.Name, token)
|
||||
MakeRequest(t, req, http.StatusForbidden)
|
||||
}
|
||||
|
||||
func TestAPIGetGitHook(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 37})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
|
||||
// user1 is an admin user
|
||||
session := loginUser(t, "user1")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/hooks/git/pre-receive?token=%s",
|
||||
owner.Name, repo.Name, token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
var apiGitHook *api.GitHook
|
||||
DecodeJSON(t, resp, &apiGitHook)
|
||||
assert.True(t, apiGitHook.IsActive)
|
||||
assert.Equal(t, testHookContent, apiGitHook.Content)
|
||||
}
|
||||
|
||||
func TestAPIGetGitHookNoAccess(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(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)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/hooks/git/pre-receive?token=%s",
|
||||
owner.Name, repo.Name, token)
|
||||
MakeRequest(t, req, http.StatusForbidden)
|
||||
}
|
||||
|
||||
func TestAPIEditGitHook(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
|
||||
// user1 is an admin user
|
||||
session := loginUser(t, "user1")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/hooks/git/pre-receive?token=%s",
|
||||
owner.Name, repo.Name, token)
|
||||
req := NewRequestWithJSON(t, "PATCH", urlStr, &api.EditGitHookOption{
|
||||
Content: testHookContent,
|
||||
})
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
var apiGitHook *api.GitHook
|
||||
DecodeJSON(t, resp, &apiGitHook)
|
||||
assert.True(t, apiGitHook.IsActive)
|
||||
assert.Equal(t, testHookContent, apiGitHook.Content)
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/hooks/git/pre-receive?token=%s",
|
||||
owner.Name, repo.Name, token)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
var apiGitHook2 *api.GitHook
|
||||
DecodeJSON(t, resp, &apiGitHook2)
|
||||
assert.True(t, apiGitHook2.IsActive)
|
||||
assert.Equal(t, testHookContent, apiGitHook2.Content)
|
||||
}
|
||||
|
||||
func TestAPIEditGitHookNoAccess(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(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)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/hooks/git/pre-receive?token=%s",
|
||||
owner.Name, repo.Name, token)
|
||||
req := NewRequestWithJSON(t, "PATCH", urlStr, &api.EditGitHookOption{
|
||||
Content: testHookContent,
|
||||
})
|
||||
MakeRequest(t, req, http.StatusForbidden)
|
||||
}
|
||||
|
||||
func TestAPIDeleteGitHook(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 37})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
|
||||
// user1 is an admin user
|
||||
session := loginUser(t, "user1")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/hooks/git/pre-receive?token=%s",
|
||||
owner.Name, repo.Name, token)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/hooks/git/pre-receive?token=%s",
|
||||
owner.Name, repo.Name, token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
var apiGitHook2 *api.GitHook
|
||||
DecodeJSON(t, resp, &apiGitHook2)
|
||||
assert.False(t, apiGitHook2.IsActive)
|
||||
assert.Empty(t, apiGitHook2.Content)
|
||||
}
|
||||
|
||||
func TestAPIDeleteGitHookNoAccess(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(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)
|
||||
req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/hooks/git/pre-receive?token=%s",
|
||||
owner.Name, repo.Name, token)
|
||||
MakeRequest(t, req, http.StatusForbidden)
|
||||
}
|
41
tests/integration/api_repo_git_notes_test.go
Normal file
41
tests/integration/api_repo_git_notes_test.go
Normal file
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIReposGitNotes(t *testing.T) {
|
||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
// Login as User2.
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
// check invalid requests
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/git/notes/12345?token=%s", user.Name, token)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/git/notes/..?token=%s", user.Name, token)
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
|
||||
// check valid request
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/git/notes/65f1bf27bc3bf70f64657658635e66094edbcb4d?token=%s", user.Name, token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var apiData api.Note
|
||||
DecodeJSON(t, resp, &apiData)
|
||||
assert.Equal(t, "This is a test note\n", apiData.Message)
|
||||
})
|
||||
}
|
36
tests/integration/api_repo_git_ref_test.go
Normal file
36
tests/integration/api_repo_git_ref_test.go
Normal file
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/tests"
|
||||
)
|
||||
|
||||
func TestAPIReposGitRefs(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
// Login as User2.
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
for _, ref := range [...]string{
|
||||
"refs/heads/master", // Branch
|
||||
"refs/tags/v1.1", // Tag
|
||||
} {
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/git/%s?token="+token, user.Name, ref)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
// Test getting all refs
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/git/refs?token="+token, user.Name)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
// Test getting non-existent refs
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/git/refs/heads/unknown?token="+token, user.Name)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
88
tests/integration/api_repo_git_tags_test.go
Normal file
88
tests/integration/api_repo_git_tags_test.go
Normal file
|
@ -0,0 +1,88 @@
|
|||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
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/modules/util"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIGitTags(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
// Login as User2.
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
// Set up git config for the tagger
|
||||
_ = git.NewCommand(git.DefaultContext, "config", "user.name", user.Name).Run(&git.RunOpts{Dir: repo.RepoPath()})
|
||||
_ = git.NewCommand(git.DefaultContext, "config", "user.email", user.Email).Run(&git.RunOpts{Dir: repo.RepoPath()})
|
||||
|
||||
gitRepo, _ := git.OpenRepository(git.DefaultContext, repo.RepoPath())
|
||||
defer gitRepo.Close()
|
||||
|
||||
commit, _ := gitRepo.GetBranchCommit("master")
|
||||
lTagName := "lightweightTag"
|
||||
gitRepo.CreateTag(lTagName, commit.ID.String())
|
||||
|
||||
aTagName := "annotatedTag"
|
||||
aTagMessage := "my annotated message"
|
||||
gitRepo.CreateAnnotatedTag(aTagName, aTagMessage, commit.ID.String())
|
||||
aTag, _ := gitRepo.GetTag(aTagName)
|
||||
|
||||
// SHOULD work for annotated tags
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/tags/%s?token=%s", user.Name, repo.Name, aTag.ID.String(), token)
|
||||
res := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var tag *api.AnnotatedTag
|
||||
DecodeJSON(t, res, &tag)
|
||||
|
||||
assert.Equal(t, aTagName, tag.Tag)
|
||||
assert.Equal(t, aTag.ID.String(), tag.SHA)
|
||||
assert.Equal(t, commit.ID.String(), tag.Object.SHA)
|
||||
assert.Equal(t, aTagMessage+"\n", tag.Message)
|
||||
assert.Equal(t, user.Name, tag.Tagger.Name)
|
||||
assert.Equal(t, user.Email, tag.Tagger.Email)
|
||||
assert.Equal(t, util.URLJoin(repo.APIURL(), "git/tags", aTag.ID.String()), tag.URL)
|
||||
|
||||
// Should NOT work for lightweight tags
|
||||
badReq := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/tags/%s?token=%s", user.Name, repo.Name, commit.ID.String(), token)
|
||||
session.MakeRequest(t, badReq, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
func TestAPIDeleteTagByName(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
session := loginUser(t, owner.LowerName)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/tags/delete-tag?token=%s",
|
||||
owner.Name, repo.Name, token)
|
||||
|
||||
req := NewRequestf(t, http.MethodDelete, urlStr)
|
||||
_ = session.MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
// Make sure that actual releases can't be deleted outright
|
||||
createNewReleaseUsingAPI(t, session, token, owner, repo, "release-tag", "", "Release Tag", "test")
|
||||
urlStr = fmt.Sprintf("/api/v1/repos/%s/%s/tags/release-tag?token=%s",
|
||||
owner.Name, repo.Name, token)
|
||||
|
||||
req = NewRequestf(t, http.MethodDelete, urlStr)
|
||||
_ = session.MakeRequest(t, req, http.StatusConflict)
|
||||
}
|
77
tests/integration/api_repo_git_trees_test.go
Normal file
77
tests/integration/api_repo_git_trees_test.go
Normal file
|
@ -0,0 +1,77 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
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/tests"
|
||||
)
|
||||
|
||||
func TestAPIReposGitTrees(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo1 & repo16
|
||||
user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of the repo3
|
||||
user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // owner of neither repos
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo
|
||||
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // public repo
|
||||
repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) // private repo
|
||||
repo1TreeSHA := "65f1bf27bc3bf70f64657658635e66094edbcb4d"
|
||||
repo3TreeSHA := "2a47ca4b614a9f5a43abbd5ad851a54a616ffee6"
|
||||
repo16TreeSHA := "69554a64c1e6030f051e5c3f94bfbd773cd6a324"
|
||||
badSHA := "0000000000000000000000000000000000000000"
|
||||
|
||||
// Login as User2.
|
||||
session := loginUser(t, user2.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
session = emptyTestSession(t) // don't want anyone logged in for this
|
||||
|
||||
// Test a public repo that anyone can GET the tree of
|
||||
for _, ref := range [...]string{
|
||||
"master", // Branch
|
||||
repo1TreeSHA, // Tree SHA
|
||||
} {
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/trees/%s", user2.Name, repo1.Name, ref)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
|
||||
// Tests a private repo with no token so will fail
|
||||
for _, ref := range [...]string{
|
||||
"master", // Branch
|
||||
repo1TreeSHA, // Tag
|
||||
} {
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/trees/%s", user2.Name, repo16.Name, ref)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
||||
|
||||
// Test using access token for a private repo that the user of the token owns
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/trees/%s?token=%s", user2.Name, repo16.Name, repo16TreeSHA, token)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// Test using bad sha
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/trees/%s", user2.Name, repo1.Name, badSHA)
|
||||
session.MakeRequest(t, req, http.StatusBadRequest)
|
||||
|
||||
// Test using org repo "user3/repo3" where user2 is a collaborator
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/trees/%s?token=%s", user3.Name, repo3.Name, repo3TreeSHA, token)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// Test using org repo "user3/repo3" with no user token
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/trees/%s", user3.Name, repo3TreeSHA, repo3.Name)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Login as User4.
|
||||
session = loginUser(t, user4.Name)
|
||||
token4 := getTokenForLoggedInUser(t, session)
|
||||
session = emptyTestSession(t) // don't want anyone logged in for this
|
||||
|
||||
// Test using org repo "user3/repo3" where user4 is a NOT collaborator
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/trees/d56a3073c1dbb7b15963110a049d50cdb5db99fc?access=%s", user3.Name, repo3.Name, token4)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
50
tests/integration/api_repo_languages_test.go
Normal file
50
tests/integration/api_repo_languages_test.go
Normal file
|
@ -0,0 +1,50 @@
|
|||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRepoLanguages(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
session := loginUser(t, "user2")
|
||||
|
||||
// Request editor page
|
||||
req := NewRequest(t, "GET", "/user2/repo1/_new/master/")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
lastCommit := doc.GetInputValueByName("last_commit")
|
||||
assert.NotEmpty(t, lastCommit)
|
||||
|
||||
// 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",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
||||
// let gitea calculate language stats
|
||||
time.Sleep(time.Second)
|
||||
|
||||
// Save new file to master branch
|
||||
req = NewRequest(t, "GET", "/api/v1/repos/user2/repo1/languages")
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var languages map[string]int64
|
||||
DecodeJSON(t, resp, &languages)
|
||||
|
||||
assert.InDeltaMapValues(t, map[string]int64{"Go": 12}, languages, 0)
|
||||
})
|
||||
}
|
181
tests/integration/api_repo_lfs_locks_test.go
Normal file
181
tests/integration/api_repo_lfs_locks_test.go
Normal file
|
@ -0,0 +1,181 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
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/lfs"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPILFSLocksNotStarted(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
setting.LFS.StartServer = false
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
|
||||
req := NewRequestf(t, "GET", "/%s/%s.git/info/lfs/locks", user.Name, repo.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
req = NewRequestf(t, "POST", "/%s/%s.git/info/lfs/locks", user.Name, repo.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
req = NewRequestf(t, "GET", "/%s/%s.git/info/lfs/locks/verify", user.Name, repo.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
req = NewRequestf(t, "GET", "/%s/%s.git/info/lfs/locks/10/unlock", user.Name, repo.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
||||
|
||||
func TestAPILFSLocksNotLogin(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
setting.LFS.StartServer = true
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
|
||||
req := NewRequestf(t, "GET", "/%s/%s.git/info/lfs/locks", user.Name, repo.Name)
|
||||
req.Header.Set("Accept", lfs.MediaType)
|
||||
resp := MakeRequest(t, req, http.StatusUnauthorized)
|
||||
var lfsLockError api.LFSLockError
|
||||
DecodeJSON(t, resp, &lfsLockError)
|
||||
assert.Equal(t, "You must have pull access to list locks", lfsLockError.Message)
|
||||
}
|
||||
|
||||
func TestAPILFSLocksLogged(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
setting.LFS.StartServer = true
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // in org 3
|
||||
user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // in org 3
|
||||
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // own by org 3
|
||||
|
||||
tests := []struct {
|
||||
user *user_model.User
|
||||
repo *repo_model.Repository
|
||||
path string
|
||||
httpResult int
|
||||
addTime []int
|
||||
}{
|
||||
{user: user2, repo: repo1, path: "foo/bar.zip", httpResult: http.StatusCreated, addTime: []int{0}},
|
||||
{user: user2, repo: repo1, path: "path/test", httpResult: http.StatusCreated, addTime: []int{0}},
|
||||
{user: user2, repo: repo1, path: "path/test", httpResult: http.StatusConflict},
|
||||
{user: user2, repo: repo1, path: "Foo/BaR.zip", httpResult: http.StatusConflict},
|
||||
{user: user2, repo: repo1, path: "Foo/Test/../subFOlder/../Relative/../BaR.zip", httpResult: http.StatusConflict},
|
||||
{user: user4, repo: repo1, path: "FoO/BaR.zip", httpResult: http.StatusUnauthorized},
|
||||
{user: user4, repo: repo1, path: "path/test-user4", httpResult: http.StatusUnauthorized},
|
||||
{user: user2, repo: repo1, path: "patH/Test-user4", httpResult: http.StatusCreated, addTime: []int{0}},
|
||||
{user: user2, repo: repo1, path: "some/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/path", httpResult: http.StatusCreated, addTime: []int{0}},
|
||||
|
||||
{user: user2, repo: repo3, path: "test/foo/bar.zip", httpResult: http.StatusCreated, addTime: []int{1, 2}},
|
||||
{user: user4, repo: repo3, path: "test/foo/bar.zip", httpResult: http.StatusConflict},
|
||||
{user: user4, repo: repo3, path: "test/foo/bar.bin", httpResult: http.StatusCreated, addTime: []int{1, 2}},
|
||||
}
|
||||
|
||||
resultsTests := []struct {
|
||||
user *user_model.User
|
||||
repo *repo_model.Repository
|
||||
totalCount int
|
||||
oursCount int
|
||||
theirsCount int
|
||||
locksOwners []*user_model.User
|
||||
locksTimes []time.Time
|
||||
}{
|
||||
{user: user2, repo: repo1, totalCount: 4, oursCount: 4, theirsCount: 0, locksOwners: []*user_model.User{user2, user2, user2, user2}, locksTimes: []time.Time{}},
|
||||
{user: user2, repo: repo3, totalCount: 2, oursCount: 1, theirsCount: 1, locksOwners: []*user_model.User{user2, user4}, locksTimes: []time.Time{}},
|
||||
{user: user4, repo: repo3, totalCount: 2, oursCount: 1, theirsCount: 1, locksOwners: []*user_model.User{user2, user4}, locksTimes: []time.Time{}},
|
||||
}
|
||||
|
||||
deleteTests := []struct {
|
||||
user *user_model.User
|
||||
repo *repo_model.Repository
|
||||
lockID string
|
||||
}{}
|
||||
|
||||
// create locks
|
||||
for _, test := range tests {
|
||||
session := loginUser(t, test.user.Name)
|
||||
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/%s.git/info/lfs/locks", test.repo.FullName()), map[string]string{"path": test.path})
|
||||
req.Header.Set("Accept", lfs.MediaType)
|
||||
req.Header.Set("Content-Type", lfs.MediaType)
|
||||
resp := session.MakeRequest(t, req, test.httpResult)
|
||||
if len(test.addTime) > 0 {
|
||||
var lfsLock api.LFSLockResponse
|
||||
DecodeJSON(t, resp, &lfsLock)
|
||||
assert.EqualValues(t, lfsLock.Lock.LockedAt.Format(time.RFC3339), lfsLock.Lock.LockedAt.Format(time.RFC3339Nano)) // locked at should be rounded to second
|
||||
for _, id := range test.addTime {
|
||||
resultsTests[id].locksTimes = append(resultsTests[id].locksTimes, time.Now())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check creation
|
||||
for _, test := range resultsTests {
|
||||
session := loginUser(t, test.user.Name)
|
||||
req := NewRequestf(t, "GET", "/%s.git/info/lfs/locks", test.repo.FullName())
|
||||
req.Header.Set("Accept", lfs.MediaType)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var lfsLocks api.LFSLockList
|
||||
DecodeJSON(t, resp, &lfsLocks)
|
||||
assert.Len(t, lfsLocks.Locks, test.totalCount)
|
||||
for i, lock := range lfsLocks.Locks {
|
||||
assert.EqualValues(t, test.locksOwners[i].DisplayName(), lock.Owner.Name)
|
||||
assert.WithinDuration(t, test.locksTimes[i], lock.LockedAt, 10*time.Second)
|
||||
assert.EqualValues(t, lock.LockedAt.Format(time.RFC3339), lock.LockedAt.Format(time.RFC3339Nano)) // locked at should be rounded to second
|
||||
}
|
||||
|
||||
req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/%s.git/info/lfs/locks/verify", test.repo.FullName()), map[string]string{})
|
||||
req.Header.Set("Accept", lfs.MediaType)
|
||||
req.Header.Set("Content-Type", lfs.MediaType)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
var lfsLocksVerify api.LFSLockListVerify
|
||||
DecodeJSON(t, resp, &lfsLocksVerify)
|
||||
assert.Len(t, lfsLocksVerify.Ours, test.oursCount)
|
||||
assert.Len(t, lfsLocksVerify.Theirs, test.theirsCount)
|
||||
for _, lock := range lfsLocksVerify.Ours {
|
||||
assert.EqualValues(t, test.user.DisplayName(), lock.Owner.Name)
|
||||
deleteTests = append(deleteTests, struct {
|
||||
user *user_model.User
|
||||
repo *repo_model.Repository
|
||||
lockID string
|
||||
}{test.user, test.repo, lock.ID})
|
||||
}
|
||||
for _, lock := range lfsLocksVerify.Theirs {
|
||||
assert.NotEqual(t, test.user.DisplayName(), lock.Owner.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// remove all locks
|
||||
for _, test := range deleteTests {
|
||||
session := loginUser(t, test.user.Name)
|
||||
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/%s.git/info/lfs/locks/%s/unlock", test.repo.FullName(), test.lockID), map[string]string{})
|
||||
req.Header.Set("Accept", lfs.MediaType)
|
||||
req.Header.Set("Content-Type", lfs.MediaType)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var lfsLockRep api.LFSLockResponse
|
||||
DecodeJSON(t, resp, &lfsLockRep)
|
||||
assert.Equal(t, test.lockID, lfsLockRep.Lock.ID)
|
||||
assert.Equal(t, test.user.DisplayName(), lfsLockRep.Lock.Owner.Name)
|
||||
}
|
||||
|
||||
// check that we don't have any lock
|
||||
for _, test := range resultsTests {
|
||||
session := loginUser(t, test.user.Name)
|
||||
req := NewRequestf(t, "GET", "/%s.git/info/lfs/locks", test.repo.FullName())
|
||||
req.Header.Set("Accept", lfs.MediaType)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var lfsLocks api.LFSLockList
|
||||
DecodeJSON(t, resp, &lfsLocks)
|
||||
assert.Len(t, lfsLocks.Locks, 0)
|
||||
}
|
||||
}
|
54
tests/integration/api_repo_lfs_migrate_test.go
Normal file
54
tests/integration/api_repo_lfs_migrate_test.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/lfs"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/services/migrations"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIRepoLFSMigrateLocal(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
oldImportLocalPaths := setting.ImportLocalPaths
|
||||
oldAllowLocalNetworks := setting.Migrations.AllowLocalNetworks
|
||||
setting.ImportLocalPaths = true
|
||||
setting.Migrations.AllowLocalNetworks = true
|
||||
assert.NoError(t, migrations.Init())
|
||||
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/repos/migrate?token="+token, &api.MigrateRepoOptions{
|
||||
CloneAddr: path.Join(setting.RepoRootPath, "migration/lfs-test.git"),
|
||||
RepoOwnerID: user.ID,
|
||||
RepoName: "lfs-test-local",
|
||||
LFS: true,
|
||||
})
|
||||
resp := MakeRequest(t, req, NoExpectedStatus)
|
||||
assert.EqualValues(t, http.StatusCreated, resp.Code)
|
||||
|
||||
store := lfs.NewContentStore()
|
||||
ok, _ := store.Verify(lfs.Pointer{Oid: "fb8f7d8435968c4f82a726a92395be4d16f2f63116caf36c8ad35c60831ab041", Size: 6})
|
||||
assert.True(t, ok)
|
||||
ok, _ = store.Verify(lfs.Pointer{Oid: "d6f175817f886ec6fbbc1515326465fa96c3bfd54a4ea06cfd6dbbd8340e0152", Size: 6})
|
||||
assert.True(t, ok)
|
||||
|
||||
setting.ImportLocalPaths = oldImportLocalPaths
|
||||
setting.Migrations.AllowLocalNetworks = oldAllowLocalNetworks
|
||||
assert.NoError(t, migrations.Init()) // reset old migration settings
|
||||
}
|
487
tests/integration/api_repo_lfs_test.go
Normal file
487
tests/integration/api_repo_lfs_test.go
Normal file
|
@ -0,0 +1,487 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
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/json"
|
||||
"code.gitea.io/gitea/modules/lfs"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPILFSNotStarted(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
setting.LFS.StartServer = false
|
||||
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
|
||||
req := NewRequestf(t, "POST", "/%s/%s.git/info/lfs/objects/batch", user.Name, repo.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
req = NewRequestf(t, "PUT", "/%s/%s.git/info/lfs/objects/oid/10", user.Name, repo.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
req = NewRequestf(t, "GET", "/%s/%s.git/info/lfs/objects/oid/name", user.Name, repo.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
req = NewRequestf(t, "GET", "/%s/%s.git/info/lfs/objects/oid", user.Name, repo.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
req = NewRequestf(t, "POST", "/%s/%s.git/info/lfs/verify", user.Name, repo.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
||||
|
||||
func TestAPILFSMediaType(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
setting.LFS.StartServer = true
|
||||
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
|
||||
req := NewRequestf(t, "POST", "/%s/%s.git/info/lfs/objects/batch", user.Name, repo.Name)
|
||||
MakeRequest(t, req, http.StatusUnsupportedMediaType)
|
||||
req = NewRequestf(t, "POST", "/%s/%s.git/info/lfs/verify", user.Name, repo.Name)
|
||||
MakeRequest(t, req, http.StatusUnsupportedMediaType)
|
||||
}
|
||||
|
||||
func createLFSTestRepository(t *testing.T, name string) *repo_model.Repository {
|
||||
ctx := NewAPITestContext(t, "user2", "lfs-"+name+"-repo")
|
||||
t.Run("CreateRepo", doAPICreateRepository(ctx, false))
|
||||
|
||||
repo, err := repo_model.GetRepositoryByOwnerAndName("user2", "lfs-"+name+"-repo")
|
||||
assert.NoError(t, err)
|
||||
|
||||
return repo
|
||||
}
|
||||
|
||||
func TestAPILFSBatch(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
setting.LFS.StartServer = true
|
||||
|
||||
repo := createLFSTestRepository(t, "batch")
|
||||
|
||||
content := []byte("dummy1")
|
||||
oid := storeObjectInRepo(t, repo.ID, &content)
|
||||
defer git_model.RemoveLFSMetaObjectByOid(repo.ID, oid)
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
|
||||
newRequest := func(t testing.TB, br *lfs.BatchRequest) *http.Request {
|
||||
req := NewRequestWithJSON(t, "POST", "/user2/lfs-batch-repo.git/info/lfs/objects/batch", br)
|
||||
req.Header.Set("Accept", lfs.MediaType)
|
||||
req.Header.Set("Content-Type", lfs.MediaType)
|
||||
return req
|
||||
}
|
||||
decodeResponse := func(t *testing.T, b *bytes.Buffer) *lfs.BatchResponse {
|
||||
var br lfs.BatchResponse
|
||||
|
||||
assert.NoError(t, json.Unmarshal(b.Bytes(), &br))
|
||||
return &br
|
||||
}
|
||||
|
||||
t.Run("InvalidJsonRequest", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := newRequest(t, nil)
|
||||
|
||||
session.MakeRequest(t, req, http.StatusBadRequest)
|
||||
})
|
||||
|
||||
t.Run("InvalidOperation", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := newRequest(t, &lfs.BatchRequest{
|
||||
Operation: "dummy",
|
||||
})
|
||||
|
||||
session.MakeRequest(t, req, http.StatusBadRequest)
|
||||
})
|
||||
|
||||
t.Run("InvalidPointer", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := newRequest(t, &lfs.BatchRequest{
|
||||
Operation: "download",
|
||||
Objects: []lfs.Pointer{
|
||||
{Oid: "dummy"},
|
||||
{Oid: oid, Size: -1},
|
||||
},
|
||||
})
|
||||
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
br := decodeResponse(t, resp.Body)
|
||||
assert.Len(t, br.Objects, 2)
|
||||
assert.Equal(t, "dummy", br.Objects[0].Oid)
|
||||
assert.Equal(t, oid, br.Objects[1].Oid)
|
||||
assert.Equal(t, int64(0), br.Objects[0].Size)
|
||||
assert.Equal(t, int64(-1), br.Objects[1].Size)
|
||||
assert.NotNil(t, br.Objects[0].Error)
|
||||
assert.NotNil(t, br.Objects[1].Error)
|
||||
assert.Equal(t, http.StatusUnprocessableEntity, br.Objects[0].Error.Code)
|
||||
assert.Equal(t, http.StatusUnprocessableEntity, br.Objects[1].Error.Code)
|
||||
assert.Equal(t, "Oid or size are invalid", br.Objects[0].Error.Message)
|
||||
assert.Equal(t, "Oid or size are invalid", br.Objects[1].Error.Message)
|
||||
})
|
||||
|
||||
t.Run("PointerSizeMismatch", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := newRequest(t, &lfs.BatchRequest{
|
||||
Operation: "download",
|
||||
Objects: []lfs.Pointer{
|
||||
{Oid: oid, Size: 1},
|
||||
},
|
||||
})
|
||||
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
br := decodeResponse(t, resp.Body)
|
||||
assert.Len(t, br.Objects, 1)
|
||||
assert.NotNil(t, br.Objects[0].Error)
|
||||
assert.Equal(t, http.StatusUnprocessableEntity, br.Objects[0].Error.Code)
|
||||
assert.Equal(t, "Object "+oid+" is not 1 bytes", br.Objects[0].Error.Message)
|
||||
})
|
||||
|
||||
t.Run("Download", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
t.Run("PointerNotInStore", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := newRequest(t, &lfs.BatchRequest{
|
||||
Operation: "download",
|
||||
Objects: []lfs.Pointer{
|
||||
{Oid: "fb8f7d8435968c4f82a726a92395be4d16f2f63116caf36c8ad35c60831ab042", Size: 6},
|
||||
},
|
||||
})
|
||||
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
br := decodeResponse(t, resp.Body)
|
||||
assert.Len(t, br.Objects, 1)
|
||||
assert.NotNil(t, br.Objects[0].Error)
|
||||
assert.Equal(t, http.StatusNotFound, br.Objects[0].Error.Code)
|
||||
})
|
||||
|
||||
t.Run("MetaNotFound", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
p := lfs.Pointer{Oid: "05eeb4eb5be71f2dd291ca39157d6d9effd7d1ea19cbdc8a99411fe2a8f26a00", Size: 6}
|
||||
|
||||
contentStore := lfs.NewContentStore()
|
||||
exist, err := contentStore.Exists(p)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, exist)
|
||||
err = contentStore.Put(p, bytes.NewReader([]byte("dummy0")))
|
||||
assert.NoError(t, err)
|
||||
|
||||
req := newRequest(t, &lfs.BatchRequest{
|
||||
Operation: "download",
|
||||
Objects: []lfs.Pointer{p},
|
||||
})
|
||||
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
br := decodeResponse(t, resp.Body)
|
||||
assert.Len(t, br.Objects, 1)
|
||||
assert.NotNil(t, br.Objects[0].Error)
|
||||
assert.Equal(t, http.StatusNotFound, br.Objects[0].Error.Code)
|
||||
})
|
||||
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := newRequest(t, &lfs.BatchRequest{
|
||||
Operation: "download",
|
||||
Objects: []lfs.Pointer{
|
||||
{Oid: oid, Size: 6},
|
||||
},
|
||||
})
|
||||
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
br := decodeResponse(t, resp.Body)
|
||||
assert.Len(t, br.Objects, 1)
|
||||
assert.Nil(t, br.Objects[0].Error)
|
||||
assert.Contains(t, br.Objects[0].Actions, "download")
|
||||
l := br.Objects[0].Actions["download"]
|
||||
assert.NotNil(t, l)
|
||||
assert.NotEmpty(t, l.Href)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
t.Run("FileTooBig", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
oldMaxFileSize := setting.LFS.MaxFileSize
|
||||
setting.LFS.MaxFileSize = 2
|
||||
|
||||
req := newRequest(t, &lfs.BatchRequest{
|
||||
Operation: "upload",
|
||||
Objects: []lfs.Pointer{
|
||||
{Oid: "fb8f7d8435968c4f82a726a92395be4d16f2f63116caf36c8ad35c60831ab042", Size: 6},
|
||||
},
|
||||
})
|
||||
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
br := decodeResponse(t, resp.Body)
|
||||
assert.Len(t, br.Objects, 1)
|
||||
assert.NotNil(t, br.Objects[0].Error)
|
||||
assert.Equal(t, http.StatusUnprocessableEntity, br.Objects[0].Error.Code)
|
||||
assert.Equal(t, "Size must be less than or equal to 2", br.Objects[0].Error.Message)
|
||||
|
||||
setting.LFS.MaxFileSize = oldMaxFileSize
|
||||
})
|
||||
|
||||
t.Run("AddMeta", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
p := lfs.Pointer{Oid: "05eeb4eb5be71f2dd291ca39157d6d9effd7d1ea19cbdc8a99411fe2a8f26a00", Size: 6}
|
||||
|
||||
contentStore := lfs.NewContentStore()
|
||||
exist, err := contentStore.Exists(p)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, exist)
|
||||
|
||||
repo2 := createLFSTestRepository(t, "batch2")
|
||||
content := []byte("dummy0")
|
||||
storeObjectInRepo(t, repo2.ID, &content)
|
||||
|
||||
meta, err := git_model.GetLFSMetaObjectByOid(repo.ID, p.Oid)
|
||||
assert.Nil(t, meta)
|
||||
assert.Equal(t, git_model.ErrLFSObjectNotExist, err)
|
||||
|
||||
req := newRequest(t, &lfs.BatchRequest{
|
||||
Operation: "upload",
|
||||
Objects: []lfs.Pointer{p},
|
||||
})
|
||||
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
br := decodeResponse(t, resp.Body)
|
||||
assert.Len(t, br.Objects, 1)
|
||||
assert.Nil(t, br.Objects[0].Error)
|
||||
assert.Empty(t, br.Objects[0].Actions)
|
||||
|
||||
meta, err = git_model.GetLFSMetaObjectByOid(repo.ID, p.Oid)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, meta)
|
||||
|
||||
// Cleanup
|
||||
err = contentStore.Delete(p.RelativePath())
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("AlreadyExists", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := newRequest(t, &lfs.BatchRequest{
|
||||
Operation: "upload",
|
||||
Objects: []lfs.Pointer{
|
||||
{Oid: oid, Size: 6},
|
||||
},
|
||||
})
|
||||
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
br := decodeResponse(t, resp.Body)
|
||||
assert.Len(t, br.Objects, 1)
|
||||
assert.Nil(t, br.Objects[0].Error)
|
||||
assert.Empty(t, br.Objects[0].Actions)
|
||||
})
|
||||
|
||||
t.Run("NewFile", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := newRequest(t, &lfs.BatchRequest{
|
||||
Operation: "upload",
|
||||
Objects: []lfs.Pointer{
|
||||
{Oid: "d6f175817f886ec6fbbc1515326465fa96c3bfd54a4ea06cfd6dbbd8340e0153", Size: 1},
|
||||
},
|
||||
})
|
||||
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
br := decodeResponse(t, resp.Body)
|
||||
assert.Len(t, br.Objects, 1)
|
||||
assert.Nil(t, br.Objects[0].Error)
|
||||
assert.Contains(t, br.Objects[0].Actions, "upload")
|
||||
ul := br.Objects[0].Actions["upload"]
|
||||
assert.NotNil(t, ul)
|
||||
assert.NotEmpty(t, ul.Href)
|
||||
assert.Contains(t, br.Objects[0].Actions, "verify")
|
||||
vl := br.Objects[0].Actions["verify"]
|
||||
assert.NotNil(t, vl)
|
||||
assert.NotEmpty(t, vl.Href)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestAPILFSUpload(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
setting.LFS.StartServer = true
|
||||
|
||||
repo := createLFSTestRepository(t, "upload")
|
||||
|
||||
content := []byte("dummy3")
|
||||
oid := storeObjectInRepo(t, repo.ID, &content)
|
||||
defer git_model.RemoveLFSMetaObjectByOid(repo.ID, oid)
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
|
||||
newRequest := func(t testing.TB, p lfs.Pointer, content string) *http.Request {
|
||||
req := NewRequestWithBody(t, "PUT", path.Join("/user2/lfs-upload-repo.git/info/lfs/objects/", p.Oid, strconv.FormatInt(p.Size, 10)), strings.NewReader(content))
|
||||
return req
|
||||
}
|
||||
|
||||
t.Run("InvalidPointer", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := newRequest(t, lfs.Pointer{Oid: "dummy"}, "")
|
||||
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
})
|
||||
|
||||
t.Run("AlreadyExistsInStore", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
p := lfs.Pointer{Oid: "83de2e488b89a0aa1c97496b888120a28b0c1e15463a4adb8405578c540f36d4", Size: 6}
|
||||
|
||||
contentStore := lfs.NewContentStore()
|
||||
exist, err := contentStore.Exists(p)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, exist)
|
||||
err = contentStore.Put(p, bytes.NewReader([]byte("dummy5")))
|
||||
assert.NoError(t, err)
|
||||
|
||||
meta, err := git_model.GetLFSMetaObjectByOid(repo.ID, p.Oid)
|
||||
assert.Nil(t, meta)
|
||||
assert.Equal(t, git_model.ErrLFSObjectNotExist, err)
|
||||
|
||||
t.Run("InvalidAccess", func(t *testing.T) {
|
||||
req := newRequest(t, p, "invalid")
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
})
|
||||
|
||||
t.Run("ValidAccess", func(t *testing.T) {
|
||||
req := newRequest(t, p, "dummy5")
|
||||
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
meta, err = git_model.GetLFSMetaObjectByOid(repo.ID, p.Oid)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, meta)
|
||||
})
|
||||
|
||||
// Cleanup
|
||||
err = contentStore.Delete(p.RelativePath())
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("MetaAlreadyExists", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := newRequest(t, lfs.Pointer{Oid: oid, Size: 6}, "")
|
||||
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
})
|
||||
|
||||
t.Run("HashMismatch", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := newRequest(t, lfs.Pointer{Oid: "2581dd7bbc1fe44726de4b7dd806a087a978b9c5aec0a60481259e34be09b06a", Size: 1}, "a")
|
||||
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
})
|
||||
|
||||
t.Run("SizeMismatch", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := newRequest(t, lfs.Pointer{Oid: "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", Size: 2}, "a")
|
||||
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
})
|
||||
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
p := lfs.Pointer{Oid: "6ccce4863b70f258d691f59609d31b4502e1ba5199942d3bc5d35d17a4ce771d", Size: 5}
|
||||
|
||||
req := newRequest(t, p, "gitea")
|
||||
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
contentStore := lfs.NewContentStore()
|
||||
exist, err := contentStore.Exists(p)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, exist)
|
||||
|
||||
meta, err := git_model.GetLFSMetaObjectByOid(repo.ID, p.Oid)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, meta)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAPILFSVerify(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
setting.LFS.StartServer = true
|
||||
|
||||
repo := createLFSTestRepository(t, "verify")
|
||||
|
||||
content := []byte("dummy3")
|
||||
oid := storeObjectInRepo(t, repo.ID, &content)
|
||||
defer git_model.RemoveLFSMetaObjectByOid(repo.ID, oid)
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
|
||||
newRequest := func(t testing.TB, p *lfs.Pointer) *http.Request {
|
||||
req := NewRequestWithJSON(t, "POST", "/user2/lfs-verify-repo.git/info/lfs/verify", p)
|
||||
req.Header.Set("Accept", lfs.MediaType)
|
||||
req.Header.Set("Content-Type", lfs.MediaType)
|
||||
return req
|
||||
}
|
||||
|
||||
t.Run("InvalidJsonRequest", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := newRequest(t, nil)
|
||||
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
})
|
||||
|
||||
t.Run("InvalidPointer", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := newRequest(t, &lfs.Pointer{})
|
||||
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
})
|
||||
|
||||
t.Run("PointerNotExisting", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := newRequest(t, &lfs.Pointer{Oid: "fb8f7d8435968c4f82a726a92395be4d16f2f63116caf36c8ad35c60831ab042", Size: 6})
|
||||
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := newRequest(t, &lfs.Pointer{Oid: oid, Size: 6})
|
||||
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
})
|
||||
}
|
38
tests/integration/api_repo_raw_test.go
Normal file
38
tests/integration/api_repo_raw_test.go
Normal file
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIReposRaw(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
// Login as User2.
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
for _, ref := range [...]string{
|
||||
"master", // Branch
|
||||
"v1.1", // Tag
|
||||
"65f1bf27bc3bf70f64657658635e66094edbcb4d", // Commit
|
||||
} {
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/%s/README.md?token="+token, user.Name, ref)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.EqualValues(t, "file", resp.Header().Get("x-gitea-object-type"))
|
||||
}
|
||||
// Test default branch
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/README.md?token="+token, user.Name)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.EqualValues(t, "file", resp.Header().Get("x-gitea-object-type"))
|
||||
}
|
84
tests/integration/api_repo_tags_test.go
Normal file
84
tests/integration/api_repo_tags_test.go
Normal file
|
@ -0,0 +1,84 @@
|
|||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"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/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIRepoTags(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
// Login as User2.
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
repoName := "repo1"
|
||||
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/tags?token=%s", user.Name, repoName, token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var tags []*api.Tag
|
||||
DecodeJSON(t, resp, &tags)
|
||||
|
||||
assert.Len(t, tags, 1)
|
||||
assert.Equal(t, "v1.1", tags[0].Name)
|
||||
assert.Equal(t, "Initial commit", tags[0].Message)
|
||||
assert.Equal(t, "65f1bf27bc3bf70f64657658635e66094edbcb4d", tags[0].Commit.SHA)
|
||||
assert.Equal(t, setting.AppURL+"api/v1/repos/user2/repo1/git/commits/65f1bf27bc3bf70f64657658635e66094edbcb4d", tags[0].Commit.URL)
|
||||
assert.Equal(t, setting.AppURL+"user2/repo1/archive/v1.1.zip", tags[0].ZipballURL)
|
||||
assert.Equal(t, setting.AppURL+"user2/repo1/archive/v1.1.tar.gz", tags[0].TarballURL)
|
||||
|
||||
newTag := createNewTagUsingAPI(t, session, token, user.Name, repoName, "gitea/22", "", "nice!\nand some text")
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &tags)
|
||||
assert.Len(t, tags, 2)
|
||||
for _, tag := range tags {
|
||||
if tag.Name != "v1.1" {
|
||||
assert.EqualValues(t, newTag.Name, tag.Name)
|
||||
assert.EqualValues(t, newTag.Message, tag.Message)
|
||||
assert.EqualValues(t, "nice!\nand some text", tag.Message)
|
||||
assert.EqualValues(t, newTag.Commit.SHA, tag.Commit.SHA)
|
||||
}
|
||||
}
|
||||
|
||||
// get created tag
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/tags/%s?token=%s", user.Name, repoName, newTag.Name, token)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
var tag *api.Tag
|
||||
DecodeJSON(t, resp, &tag)
|
||||
assert.EqualValues(t, newTag, tag)
|
||||
|
||||
// delete tag
|
||||
delReq := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/tags/%s?token=%s", user.Name, repoName, newTag.Name, token)
|
||||
session.MakeRequest(t, delReq, http.StatusNoContent)
|
||||
|
||||
// check if it's gone
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
||||
|
||||
func createNewTagUsingAPI(t *testing.T, session *TestSession, token, ownerName, repoName, name, target, msg string) *api.Tag {
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/tags?token=%s", ownerName, repoName, token)
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateTagOption{
|
||||
TagName: name,
|
||||
Message: msg,
|
||||
Target: target,
|
||||
})
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
var respObj api.Tag
|
||||
DecodeJSON(t, resp, &respObj)
|
||||
return &respObj
|
||||
}
|
82
tests/integration/api_repo_teams_test.go
Normal file
82
tests/integration/api_repo_teams_test.go
Normal file
|
@ -0,0 +1,82 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
"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/modules/util"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIRepoTeams(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
// publicOrgRepo = user3/repo21
|
||||
publicOrgRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 32})
|
||||
// user4
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
// ListTeams
|
||||
url := fmt.Sprintf("/api/v1/repos/%s/teams?token=%s", publicOrgRepo.FullName(), token)
|
||||
req := NewRequest(t, "GET", url)
|
||||
res := session.MakeRequest(t, req, http.StatusOK)
|
||||
var teams []*api.Team
|
||||
DecodeJSON(t, res, &teams)
|
||||
if assert.Len(t, teams, 2) {
|
||||
assert.EqualValues(t, "Owners", teams[0].Name)
|
||||
assert.True(t, teams[0].CanCreateOrgRepo)
|
||||
assert.True(t, util.IsEqualSlice(unit.AllUnitKeyNames(), teams[0].Units), fmt.Sprintf("%v == %v", unit.AllUnitKeyNames(), teams[0].Units))
|
||||
assert.EqualValues(t, "owner", teams[0].Permission)
|
||||
|
||||
assert.EqualValues(t, "test_team", teams[1].Name)
|
||||
assert.False(t, teams[1].CanCreateOrgRepo)
|
||||
assert.EqualValues(t, []string{"repo.issues"}, teams[1].Units)
|
||||
assert.EqualValues(t, "write", teams[1].Permission)
|
||||
}
|
||||
|
||||
// IsTeam
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/teams/%s?token=%s", publicOrgRepo.FullName(), "Test_Team", token)
|
||||
req = NewRequest(t, "GET", url)
|
||||
res = session.MakeRequest(t, req, http.StatusOK)
|
||||
var team *api.Team
|
||||
DecodeJSON(t, res, &team)
|
||||
assert.EqualValues(t, teams[1], team)
|
||||
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/teams/%s?token=%s", publicOrgRepo.FullName(), "NonExistingTeam", token)
|
||||
req = NewRequest(t, "GET", url)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// AddTeam with user4
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/teams/%s?token=%s", publicOrgRepo.FullName(), "team1", token)
|
||||
req = NewRequest(t, "PUT", url)
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
|
||||
// AddTeam with user2
|
||||
user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
session = loginUser(t, user.Name)
|
||||
token = getTokenForLoggedInUser(t, session)
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/teams/%s?token=%s", publicOrgRepo.FullName(), "team1", token)
|
||||
req = NewRequest(t, "PUT", url)
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity) // test duplicate request
|
||||
|
||||
// DeleteTeam
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/teams/%s?token=%s", publicOrgRepo.FullName(), "team1", token)
|
||||
req = NewRequest(t, "DELETE", url)
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity) // test duplicate request
|
||||
}
|
694
tests/integration/api_repo_test.go
Normal file
694
tests/integration/api_repo_test.go
Normal file
|
@ -0,0 +1,694 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
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/util"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIUserReposNotLogin(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
req := NewRequestf(t, "GET", "/api/v1/users/%s/repos", user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var apiRepos []api.Repository
|
||||
DecodeJSON(t, resp, &apiRepos)
|
||||
expectedLen := unittest.GetCount(t, repo_model.Repository{OwnerID: user.ID},
|
||||
unittest.Cond("is_private = ?", false))
|
||||
assert.Len(t, apiRepos, expectedLen)
|
||||
for _, repo := range apiRepos {
|
||||
assert.EqualValues(t, user.ID, repo.Owner.ID)
|
||||
assert.False(t, repo.Private)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPISearchRepo(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
const keyword = "test"
|
||||
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/search?q=%s", keyword)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var body api.SearchResults
|
||||
DecodeJSON(t, resp, &body)
|
||||
assert.NotEmpty(t, body.Data)
|
||||
for _, repo := range body.Data {
|
||||
assert.Contains(t, repo.Name, keyword)
|
||||
assert.False(t, repo.Private)
|
||||
}
|
||||
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15})
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 16})
|
||||
user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 18})
|
||||
user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 20})
|
||||
orgUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 17})
|
||||
|
||||
oldAPIDefaultNum := setting.API.DefaultPagingNum
|
||||
defer func() {
|
||||
setting.API.DefaultPagingNum = oldAPIDefaultNum
|
||||
}()
|
||||
setting.API.DefaultPagingNum = 10
|
||||
|
||||
// Map of expected results, where key is user for login
|
||||
type expectedResults map[*user_model.User]struct {
|
||||
count int
|
||||
repoOwnerID int64
|
||||
repoName string
|
||||
includesPrivate bool
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name, requestURL string
|
||||
expectedResults
|
||||
}{
|
||||
{
|
||||
name: "RepositoriesMax50", requestURL: "/api/v1/repos/search?limit=50&private=false", expectedResults: expectedResults{
|
||||
nil: {count: 30},
|
||||
user: {count: 30},
|
||||
user2: {count: 30},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "RepositoriesMax10", requestURL: "/api/v1/repos/search?limit=10&private=false", expectedResults: expectedResults{
|
||||
nil: {count: 10},
|
||||
user: {count: 10},
|
||||
user2: {count: 10},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "RepositoriesDefault", requestURL: "/api/v1/repos/search?default&private=false", expectedResults: expectedResults{
|
||||
nil: {count: 10},
|
||||
user: {count: 10},
|
||||
user2: {count: 10},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "RepositoriesByName", requestURL: fmt.Sprintf("/api/v1/repos/search?q=%s&private=false", "big_test_"), expectedResults: expectedResults{
|
||||
nil: {count: 7, repoName: "big_test_"},
|
||||
user: {count: 7, repoName: "big_test_"},
|
||||
user2: {count: 7, repoName: "big_test_"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "RepositoriesByName", requestURL: fmt.Sprintf("/api/v1/repos/search?q=%s&private=false", "user2/big_test_"), expectedResults: expectedResults{
|
||||
user2: {count: 2, repoName: "big_test_"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "RepositoriesAccessibleAndRelatedToUser", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user.ID), expectedResults: expectedResults{
|
||||
nil: {count: 5},
|
||||
user: {count: 9, includesPrivate: true},
|
||||
user2: {count: 6, includesPrivate: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "RepositoriesAccessibleAndRelatedToUser2", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user2.ID), expectedResults: expectedResults{
|
||||
nil: {count: 1},
|
||||
user: {count: 2, includesPrivate: true},
|
||||
user2: {count: 2, includesPrivate: true},
|
||||
user4: {count: 1},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "RepositoriesAccessibleAndRelatedToUser3", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user3.ID), expectedResults: expectedResults{
|
||||
nil: {count: 1},
|
||||
user: {count: 4, includesPrivate: true},
|
||||
user2: {count: 3, includesPrivate: true},
|
||||
user3: {count: 4, includesPrivate: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "RepositoriesOwnedByOrganization", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", orgUser.ID), expectedResults: expectedResults{
|
||||
nil: {count: 1, repoOwnerID: orgUser.ID},
|
||||
user: {count: 2, repoOwnerID: orgUser.ID, includesPrivate: true},
|
||||
user2: {count: 1, repoOwnerID: orgUser.ID},
|
||||
},
|
||||
},
|
||||
{name: "RepositoriesAccessibleAndRelatedToUser4", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user4.ID), expectedResults: expectedResults{
|
||||
nil: {count: 3},
|
||||
user: {count: 4, includesPrivate: true},
|
||||
user4: {count: 7, includesPrivate: true},
|
||||
}},
|
||||
{name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeSource", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "source"), expectedResults: expectedResults{
|
||||
nil: {count: 0},
|
||||
user: {count: 1, includesPrivate: true},
|
||||
user4: {count: 1, includesPrivate: true},
|
||||
}},
|
||||
{name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeFork", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "fork"), expectedResults: expectedResults{
|
||||
nil: {count: 1},
|
||||
user: {count: 1},
|
||||
user4: {count: 2, includesPrivate: true},
|
||||
}},
|
||||
{name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeFork/Exclusive", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s&exclusive=1", user4.ID, "fork"), expectedResults: expectedResults{
|
||||
nil: {count: 1},
|
||||
user: {count: 1},
|
||||
user4: {count: 2, includesPrivate: true},
|
||||
}},
|
||||
{name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeMirror", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "mirror"), expectedResults: expectedResults{
|
||||
nil: {count: 2},
|
||||
user: {count: 2},
|
||||
user4: {count: 4, includesPrivate: true},
|
||||
}},
|
||||
{name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeMirror/Exclusive", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s&exclusive=1", user4.ID, "mirror"), expectedResults: expectedResults{
|
||||
nil: {count: 1},
|
||||
user: {count: 1},
|
||||
user4: {count: 2, includesPrivate: true},
|
||||
}},
|
||||
{name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeCollaborative", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "collaborative"), expectedResults: expectedResults{
|
||||
nil: {count: 0},
|
||||
user: {count: 1, includesPrivate: true},
|
||||
user4: {count: 1, includesPrivate: true},
|
||||
}},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
for userToLogin, expected := range testCase.expectedResults {
|
||||
var session *TestSession
|
||||
var testName string
|
||||
var userID int64
|
||||
var token string
|
||||
if userToLogin != nil && userToLogin.ID > 0 {
|
||||
testName = fmt.Sprintf("LoggedUser%d", userToLogin.ID)
|
||||
session = loginUser(t, userToLogin.Name)
|
||||
token = getTokenForLoggedInUser(t, session)
|
||||
userID = userToLogin.ID
|
||||
} else {
|
||||
testName = "AnonymousUser"
|
||||
session = emptyTestSession(t)
|
||||
}
|
||||
|
||||
t.Run(testName, func(t *testing.T) {
|
||||
request := NewRequest(t, "GET", testCase.requestURL+"&token="+token)
|
||||
response := session.MakeRequest(t, request, http.StatusOK)
|
||||
|
||||
var body api.SearchResults
|
||||
DecodeJSON(t, response, &body)
|
||||
|
||||
repoNames := make([]string, 0, len(body.Data))
|
||||
for _, repo := range body.Data {
|
||||
repoNames = append(repoNames, fmt.Sprintf("%d:%s:%t", repo.ID, repo.FullName, repo.Private))
|
||||
}
|
||||
assert.Len(t, repoNames, expected.count)
|
||||
for _, repo := range body.Data {
|
||||
r := getRepo(t, repo.ID)
|
||||
hasAccess, err := access_model.HasAccess(db.DefaultContext, userID, r)
|
||||
assert.NoError(t, err, "Error when checking if User: %d has access to %s: %v", userID, repo.FullName, err)
|
||||
assert.True(t, hasAccess, "User: %d does not have access to %s", userID, repo.FullName)
|
||||
|
||||
assert.NotEmpty(t, repo.Name)
|
||||
assert.Equal(t, repo.Name, r.Name)
|
||||
|
||||
if len(expected.repoName) > 0 {
|
||||
assert.Contains(t, repo.Name, expected.repoName)
|
||||
}
|
||||
|
||||
if expected.repoOwnerID > 0 {
|
||||
assert.Equal(t, expected.repoOwnerID, repo.Owner.ID)
|
||||
}
|
||||
|
||||
if !expected.includesPrivate {
|
||||
assert.False(t, repo.Private, "User: %d not expecting private repository: %s", userID, repo.FullName)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var repoCache = make(map[int64]*repo_model.Repository)
|
||||
|
||||
func getRepo(t *testing.T, repoID int64) *repo_model.Repository {
|
||||
if _, ok := repoCache[repoID]; !ok {
|
||||
repoCache[repoID] = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID})
|
||||
}
|
||||
return repoCache[repoID]
|
||||
}
|
||||
|
||||
func TestAPIViewRepo(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
var repo api.Repository
|
||||
|
||||
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo1")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &repo)
|
||||
assert.EqualValues(t, 1, repo.ID)
|
||||
assert.EqualValues(t, "repo1", repo.Name)
|
||||
assert.EqualValues(t, 2, repo.Releases)
|
||||
assert.EqualValues(t, 1, repo.OpenIssues)
|
||||
assert.EqualValues(t, 3, repo.OpenPulls)
|
||||
|
||||
req = NewRequest(t, "GET", "/api/v1/repos/user12/repo10")
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &repo)
|
||||
assert.EqualValues(t, 10, repo.ID)
|
||||
assert.EqualValues(t, "repo10", repo.Name)
|
||||
assert.EqualValues(t, 1, repo.OpenPulls)
|
||||
assert.EqualValues(t, 1, repo.Forks)
|
||||
|
||||
req = NewRequest(t, "GET", "/api/v1/repos/user5/repo4")
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &repo)
|
||||
assert.EqualValues(t, 4, repo.ID)
|
||||
assert.EqualValues(t, "repo4", repo.Name)
|
||||
assert.EqualValues(t, 1, repo.Stars)
|
||||
}
|
||||
|
||||
func TestAPIOrgRepos(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||
user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
|
||||
// User3 is an Org. Check their repos.
|
||||
sourceOrg := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3})
|
||||
|
||||
expectedResults := map[*user_model.User]struct {
|
||||
count int
|
||||
includesPrivate bool
|
||||
}{
|
||||
nil: {count: 1},
|
||||
user: {count: 3, includesPrivate: true},
|
||||
user2: {count: 3, includesPrivate: true},
|
||||
user3: {count: 1},
|
||||
}
|
||||
|
||||
for userToLogin, expected := range expectedResults {
|
||||
var session *TestSession
|
||||
var testName string
|
||||
var token string
|
||||
if userToLogin != nil && userToLogin.ID > 0 {
|
||||
testName = fmt.Sprintf("LoggedUser%d", userToLogin.ID)
|
||||
session = loginUser(t, userToLogin.Name)
|
||||
token = getTokenForLoggedInUser(t, session)
|
||||
} else {
|
||||
testName = "AnonymousUser"
|
||||
session = emptyTestSession(t)
|
||||
}
|
||||
t.Run(testName, func(t *testing.T) {
|
||||
req := NewRequestf(t, "GET", "/api/v1/orgs/%s/repos?token="+token, sourceOrg.Name)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var apiRepos []*api.Repository
|
||||
DecodeJSON(t, resp, &apiRepos)
|
||||
assert.Len(t, apiRepos, expected.count)
|
||||
for _, repo := range apiRepos {
|
||||
if !expected.includesPrivate {
|
||||
assert.False(t, repo.Private)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIGetRepoByIDUnauthorized(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)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repositories/2?token="+token)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
||||
|
||||
func TestAPIRepoMigrate(t *testing.T) {
|
||||
testCases := []struct {
|
||||
ctxUserID, userID int64
|
||||
cloneURL, repoName string
|
||||
expectedStatus int
|
||||
}{
|
||||
{ctxUserID: 1, userID: 2, cloneURL: "https://github.com/go-gitea/test_repo.git", repoName: "git-admin", expectedStatus: http.StatusCreated},
|
||||
{ctxUserID: 2, userID: 2, cloneURL: "https://github.com/go-gitea/test_repo.git", repoName: "git-own", expectedStatus: http.StatusCreated},
|
||||
{ctxUserID: 2, userID: 1, cloneURL: "https://github.com/go-gitea/test_repo.git", repoName: "git-bad", expectedStatus: http.StatusForbidden},
|
||||
{ctxUserID: 2, userID: 3, cloneURL: "https://github.com/go-gitea/test_repo.git", repoName: "git-org", expectedStatus: http.StatusCreated},
|
||||
{ctxUserID: 2, userID: 6, cloneURL: "https://github.com/go-gitea/test_repo.git", repoName: "git-bad-org", expectedStatus: http.StatusForbidden},
|
||||
{ctxUserID: 2, userID: 3, cloneURL: "https://localhost:3000/user/test_repo.git", repoName: "private-ip", expectedStatus: http.StatusUnprocessableEntity},
|
||||
{ctxUserID: 2, userID: 3, cloneURL: "https://10.0.0.1/user/test_repo.git", repoName: "private-ip", expectedStatus: http.StatusUnprocessableEntity},
|
||||
}
|
||||
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
for _, testCase := range testCases {
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: testCase.ctxUserID})
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/repos/migrate?token="+token, &api.MigrateRepoOptions{
|
||||
CloneAddr: testCase.cloneURL,
|
||||
RepoOwnerID: testCase.userID,
|
||||
RepoName: testCase.repoName,
|
||||
})
|
||||
resp := MakeRequest(t, req, NoExpectedStatus)
|
||||
if resp.Code == http.StatusUnprocessableEntity {
|
||||
respJSON := map[string]string{}
|
||||
DecodeJSON(t, resp, &respJSON)
|
||||
switch respJSON["message"] {
|
||||
case "Remote visit addressed rate limitation.":
|
||||
t.Log("test hit github rate limitation")
|
||||
case "You can not import from disallowed hosts.":
|
||||
assert.EqualValues(t, "private-ip", testCase.repoName)
|
||||
default:
|
||||
assert.Failf(t, "unexpected error '%v' on url '%s'", respJSON["message"], testCase.cloneURL)
|
||||
}
|
||||
} else {
|
||||
assert.EqualValues(t, testCase.expectedStatus, resp.Code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIRepoMigrateConflict(t *testing.T) {
|
||||
onGiteaRun(t, testAPIRepoMigrateConflict)
|
||||
}
|
||||
|
||||
func testAPIRepoMigrateConflict(t *testing.T, u *url.URL) {
|
||||
username := "user2"
|
||||
baseAPITestContext := NewAPITestContext(t, username, "repo1")
|
||||
|
||||
u.Path = baseAPITestContext.GitPath()
|
||||
|
||||
t.Run("Existing", func(t *testing.T) {
|
||||
httpContext := baseAPITestContext
|
||||
|
||||
httpContext.Reponame = "repo-tmp-17"
|
||||
dstPath, err := os.MkdirTemp("", httpContext.Reponame)
|
||||
assert.NoError(t, err)
|
||||
defer util.RemoveAll(dstPath)
|
||||
t.Run("CreateRepo", doAPICreateRepository(httpContext, false))
|
||||
|
||||
user, err := user_model.GetUserByName(db.DefaultContext, httpContext.Username)
|
||||
assert.NoError(t, err)
|
||||
userID := user.ID
|
||||
|
||||
cloneURL := "https://github.com/go-gitea/test_repo.git"
|
||||
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/repos/migrate?token="+httpContext.Token,
|
||||
&api.MigrateRepoOptions{
|
||||
CloneAddr: cloneURL,
|
||||
RepoOwnerID: userID,
|
||||
RepoName: httpContext.Reponame,
|
||||
})
|
||||
resp := httpContext.Session.MakeRequest(t, req, http.StatusConflict)
|
||||
respJSON := map[string]string{}
|
||||
DecodeJSON(t, resp, &respJSON)
|
||||
assert.Equal(t, "The repository with the same name already exists.", respJSON["message"])
|
||||
})
|
||||
}
|
||||
|
||||
// mirror-sync must fail with "400 (Bad Request)" when an attempt is made to
|
||||
// sync a non-mirror repository.
|
||||
func TestAPIMirrorSyncNonMirrorRepo(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
var repo api.Repository
|
||||
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo1")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &repo)
|
||||
assert.EqualValues(t, false, repo.Mirror)
|
||||
|
||||
req = NewRequestf(t, "POST", "/api/v1/repos/user2/repo1/mirror-sync?token=%s", token)
|
||||
resp = session.MakeRequest(t, req, http.StatusBadRequest)
|
||||
errRespJSON := map[string]string{}
|
||||
DecodeJSON(t, resp, &errRespJSON)
|
||||
assert.Equal(t, "Repository is not a mirror", errRespJSON["message"])
|
||||
}
|
||||
|
||||
func TestAPIOrgRepoCreate(t *testing.T) {
|
||||
testCases := []struct {
|
||||
ctxUserID int64
|
||||
orgName, repoName string
|
||||
expectedStatus int
|
||||
}{
|
||||
{ctxUserID: 1, orgName: "user3", repoName: "repo-admin", expectedStatus: http.StatusCreated},
|
||||
{ctxUserID: 2, orgName: "user3", repoName: "repo-own", expectedStatus: http.StatusCreated},
|
||||
{ctxUserID: 2, orgName: "user6", repoName: "repo-bad-org", expectedStatus: http.StatusForbidden},
|
||||
{ctxUserID: 28, orgName: "user3", repoName: "repo-creator", expectedStatus: http.StatusCreated},
|
||||
{ctxUserID: 28, orgName: "user6", repoName: "repo-not-creator", expectedStatus: http.StatusForbidden},
|
||||
}
|
||||
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
for _, testCase := range testCases {
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: testCase.ctxUserID})
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/org/%s/repos?token="+token, testCase.orgName), &api.CreateRepoOption{
|
||||
Name: testCase.repoName,
|
||||
})
|
||||
session.MakeRequest(t, req, testCase.expectedStatus)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIRepoCreateConflict(t *testing.T) {
|
||||
onGiteaRun(t, testAPIRepoCreateConflict)
|
||||
}
|
||||
|
||||
func testAPIRepoCreateConflict(t *testing.T, u *url.URL) {
|
||||
username := "user2"
|
||||
baseAPITestContext := NewAPITestContext(t, username, "repo1")
|
||||
|
||||
u.Path = baseAPITestContext.GitPath()
|
||||
|
||||
t.Run("Existing", func(t *testing.T) {
|
||||
httpContext := baseAPITestContext
|
||||
|
||||
httpContext.Reponame = "repo-tmp-17"
|
||||
dstPath, err := os.MkdirTemp("", httpContext.Reponame)
|
||||
assert.NoError(t, err)
|
||||
defer util.RemoveAll(dstPath)
|
||||
t.Run("CreateRepo", doAPICreateRepository(httpContext, false))
|
||||
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos?token="+httpContext.Token,
|
||||
&api.CreateRepoOption{
|
||||
Name: httpContext.Reponame,
|
||||
})
|
||||
resp := httpContext.Session.MakeRequest(t, req, http.StatusConflict)
|
||||
respJSON := map[string]string{}
|
||||
DecodeJSON(t, resp, &respJSON)
|
||||
assert.Equal(t, respJSON["message"], "The repository with the same name already exists.")
|
||||
})
|
||||
}
|
||||
|
||||
func TestAPIRepoTransfer(t *testing.T) {
|
||||
testCases := []struct {
|
||||
ctxUserID int64
|
||||
newOwner string
|
||||
teams *[]int64
|
||||
expectedStatus int
|
||||
}{
|
||||
// Disclaimer for test story: "user1" is an admin, "user2" is normal user and part of in owner team of org "user3"
|
||||
// Transfer to a user with teams in another org should fail
|
||||
{ctxUserID: 1, newOwner: "user3", teams: &[]int64{5}, expectedStatus: http.StatusForbidden},
|
||||
// Transfer to a user with non-existent team IDs should fail
|
||||
{ctxUserID: 1, newOwner: "user2", teams: &[]int64{2}, expectedStatus: http.StatusUnprocessableEntity},
|
||||
// Transfer should go through
|
||||
{ctxUserID: 1, newOwner: "user3", teams: &[]int64{2}, expectedStatus: http.StatusAccepted},
|
||||
// Let user transfer it back to himself
|
||||
{ctxUserID: 2, newOwner: "user2", expectedStatus: http.StatusAccepted},
|
||||
// And revert transfer
|
||||
{ctxUserID: 2, newOwner: "user3", teams: &[]int64{2}, expectedStatus: http.StatusAccepted},
|
||||
// Cannot start transfer to an existing repo
|
||||
{ctxUserID: 2, newOwner: "user3", teams: nil, expectedStatus: http.StatusUnprocessableEntity},
|
||||
// Start transfer, repo is now in pending transfer mode
|
||||
{ctxUserID: 2, newOwner: "user6", teams: nil, expectedStatus: http.StatusCreated},
|
||||
}
|
||||
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
// create repo to move
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
repoName := "moveME"
|
||||
apiRepo := new(api.Repository)
|
||||
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/user/repos?token=%s", token), &api.CreateRepoOption{
|
||||
Name: repoName,
|
||||
Description: "repo move around",
|
||||
Private: false,
|
||||
Readme: "Default",
|
||||
AutoInit: true,
|
||||
})
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
DecodeJSON(t, resp, apiRepo)
|
||||
|
||||
// start testing
|
||||
for _, testCase := range testCases {
|
||||
user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: testCase.ctxUserID})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiRepo.ID})
|
||||
session = loginUser(t, user.Name)
|
||||
token = getTokenForLoggedInUser(t, session)
|
||||
req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/transfer?token=%s", repo.OwnerName, repo.Name, token), &api.TransferRepoOption{
|
||||
NewOwner: testCase.newOwner,
|
||||
TeamIDs: testCase.teams,
|
||||
})
|
||||
session.MakeRequest(t, req, testCase.expectedStatus)
|
||||
}
|
||||
|
||||
// cleanup
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiRepo.ID})
|
||||
_ = models.DeleteRepository(user, repo.OwnerID, repo.ID)
|
||||
}
|
||||
|
||||
func transfer(t *testing.T) *repo_model.Repository {
|
||||
// create repo to move
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
repoName := "moveME"
|
||||
apiRepo := new(api.Repository)
|
||||
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/user/repos?token=%s", token), &api.CreateRepoOption{
|
||||
Name: repoName,
|
||||
Description: "repo move around",
|
||||
Private: false,
|
||||
Readme: "Default",
|
||||
AutoInit: true,
|
||||
})
|
||||
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
DecodeJSON(t, resp, apiRepo)
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiRepo.ID})
|
||||
req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/transfer?token=%s", repo.OwnerName, repo.Name, token), &api.TransferRepoOption{
|
||||
NewOwner: "user4",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
return repo
|
||||
}
|
||||
|
||||
func TestAPIAcceptTransfer(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
repo := transfer(t)
|
||||
|
||||
// try to accept with not authorized user
|
||||
session := loginUser(t, "user2")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequest(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/transfer/reject?token=%s", repo.OwnerName, repo.Name, token))
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
|
||||
// try to accept repo that's not marked as transferred
|
||||
req = NewRequest(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/transfer/accept?token=%s", "user2", "repo1", token))
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// accept transfer
|
||||
session = loginUser(t, "user4")
|
||||
token = getTokenForLoggedInUser(t, session)
|
||||
|
||||
req = NewRequest(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/transfer/accept?token=%s", repo.OwnerName, repo.Name, token))
|
||||
resp := session.MakeRequest(t, req, http.StatusAccepted)
|
||||
apiRepo := new(api.Repository)
|
||||
DecodeJSON(t, resp, apiRepo)
|
||||
assert.Equal(t, "user4", apiRepo.Owner.UserName)
|
||||
}
|
||||
|
||||
func TestAPIRejectTransfer(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
repo := transfer(t)
|
||||
|
||||
// try to reject with not authorized user
|
||||
session := loginUser(t, "user2")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequest(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/transfer/reject?token=%s", repo.OwnerName, repo.Name, token))
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
|
||||
// try to reject repo that's not marked as transferred
|
||||
req = NewRequest(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/transfer/reject?token=%s", "user2", "repo1", token))
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// reject transfer
|
||||
session = loginUser(t, "user4")
|
||||
token = getTokenForLoggedInUser(t, session)
|
||||
|
||||
req = NewRequest(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/transfer/reject?token=%s", repo.OwnerName, repo.Name, token))
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
apiRepo := new(api.Repository)
|
||||
DecodeJSON(t, resp, apiRepo)
|
||||
assert.Equal(t, "user2", apiRepo.Owner.UserName)
|
||||
}
|
||||
|
||||
func TestAPIGenerateRepo(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
templateRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 44})
|
||||
|
||||
// user
|
||||
repo := new(api.Repository)
|
||||
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/generate?token=%s", templateRepo.OwnerName, templateRepo.Name, token), &api.GenerateRepoOption{
|
||||
Owner: user.Name,
|
||||
Name: "new-repo",
|
||||
Description: "test generate repo",
|
||||
Private: false,
|
||||
GitContent: true,
|
||||
})
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
DecodeJSON(t, resp, repo)
|
||||
|
||||
assert.Equal(t, "new-repo", repo.Name)
|
||||
|
||||
// org
|
||||
req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/generate?token=%s", templateRepo.OwnerName, templateRepo.Name, token), &api.GenerateRepoOption{
|
||||
Owner: "user3",
|
||||
Name: "new-repo",
|
||||
Description: "test generate repo",
|
||||
Private: false,
|
||||
GitContent: true,
|
||||
})
|
||||
resp = session.MakeRequest(t, req, http.StatusCreated)
|
||||
DecodeJSON(t, resp, repo)
|
||||
|
||||
assert.Equal(t, "new-repo", repo.Name)
|
||||
}
|
||||
|
||||
func TestAPIRepoGetReviewers(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)
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/reviewers?token=%s", user.Name, repo.Name, token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var reviewers []*api.User
|
||||
DecodeJSON(t, resp, &reviewers)
|
||||
assert.Len(t, reviewers, 4)
|
||||
}
|
||||
|
||||
func TestAPIRepoGetAssignees(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)
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/assignees?token=%s", user.Name, repo.Name, token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var assignees []*api.User
|
||||
DecodeJSON(t, resp, &assignees)
|
||||
assert.Len(t, assignees, 1)
|
||||
}
|
155
tests/integration/api_repo_topic_test.go
Normal file
155
tests/integration/api_repo_topic_test.go
Normal file
|
@ -0,0 +1,155 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
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"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPITopicSearch(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
searchURL, _ := url.Parse("/api/v1/topics/search")
|
||||
var topics struct {
|
||||
TopicNames []*api.TopicResponse `json:"topics"`
|
||||
}
|
||||
|
||||
query := url.Values{"page": []string{"1"}, "limit": []string{"4"}}
|
||||
|
||||
searchURL.RawQuery = query.Encode()
|
||||
res := MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK)
|
||||
DecodeJSON(t, res, &topics)
|
||||
assert.Len(t, topics.TopicNames, 4)
|
||||
assert.EqualValues(t, "6", res.Header().Get("x-total-count"))
|
||||
|
||||
query.Add("q", "topic")
|
||||
searchURL.RawQuery = query.Encode()
|
||||
res = MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK)
|
||||
DecodeJSON(t, res, &topics)
|
||||
assert.Len(t, topics.TopicNames, 2)
|
||||
|
||||
query.Set("q", "database")
|
||||
searchURL.RawQuery = query.Encode()
|
||||
res = MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK)
|
||||
DecodeJSON(t, res, &topics)
|
||||
if assert.Len(t, topics.TopicNames, 1) {
|
||||
assert.EqualValues(t, 2, topics.TopicNames[0].ID)
|
||||
assert.EqualValues(t, "database", topics.TopicNames[0].Name)
|
||||
assert.EqualValues(t, 1, topics.TopicNames[0].RepoCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIRepoTopic(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of repo2
|
||||
user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of repo3
|
||||
user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // write access to repo 3
|
||||
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
|
||||
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
|
||||
|
||||
// Get user2's token
|
||||
token2 := getUserToken(t, user2.Name)
|
||||
|
||||
// Test read topics using login
|
||||
url := fmt.Sprintf("/api/v1/repos/%s/%s/topics", user2.Name, repo2.Name)
|
||||
req := NewRequest(t, "GET", url+"?token="+token2)
|
||||
res := MakeRequest(t, req, http.StatusOK)
|
||||
var topics *api.TopicName
|
||||
DecodeJSON(t, res, &topics)
|
||||
assert.ElementsMatch(t, []string{"topicname1", "topicname2"}, topics.TopicNames)
|
||||
|
||||
// Log out user2
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/topics?token=%s", user2.Name, repo2.Name, token2)
|
||||
|
||||
// Test delete a topic
|
||||
req = NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/topics/%s?token=%s", user2.Name, repo2.Name, "Topicname1", token2)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
// Test add an existing topic
|
||||
req = NewRequestf(t, "PUT", "/api/v1/repos/%s/%s/topics/%s?token=%s", user2.Name, repo2.Name, "Golang", token2)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
// Test add a topic
|
||||
req = NewRequestf(t, "PUT", "/api/v1/repos/%s/%s/topics/%s?token=%s", user2.Name, repo2.Name, "topicName3", token2)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
// Test read topics using token
|
||||
req = NewRequest(t, "GET", url)
|
||||
res = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, res, &topics)
|
||||
assert.ElementsMatch(t, []string{"topicname2", "golang", "topicname3"}, topics.TopicNames)
|
||||
|
||||
// Test replace topics
|
||||
newTopics := []string{" windows ", " ", "MAC "}
|
||||
req = NewRequestWithJSON(t, "PUT", url, &api.RepoTopicOptions{
|
||||
Topics: newTopics,
|
||||
})
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
req = NewRequest(t, "GET", url)
|
||||
res = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, res, &topics)
|
||||
assert.ElementsMatch(t, []string{"windows", "mac"}, topics.TopicNames)
|
||||
|
||||
// Test replace topics with something invalid
|
||||
newTopics = []string{"topicname1", "topicname2", "topicname!"}
|
||||
req = NewRequestWithJSON(t, "PUT", url, &api.RepoTopicOptions{
|
||||
Topics: newTopics,
|
||||
})
|
||||
MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
req = NewRequest(t, "GET", url)
|
||||
res = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, res, &topics)
|
||||
assert.ElementsMatch(t, []string{"windows", "mac"}, topics.TopicNames)
|
||||
|
||||
// Test with some topics multiple times, less than 25 unique
|
||||
newTopics = []string{"t1", "t2", "t1", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "t10", "t11", "t12", "t13", "t14", "t15", "t16", "17", "t18", "t19", "t20", "t21", "t22", "t23", "t24", "t25"}
|
||||
req = NewRequestWithJSON(t, "PUT", url, &api.RepoTopicOptions{
|
||||
Topics: newTopics,
|
||||
})
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
req = NewRequest(t, "GET", url)
|
||||
res = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, res, &topics)
|
||||
assert.Len(t, topics.TopicNames, 25)
|
||||
|
||||
// Test writing more topics than allowed
|
||||
newTopics = append(newTopics, "t26")
|
||||
req = NewRequestWithJSON(t, "PUT", url, &api.RepoTopicOptions{
|
||||
Topics: newTopics,
|
||||
})
|
||||
MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
|
||||
// Test add a topic when there is already maximum
|
||||
req = NewRequestf(t, "PUT", "/api/v1/repos/%s/%s/topics/%s?token=%s", user2.Name, repo2.Name, "t26", token2)
|
||||
MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
|
||||
// Test delete a topic that repo doesn't have
|
||||
req = NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/topics/%s?token=%s", user2.Name, repo2.Name, "Topicname1", token2)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Get user4's token
|
||||
token4 := getUserToken(t, user4.Name)
|
||||
|
||||
// Test read topics with write access
|
||||
url = fmt.Sprintf("/api/v1/repos/%s/%s/topics?token=%s", user3.Name, repo3.Name, token4)
|
||||
req = NewRequest(t, "GET", url)
|
||||
res = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, res, &topics)
|
||||
assert.Empty(t, topics.TopicNames)
|
||||
|
||||
// Test add a topic to repo with write access (requires repo admin access)
|
||||
req = NewRequestf(t, "PUT", "/api/v1/repos/%s/%s/topics/%s?token=%s", user3.Name, repo3.Name, "topicName", token4)
|
||||
MakeRequest(t, req, http.StatusForbidden)
|
||||
}
|
65
tests/integration/api_settings_test.go
Normal file
65
tests/integration/api_settings_test.go
Normal file
|
@ -0,0 +1,65 @@
|
|||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIExposedSettings(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
ui := new(api.GeneralUISettings)
|
||||
req := NewRequest(t, "GET", "/api/v1/settings/ui")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
DecodeJSON(t, resp, &ui)
|
||||
assert.Len(t, ui.AllowedReactions, len(setting.UI.Reactions))
|
||||
assert.ElementsMatch(t, setting.UI.Reactions, ui.AllowedReactions)
|
||||
|
||||
apiSettings := new(api.GeneralAPISettings)
|
||||
req = NewRequest(t, "GET", "/api/v1/settings/api")
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
DecodeJSON(t, resp, &apiSettings)
|
||||
assert.EqualValues(t, &api.GeneralAPISettings{
|
||||
MaxResponseItems: setting.API.MaxResponseItems,
|
||||
DefaultPagingNum: setting.API.DefaultPagingNum,
|
||||
DefaultGitTreesPerPage: setting.API.DefaultGitTreesPerPage,
|
||||
DefaultMaxBlobSize: setting.API.DefaultMaxBlobSize,
|
||||
}, apiSettings)
|
||||
|
||||
repo := new(api.GeneralRepoSettings)
|
||||
req = NewRequest(t, "GET", "/api/v1/settings/repository")
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
DecodeJSON(t, resp, &repo)
|
||||
assert.EqualValues(t, &api.GeneralRepoSettings{
|
||||
MirrorsDisabled: !setting.Mirror.Enabled,
|
||||
HTTPGitDisabled: setting.Repository.DisableHTTPGit,
|
||||
MigrationsDisabled: setting.Repository.DisableMigrations,
|
||||
TimeTrackingDisabled: false,
|
||||
LFSDisabled: !setting.LFS.StartServer,
|
||||
}, repo)
|
||||
|
||||
attachment := new(api.GeneralAttachmentSettings)
|
||||
req = NewRequest(t, "GET", "/api/v1/settings/attachment")
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
DecodeJSON(t, resp, &attachment)
|
||||
assert.EqualValues(t, &api.GeneralAttachmentSettings{
|
||||
Enabled: setting.Attachment.Enabled,
|
||||
AllowedTypes: setting.Attachment.AllowedTypes,
|
||||
MaxFiles: setting.Attachment.MaxFiles,
|
||||
MaxSize: setting.Attachment.MaxSize,
|
||||
}, attachment)
|
||||
}
|
268
tests/integration/api_team_test.go
Normal file
268
tests/integration/api_team_test.go
Normal file
|
@ -0,0 +1,268 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
"code.gitea.io/gitea/models/repo"
|
||||
"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/convert"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPITeam(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
teamUser := unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{})
|
||||
team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamUser.TeamID})
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: teamUser.UID})
|
||||
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "GET", "/api/v1/teams/%d?token="+token, teamUser.TeamID)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var apiTeam api.Team
|
||||
DecodeJSON(t, resp, &apiTeam)
|
||||
assert.EqualValues(t, team.ID, apiTeam.ID)
|
||||
assert.Equal(t, team.Name, apiTeam.Name)
|
||||
|
||||
// non team member user will not access the teams details
|
||||
teamUser2 := unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{ID: 3})
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: teamUser2.UID})
|
||||
|
||||
session = loginUser(t, user2.Name)
|
||||
token = getTokenForLoggedInUser(t, session)
|
||||
req = NewRequestf(t, "GET", "/api/v1/teams/%d?token="+token, teamUser.TeamID)
|
||||
_ = session.MakeRequest(t, req, http.StatusForbidden)
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/teams/%d", teamUser.TeamID)
|
||||
_ = session.MakeRequest(t, req, http.StatusUnauthorized)
|
||||
|
||||
// Get an admin user able to create, update and delete teams.
|
||||
user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||
session = loginUser(t, user.Name)
|
||||
token = getTokenForLoggedInUser(t, session)
|
||||
|
||||
org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 6})
|
||||
|
||||
// Create team.
|
||||
teamToCreate := &api.CreateTeamOption{
|
||||
Name: "team1",
|
||||
Description: "team one",
|
||||
IncludesAllRepositories: true,
|
||||
Permission: "write",
|
||||
Units: []string{"repo.code", "repo.issues"},
|
||||
}
|
||||
req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/orgs/%s/teams?token=%s", org.Name, token), teamToCreate)
|
||||
resp = session.MakeRequest(t, req, http.StatusCreated)
|
||||
apiTeam = api.Team{}
|
||||
DecodeJSON(t, resp, &apiTeam)
|
||||
checkTeamResponse(t, "CreateTeam1", &apiTeam, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories,
|
||||
teamToCreate.Permission, teamToCreate.Units, nil)
|
||||
checkTeamBean(t, apiTeam.ID, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories,
|
||||
teamToCreate.Permission, teamToCreate.Units, nil)
|
||||
teamID := apiTeam.ID
|
||||
|
||||
// Edit team.
|
||||
editDescription := "team 1"
|
||||
editFalse := false
|
||||
teamToEdit := &api.EditTeamOption{
|
||||
Name: "teamone",
|
||||
Description: &editDescription,
|
||||
Permission: "admin",
|
||||
IncludesAllRepositories: &editFalse,
|
||||
Units: []string{"repo.code", "repo.pulls", "repo.releases"},
|
||||
}
|
||||
|
||||
req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/teams/%d?token=%s", teamID, token), teamToEdit)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
apiTeam = api.Team{}
|
||||
DecodeJSON(t, resp, &apiTeam)
|
||||
checkTeamResponse(t, "EditTeam1", &apiTeam, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories,
|
||||
teamToEdit.Permission, unit.AllUnitKeyNames(), nil)
|
||||
checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories,
|
||||
teamToEdit.Permission, unit.AllUnitKeyNames(), nil)
|
||||
|
||||
// Edit team Description only
|
||||
editDescription = "first team"
|
||||
teamToEditDesc := api.EditTeamOption{Description: &editDescription}
|
||||
req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/teams/%d?token=%s", teamID, token), teamToEditDesc)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
apiTeam = api.Team{}
|
||||
DecodeJSON(t, resp, &apiTeam)
|
||||
checkTeamResponse(t, "EditTeam1_DescOnly", &apiTeam, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories,
|
||||
teamToEdit.Permission, unit.AllUnitKeyNames(), nil)
|
||||
checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories,
|
||||
teamToEdit.Permission, unit.AllUnitKeyNames(), nil)
|
||||
|
||||
// Read team.
|
||||
teamRead := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID})
|
||||
assert.NoError(t, teamRead.GetUnits())
|
||||
req = NewRequestf(t, "GET", "/api/v1/teams/%d?token="+token, teamID)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
apiTeam = api.Team{}
|
||||
DecodeJSON(t, resp, &apiTeam)
|
||||
checkTeamResponse(t, "ReadTeam1", &apiTeam, teamRead.Name, *teamToEditDesc.Description, teamRead.IncludesAllRepositories,
|
||||
teamRead.AccessMode.String(), teamRead.GetUnitNames(), teamRead.GetUnitsMap())
|
||||
|
||||
// Delete team.
|
||||
req = NewRequestf(t, "DELETE", "/api/v1/teams/%d?token="+token, teamID)
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
unittest.AssertNotExistsBean(t, &organization.Team{ID: teamID})
|
||||
|
||||
// create team again via UnitsMap
|
||||
// Create team.
|
||||
teamToCreate = &api.CreateTeamOption{
|
||||
Name: "team2",
|
||||
Description: "team two",
|
||||
IncludesAllRepositories: true,
|
||||
Permission: "write",
|
||||
UnitsMap: map[string]string{"repo.code": "read", "repo.issues": "write", "repo.wiki": "none"},
|
||||
}
|
||||
req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/orgs/%s/teams?token=%s", org.Name, token), teamToCreate)
|
||||
resp = session.MakeRequest(t, req, http.StatusCreated)
|
||||
apiTeam = api.Team{}
|
||||
DecodeJSON(t, resp, &apiTeam)
|
||||
checkTeamResponse(t, "CreateTeam2", &apiTeam, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories,
|
||||
"read", nil, teamToCreate.UnitsMap)
|
||||
checkTeamBean(t, apiTeam.ID, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories,
|
||||
"read", nil, teamToCreate.UnitsMap)
|
||||
teamID = apiTeam.ID
|
||||
|
||||
// Edit team.
|
||||
editDescription = "team 1"
|
||||
editFalse = false
|
||||
teamToEdit = &api.EditTeamOption{
|
||||
Name: "teamtwo",
|
||||
Description: &editDescription,
|
||||
Permission: "write",
|
||||
IncludesAllRepositories: &editFalse,
|
||||
UnitsMap: map[string]string{"repo.code": "read", "repo.pulls": "read", "repo.releases": "write"},
|
||||
}
|
||||
|
||||
req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/teams/%d?token=%s", teamID, token), teamToEdit)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
apiTeam = api.Team{}
|
||||
DecodeJSON(t, resp, &apiTeam)
|
||||
checkTeamResponse(t, "EditTeam2", &apiTeam, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories,
|
||||
"read", nil, teamToEdit.UnitsMap)
|
||||
checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories,
|
||||
"read", nil, teamToEdit.UnitsMap)
|
||||
|
||||
// Edit team Description only
|
||||
editDescription = "second team"
|
||||
teamToEditDesc = api.EditTeamOption{Description: &editDescription}
|
||||
req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/teams/%d?token=%s", teamID, token), teamToEditDesc)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
apiTeam = api.Team{}
|
||||
DecodeJSON(t, resp, &apiTeam)
|
||||
checkTeamResponse(t, "EditTeam2_DescOnly", &apiTeam, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories,
|
||||
"read", nil, teamToEdit.UnitsMap)
|
||||
checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories,
|
||||
"read", nil, teamToEdit.UnitsMap)
|
||||
|
||||
// Read team.
|
||||
teamRead = unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID})
|
||||
req = NewRequestf(t, "GET", "/api/v1/teams/%d?token="+token, teamID)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
apiTeam = api.Team{}
|
||||
DecodeJSON(t, resp, &apiTeam)
|
||||
assert.NoError(t, teamRead.GetUnits())
|
||||
checkTeamResponse(t, "ReadTeam2", &apiTeam, teamRead.Name, *teamToEditDesc.Description, teamRead.IncludesAllRepositories,
|
||||
teamRead.AccessMode.String(), teamRead.GetUnitNames(), teamRead.GetUnitsMap())
|
||||
|
||||
// Delete team.
|
||||
req = NewRequestf(t, "DELETE", "/api/v1/teams/%d?token="+token, teamID)
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
unittest.AssertNotExistsBean(t, &organization.Team{ID: teamID})
|
||||
}
|
||||
|
||||
func checkTeamResponse(t *testing.T, testName string, apiTeam *api.Team, name, description string, includesAllRepositories bool, permission string, units []string, unitsMap map[string]string) {
|
||||
t.Run(testName, func(t *testing.T) {
|
||||
assert.Equal(t, name, apiTeam.Name, "name")
|
||||
assert.Equal(t, description, apiTeam.Description, "description")
|
||||
assert.Equal(t, includesAllRepositories, apiTeam.IncludesAllRepositories, "includesAllRepositories")
|
||||
assert.Equal(t, permission, apiTeam.Permission, "permission")
|
||||
if units != nil {
|
||||
sort.StringSlice(units).Sort()
|
||||
sort.StringSlice(apiTeam.Units).Sort()
|
||||
assert.EqualValues(t, units, apiTeam.Units, "units")
|
||||
}
|
||||
if unitsMap != nil {
|
||||
assert.EqualValues(t, unitsMap, apiTeam.UnitsMap, "unitsMap")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func checkTeamBean(t *testing.T, id int64, name, description string, includesAllRepositories bool, permission string, units []string, unitsMap map[string]string) {
|
||||
team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: id})
|
||||
assert.NoError(t, team.GetUnits(), "GetUnits")
|
||||
apiTeam, err := convert.ToTeam(team)
|
||||
assert.NoError(t, err)
|
||||
checkTeamResponse(t, fmt.Sprintf("checkTeamBean/%s_%s", name, description), apiTeam, name, description, includesAllRepositories, permission, units, unitsMap)
|
||||
}
|
||||
|
||||
type TeamSearchResults struct {
|
||||
OK bool `json:"ok"`
|
||||
Data []*api.Team `json:"data"`
|
||||
}
|
||||
|
||||
func TestAPITeamSearch(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 17})
|
||||
|
||||
var results TeamSearchResults
|
||||
|
||||
token := getUserToken(t, user.Name)
|
||||
req := NewRequestf(t, "GET", "/api/v1/orgs/%s/teams/search?q=%s&token=%s", org.Name, "_team", token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &results)
|
||||
assert.NotEmpty(t, results.Data)
|
||||
assert.Len(t, results.Data, 1)
|
||||
assert.Equal(t, "test_team", results.Data[0].Name)
|
||||
|
||||
// no access if not organization member
|
||||
user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
|
||||
token5 := getUserToken(t, user5.Name)
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/teams/search?q=%s&token=%s", org.Name, "team", token5)
|
||||
MakeRequest(t, req, http.StatusForbidden)
|
||||
}
|
||||
|
||||
func TestAPIGetTeamRepo(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15})
|
||||
teamRepo := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 24})
|
||||
team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 5})
|
||||
|
||||
var results api.Repository
|
||||
|
||||
token := getUserToken(t, user.Name)
|
||||
req := NewRequestf(t, "GET", "/api/v1/teams/%d/repos/%s/?token=%s", team.ID, teamRepo.FullName(), token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &results)
|
||||
assert.Equal(t, "big_test_private_4", teamRepo.Name)
|
||||
|
||||
// no access if not organization member
|
||||
user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
|
||||
token5 := getUserToken(t, user5.Name)
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/teams/%d/repos/%s/?token=%s", team.ID, teamRepo.FullName(), token5)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
46
tests/integration/api_team_user_test.go
Normal file
46
tests/integration/api_team_user_test.go
Normal file
|
@ -0,0 +1,46 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/convert"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPITeamUser(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
normalUsername := "user2"
|
||||
session := loginUser(t, normalUsername)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequest(t, "GET", "/api/v1/teams/1/members/user1?token="+token)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequest(t, "GET", "/api/v1/teams/1/members/user2?token="+token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var user2 *api.User
|
||||
DecodeJSON(t, resp, &user2)
|
||||
user2.Created = user2.Created.In(time.Local)
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user2"})
|
||||
|
||||
expectedUser := convert.ToUser(user, user)
|
||||
|
||||
// test time via unix timestamp
|
||||
assert.EqualValues(t, expectedUser.LastLogin.Unix(), user2.LastLogin.Unix())
|
||||
assert.EqualValues(t, expectedUser.Created.Unix(), user2.Created.Unix())
|
||||
expectedUser.LastLogin = user2.LastLogin
|
||||
expectedUser.Created = user2.Created
|
||||
|
||||
assert.Equal(t, expectedUser, user2)
|
||||
}
|
66
tests/integration/api_token_test.go
Normal file
66
tests/integration/api_token_test.go
Normal file
|
@ -0,0 +1,66 @@
|
|||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
// TestAPICreateAndDeleteToken tests that token that was just created can be deleted
|
||||
func TestAPICreateAndDeleteToken(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/users/user1/tokens", map[string]string{
|
||||
"name": "test-key-1",
|
||||
})
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
var newAccessToken api.AccessToken
|
||||
DecodeJSON(t, resp, &newAccessToken)
|
||||
unittest.AssertExistsAndLoadBean(t, &auth_model.AccessToken{
|
||||
ID: newAccessToken.ID,
|
||||
Name: newAccessToken.Name,
|
||||
Token: newAccessToken.Token,
|
||||
UID: user.ID,
|
||||
})
|
||||
|
||||
req = NewRequestf(t, "DELETE", "/api/v1/users/user1/tokens/%d", newAccessToken.ID)
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
unittest.AssertNotExistsBean(t, &auth_model.AccessToken{ID: newAccessToken.ID})
|
||||
|
||||
req = NewRequestWithJSON(t, "POST", "/api/v1/users/user1/tokens", map[string]string{
|
||||
"name": "test-key-2",
|
||||
})
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp = MakeRequest(t, req, http.StatusCreated)
|
||||
DecodeJSON(t, resp, &newAccessToken)
|
||||
|
||||
req = NewRequestf(t, "DELETE", "/api/v1/users/user1/tokens/%s", newAccessToken.Name)
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
unittest.AssertNotExistsBean(t, &auth_model.AccessToken{ID: newAccessToken.ID})
|
||||
}
|
||||
|
||||
// TestAPIDeleteMissingToken ensures that error is thrown when token not found
|
||||
func TestAPIDeleteMissingToken(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||
|
||||
req := NewRequestf(t, "DELETE", "/api/v1/users/user1/tokens/%d", unittest.NonexistentID)
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
112
tests/integration/api_user_email_test.go
Normal file
112
tests/integration/api_user_email_test.go
Normal file
|
@ -0,0 +1,112 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIListEmails(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
normalUsername := "user2"
|
||||
session := loginUser(t, normalUsername)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
req := NewRequest(t, "GET", "/api/v1/user/emails?token="+token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var emails []*api.Email
|
||||
DecodeJSON(t, resp, &emails)
|
||||
|
||||
assert.EqualValues(t, []*api.Email{
|
||||
{
|
||||
Email: "user2@example.com",
|
||||
Verified: true,
|
||||
Primary: true,
|
||||
},
|
||||
{
|
||||
Email: "user2-2@example.com",
|
||||
Verified: false,
|
||||
Primary: false,
|
||||
},
|
||||
}, emails)
|
||||
}
|
||||
|
||||
func TestAPIAddEmail(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
normalUsername := "user2"
|
||||
session := loginUser(t, normalUsername)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
opts := api.CreateEmailOption{
|
||||
Emails: []string{"user101@example.com"},
|
||||
}
|
||||
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/user/emails?token="+token, &opts)
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
|
||||
opts = api.CreateEmailOption{
|
||||
Emails: []string{"user2-3@example.com"},
|
||||
}
|
||||
req = NewRequestWithJSON(t, "POST", "/api/v1/user/emails?token="+token, &opts)
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
var emails []*api.Email
|
||||
DecodeJSON(t, resp, &emails)
|
||||
assert.EqualValues(t, []*api.Email{
|
||||
{
|
||||
Email: "user2-3@example.com",
|
||||
Verified: true,
|
||||
Primary: false,
|
||||
},
|
||||
}, emails)
|
||||
|
||||
opts = api.CreateEmailOption{
|
||||
Emails: []string{"notAEmail"},
|
||||
}
|
||||
req = NewRequestWithJSON(t, "POST", "/api/v1/user/emails?token="+token, &opts)
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
}
|
||||
|
||||
func TestAPIDeleteEmail(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
normalUsername := "user2"
|
||||
session := loginUser(t, normalUsername)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
opts := api.DeleteEmailOption{
|
||||
Emails: []string{"user2-3@example.com"},
|
||||
}
|
||||
req := NewRequestWithJSON(t, "DELETE", "/api/v1/user/emails?token="+token, &opts)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
opts = api.DeleteEmailOption{
|
||||
Emails: []string{"user2-2@example.com"},
|
||||
}
|
||||
req = NewRequestWithJSON(t, "DELETE", "/api/v1/user/emails?token="+token, &opts)
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
req = NewRequest(t, "GET", "/api/v1/user/emails?token="+token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var emails []*api.Email
|
||||
DecodeJSON(t, resp, &emails)
|
||||
assert.EqualValues(t, []*api.Email{
|
||||
{
|
||||
Email: "user2@example.com",
|
||||
Verified: true,
|
||||
Primary: true,
|
||||
},
|
||||
}, emails)
|
||||
}
|
39
tests/integration/api_user_heatmap_test.go
Normal file
39
tests/integration/api_user_heatmap_test.go
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.package models
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
activities_model "code.gitea.io/gitea/models/activities"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUserHeatmap(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
adminUsername := "user1"
|
||||
normalUsername := "user2"
|
||||
token := getUserToken(t, adminUsername)
|
||||
|
||||
fakeNow := time.Date(2011, 10, 20, 0, 0, 0, 0, time.Local)
|
||||
timeutil.Set(fakeNow)
|
||||
defer timeutil.Unset()
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/users/%s/heatmap?token=%s", normalUsername, token)
|
||||
req := NewRequest(t, "GET", urlStr)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
var heatmap []*activities_model.UserHeatmapData
|
||||
DecodeJSON(t, resp, &heatmap)
|
||||
var dummyheatmap []*activities_model.UserHeatmapData
|
||||
dummyheatmap = append(dummyheatmap, &activities_model.UserHeatmapData{Timestamp: 1603227600, Contributions: 1})
|
||||
|
||||
assert.Equal(t, dummyheatmap, heatmap)
|
||||
}
|
151
tests/integration/api_user_org_perm_test.go
Normal file
151
tests/integration/api_user_org_perm_test.go
Normal file
|
@ -0,0 +1,151 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type apiUserOrgPermTestCase struct {
|
||||
LoginUser string
|
||||
User string
|
||||
Organization string
|
||||
ExpectedOrganizationPermissions api.OrganizationPermissions
|
||||
}
|
||||
|
||||
func TestTokenNeeded(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
session := emptyTestSession(t)
|
||||
req := NewRequest(t, "GET", "/api/v1/users/user1/orgs/user6/permissions")
|
||||
session.MakeRequest(t, req, http.StatusUnauthorized)
|
||||
}
|
||||
|
||||
func sampleTest(t *testing.T, auoptc apiUserOrgPermTestCase) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
session := loginUser(t, auoptc.LoginUser)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/users/%s/orgs/%s/permissions?token=%s", auoptc.User, auoptc.Organization, token))
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var apiOP api.OrganizationPermissions
|
||||
DecodeJSON(t, resp, &apiOP)
|
||||
assert.Equal(t, auoptc.ExpectedOrganizationPermissions.IsOwner, apiOP.IsOwner)
|
||||
assert.Equal(t, auoptc.ExpectedOrganizationPermissions.IsAdmin, apiOP.IsAdmin)
|
||||
assert.Equal(t, auoptc.ExpectedOrganizationPermissions.CanWrite, apiOP.CanWrite)
|
||||
assert.Equal(t, auoptc.ExpectedOrganizationPermissions.CanRead, apiOP.CanRead)
|
||||
assert.Equal(t, auoptc.ExpectedOrganizationPermissions.CanCreateRepository, apiOP.CanCreateRepository)
|
||||
}
|
||||
|
||||
func TestWithOwnerUser(t *testing.T) {
|
||||
sampleTest(t, apiUserOrgPermTestCase{
|
||||
LoginUser: "user2",
|
||||
User: "user2",
|
||||
Organization: "user3",
|
||||
ExpectedOrganizationPermissions: api.OrganizationPermissions{
|
||||
IsOwner: true,
|
||||
IsAdmin: true,
|
||||
CanWrite: true,
|
||||
CanRead: true,
|
||||
CanCreateRepository: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestCanWriteUser(t *testing.T) {
|
||||
sampleTest(t, apiUserOrgPermTestCase{
|
||||
LoginUser: "user4",
|
||||
User: "user4",
|
||||
Organization: "user3",
|
||||
ExpectedOrganizationPermissions: api.OrganizationPermissions{
|
||||
IsOwner: false,
|
||||
IsAdmin: false,
|
||||
CanWrite: true,
|
||||
CanRead: true,
|
||||
CanCreateRepository: false,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAdminUser(t *testing.T) {
|
||||
sampleTest(t, apiUserOrgPermTestCase{
|
||||
LoginUser: "user1",
|
||||
User: "user28",
|
||||
Organization: "user3",
|
||||
ExpectedOrganizationPermissions: api.OrganizationPermissions{
|
||||
IsOwner: false,
|
||||
IsAdmin: true,
|
||||
CanWrite: true,
|
||||
CanRead: true,
|
||||
CanCreateRepository: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAdminCanNotCreateRepo(t *testing.T) {
|
||||
sampleTest(t, apiUserOrgPermTestCase{
|
||||
LoginUser: "user1",
|
||||
User: "user28",
|
||||
Organization: "user6",
|
||||
ExpectedOrganizationPermissions: api.OrganizationPermissions{
|
||||
IsOwner: false,
|
||||
IsAdmin: true,
|
||||
CanWrite: true,
|
||||
CanRead: true,
|
||||
CanCreateRepository: false,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestCanReadUser(t *testing.T) {
|
||||
sampleTest(t, apiUserOrgPermTestCase{
|
||||
LoginUser: "user1",
|
||||
User: "user24",
|
||||
Organization: "org25",
|
||||
ExpectedOrganizationPermissions: api.OrganizationPermissions{
|
||||
IsOwner: false,
|
||||
IsAdmin: false,
|
||||
CanWrite: false,
|
||||
CanRead: true,
|
||||
CanCreateRepository: false,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestUnknowUser(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
session := loginUser(t, "user1")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/users/unknow/orgs/org25/permissions?token=%s", token))
|
||||
resp := session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
var apiError api.APIError
|
||||
DecodeJSON(t, resp, &apiError)
|
||||
assert.Equal(t, "user redirect does not exist [name: unknow]", apiError.Message)
|
||||
}
|
||||
|
||||
func TestUnknowOrganization(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
session := loginUser(t, "user1")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/users/user1/orgs/unknow/permissions?token=%s", token))
|
||||
resp := session.MakeRequest(t, req, http.StatusNotFound)
|
||||
var apiError api.APIError
|
||||
DecodeJSON(t, resp, &apiError)
|
||||
assert.Equal(t, "GetUserByName", apiError.Message)
|
||||
}
|
121
tests/integration/api_user_orgs_test.go
Normal file
121
tests/integration/api_user_orgs_test.go
Normal file
|
@ -0,0 +1,121 @@
|
|||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.package models
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"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 TestUserOrgs(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
adminUsername := "user1"
|
||||
normalUsername := "user2"
|
||||
privateMemberUsername := "user4"
|
||||
unrelatedUsername := "user5"
|
||||
|
||||
orgs := getUserOrgs(t, adminUsername, normalUsername)
|
||||
|
||||
user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user3"})
|
||||
user17 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user17"})
|
||||
|
||||
assert.Equal(t, []*api.Organization{
|
||||
{
|
||||
ID: 17,
|
||||
UserName: user17.Name,
|
||||
FullName: user17.FullName,
|
||||
AvatarURL: user17.AvatarLink(),
|
||||
Description: "",
|
||||
Website: "",
|
||||
Location: "",
|
||||
Visibility: "public",
|
||||
},
|
||||
{
|
||||
ID: 3,
|
||||
UserName: user3.Name,
|
||||
FullName: user3.FullName,
|
||||
AvatarURL: user3.AvatarLink(),
|
||||
Description: "",
|
||||
Website: "",
|
||||
Location: "",
|
||||
Visibility: "public",
|
||||
},
|
||||
}, orgs)
|
||||
|
||||
// user itself should get it's org's he is a member of
|
||||
orgs = getUserOrgs(t, privateMemberUsername, privateMemberUsername)
|
||||
assert.Len(t, orgs, 1)
|
||||
|
||||
// unrelated user should not get private org membership of privateMemberUsername
|
||||
orgs = getUserOrgs(t, unrelatedUsername, privateMemberUsername)
|
||||
assert.Len(t, orgs, 0)
|
||||
|
||||
// not authenticated call also should hide org membership
|
||||
orgs = getUserOrgs(t, "", privateMemberUsername)
|
||||
assert.Len(t, orgs, 0)
|
||||
}
|
||||
|
||||
func getUserOrgs(t *testing.T, userDoer, userCheck string) (orgs []*api.Organization) {
|
||||
token := ""
|
||||
session := emptyTestSession(t)
|
||||
if len(userDoer) != 0 {
|
||||
session = loginUser(t, userDoer)
|
||||
token = getTokenForLoggedInUser(t, session)
|
||||
}
|
||||
urlStr := fmt.Sprintf("/api/v1/users/%s/orgs?token=%s", userCheck, token)
|
||||
req := NewRequest(t, "GET", urlStr)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &orgs)
|
||||
return orgs
|
||||
}
|
||||
|
||||
func TestMyOrgs(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
session := emptyTestSession(t)
|
||||
req := NewRequest(t, "GET", "/api/v1/user/orgs")
|
||||
session.MakeRequest(t, req, http.StatusUnauthorized)
|
||||
|
||||
normalUsername := "user2"
|
||||
session = loginUser(t, normalUsername)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req = NewRequest(t, "GET", "/api/v1/user/orgs?token="+token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var orgs []*api.Organization
|
||||
DecodeJSON(t, resp, &orgs)
|
||||
user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user3"})
|
||||
user17 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user17"})
|
||||
|
||||
assert.Equal(t, []*api.Organization{
|
||||
{
|
||||
ID: 17,
|
||||
UserName: user17.Name,
|
||||
FullName: user17.FullName,
|
||||
AvatarURL: user17.AvatarLink(),
|
||||
Description: "",
|
||||
Website: "",
|
||||
Location: "",
|
||||
Visibility: "public",
|
||||
},
|
||||
{
|
||||
ID: 3,
|
||||
UserName: user3.Name,
|
||||
FullName: user3.FullName,
|
||||
AvatarURL: user3.AvatarLink(),
|
||||
Description: "",
|
||||
Website: "",
|
||||
Location: "",
|
||||
Visibility: "public",
|
||||
},
|
||||
}, orgs)
|
||||
}
|
94
tests/integration/api_user_search_test.go
Normal file
94
tests/integration/api_user_search_test.go
Normal file
|
@ -0,0 +1,94 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.package models
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"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/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type SearchResults struct {
|
||||
OK bool `json:"ok"`
|
||||
Data []*api.User `json:"data"`
|
||||
}
|
||||
|
||||
func TestAPIUserSearchLoggedIn(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
adminUsername := "user1"
|
||||
session := loginUser(t, adminUsername)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
query := "user2"
|
||||
req := NewRequestf(t, "GET", "/api/v1/users/search?token=%s&q=%s", token, query)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var results SearchResults
|
||||
DecodeJSON(t, resp, &results)
|
||||
assert.NotEmpty(t, results.Data)
|
||||
for _, user := range results.Data {
|
||||
assert.Contains(t, user.UserName, query)
|
||||
assert.NotEmpty(t, user.Email)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIUserSearchNotLoggedIn(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
query := "user2"
|
||||
req := NewRequestf(t, "GET", "/api/v1/users/search?q=%s", query)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var results SearchResults
|
||||
DecodeJSON(t, resp, &results)
|
||||
assert.NotEmpty(t, results.Data)
|
||||
var modelUser *user_model.User
|
||||
for _, user := range results.Data {
|
||||
assert.Contains(t, user.UserName, query)
|
||||
modelUser = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: user.ID})
|
||||
if modelUser.KeepEmailPrivate {
|
||||
assert.EqualValues(t, fmt.Sprintf("%s@%s", modelUser.LowerName, setting.Service.NoReplyAddress), user.Email)
|
||||
} else {
|
||||
assert.EqualValues(t, modelUser.Email, user.Email)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIUserSearchAdminLoggedInUserHidden(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
adminUsername := "user1"
|
||||
session := loginUser(t, adminUsername)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
query := "user31"
|
||||
req := NewRequestf(t, "GET", "/api/v1/users/search?token=%s&q=%s", token, query)
|
||||
req.SetBasicAuth(token, "x-oauth-basic")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var results SearchResults
|
||||
DecodeJSON(t, resp, &results)
|
||||
assert.NotEmpty(t, results.Data)
|
||||
for _, user := range results.Data {
|
||||
assert.Contains(t, user.UserName, query)
|
||||
assert.NotEmpty(t, user.Email)
|
||||
assert.EqualValues(t, "private", user.Visibility)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIUserSearchNotLoggedInUserHidden(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
query := "user31"
|
||||
req := NewRequestf(t, "GET", "/api/v1/users/search?q=%s", query)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var results SearchResults
|
||||
DecodeJSON(t, resp, &results)
|
||||
assert.Empty(t, results.Data)
|
||||
}
|
252
tests/integration/api_wiki_test.go
Normal file
252
tests/integration/api_wiki_test.go
Normal file
|
@ -0,0 +1,252 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIGetWikiPage(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
username := "user2"
|
||||
session := loginUser(t, username)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/wiki/page/Home", username, "repo1")
|
||||
|
||||
req := NewRequest(t, "GET", urlStr)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var page *api.WikiPage
|
||||
DecodeJSON(t, resp, &page)
|
||||
|
||||
assert.Equal(t, &api.WikiPage{
|
||||
WikiPageMetaData: &api.WikiPageMetaData{
|
||||
Title: "Home",
|
||||
HTMLURL: page.HTMLURL,
|
||||
SubURL: "Home",
|
||||
LastCommit: &api.WikiCommit{
|
||||
ID: "2c54faec6c45d31c1abfaecdab471eac6633738a",
|
||||
Author: &api.CommitUser{
|
||||
Identity: api.Identity{
|
||||
Name: "Ethan Koenig",
|
||||
Email: "ethantkoenig@gmail.com",
|
||||
},
|
||||
Date: "2017-11-27T04:31:18Z",
|
||||
},
|
||||
Committer: &api.CommitUser{
|
||||
Identity: api.Identity{
|
||||
Name: "Ethan Koenig",
|
||||
Email: "ethantkoenig@gmail.com",
|
||||
},
|
||||
Date: "2017-11-27T04:31:18Z",
|
||||
},
|
||||
Message: "Add Home.md\n",
|
||||
},
|
||||
},
|
||||
ContentBase64: base64.RawStdEncoding.EncodeToString(
|
||||
[]byte("# Home page\n\nThis is the home page!\n"),
|
||||
),
|
||||
CommitCount: 1,
|
||||
Sidebar: "",
|
||||
Footer: "",
|
||||
}, page)
|
||||
}
|
||||
|
||||
func TestAPIListWikiPages(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
username := "user2"
|
||||
session := loginUser(t, username)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/wiki/pages", username, "repo1")
|
||||
|
||||
req := NewRequest(t, "GET", urlStr)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var meta []*api.WikiPageMetaData
|
||||
DecodeJSON(t, resp, &meta)
|
||||
|
||||
dummymeta := []*api.WikiPageMetaData{
|
||||
{
|
||||
Title: "Home",
|
||||
HTMLURL: meta[0].HTMLURL,
|
||||
SubURL: "Home",
|
||||
LastCommit: &api.WikiCommit{
|
||||
ID: "2c54faec6c45d31c1abfaecdab471eac6633738a",
|
||||
Author: &api.CommitUser{
|
||||
Identity: api.Identity{
|
||||
Name: "Ethan Koenig",
|
||||
Email: "ethantkoenig@gmail.com",
|
||||
},
|
||||
Date: "2017-11-27T04:31:18Z",
|
||||
},
|
||||
Committer: &api.CommitUser{
|
||||
Identity: api.Identity{
|
||||
Name: "Ethan Koenig",
|
||||
Email: "ethantkoenig@gmail.com",
|
||||
},
|
||||
Date: "2017-11-27T04:31:18Z",
|
||||
},
|
||||
Message: "Add Home.md\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
Title: "Page With Image",
|
||||
HTMLURL: meta[1].HTMLURL,
|
||||
SubURL: "Page-With-Image",
|
||||
LastCommit: &api.WikiCommit{
|
||||
ID: "0cf15c3f66ec8384480ed9c3cf87c9e97fbb0ec3",
|
||||
Author: &api.CommitUser{
|
||||
Identity: api.Identity{
|
||||
Name: "Gabriel Silva Simões",
|
||||
Email: "simoes.sgabriel@gmail.com",
|
||||
},
|
||||
Date: "2019-01-25T01:41:55Z",
|
||||
},
|
||||
Committer: &api.CommitUser{
|
||||
Identity: api.Identity{
|
||||
Name: "Gabriel Silva Simões",
|
||||
Email: "simoes.sgabriel@gmail.com",
|
||||
},
|
||||
Date: "2019-01-25T01:41:55Z",
|
||||
},
|
||||
Message: "Add jpeg.jpg and page with image\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
Title: "Page With Spaced Name",
|
||||
HTMLURL: meta[2].HTMLURL,
|
||||
SubURL: "Page-With-Spaced-Name",
|
||||
LastCommit: &api.WikiCommit{
|
||||
ID: "c10d10b7e655b3dab1f53176db57c8219a5488d6",
|
||||
Author: &api.CommitUser{
|
||||
Identity: api.Identity{
|
||||
Name: "Gabriel Silva Simões",
|
||||
Email: "simoes.sgabriel@gmail.com",
|
||||
},
|
||||
Date: "2019-01-25T01:39:51Z",
|
||||
},
|
||||
Committer: &api.CommitUser{
|
||||
Identity: api.Identity{
|
||||
Name: "Gabriel Silva Simões",
|
||||
Email: "simoes.sgabriel@gmail.com",
|
||||
},
|
||||
Date: "2019-01-25T01:39:51Z",
|
||||
},
|
||||
Message: "Add page with spaced name\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
Title: "Unescaped File",
|
||||
HTMLURL: meta[3].HTMLURL,
|
||||
SubURL: "Unescaped-File",
|
||||
LastCommit: &api.WikiCommit{
|
||||
ID: "0dca5bd9b5d7ef937710e056f575e86c0184ba85",
|
||||
Author: &api.CommitUser{
|
||||
Identity: api.Identity{
|
||||
Name: "6543",
|
||||
Email: "6543@obermui.de",
|
||||
},
|
||||
Date: "2021-07-19T16:42:46Z",
|
||||
},
|
||||
Committer: &api.CommitUser{
|
||||
Identity: api.Identity{
|
||||
Name: "6543",
|
||||
Email: "6543@obermui.de",
|
||||
},
|
||||
Date: "2021-07-19T16:42:46Z",
|
||||
},
|
||||
Message: "add unescaped file\n",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.Equal(t, dummymeta, meta)
|
||||
}
|
||||
|
||||
func TestAPINewWikiPage(t *testing.T) {
|
||||
for _, title := range []string{
|
||||
"New page",
|
||||
"&&&&",
|
||||
} {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
username := "user2"
|
||||
session := loginUser(t, username)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/wiki/new?token=%s", username, "repo1", token)
|
||||
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateWikiPageOptions{
|
||||
Title: title,
|
||||
ContentBase64: base64.StdEncoding.EncodeToString([]byte("Wiki page content for API unit tests")),
|
||||
Message: "",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusCreated)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIEditWikiPage(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
username := "user2"
|
||||
session := loginUser(t, username)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/wiki/page/Page-With-Spaced-Name?token=%s", username, "repo1", token)
|
||||
|
||||
req := NewRequestWithJSON(t, "PATCH", urlStr, &api.CreateWikiPageOptions{
|
||||
Title: "edited title",
|
||||
ContentBase64: base64.StdEncoding.EncodeToString([]byte("Edited wiki page content for API unit tests")),
|
||||
Message: "",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
|
||||
func TestAPIListPageRevisions(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
username := "user2"
|
||||
session := loginUser(t, username)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/wiki/revisions/Home", username, "repo1")
|
||||
|
||||
req := NewRequest(t, "GET", urlStr)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var revisions *api.WikiCommitList
|
||||
DecodeJSON(t, resp, &revisions)
|
||||
|
||||
dummyrevisions := &api.WikiCommitList{
|
||||
WikiCommits: []*api.WikiCommit{
|
||||
{
|
||||
ID: "2c54faec6c45d31c1abfaecdab471eac6633738a",
|
||||
Author: &api.CommitUser{
|
||||
Identity: api.Identity{
|
||||
Name: "Ethan Koenig",
|
||||
Email: "ethantkoenig@gmail.com",
|
||||
},
|
||||
Date: "2017-11-27T04:31:18Z",
|
||||
},
|
||||
Committer: &api.CommitUser{
|
||||
Identity: api.Identity{
|
||||
Name: "Ethan Koenig",
|
||||
Email: "ethantkoenig@gmail.com",
|
||||
},
|
||||
Date: "2017-11-27T04:31:18Z",
|
||||
},
|
||||
Message: "Add Home.md\n",
|
||||
},
|
||||
},
|
||||
Count: 1,
|
||||
}
|
||||
|
||||
assert.Equal(t, dummyrevisions, revisions)
|
||||
}
|
134
tests/integration/attachment_test.go
Normal file
134
tests/integration/attachment_test.go
Normal file
|
@ -0,0 +1,134 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"image"
|
||||
"image/png"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/modules/storage"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func generateImg() bytes.Buffer {
|
||||
// Generate image
|
||||
myImage := image.NewRGBA(image.Rect(0, 0, 32, 32))
|
||||
var buff bytes.Buffer
|
||||
png.Encode(&buff, myImage)
|
||||
return buff
|
||||
}
|
||||
|
||||
func createAttachment(t *testing.T, session *TestSession, repoURL, filename string, buff bytes.Buffer, expectedStatus int) string {
|
||||
body := &bytes.Buffer{}
|
||||
|
||||
// Setup multi-part
|
||||
writer := multipart.NewWriter(body)
|
||||
part, err := writer.CreateFormFile("file", filename)
|
||||
assert.NoError(t, err)
|
||||
_, err = io.Copy(part, &buff)
|
||||
assert.NoError(t, err)
|
||||
err = writer.Close()
|
||||
assert.NoError(t, err)
|
||||
|
||||
csrf := GetCSRF(t, session, repoURL)
|
||||
|
||||
req := NewRequestWithBody(t, "POST", repoURL+"/issues/attachments", body)
|
||||
req.Header.Add("X-Csrf-Token", csrf)
|
||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||
resp := session.MakeRequest(t, req, expectedStatus)
|
||||
|
||||
if expectedStatus != http.StatusOK {
|
||||
return ""
|
||||
}
|
||||
var obj map[string]string
|
||||
DecodeJSON(t, resp, &obj)
|
||||
return obj["uuid"]
|
||||
}
|
||||
|
||||
func TestCreateAnonymousAttachment(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
session := emptyTestSession(t)
|
||||
createAttachment(t, session, "user2/repo1", "image.png", generateImg(), http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func TestCreateIssueAttachment(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
const repoURL = "user2/repo1"
|
||||
session := loginUser(t, "user2")
|
||||
uuid := createAttachment(t, session, repoURL, "image.png", generateImg(), http.StatusOK)
|
||||
|
||||
req := NewRequest(t, "GET", repoURL+"/issues/new")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
link, exists := htmlDoc.doc.Find("form#new-issue").Attr("action")
|
||||
assert.True(t, exists, "The template has changed")
|
||||
|
||||
postData := map[string]string{
|
||||
"_csrf": htmlDoc.GetCSRF(),
|
||||
"title": "New Issue With Attachment",
|
||||
"content": "some content",
|
||||
"files": uuid,
|
||||
}
|
||||
|
||||
req = NewRequestWithValues(t, "POST", link, postData)
|
||||
resp = session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
test.RedirectURL(resp) // check that redirect URL exists
|
||||
|
||||
// Validate that attachment is available
|
||||
req = NewRequest(t, "GET", "/attachments/"+uuid)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
|
||||
func TestGetAttachment(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
adminSession := loginUser(t, "user1")
|
||||
user2Session := loginUser(t, "user2")
|
||||
user8Session := loginUser(t, "user8")
|
||||
emptySession := emptyTestSession(t)
|
||||
testCases := []struct {
|
||||
name string
|
||||
uuid string
|
||||
createFile bool
|
||||
session *TestSession
|
||||
want int
|
||||
}{
|
||||
{"LinkedIssueUUID", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", true, user2Session, http.StatusOK},
|
||||
{"LinkedCommentUUID", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a17", true, user2Session, http.StatusOK},
|
||||
{"linked_release_uuid", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a19", true, user2Session, http.StatusOK},
|
||||
{"NotExistingUUID", "b0eebc99-9c0b-4ef8-bb6d-6bb9bd380a18", false, user2Session, http.StatusNotFound},
|
||||
{"FileMissing", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a18", false, user2Session, http.StatusInternalServerError},
|
||||
{"NotLinked", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a20", true, user2Session, http.StatusNotFound},
|
||||
{"NotLinkedAccessibleByUploader", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a20", true, user8Session, http.StatusOK},
|
||||
{"PublicByNonLogged", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", true, emptySession, http.StatusOK},
|
||||
{"PrivateByNonLogged", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a12", true, emptySession, http.StatusNotFound},
|
||||
{"PrivateAccessibleByAdmin", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a12", true, adminSession, http.StatusOK},
|
||||
{"PrivateAccessibleByUser", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a12", true, user2Session, http.StatusOK},
|
||||
{"RepoNotAccessibleByUser", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a12", true, user8Session, http.StatusNotFound},
|
||||
{"OrgNotAccessibleByUser", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a21", true, user8Session, http.StatusNotFound},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// Write empty file to be available for response
|
||||
if tc.createFile {
|
||||
_, err := storage.Attachments.Save(repo_model.AttachmentRelativePath(tc.uuid), strings.NewReader("hello world"), -1)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
// Actual test
|
||||
req := NewRequest(t, "GET", "/attachments/"+tc.uuid)
|
||||
tc.session.MakeRequest(t, req, tc.want)
|
||||
})
|
||||
}
|
||||
}
|
415
tests/integration/auth_ldap_test.go
Normal file
415
tests/integration/auth_ldap_test.go
Normal file
|
@ -0,0 +1,415 @@
|
|||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
"code.gitea.io/gitea/services/auth"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type ldapUser struct {
|
||||
UserName string
|
||||
Password string
|
||||
FullName string
|
||||
Email string
|
||||
OtherEmails []string
|
||||
IsAdmin bool
|
||||
IsRestricted bool
|
||||
SSHKeys []string
|
||||
}
|
||||
|
||||
var gitLDAPUsers = []ldapUser{
|
||||
{
|
||||
UserName: "professor",
|
||||
Password: "professor",
|
||||
FullName: "Hubert Farnsworth",
|
||||
Email: "professor@planetexpress.com",
|
||||
OtherEmails: []string{"hubert@planetexpress.com"},
|
||||
IsAdmin: true,
|
||||
},
|
||||
{
|
||||
UserName: "hermes",
|
||||
Password: "hermes",
|
||||
FullName: "Conrad Hermes",
|
||||
Email: "hermes@planetexpress.com",
|
||||
SSHKeys: []string{
|
||||
"SHA256:qLY06smKfHoW/92yXySpnxFR10QFrLdRjf/GNPvwcW8",
|
||||
"SHA256:QlVTuM5OssDatqidn2ffY+Lc4YA5Fs78U+0KOHI51jQ",
|
||||
"SHA256:DXdeUKYOJCSSmClZuwrb60hUq7367j4fA+udNC3FdRI",
|
||||
},
|
||||
IsAdmin: true,
|
||||
},
|
||||
{
|
||||
UserName: "fry",
|
||||
Password: "fry",
|
||||
FullName: "Philip Fry",
|
||||
Email: "fry@planetexpress.com",
|
||||
},
|
||||
{
|
||||
UserName: "leela",
|
||||
Password: "leela",
|
||||
FullName: "Leela Turanga",
|
||||
Email: "leela@planetexpress.com",
|
||||
IsRestricted: true,
|
||||
},
|
||||
{
|
||||
UserName: "bender",
|
||||
Password: "bender",
|
||||
FullName: "Bender Rodríguez",
|
||||
Email: "bender@planetexpress.com",
|
||||
},
|
||||
}
|
||||
|
||||
var otherLDAPUsers = []ldapUser{
|
||||
{
|
||||
UserName: "zoidberg",
|
||||
Password: "zoidberg",
|
||||
FullName: "John Zoidberg",
|
||||
Email: "zoidberg@planetexpress.com",
|
||||
},
|
||||
{
|
||||
UserName: "amy",
|
||||
Password: "amy",
|
||||
FullName: "Amy Kroker",
|
||||
Email: "amy@planetexpress.com",
|
||||
},
|
||||
}
|
||||
|
||||
func skipLDAPTests() bool {
|
||||
return os.Getenv("TEST_LDAP") != "1"
|
||||
}
|
||||
|
||||
func getLDAPServerHost() string {
|
||||
host := os.Getenv("TEST_LDAP_HOST")
|
||||
if len(host) == 0 {
|
||||
host = "ldap"
|
||||
}
|
||||
return host
|
||||
}
|
||||
|
||||
func addAuthSourceLDAP(t *testing.T, sshKeyAttribute string, groupMapParams ...string) {
|
||||
groupTeamMapRemoval := "off"
|
||||
groupTeamMap := ""
|
||||
if len(groupMapParams) == 2 {
|
||||
groupTeamMapRemoval = groupMapParams[0]
|
||||
groupTeamMap = groupMapParams[1]
|
||||
}
|
||||
session := loginUser(t, "user1")
|
||||
csrf := GetCSRF(t, session, "/admin/auths/new")
|
||||
req := NewRequestWithValues(t, "POST", "/admin/auths/new", map[string]string{
|
||||
"_csrf": csrf,
|
||||
"type": "2",
|
||||
"name": "ldap",
|
||||
"host": getLDAPServerHost(),
|
||||
"port": "389",
|
||||
"bind_dn": "uid=gitea,ou=service,dc=planetexpress,dc=com",
|
||||
"bind_password": "password",
|
||||
"user_base": "ou=people,dc=planetexpress,dc=com",
|
||||
"filter": "(&(objectClass=inetOrgPerson)(memberOf=cn=git,ou=people,dc=planetexpress,dc=com)(uid=%s))",
|
||||
"admin_filter": "(memberOf=cn=admin_staff,ou=people,dc=planetexpress,dc=com)",
|
||||
"restricted_filter": "(uid=leela)",
|
||||
"attribute_username": "uid",
|
||||
"attribute_name": "givenName",
|
||||
"attribute_surname": "sn",
|
||||
"attribute_mail": "mail",
|
||||
"attribute_ssh_public_key": sshKeyAttribute,
|
||||
"is_sync_enabled": "on",
|
||||
"is_active": "on",
|
||||
"groups_enabled": "on",
|
||||
"group_dn": "ou=people,dc=planetexpress,dc=com",
|
||||
"group_member_uid": "member",
|
||||
"group_team_map": groupTeamMap,
|
||||
"group_team_map_removal": groupTeamMapRemoval,
|
||||
"user_uid": "DN",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func TestLDAPUserSignin(t *testing.T) {
|
||||
if skipLDAPTests() {
|
||||
t.Skip()
|
||||
return
|
||||
}
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
addAuthSourceLDAP(t, "")
|
||||
|
||||
u := gitLDAPUsers[0]
|
||||
|
||||
session := loginUserWithPassword(t, u.UserName, u.Password)
|
||||
req := NewRequest(t, "GET", "/user/settings")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
assert.Equal(t, u.UserName, htmlDoc.GetInputValueByName("name"))
|
||||
assert.Equal(t, u.FullName, htmlDoc.GetInputValueByName("full_name"))
|
||||
assert.Equal(t, u.Email, htmlDoc.Find(`label[for="email"]`).Siblings().First().Text())
|
||||
}
|
||||
|
||||
func TestLDAPAuthChange(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
addAuthSourceLDAP(t, "")
|
||||
|
||||
session := loginUser(t, "user1")
|
||||
req := NewRequest(t, "GET", "/admin/auths")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
href, exists := doc.Find("table.table td a").Attr("href")
|
||||
if !exists {
|
||||
assert.True(t, exists, "No authentication source found")
|
||||
return
|
||||
}
|
||||
|
||||
req = NewRequest(t, "GET", href)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
doc = NewHTMLParser(t, resp.Body)
|
||||
csrf := doc.GetCSRF()
|
||||
host, _ := doc.Find(`input[name="host"]`).Attr("value")
|
||||
assert.Equal(t, host, getLDAPServerHost())
|
||||
binddn, _ := doc.Find(`input[name="bind_dn"]`).Attr("value")
|
||||
assert.Equal(t, binddn, "uid=gitea,ou=service,dc=planetexpress,dc=com")
|
||||
|
||||
req = NewRequestWithValues(t, "POST", href, map[string]string{
|
||||
"_csrf": csrf,
|
||||
"type": "2",
|
||||
"name": "ldap",
|
||||
"host": getLDAPServerHost(),
|
||||
"port": "389",
|
||||
"bind_dn": "uid=gitea,ou=service,dc=planetexpress,dc=com",
|
||||
"bind_password": "password",
|
||||
"user_base": "ou=people,dc=planetexpress,dc=com",
|
||||
"filter": "(&(objectClass=inetOrgPerson)(memberOf=cn=git,ou=people,dc=planetexpress,dc=com)(uid=%s))",
|
||||
"admin_filter": "(memberOf=cn=admin_staff,ou=people,dc=planetexpress,dc=com)",
|
||||
"restricted_filter": "(uid=leela)",
|
||||
"attribute_username": "uid",
|
||||
"attribute_name": "givenName",
|
||||
"attribute_surname": "sn",
|
||||
"attribute_mail": "mail",
|
||||
"attribute_ssh_public_key": "",
|
||||
"is_sync_enabled": "on",
|
||||
"is_active": "on",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
||||
req = NewRequest(t, "GET", href)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
doc = NewHTMLParser(t, resp.Body)
|
||||
host, _ = doc.Find(`input[name="host"]`).Attr("value")
|
||||
assert.Equal(t, host, getLDAPServerHost())
|
||||
binddn, _ = doc.Find(`input[name="bind_dn"]`).Attr("value")
|
||||
assert.Equal(t, binddn, "uid=gitea,ou=service,dc=planetexpress,dc=com")
|
||||
}
|
||||
|
||||
func TestLDAPUserSync(t *testing.T) {
|
||||
if skipLDAPTests() {
|
||||
t.Skip()
|
||||
return
|
||||
}
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
addAuthSourceLDAP(t, "")
|
||||
auth.SyncExternalUsers(context.Background(), true)
|
||||
|
||||
session := loginUser(t, "user1")
|
||||
// Check if users exists
|
||||
for _, u := range gitLDAPUsers {
|
||||
req := NewRequest(t, "GET", "/admin/users?q="+u.UserName)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
tr := htmlDoc.doc.Find("table.table tbody tr")
|
||||
if !assert.True(t, tr.Length() == 1) {
|
||||
continue
|
||||
}
|
||||
tds := tr.Find("td")
|
||||
if !assert.True(t, tds.Length() > 0) {
|
||||
continue
|
||||
}
|
||||
assert.Equal(t, u.UserName, strings.TrimSpace(tds.Find("td:nth-child(2) a").Text()))
|
||||
assert.Equal(t, u.Email, strings.TrimSpace(tds.Find("td:nth-child(3) span").Text()))
|
||||
if u.IsAdmin {
|
||||
assert.True(t, tds.Find("td:nth-child(5) svg").HasClass("octicon-check"))
|
||||
} else {
|
||||
assert.True(t, tds.Find("td:nth-child(5) svg").HasClass("octicon-x"))
|
||||
}
|
||||
if u.IsRestricted {
|
||||
assert.True(t, tds.Find("td:nth-child(6) svg").HasClass("octicon-check"))
|
||||
} else {
|
||||
assert.True(t, tds.Find("td:nth-child(6) svg").HasClass("octicon-x"))
|
||||
}
|
||||
}
|
||||
|
||||
// Check if no users exist
|
||||
for _, u := range otherLDAPUsers {
|
||||
req := NewRequest(t, "GET", "/admin/users?q="+u.UserName)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
tr := htmlDoc.doc.Find("table.table tbody tr")
|
||||
assert.True(t, tr.Length() == 0)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLDAPUserSigninFailed(t *testing.T) {
|
||||
if skipLDAPTests() {
|
||||
t.Skip()
|
||||
return
|
||||
}
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
addAuthSourceLDAP(t, "")
|
||||
|
||||
u := otherLDAPUsers[0]
|
||||
testLoginFailed(t, u.UserName, u.Password, translation.NewLocale("en-US").Tr("form.username_password_incorrect"))
|
||||
}
|
||||
|
||||
func TestLDAPUserSSHKeySync(t *testing.T) {
|
||||
if skipLDAPTests() {
|
||||
t.Skip()
|
||||
return
|
||||
}
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
addAuthSourceLDAP(t, "sshPublicKey")
|
||||
|
||||
auth.SyncExternalUsers(context.Background(), true)
|
||||
|
||||
// Check if users has SSH keys synced
|
||||
for _, u := range gitLDAPUsers {
|
||||
if len(u.SSHKeys) == 0 {
|
||||
continue
|
||||
}
|
||||
session := loginUserWithPassword(t, u.UserName, u.Password)
|
||||
|
||||
req := NewRequest(t, "GET", "/user/settings/keys")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
divs := htmlDoc.doc.Find(".key.list .print.meta")
|
||||
|
||||
syncedKeys := make([]string, divs.Length())
|
||||
for i := 0; i < divs.Length(); i++ {
|
||||
syncedKeys[i] = strings.TrimSpace(divs.Eq(i).Text())
|
||||
}
|
||||
|
||||
assert.ElementsMatch(t, u.SSHKeys, syncedKeys, "Unequal number of keys synchronized for user: %s", u.UserName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLDAPGroupTeamSyncAddMember(t *testing.T) {
|
||||
if skipLDAPTests() {
|
||||
t.Skip()
|
||||
return
|
||||
}
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
addAuthSourceLDAP(t, "", "on", `{"cn=ship_crew,ou=people,dc=planetexpress,dc=com":{"org26": ["team11"]},"cn=admin_staff,ou=people,dc=planetexpress,dc=com": {"non-existent": ["non-existent"]}}`)
|
||||
org, err := organization.GetOrgByName("org26")
|
||||
assert.NoError(t, err)
|
||||
team, err := organization.GetTeam(db.DefaultContext, org.ID, "team11")
|
||||
assert.NoError(t, err)
|
||||
auth.SyncExternalUsers(context.Background(), true)
|
||||
for _, gitLDAPUser := range gitLDAPUsers {
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{
|
||||
Name: gitLDAPUser.UserName,
|
||||
})
|
||||
usersOrgs, err := organization.FindOrgs(organization.FindOrgOptions{
|
||||
UserID: user.ID,
|
||||
IncludePrivate: true,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
allOrgTeams, err := organization.GetUserOrgTeams(db.DefaultContext, org.ID, user.ID)
|
||||
assert.NoError(t, err)
|
||||
if user.Name == "fry" || user.Name == "leela" || user.Name == "bender" {
|
||||
// assert members of LDAP group "cn=ship_crew" are added to mapped teams
|
||||
assert.Equal(t, len(usersOrgs), 1, "User [%s] should be member of one organization", user.Name)
|
||||
assert.Equal(t, usersOrgs[0].Name, "org26", "Membership should be added to the right organization")
|
||||
isMember, err := organization.IsTeamMember(db.DefaultContext, usersOrgs[0].ID, team.ID, user.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, isMember, "Membership should be added to the right team")
|
||||
err = models.RemoveTeamMember(team, user.ID)
|
||||
assert.NoError(t, err)
|
||||
err = models.RemoveOrgUser(usersOrgs[0].ID, user.ID)
|
||||
assert.NoError(t, err)
|
||||
} else {
|
||||
// assert members of LDAP group "cn=admin_staff" keep initial team membership since mapped team does not exist
|
||||
assert.Empty(t, usersOrgs, "User should be member of no organization")
|
||||
isMember, err := organization.IsTeamMember(db.DefaultContext, org.ID, team.ID, user.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, isMember, "User should no be added to this team")
|
||||
assert.Empty(t, allOrgTeams, "User should not be added to any team")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLDAPGroupTeamSyncRemoveMember(t *testing.T) {
|
||||
if skipLDAPTests() {
|
||||
t.Skip()
|
||||
return
|
||||
}
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
addAuthSourceLDAP(t, "", "on", `{"cn=dispatch,ou=people,dc=planetexpress,dc=com": {"org26": ["team11"]}}`)
|
||||
org, err := organization.GetOrgByName("org26")
|
||||
assert.NoError(t, err)
|
||||
team, err := organization.GetTeam(db.DefaultContext, org.ID, "team11")
|
||||
assert.NoError(t, err)
|
||||
loginUserWithPassword(t, gitLDAPUsers[0].UserName, gitLDAPUsers[0].Password)
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{
|
||||
Name: gitLDAPUsers[0].UserName,
|
||||
})
|
||||
err = organization.AddOrgUser(org.ID, user.ID)
|
||||
assert.NoError(t, err)
|
||||
err = models.AddTeamMember(team, user.ID)
|
||||
assert.NoError(t, err)
|
||||
isMember, err := organization.IsOrganizationMember(db.DefaultContext, org.ID, user.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, isMember, "User should be member of this organization")
|
||||
isMember, err = organization.IsTeamMember(db.DefaultContext, org.ID, team.ID, user.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, isMember, "User should be member of this team")
|
||||
// assert team member "professor" gets removed from org26 team11
|
||||
loginUserWithPassword(t, gitLDAPUsers[0].UserName, gitLDAPUsers[0].Password)
|
||||
isMember, err = organization.IsOrganizationMember(db.DefaultContext, org.ID, user.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, isMember, "User membership should have been removed from organization")
|
||||
isMember, err = organization.IsTeamMember(db.DefaultContext, org.ID, team.ID, user.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, isMember, "User membership should have been removed from team")
|
||||
}
|
||||
|
||||
// Login should work even if Team Group Map contains a broken JSON
|
||||
func TestBrokenLDAPMapUserSignin(t *testing.T) {
|
||||
if skipLDAPTests() {
|
||||
t.Skip()
|
||||
return
|
||||
}
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
addAuthSourceLDAP(t, "", "on", `{"NOT_A_VALID_JSON"["MISSING_DOUBLE_POINT"]}`)
|
||||
|
||||
u := gitLDAPUsers[0]
|
||||
|
||||
session := loginUserWithPassword(t, u.UserName, u.Password)
|
||||
req := NewRequest(t, "GET", "/user/settings")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
assert.Equal(t, u.UserName, htmlDoc.GetInputValueByName("name"))
|
||||
assert.Equal(t, u.FullName, htmlDoc.GetInputValueByName("full_name"))
|
||||
assert.Equal(t, u.Email, htmlDoc.Find(`label[for="email"]`).Siblings().First().Text())
|
||||
}
|
72
tests/integration/benchmarks_test.go
Normal file
72
tests/integration/benchmarks_test.go
Normal file
|
@ -0,0 +1,72 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
// StringWithCharset random string (from https://www.calhoun.io/creating-random-strings-in-go/)
|
||||
func StringWithCharset(length int, charset string) string {
|
||||
b := make([]byte, length)
|
||||
for i := range b {
|
||||
b[i] = charset[rand.Intn(len(charset))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func BenchmarkRepoBranchCommit(b *testing.B) {
|
||||
onGiteaRunTB(b, func(t testing.TB, u *url.URL) {
|
||||
b := t.(*testing.B)
|
||||
|
||||
samples := []int64{1, 2, 3}
|
||||
b.ResetTimer()
|
||||
|
||||
for _, repoID := range samples {
|
||||
b.StopTimer()
|
||||
repo := unittest.AssertExistsAndLoadBean(b, &repo_model.Repository{ID: repoID})
|
||||
b.StartTimer()
|
||||
b.Run(repo.Name, func(b *testing.B) {
|
||||
session := loginUser(b, "user2")
|
||||
b.ResetTimer()
|
||||
b.Run("CreateBranch", func(b *testing.B) {
|
||||
b.StopTimer()
|
||||
branchName := StringWithCharset(5+rand.Intn(10), "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
b.Run("new_"+branchName, func(b *testing.B) {
|
||||
b.Skip("benchmark broken") // TODO fix
|
||||
testAPICreateBranch(b, session, repo.OwnerName, repo.Name, repo.DefaultBranch, "new_"+branchName, http.StatusCreated)
|
||||
})
|
||||
}
|
||||
})
|
||||
b.Run("GetBranches", func(b *testing.B) {
|
||||
req := NewRequestf(b, "GET", "/api/v1/repos/%s/branches", repo.FullName())
|
||||
session.MakeRequest(b, req, http.StatusOK)
|
||||
})
|
||||
b.Run("AccessCommits", func(b *testing.B) {
|
||||
var branches []*api.Branch
|
||||
req := NewRequestf(b, "GET", "/api/v1/repos/%s/branches", repo.FullName())
|
||||
resp := session.MakeRequest(b, req, http.StatusOK)
|
||||
DecodeJSON(b, resp, &branches)
|
||||
b.ResetTimer() // We measure from here
|
||||
if len(branches) != 0 {
|
||||
for i := 0; i < b.N; i++ {
|
||||
req := NewRequestf(b, "GET", "/api/v1/repos/%s/commits?sha=%s", repo.FullName(), branches[i%len(branches)].Name)
|
||||
session.MakeRequest(b, req, http.StatusOK)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
76
tests/integration/branches_test.go
Normal file
76
tests/integration/branches_test.go
Normal file
|
@ -0,0 +1,76 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"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) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
deleteBranch(t)
|
||||
htmlDoc, name := branchAction(t, ".undo-button")
|
||||
assert.Contains(t,
|
||||
htmlDoc.doc.Find(".ui.positive.message").Text(),
|
||||
translation.NewLocale("en-US").Tr("repo.branch.restore_success", name),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
41
tests/integration/change_default_branch_test.go
Normal file
41
tests/integration/change_default_branch_test.go
Normal file
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
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/tests"
|
||||
)
|
||||
|
||||
func TestChangeDefaultBranch(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(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)
|
||||
branchesURL := fmt.Sprintf("/%s/%s/settings/branches", owner.Name, repo.Name)
|
||||
|
||||
csrf := GetCSRF(t, session, branchesURL)
|
||||
req := NewRequestWithValues(t, "POST", branchesURL, map[string]string{
|
||||
"_csrf": csrf,
|
||||
"action": "default_branch",
|
||||
"branch": "DefaultBranch",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
||||
csrf = GetCSRF(t, session, branchesURL)
|
||||
req = NewRequestWithValues(t, "POST", branchesURL, map[string]string{
|
||||
"_csrf": csrf,
|
||||
"action": "default_branch",
|
||||
"branch": "does_not_exist",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
65
tests/integration/cmd_keys_test.go
Normal file
65
tests/integration/cmd_keys_test.go
Normal file
|
@ -0,0 +1,65 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/cmd"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func Test_CmdKeys(t *testing.T) {
|
||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
wantErr bool
|
||||
expectedOutput string
|
||||
}{
|
||||
{"test_empty_1", []string{"keys", "--username=git", "--type=test", "--content=test"}, true, ""},
|
||||
{"test_empty_2", []string{"keys", "-e", "git", "-u", "git", "-t", "test", "-k", "test"}, true, ""},
|
||||
{
|
||||
"with_key",
|
||||
[]string{"keys", "-e", "git", "-u", "git", "-t", "ssh-rsa", "-k", "AAAAB3NzaC1yc2EAAAADAQABAAABgQDWVj0fQ5N8wNc0LVNA41wDLYJ89ZIbejrPfg/avyj3u/ZohAKsQclxG4Ju0VirduBFF9EOiuxoiFBRr3xRpqzpsZtnMPkWVWb+akZwBFAx8p+jKdy4QXR/SZqbVobrGwip2UjSrri1CtBxpJikojRIZfCnDaMOyd9Jp6KkujvniFzUWdLmCPxUE9zhTaPu0JsEP7MW0m6yx7ZUhHyfss+NtqmFTaDO+QlMR7L2QkDliN2Jl3Xa3PhuWnKJfWhdAq1Cw4oraKUOmIgXLkuiuxVQ6mD3AiFupkmfqdHq6h+uHHmyQqv3gU+/sD8GbGAhf6ftqhTsXjnv1Aj4R8NoDf9BS6KRkzkeun5UisSzgtfQzjOMEiJtmrep2ZQrMGahrXa+q4VKr0aKJfm+KlLfwm/JztfsBcqQWNcTURiCFqz+fgZw0Ey/de0eyMzldYTdXXNRYCKjs9bvBK+6SSXRM7AhftfQ0ZuoW5+gtinPrnmoOaSCEJbAiEiTO/BzOHgowiM="},
|
||||
false,
|
||||
"# gitea public key\ncommand=\"" + setting.AppPath + " --config=" + util.ShellEscape(setting.CustomConf) + " serv key-1\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,no-user-rc,restrict ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDWVj0fQ5N8wNc0LVNA41wDLYJ89ZIbejrPfg/avyj3u/ZohAKsQclxG4Ju0VirduBFF9EOiuxoiFBRr3xRpqzpsZtnMPkWVWb+akZwBFAx8p+jKdy4QXR/SZqbVobrGwip2UjSrri1CtBxpJikojRIZfCnDaMOyd9Jp6KkujvniFzUWdLmCPxUE9zhTaPu0JsEP7MW0m6yx7ZUhHyfss+NtqmFTaDO+QlMR7L2QkDliN2Jl3Xa3PhuWnKJfWhdAq1Cw4oraKUOmIgXLkuiuxVQ6mD3AiFupkmfqdHq6h+uHHmyQqv3gU+/sD8GbGAhf6ftqhTsXjnv1Aj4R8NoDf9BS6KRkzkeun5UisSzgtfQzjOMEiJtmrep2ZQrMGahrXa+q4VKr0aKJfm+KlLfwm/JztfsBcqQWNcTURiCFqz+fgZw0Ey/de0eyMzldYTdXXNRYCKjs9bvBK+6SSXRM7AhftfQ0ZuoW5+gtinPrnmoOaSCEJbAiEiTO/BzOHgowiM= user2@localhost\n",
|
||||
},
|
||||
{"invalid", []string{"keys", "--not-a-flag=git"}, true, "Incorrect Usage: flag provided but not defined: -not-a-flag\n\n"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
realStdout := os.Stdout // Backup Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
set := flag.NewFlagSet("keys", 0)
|
||||
_ = set.Parse(tt.args)
|
||||
context := cli.NewContext(&cli.App{Writer: os.Stdout}, set, nil)
|
||||
err := cmd.CmdKeys.Run(context)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("CmdKeys.Run() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
w.Close()
|
||||
var buf bytes.Buffer
|
||||
io.Copy(&buf, r)
|
||||
commandOutput := buf.String()
|
||||
if tt.expectedOutput != commandOutput {
|
||||
t.Errorf("expectedOutput: %#v, commandOutput: %#v", tt.expectedOutput, commandOutput)
|
||||
}
|
||||
// Restore stdout
|
||||
os.Stdout = realStdout
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
42
tests/integration/compare_test.go
Normal file
42
tests/integration/compare_test.go
Normal file
|
@ -0,0 +1,42 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/tests"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCompareTag(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
req := NewRequest(t, "GET", "/user2/repo1/compare/v1.1...master")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
selection := htmlDoc.doc.Find(".choose.branch .filter.dropdown")
|
||||
// A dropdown for both base and head.
|
||||
assert.Lenf(t, selection.Nodes, 2, "The template has changed")
|
||||
|
||||
req = NewRequest(t, "GET", "/user2/repo1/compare/invalid")
|
||||
resp = session.MakeRequest(t, req, http.StatusNotFound)
|
||||
assert.False(t, strings.Contains(resp.Body.String(), "/assets/img/500.png"), "expect 404 page not 500")
|
||||
}
|
||||
|
||||
// Compare with inferred default branch (master)
|
||||
func TestCompareDefault(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
req := NewRequest(t, "GET", "/user2/repo1/compare/v1.1")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
selection := htmlDoc.doc.Find(".choose.branch .filter.dropdown")
|
||||
assert.Lenf(t, selection.Nodes, 2, "The template has changed")
|
||||
}
|
23
tests/integration/cors_test.go
Normal file
23
tests/integration/cors_test.go
Normal file
|
@ -0,0 +1,23 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/tests"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCORSNotSet(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
req := NewRequestf(t, "GET", "/api/v1/version")
|
||||
session := loginUser(t, "user2")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, resp.Code, http.StatusOK)
|
||||
corsHeader := resp.Header().Get("Access-Control-Allow-Origin")
|
||||
assert.Equal(t, corsHeader, "", "Access-Control-Allow-Origin: generated header should match") // header not set
|
||||
}
|
120
tests/integration/create_no_session_test.go
Normal file
120
tests/integration/create_no_session_test.go
Normal file
|
@ -0,0 +1,120 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/routers"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"gitea.com/go-chi/session"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func getSessionID(t *testing.T, resp *httptest.ResponseRecorder) string {
|
||||
cookies := resp.Result().Cookies()
|
||||
found := false
|
||||
sessionID := ""
|
||||
for _, cookie := range cookies {
|
||||
if cookie.Name == setting.SessionConfig.CookieName {
|
||||
sessionID = cookie.Value
|
||||
found = true
|
||||
}
|
||||
}
|
||||
assert.True(t, found)
|
||||
assert.NotEmpty(t, sessionID)
|
||||
return sessionID
|
||||
}
|
||||
|
||||
func sessionFile(tmpDir, sessionID string) string {
|
||||
return filepath.Join(tmpDir, sessionID[0:1], sessionID[1:2], sessionID)
|
||||
}
|
||||
|
||||
func sessionFileExist(t *testing.T, tmpDir, sessionID string) bool {
|
||||
sessionFile := sessionFile(tmpDir, sessionID)
|
||||
_, err := os.Lstat(sessionFile)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func TestSessionFileCreation(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
oldSessionConfig := setting.SessionConfig.ProviderConfig
|
||||
defer func() {
|
||||
setting.SessionConfig.ProviderConfig = oldSessionConfig
|
||||
c = routers.NormalRoutes(context.TODO())
|
||||
}()
|
||||
|
||||
var config session.Options
|
||||
|
||||
err := json.Unmarshal([]byte(oldSessionConfig), &config)
|
||||
assert.NoError(t, err)
|
||||
|
||||
config.Provider = "file"
|
||||
|
||||
// Now create a temporaryDirectory
|
||||
tmpDir, err := os.MkdirTemp("", "sessions")
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
if _, err := os.Stat(tmpDir); !os.IsNotExist(err) {
|
||||
_ = util.RemoveAll(tmpDir)
|
||||
}
|
||||
}()
|
||||
config.ProviderConfig = tmpDir
|
||||
|
||||
newConfigBytes, err := json.Marshal(config)
|
||||
assert.NoError(t, err)
|
||||
|
||||
setting.SessionConfig.ProviderConfig = string(newConfigBytes)
|
||||
|
||||
c = routers.NormalRoutes(context.TODO())
|
||||
|
||||
t.Run("NoSessionOnViewIssue", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user2/repo1/issues/1")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
sessionID := getSessionID(t, resp)
|
||||
|
||||
// We're not logged in so there should be no session
|
||||
assert.False(t, sessionFileExist(t, tmpDir, sessionID))
|
||||
})
|
||||
t.Run("CreateSessionOnLogin", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user/login")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
sessionID := getSessionID(t, resp)
|
||||
|
||||
// We're not logged in so there should be no session
|
||||
assert.False(t, sessionFileExist(t, tmpDir, sessionID))
|
||||
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
req = NewRequestWithValues(t, "POST", "/user/login", map[string]string{
|
||||
"_csrf": doc.GetCSRF(),
|
||||
"user_name": "user2",
|
||||
"password": userPassword,
|
||||
})
|
||||
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||
sessionID = getSessionID(t, resp)
|
||||
|
||||
assert.FileExists(t, sessionFile(tmpDir, sessionID))
|
||||
})
|
||||
}
|
53
tests/integration/csrf_test.go
Normal file
53
tests/integration/csrf_test.go
Normal file
|
@ -0,0 +1,53 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCsrfProtection(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
// test web form csrf via form
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
session := loginUser(t, user.Name)
|
||||
req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{
|
||||
"_csrf": "fake_csrf",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
||||
resp := session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
loc := resp.Header().Get("Location")
|
||||
assert.Equal(t, setting.AppSubURL+"/", loc)
|
||||
resp = session.MakeRequest(t, NewRequest(t, "GET", loc), http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
assert.Equal(t, "Bad Request: invalid CSRF token",
|
||||
strings.TrimSpace(htmlDoc.doc.Find(".ui.message").Text()),
|
||||
)
|
||||
|
||||
// test web form csrf via header. TODO: should use an UI api to test
|
||||
req = NewRequest(t, "POST", "/user/settings")
|
||||
req.Header.Add("X-Csrf-Token", "fake_csrf")
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
||||
resp = session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
loc = resp.Header().Get("Location")
|
||||
assert.Equal(t, setting.AppSubURL+"/", loc)
|
||||
resp = session.MakeRequest(t, NewRequest(t, "GET", loc), http.StatusOK)
|
||||
htmlDoc = NewHTMLParser(t, resp.Body)
|
||||
assert.Equal(t, "Bad Request: invalid CSRF token",
|
||||
strings.TrimSpace(htmlDoc.doc.Find(".ui.message").Text()),
|
||||
)
|
||||
}
|
61
tests/integration/delete_user_test.go
Normal file
61
tests/integration/delete_user_test.go
Normal file
|
@ -0,0 +1,61 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
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/tests"
|
||||
)
|
||||
|
||||
func assertUserDeleted(t *testing.T, userID int64) {
|
||||
unittest.AssertNotExistsBean(t, &user_model.User{ID: userID})
|
||||
unittest.AssertNotExistsBean(t, &user_model.Follow{UserID: userID})
|
||||
unittest.AssertNotExistsBean(t, &user_model.Follow{FollowID: userID})
|
||||
unittest.AssertNotExistsBean(t, &repo_model.Repository{OwnerID: userID})
|
||||
unittest.AssertNotExistsBean(t, &access_model.Access{UserID: userID})
|
||||
unittest.AssertNotExistsBean(t, &organization.OrgUser{UID: userID})
|
||||
unittest.AssertNotExistsBean(t, &issues_model.IssueUser{UID: userID})
|
||||
unittest.AssertNotExistsBean(t, &organization.TeamUser{UID: userID})
|
||||
unittest.AssertNotExistsBean(t, &repo_model.Star{UID: userID})
|
||||
}
|
||||
|
||||
func TestUserDeleteAccount(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
session := loginUser(t, "user8")
|
||||
csrf := GetCSRF(t, session, "/user/settings/account")
|
||||
urlStr := fmt.Sprintf("/user/settings/account/delete?password=%s", userPassword)
|
||||
req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
|
||||
"_csrf": csrf,
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
||||
assertUserDeleted(t, 8)
|
||||
unittest.CheckConsistencyFor(t, &user_model.User{})
|
||||
}
|
||||
|
||||
func TestUserDeleteAccountStillOwnRepos(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
csrf := GetCSRF(t, session, "/user/settings/account")
|
||||
urlStr := fmt.Sprintf("/user/settings/account/delete?password=%s", userPassword)
|
||||
req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
|
||||
"_csrf": csrf,
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
||||
// user should not have been deleted, because the user still owns repos
|
||||
unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
}
|
94
tests/integration/download_test.go
Normal file
94
tests/integration/download_test.go
Normal file
|
@ -0,0 +1,94 @@
|
|||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDownloadByID(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
|
||||
// Request raw blob
|
||||
req := NewRequest(t, "GET", "/user2/repo1/raw/blob/4b4851ad51df6a7d9f25c979345979eaeb5b349f")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, "# repo1\n\nDescription for repo1", resp.Body.String())
|
||||
}
|
||||
|
||||
func TestDownloadByIDForSVGUsesSecureHeaders(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
|
||||
// Request raw blob
|
||||
req := NewRequest(t, "GET", "/user2/repo2/raw/blob/6395b68e1feebb1e4c657b4f9f6ba2676a283c0b")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, "default-src 'none'; style-src 'unsafe-inline'; sandbox", resp.HeaderMap.Get("Content-Security-Policy"))
|
||||
assert.Equal(t, "image/svg+xml", resp.HeaderMap.Get("Content-Type"))
|
||||
assert.Equal(t, "nosniff", resp.HeaderMap.Get("X-Content-Type-Options"))
|
||||
}
|
||||
|
||||
func TestDownloadByIDMedia(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
|
||||
// Request raw blob
|
||||
req := NewRequest(t, "GET", "/user2/repo1/media/blob/4b4851ad51df6a7d9f25c979345979eaeb5b349f")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, "# repo1\n\nDescription for repo1", resp.Body.String())
|
||||
}
|
||||
|
||||
func TestDownloadByIDMediaForSVGUsesSecureHeaders(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
|
||||
// Request raw blob
|
||||
req := NewRequest(t, "GET", "/user2/repo2/media/blob/6395b68e1feebb1e4c657b4f9f6ba2676a283c0b")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, "default-src 'none'; style-src 'unsafe-inline'; sandbox", resp.HeaderMap.Get("Content-Security-Policy"))
|
||||
assert.Equal(t, "image/svg+xml", resp.HeaderMap.Get("Content-Type"))
|
||||
assert.Equal(t, "nosniff", resp.HeaderMap.Get("X-Content-Type-Options"))
|
||||
}
|
||||
|
||||
func TestDownloadRawTextFileWithoutMimeTypeMapping(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
|
||||
req := NewRequest(t, "GET", "/user2/repo2/raw/branch/master/test.xml")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, "text/plain; charset=utf-8", resp.HeaderMap.Get("Content-Type"))
|
||||
}
|
||||
|
||||
func TestDownloadRawTextFileWithMimeTypeMapping(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
setting.MimeTypeMap.Map[".xml"] = "text/xml"
|
||||
setting.MimeTypeMap.Enabled = true
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
|
||||
req := NewRequest(t, "GET", "/user2/repo2/raw/branch/master/test.xml")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, "text/xml; charset=utf-8", resp.HeaderMap.Get("Content-Type"))
|
||||
|
||||
delete(setting.MimeTypeMap.Map, ".xml")
|
||||
setting.MimeTypeMap.Enabled = false
|
||||
}
|
328
tests/integration/dump_restore_test.go
Normal file
328
tests/integration/dump_restore_test.go
Normal file
|
@ -0,0 +1,328 @@
|
|||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
base "code.gitea.io/gitea/modules/migration"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/services/migrations"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
func TestDumpRestore(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
AllowLocalNetworks := setting.Migrations.AllowLocalNetworks
|
||||
setting.Migrations.AllowLocalNetworks = true
|
||||
AppVer := setting.AppVer
|
||||
// Gitea SDK (go-sdk) need to parse the AppVer from server response, so we must set it to a valid version string.
|
||||
setting.AppVer = "1.16.0"
|
||||
defer func() {
|
||||
setting.Migrations.AllowLocalNetworks = AllowLocalNetworks
|
||||
setting.AppVer = AppVer
|
||||
}()
|
||||
|
||||
assert.NoError(t, migrations.Init())
|
||||
|
||||
reponame := "repo1"
|
||||
|
||||
basePath, err := os.MkdirTemp("", reponame)
|
||||
assert.NoError(t, err)
|
||||
defer util.RemoveAll(basePath)
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame})
|
||||
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
session := loginUser(t, repoOwner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
//
|
||||
// Phase 1: dump repo1 from the Gitea instance to the filesystem
|
||||
//
|
||||
|
||||
ctx := context.Background()
|
||||
opts := migrations.MigrateOptions{
|
||||
GitServiceType: structs.GiteaService,
|
||||
Issues: true,
|
||||
PullRequests: true,
|
||||
Labels: true,
|
||||
Milestones: true,
|
||||
Comments: true,
|
||||
AuthToken: token,
|
||||
CloneAddr: repo.CloneLink().HTTPS,
|
||||
RepoName: reponame,
|
||||
}
|
||||
err = migrations.DumpRepository(ctx, basePath, repoOwner.Name, opts)
|
||||
assert.NoError(t, err)
|
||||
|
||||
//
|
||||
// Verify desired side effects of the dump
|
||||
//
|
||||
d := filepath.Join(basePath, repo.OwnerName, repo.Name)
|
||||
for _, f := range []string{"repo.yml", "topic.yml", "label.yml", "milestone.yml", "issue.yml"} {
|
||||
assert.FileExists(t, filepath.Join(d, f))
|
||||
}
|
||||
|
||||
//
|
||||
// Phase 2: restore from the filesystem to the Gitea instance in restoredrepo
|
||||
//
|
||||
|
||||
newreponame := "restored"
|
||||
err = migrations.RestoreRepository(ctx, d, repo.OwnerName, newreponame, []string{
|
||||
"labels", "issues", "comments", "milestones", "pull_requests",
|
||||
}, false)
|
||||
assert.NoError(t, err)
|
||||
|
||||
newrepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: newreponame})
|
||||
|
||||
//
|
||||
// Phase 3: dump restored from the Gitea instance to the filesystem
|
||||
//
|
||||
opts.RepoName = newreponame
|
||||
opts.CloneAddr = newrepo.CloneLink().HTTPS
|
||||
err = migrations.DumpRepository(ctx, basePath, repoOwner.Name, opts)
|
||||
assert.NoError(t, err)
|
||||
|
||||
//
|
||||
// Verify the dump of restored is the same as the dump of repo1
|
||||
//
|
||||
comparator := &compareDump{
|
||||
t: t,
|
||||
basePath: basePath,
|
||||
}
|
||||
comparator.assertEquals(repo, newrepo)
|
||||
})
|
||||
}
|
||||
|
||||
type compareDump struct {
|
||||
t *testing.T
|
||||
basePath string
|
||||
repoBefore *repo_model.Repository
|
||||
dirBefore string
|
||||
repoAfter *repo_model.Repository
|
||||
dirAfter string
|
||||
}
|
||||
|
||||
type compareField struct {
|
||||
before interface{}
|
||||
after interface{}
|
||||
ignore bool
|
||||
transform func(string) string
|
||||
nested *compareFields
|
||||
}
|
||||
|
||||
type compareFields map[string]compareField
|
||||
|
||||
func (c *compareDump) replaceRepoName(original string) string {
|
||||
return strings.ReplaceAll(original, c.repoBefore.Name, c.repoAfter.Name)
|
||||
}
|
||||
|
||||
func (c *compareDump) assertEquals(repoBefore, repoAfter *repo_model.Repository) {
|
||||
c.repoBefore = repoBefore
|
||||
c.dirBefore = filepath.Join(c.basePath, repoBefore.OwnerName, repoBefore.Name)
|
||||
c.repoAfter = repoAfter
|
||||
c.dirAfter = filepath.Join(c.basePath, repoAfter.OwnerName, repoAfter.Name)
|
||||
|
||||
//
|
||||
// base.Repository
|
||||
//
|
||||
_ = c.assertEqual("repo.yml", base.Repository{}, compareFields{
|
||||
"Name": {
|
||||
before: c.repoBefore.Name,
|
||||
after: c.repoAfter.Name,
|
||||
},
|
||||
"CloneURL": {transform: c.replaceRepoName},
|
||||
"OriginalURL": {transform: c.replaceRepoName},
|
||||
})
|
||||
|
||||
//
|
||||
// base.Label
|
||||
//
|
||||
labels, ok := c.assertEqual("label.yml", []base.Label{}, compareFields{}).([]*base.Label)
|
||||
assert.True(c.t, ok)
|
||||
assert.GreaterOrEqual(c.t, len(labels), 1)
|
||||
|
||||
//
|
||||
// base.Milestone
|
||||
//
|
||||
milestones, ok := c.assertEqual("milestone.yml", []base.Milestone{}, compareFields{
|
||||
"Updated": {ignore: true}, // the database updates that field independently
|
||||
}).([]*base.Milestone)
|
||||
assert.True(c.t, ok)
|
||||
assert.GreaterOrEqual(c.t, len(milestones), 1)
|
||||
|
||||
//
|
||||
// base.Issue and the associated comments
|
||||
//
|
||||
issues, ok := c.assertEqual("issue.yml", []base.Issue{}, compareFields{
|
||||
"Assignees": {ignore: true}, // not implemented yet
|
||||
}).([]*base.Issue)
|
||||
assert.True(c.t, ok)
|
||||
assert.GreaterOrEqual(c.t, len(issues), 1)
|
||||
for _, issue := range issues {
|
||||
filename := filepath.Join("comments", fmt.Sprintf("%d.yml", issue.Number))
|
||||
comments, ok := c.assertEqual(filename, []base.Comment{}, compareFields{
|
||||
"Index": {ignore: true},
|
||||
}).([]*base.Comment)
|
||||
assert.True(c.t, ok)
|
||||
for _, comment := range comments {
|
||||
assert.EqualValues(c.t, issue.Number, comment.IssueIndex)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// base.PullRequest and the associated comments
|
||||
//
|
||||
comparePullRequestBranch := &compareFields{
|
||||
"RepoName": {
|
||||
before: c.repoBefore.Name,
|
||||
after: c.repoAfter.Name,
|
||||
},
|
||||
"CloneURL": {transform: c.replaceRepoName},
|
||||
}
|
||||
prs, ok := c.assertEqual("pull_request.yml", []base.PullRequest{}, compareFields{
|
||||
"Assignees": {ignore: true}, // not implemented yet
|
||||
"Head": {nested: comparePullRequestBranch},
|
||||
"Base": {nested: comparePullRequestBranch},
|
||||
"Labels": {ignore: true}, // because org labels are not handled properly
|
||||
}).([]*base.PullRequest)
|
||||
assert.True(c.t, ok)
|
||||
assert.GreaterOrEqual(c.t, len(prs), 1)
|
||||
for _, pr := range prs {
|
||||
filename := filepath.Join("comments", fmt.Sprintf("%d.yml", pr.Number))
|
||||
comments, ok := c.assertEqual(filename, []base.Comment{}, compareFields{}).([]*base.Comment)
|
||||
assert.True(c.t, ok)
|
||||
for _, comment := range comments {
|
||||
assert.EqualValues(c.t, pr.Number, comment.IssueIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compareDump) assertLoadYAMLFiles(beforeFilename, afterFilename string, before, after interface{}) {
|
||||
_, beforeErr := os.Stat(beforeFilename)
|
||||
_, afterErr := os.Stat(afterFilename)
|
||||
assert.EqualValues(c.t, errors.Is(beforeErr, os.ErrNotExist), errors.Is(afterErr, os.ErrNotExist))
|
||||
if errors.Is(beforeErr, os.ErrNotExist) {
|
||||
return
|
||||
}
|
||||
|
||||
beforeBytes, err := os.ReadFile(beforeFilename)
|
||||
assert.NoError(c.t, err)
|
||||
assert.NoError(c.t, yaml.Unmarshal(beforeBytes, before))
|
||||
afterBytes, err := os.ReadFile(afterFilename)
|
||||
assert.NoError(c.t, err)
|
||||
assert.NoError(c.t, yaml.Unmarshal(afterBytes, after))
|
||||
}
|
||||
|
||||
func (c *compareDump) assertLoadFiles(beforeFilename, afterFilename string, t reflect.Type) (before, after reflect.Value) {
|
||||
var beforePtr, afterPtr reflect.Value
|
||||
if t.Kind() == reflect.Slice {
|
||||
//
|
||||
// Given []Something{} create afterPtr, beforePtr []*Something{}
|
||||
//
|
||||
sliceType := reflect.SliceOf(reflect.PtrTo(t.Elem()))
|
||||
beforeSlice := reflect.MakeSlice(sliceType, 0, 10)
|
||||
beforePtr = reflect.New(beforeSlice.Type())
|
||||
beforePtr.Elem().Set(beforeSlice)
|
||||
afterSlice := reflect.MakeSlice(sliceType, 0, 10)
|
||||
afterPtr = reflect.New(afterSlice.Type())
|
||||
afterPtr.Elem().Set(afterSlice)
|
||||
} else {
|
||||
//
|
||||
// Given Something{} create afterPtr, beforePtr *Something{}
|
||||
//
|
||||
beforePtr = reflect.New(t)
|
||||
afterPtr = reflect.New(t)
|
||||
}
|
||||
c.assertLoadYAMLFiles(beforeFilename, afterFilename, beforePtr.Interface(), afterPtr.Interface())
|
||||
return beforePtr.Elem(), afterPtr.Elem()
|
||||
}
|
||||
|
||||
func (c *compareDump) assertEqual(filename string, kind interface{}, fields compareFields) (i interface{}) {
|
||||
beforeFilename := filepath.Join(c.dirBefore, filename)
|
||||
afterFilename := filepath.Join(c.dirAfter, filename)
|
||||
|
||||
typeOf := reflect.TypeOf(kind)
|
||||
before, after := c.assertLoadFiles(beforeFilename, afterFilename, typeOf)
|
||||
if typeOf.Kind() == reflect.Slice {
|
||||
i = c.assertEqualSlices(before, after, fields)
|
||||
} else {
|
||||
i = c.assertEqualValues(before, after, fields)
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func (c *compareDump) assertEqualSlices(before, after reflect.Value, fields compareFields) interface{} {
|
||||
assert.EqualValues(c.t, before.Len(), after.Len())
|
||||
if before.Len() == after.Len() {
|
||||
for i := 0; i < before.Len(); i++ {
|
||||
_ = c.assertEqualValues(
|
||||
reflect.Indirect(before.Index(i).Elem()),
|
||||
reflect.Indirect(after.Index(i).Elem()),
|
||||
fields)
|
||||
}
|
||||
}
|
||||
return after.Interface()
|
||||
}
|
||||
|
||||
func (c *compareDump) assertEqualValues(before, after reflect.Value, fields compareFields) interface{} {
|
||||
for _, field := range reflect.VisibleFields(before.Type()) {
|
||||
bf := before.FieldByName(field.Name)
|
||||
bi := bf.Interface()
|
||||
af := after.FieldByName(field.Name)
|
||||
ai := af.Interface()
|
||||
if compare, ok := fields[field.Name]; ok {
|
||||
if compare.ignore == true {
|
||||
//
|
||||
// Ignore
|
||||
//
|
||||
continue
|
||||
}
|
||||
if compare.transform != nil {
|
||||
//
|
||||
// Transform these strings before comparing them
|
||||
//
|
||||
bs, ok := bi.(string)
|
||||
assert.True(c.t, ok)
|
||||
as, ok := ai.(string)
|
||||
assert.True(c.t, ok)
|
||||
assert.EqualValues(c.t, compare.transform(bs), compare.transform(as))
|
||||
continue
|
||||
}
|
||||
if compare.before != nil && compare.after != nil {
|
||||
//
|
||||
// The fields are expected to have different values
|
||||
//
|
||||
assert.EqualValues(c.t, compare.before, bi)
|
||||
assert.EqualValues(c.t, compare.after, ai)
|
||||
continue
|
||||
}
|
||||
if compare.nested != nil {
|
||||
//
|
||||
// The fields are a struct, recurse
|
||||
//
|
||||
c.assertEqualValues(bf, af, *compare.nested)
|
||||
continue
|
||||
}
|
||||
}
|
||||
assert.EqualValues(c.t, bi, ai)
|
||||
}
|
||||
return after.Interface()
|
||||
}
|
164
tests/integration/editor_test.go
Normal file
164
tests/integration/editor_test.go
Normal file
|
@ -0,0 +1,164 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCreateFile(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
session := loginUser(t, "user2")
|
||||
|
||||
// Request editor page
|
||||
req := NewRequest(t, "GET", "/user2/repo1/_new/master/")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
lastCommit := doc.GetInputValueByName("last_commit")
|
||||
assert.NotEmpty(t, lastCommit)
|
||||
|
||||
// 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",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCreateFileOnProtectedBranch(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
session := loginUser(t, "user2")
|
||||
|
||||
csrf := GetCSRF(t, session, "/user2/repo1/settings/branches")
|
||||
// Change master branch to protected
|
||||
req := NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/master", map[string]string{
|
||||
"_csrf": csrf,
|
||||
"protected": "on",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
// Check if master branch has been locked successfully
|
||||
flashCookie := session.GetCookie("macaron_flash")
|
||||
assert.NotNil(t, flashCookie)
|
||||
assert.EqualValues(t, "success%3DBranch%2Bprotection%2Bfor%2Bbranch%2B%2527master%2527%2Bhas%2Bbeen%2Bupdated.", flashCookie.Value)
|
||||
|
||||
// Request editor page
|
||||
req = NewRequest(t, "GET", "/user2/repo1/_new/master/")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
lastCommit := doc.GetInputValueByName("last_commit")
|
||||
assert.NotEmpty(t, lastCommit)
|
||||
|
||||
// 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",
|
||||
})
|
||||
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
// Check body for error message
|
||||
assert.Contains(t, resp.Body.String(), "Cannot commit to protected branch 'master'.")
|
||||
|
||||
// remove the protected branch
|
||||
csrf = GetCSRF(t, session, "/user2/repo1/settings/branches")
|
||||
// Change master branch to protected
|
||||
req = NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/master", map[string]string{
|
||||
"_csrf": csrf,
|
||||
"protected": "off",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
// Check if master branch has been locked successfully
|
||||
flashCookie = session.GetCookie("macaron_flash")
|
||||
assert.NotNil(t, flashCookie)
|
||||
assert.EqualValues(t, "success%3DBranch%2Bprotection%2Bfor%2Bbranch%2B%2527master%2527%2Bhas%2Bbeen%2Bdisabled.", flashCookie.Value)
|
||||
})
|
||||
}
|
||||
|
||||
func testEditFile(t *testing.T, session *TestSession, user, repo, branch, filePath, newContent string) *httptest.ResponseRecorder {
|
||||
// Get to the 'edit this file' page
|
||||
req := NewRequest(t, "GET", path.Join(user, repo, "_edit", branch, filePath))
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
lastCommit := htmlDoc.GetInputValueByName("last_commit")
|
||||
assert.NotEmpty(t, lastCommit)
|
||||
|
||||
// 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",
|
||||
},
|
||||
)
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
||||
// Verify the change
|
||||
req = NewRequest(t, "GET", path.Join(user, repo, "raw/branch", branch, filePath))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.EqualValues(t, newContent, resp.Body.String())
|
||||
|
||||
return resp
|
||||
}
|
||||
|
||||
func testEditFileToNewBranch(t *testing.T, session *TestSession, user, repo, branch, targetBranch, filePath, newContent string) *httptest.ResponseRecorder {
|
||||
// Get to the 'edit this file' page
|
||||
req := NewRequest(t, "GET", path.Join(user, repo, "_edit", branch, filePath))
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
lastCommit := htmlDoc.GetInputValueByName("last_commit")
|
||||
assert.NotEmpty(t, lastCommit)
|
||||
|
||||
// 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": "commit-to-new-branch",
|
||||
"new_branch_name": targetBranch,
|
||||
},
|
||||
)
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
||||
// Verify the change
|
||||
req = NewRequest(t, "GET", path.Join(user, repo, "raw/branch", targetBranch, filePath))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.EqualValues(t, newContent, resp.Body.String())
|
||||
|
||||
return resp
|
||||
}
|
||||
|
||||
func TestEditFile(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
session := loginUser(t, "user2")
|
||||
testEditFile(t, session, "user2", "repo1", "master", "README.md", "Hello, World (Edited)\n")
|
||||
})
|
||||
}
|
||||
|
||||
func TestEditFileToNewBranch(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
session := loginUser(t, "user2")
|
||||
testEditFileToNewBranch(t, session, "user2", "repo1", "master", "feature/test", "README.md", "Hello, World (Edited)\n")
|
||||
})
|
||||
}
|
31
tests/integration/empty_repo_test.go
Normal file
31
tests/integration/empty_repo_test.go
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
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/tests"
|
||||
)
|
||||
|
||||
func TestEmptyRepo(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
subpaths := []string{
|
||||
"commits/master",
|
||||
"raw/foo",
|
||||
"commit/1ae57b34ccf7e18373",
|
||||
"graph",
|
||||
}
|
||||
emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{}, unittest.Cond("is_empty = ?", true))
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: emptyRepo.OwnerID})
|
||||
for _, subpath := range subpaths {
|
||||
req := NewRequestf(t, "GET", "/%s/%s/%s", owner.Name, emptyRepo.Name, subpath)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
||||
}
|
83
tests/integration/eventsource_test.go
Normal file
83
tests/integration/eventsource_test.go
Normal file
|
@ -0,0 +1,83 @@
|
|||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
activities_model "code.gitea.io/gitea/models/activities"
|
||||
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/eventsource"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEventSourceManagerRun(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
manager := eventsource.GetManager()
|
||||
|
||||
eventChan := manager.Register(2)
|
||||
defer func() {
|
||||
manager.Unregister(2, eventChan)
|
||||
// ensure the eventChan is closed
|
||||
for {
|
||||
_, ok := <-eventChan
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
expectNotificationCountEvent := func(count int64) func() bool {
|
||||
return func() bool {
|
||||
select {
|
||||
case event, ok := <-eventChan:
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
data, ok := event.Data.(activities_model.UserIDCount)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return event.Name == "notification-count" && data.Count == count
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
thread5 := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{ID: 5})
|
||||
assert.NoError(t, thread5.LoadAttributes())
|
||||
session := loginUser(t, user2.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
var apiNL []api.NotificationThread
|
||||
|
||||
// -- mark notifications as read --
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?status-types=unread&token=%s", token))
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
DecodeJSON(t, resp, &apiNL)
|
||||
assert.Len(t, apiNL, 2)
|
||||
|
||||
lastReadAt := "2000-01-01T00%3A50%3A01%2B00%3A00" // 946687801 <- only Notification 4 is in this filter ...
|
||||
req = NewRequest(t, "PUT", fmt.Sprintf("/api/v1/repos/%s/%s/notifications?last_read_at=%s&token=%s", user2.Name, repo1.Name, lastReadAt, token))
|
||||
session.MakeRequest(t, req, http.StatusResetContent)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?token=%s&status-types=unread", token))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiNL)
|
||||
assert.Len(t, apiNL, 1)
|
||||
|
||||
assert.Eventually(t, expectNotificationCountEvent(1), 30*time.Second, 1*time.Second)
|
||||
}
|
19
tests/integration/explore_repos_test.go
Normal file
19
tests/integration/explore_repos_test.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/tests"
|
||||
)
|
||||
|
||||
func TestExploreRepos(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/explore/repos")
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
}
|
53
tests/integration/git_clone_wiki_test.go
Normal file
53
tests/integration/git_clone_wiki_test.go
Normal file
|
@ -0,0 +1,53 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func assertFileExist(t *testing.T, p string) {
|
||||
exist, err := util.IsExist(p)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, exist)
|
||||
}
|
||||
|
||||
func assertFileEqual(t *testing.T, p string, content []byte) {
|
||||
bs, err := os.ReadFile(p)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, content, bs)
|
||||
}
|
||||
|
||||
func TestRepoCloneWiki(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
dstPath, err := os.MkdirTemp("", "clone_wiki")
|
||||
assert.NoError(t, err)
|
||||
|
||||
r := fmt.Sprintf("%suser2/repo1.wiki.git", u.String())
|
||||
u, _ = url.Parse(r)
|
||||
u.User = url.UserPassword("user2", userPassword)
|
||||
t.Run("Clone", func(t *testing.T) {
|
||||
assert.NoError(t, git.CloneWithArgs(context.Background(), u.String(), dstPath, git.AllowLFSFiltersArgs(), git.CloneRepoOptions{}))
|
||||
assertFileEqual(t, filepath.Join(dstPath, "Home.md"), []byte("# Home page\n\nThis is the home page!\n"))
|
||||
assertFileExist(t, filepath.Join(dstPath, "Page-With-Image.md"))
|
||||
assertFileExist(t, filepath.Join(dstPath, "Page-With-Spaced-Name.md"))
|
||||
assertFileExist(t, filepath.Join(dstPath, "images"))
|
||||
assertFileExist(t, filepath.Join(dstPath, "jpeg.jpg"))
|
||||
})
|
||||
})
|
||||
}
|
202
tests/integration/git_helper_for_declarative_test.go
Normal file
202
tests/integration/git_helper_for_declarative_test.go
Normal file
|
@ -0,0 +1,202 @@
|
|||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/ssh"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func withKeyFile(t *testing.T, keyname string, callback func(string)) {
|
||||
tmpDir, err := os.MkdirTemp("", "key-file")
|
||||
assert.NoError(t, err)
|
||||
defer util.RemoveAll(tmpDir)
|
||||
|
||||
err = os.Chmod(tmpDir, 0o700)
|
||||
assert.NoError(t, err)
|
||||
|
||||
keyFile := filepath.Join(tmpDir, keyname)
|
||||
err = ssh.GenKeyPair(keyFile)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = os.WriteFile(path.Join(tmpDir, "ssh"), []byte("#!/bin/bash\n"+
|
||||
"ssh -o \"UserKnownHostsFile=/dev/null\" -o \"StrictHostKeyChecking=no\" -o \"IdentitiesOnly=yes\" -i \""+keyFile+"\" \"$@\""), 0o700)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Setup ssh wrapper
|
||||
os.Setenv("GIT_SSH", path.Join(tmpDir, "ssh"))
|
||||
os.Setenv("GIT_SSH_COMMAND",
|
||||
"ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentitiesOnly=yes -i \""+keyFile+"\"")
|
||||
os.Setenv("GIT_SSH_VARIANT", "ssh")
|
||||
|
||||
callback(keyFile)
|
||||
}
|
||||
|
||||
func createSSHUrl(gitPath string, u *url.URL) *url.URL {
|
||||
u2 := *u
|
||||
u2.Scheme = "ssh"
|
||||
u2.User = url.User("git")
|
||||
u2.Host = net.JoinHostPort(setting.SSH.ListenHost, strconv.Itoa(setting.SSH.ListenPort))
|
||||
u2.Path = gitPath
|
||||
return &u2
|
||||
}
|
||||
|
||||
func onGiteaRunTB(t testing.TB, callback func(testing.TB, *url.URL), prepare ...bool) {
|
||||
if len(prepare) == 0 || prepare[0] {
|
||||
defer tests.PrepareTestEnv(t, 1)()
|
||||
}
|
||||
s := http.Server{
|
||||
Handler: c,
|
||||
}
|
||||
|
||||
u, err := url.Parse(setting.AppURL)
|
||||
assert.NoError(t, err)
|
||||
listener, err := net.Listen("tcp", u.Host)
|
||||
i := 0
|
||||
for err != nil && i <= 10 {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
listener, err = net.Listen("tcp", u.Host)
|
||||
i++
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
u.Host = listener.Addr().String()
|
||||
|
||||
defer func() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||
s.Shutdown(ctx)
|
||||
cancel()
|
||||
}()
|
||||
|
||||
go s.Serve(listener)
|
||||
// Started by config go ssh.Listen(setting.SSH.ListenHost, setting.SSH.ListenPort, setting.SSH.ServerCiphers, setting.SSH.ServerKeyExchanges, setting.SSH.ServerMACs)
|
||||
|
||||
callback(t, u)
|
||||
}
|
||||
|
||||
func onGiteaRun(t *testing.T, callback func(*testing.T, *url.URL), prepare ...bool) {
|
||||
onGiteaRunTB(t, func(t testing.TB, u *url.URL) {
|
||||
callback(t.(*testing.T), u)
|
||||
}, prepare...)
|
||||
}
|
||||
|
||||
func doGitClone(dstLocalPath string, u *url.URL) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
assert.NoError(t, git.CloneWithArgs(context.Background(), u.String(), dstLocalPath, git.AllowLFSFiltersArgs(), git.CloneRepoOptions{}))
|
||||
exist, err := util.IsExist(filepath.Join(dstLocalPath, "README.md"))
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, exist)
|
||||
}
|
||||
}
|
||||
|
||||
func doPartialGitClone(dstLocalPath string, u *url.URL) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
assert.NoError(t, git.CloneWithArgs(context.Background(), u.String(), dstLocalPath, git.AllowLFSFiltersArgs(), git.CloneRepoOptions{
|
||||
Filter: "blob:none",
|
||||
}))
|
||||
exist, err := util.IsExist(filepath.Join(dstLocalPath, "README.md"))
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, exist)
|
||||
}
|
||||
}
|
||||
|
||||
func doGitCloneFail(u *url.URL) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
tmpDir, err := os.MkdirTemp("", "doGitCloneFail")
|
||||
assert.NoError(t, err)
|
||||
defer util.RemoveAll(tmpDir)
|
||||
assert.Error(t, git.Clone(git.DefaultContext, u.String(), tmpDir, git.CloneRepoOptions{}))
|
||||
exist, err := util.IsExist(filepath.Join(tmpDir, "README.md"))
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, exist)
|
||||
}
|
||||
}
|
||||
|
||||
func doGitInitTestRepository(dstPath string) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
// Init repository in dstPath
|
||||
assert.NoError(t, git.InitRepository(git.DefaultContext, dstPath, false))
|
||||
// forcibly set default branch to master
|
||||
_, _, err := git.NewCommand(git.DefaultContext, "symbolic-ref", "HEAD", git.BranchPrefix+"master").RunStdString(&git.RunOpts{Dir: dstPath})
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, os.WriteFile(filepath.Join(dstPath, "README.md"), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s", dstPath)), 0o644))
|
||||
assert.NoError(t, git.AddChanges(dstPath, true))
|
||||
signature := git.Signature{
|
||||
Email: "test@example.com",
|
||||
Name: "test",
|
||||
When: time.Now(),
|
||||
}
|
||||
assert.NoError(t, git.CommitChanges(dstPath, git.CommitChangesOptions{
|
||||
Committer: &signature,
|
||||
Author: &signature,
|
||||
Message: "Initial Commit",
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
func doGitAddRemote(dstPath, remoteName string, u *url.URL) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
_, _, err := git.NewCommand(git.DefaultContext, "remote", "add", remoteName, u.String()).RunStdString(&git.RunOpts{Dir: dstPath})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func doGitPushTestRepository(dstPath string, args ...string) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
_, _, err := git.NewCommand(git.DefaultContext, append([]string{"push", "-u"}, args...)...).RunStdString(&git.RunOpts{Dir: dstPath})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func doGitPushTestRepositoryFail(dstPath string, args ...string) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
_, _, err := git.NewCommand(git.DefaultContext, append([]string{"push"}, args...)...).RunStdString(&git.RunOpts{Dir: dstPath})
|
||||
assert.Error(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func doGitCreateBranch(dstPath, branch string) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
_, _, err := git.NewCommand(git.DefaultContext, "checkout", "-b", branch).RunStdString(&git.RunOpts{Dir: dstPath})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func doGitCheckoutBranch(dstPath string, args ...string) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
_, _, err := git.NewCommandNoGlobals(append(append(git.AllowLFSFiltersArgs(), "checkout"), args...)...).RunStdString(&git.RunOpts{Dir: dstPath})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func doGitMerge(dstPath string, args ...string) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
_, _, err := git.NewCommand(git.DefaultContext, append([]string{"merge"}, args...)...).RunStdString(&git.RunOpts{Dir: dstPath})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func doGitPull(dstPath string, args ...string) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
_, _, err := git.NewCommandNoGlobals(append(append(git.AllowLFSFiltersArgs(), "pull"), args...)...).RunStdString(&git.RunOpts{Dir: dstPath})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
69
tests/integration/git_smart_http_test.go
Normal file
69
tests/integration/git_smart_http_test.go
Normal file
|
@ -0,0 +1,69 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGitSmartHTTP(t *testing.T) {
|
||||
onGiteaRun(t, testGitSmartHTTP)
|
||||
}
|
||||
|
||||
func testGitSmartHTTP(t *testing.T, u *url.URL) {
|
||||
kases := []struct {
|
||||
p string
|
||||
code int
|
||||
}{
|
||||
{
|
||||
p: "user2/repo1/info/refs",
|
||||
code: http.StatusOK,
|
||||
},
|
||||
{
|
||||
p: "user2/repo1/HEAD",
|
||||
code: http.StatusOK,
|
||||
},
|
||||
{
|
||||
p: "user2/repo1/objects/info/alternates",
|
||||
code: http.StatusNotFound,
|
||||
},
|
||||
{
|
||||
p: "user2/repo1/objects/info/http-alternates",
|
||||
code: http.StatusNotFound,
|
||||
},
|
||||
{
|
||||
p: "user2/repo1/../../custom/conf/app.ini",
|
||||
code: http.StatusNotFound,
|
||||
},
|
||||
{
|
||||
p: "user2/repo1/objects/info/../../../../custom/conf/app.ini",
|
||||
code: http.StatusNotFound,
|
||||
},
|
||||
{
|
||||
p: `user2/repo1/objects/info/..\..\..\..\custom\conf\app.ini`,
|
||||
code: http.StatusBadRequest,
|
||||
},
|
||||
}
|
||||
|
||||
for _, kase := range kases {
|
||||
t.Run(kase.p, func(t *testing.T) {
|
||||
p := u.String() + kase.p
|
||||
req, err := http.NewRequest("GET", p, nil)
|
||||
assert.NoError(t, err)
|
||||
req.SetBasicAuth("user2", userPassword)
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
assert.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
assert.EqualValues(t, kase.code, resp.StatusCode)
|
||||
_, err = io.ReadAll(resp.Body)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
851
tests/integration/git_test.go
Normal file
851
tests/integration/git_test.go
Normal file
|
@ -0,0 +1,851 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
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/lfs"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const (
|
||||
littleSize = 1024 // 1ko
|
||||
bigSize = 128 * 1024 * 1024 // 128Mo
|
||||
)
|
||||
|
||||
func TestGit(t *testing.T) {
|
||||
onGiteaRun(t, testGit)
|
||||
}
|
||||
|
||||
func testGit(t *testing.T, u *url.URL) {
|
||||
username := "user2"
|
||||
baseAPITestContext := NewAPITestContext(t, username, "repo1")
|
||||
|
||||
u.Path = baseAPITestContext.GitPath()
|
||||
|
||||
forkedUserCtx := NewAPITestContext(t, "user4", "repo1")
|
||||
|
||||
t.Run("HTTP", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
ensureAnonymousClone(t, u)
|
||||
httpContext := baseAPITestContext
|
||||
httpContext.Reponame = "repo-tmp-17"
|
||||
forkedUserCtx.Reponame = httpContext.Reponame
|
||||
|
||||
dstPath, err := os.MkdirTemp("", httpContext.Reponame)
|
||||
assert.NoError(t, err)
|
||||
defer util.RemoveAll(dstPath)
|
||||
|
||||
t.Run("CreateRepoInDifferentUser", doAPICreateRepository(forkedUserCtx, false))
|
||||
t.Run("AddUserAsCollaborator", doAPIAddCollaborator(forkedUserCtx, httpContext.Username, perm.AccessModeRead))
|
||||
|
||||
t.Run("ForkFromDifferentUser", doAPIForkRepository(httpContext, forkedUserCtx.Username))
|
||||
|
||||
u.Path = httpContext.GitPath()
|
||||
u.User = url.UserPassword(username, userPassword)
|
||||
|
||||
t.Run("Clone", doGitClone(dstPath, u))
|
||||
|
||||
dstPath2, err := os.MkdirTemp("", httpContext.Reponame)
|
||||
assert.NoError(t, err)
|
||||
defer util.RemoveAll(dstPath2)
|
||||
|
||||
t.Run("Partial Clone", doPartialGitClone(dstPath2, u))
|
||||
|
||||
little, big := standardCommitAndPushTest(t, dstPath)
|
||||
littleLFS, bigLFS := lfsCommitAndPushTest(t, dstPath)
|
||||
rawTest(t, &httpContext, little, big, littleLFS, bigLFS)
|
||||
mediaTest(t, &httpContext, little, big, littleLFS, bigLFS)
|
||||
|
||||
t.Run("CreateAgitFlowPull", doCreateAgitFlowPull(dstPath, &httpContext, "master", "test/head"))
|
||||
t.Run("BranchProtectMerge", doBranchProtectPRMerge(&httpContext, dstPath))
|
||||
t.Run("AutoMerge", doAutoPRMerge(&httpContext, dstPath))
|
||||
t.Run("CreatePRAndSetManuallyMerged", doCreatePRAndSetManuallyMerged(httpContext, httpContext, dstPath, "master", "test-manually-merge"))
|
||||
t.Run("MergeFork", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
t.Run("CreatePRAndMerge", doMergeFork(httpContext, forkedUserCtx, "master", httpContext.Username+":master"))
|
||||
rawTest(t, &forkedUserCtx, little, big, littleLFS, bigLFS)
|
||||
mediaTest(t, &forkedUserCtx, little, big, littleLFS, bigLFS)
|
||||
})
|
||||
|
||||
t.Run("PushCreate", doPushCreate(httpContext, u))
|
||||
})
|
||||
t.Run("SSH", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
sshContext := baseAPITestContext
|
||||
sshContext.Reponame = "repo-tmp-18"
|
||||
keyname := "my-testing-key"
|
||||
forkedUserCtx.Reponame = sshContext.Reponame
|
||||
t.Run("CreateRepoInDifferentUser", doAPICreateRepository(forkedUserCtx, false))
|
||||
t.Run("AddUserAsCollaborator", doAPIAddCollaborator(forkedUserCtx, sshContext.Username, perm.AccessModeRead))
|
||||
t.Run("ForkFromDifferentUser", doAPIForkRepository(sshContext, forkedUserCtx.Username))
|
||||
|
||||
// Setup key the user ssh key
|
||||
withKeyFile(t, keyname, func(keyFile string) {
|
||||
t.Run("CreateUserKey", doAPICreateUserKey(sshContext, "test-key", keyFile))
|
||||
|
||||
// Setup remote link
|
||||
// TODO: get url from api
|
||||
sshURL := createSSHUrl(sshContext.GitPath(), u)
|
||||
|
||||
// Setup clone folder
|
||||
dstPath, err := os.MkdirTemp("", sshContext.Reponame)
|
||||
assert.NoError(t, err)
|
||||
defer util.RemoveAll(dstPath)
|
||||
|
||||
t.Run("Clone", doGitClone(dstPath, sshURL))
|
||||
|
||||
little, big := standardCommitAndPushTest(t, dstPath)
|
||||
littleLFS, bigLFS := lfsCommitAndPushTest(t, dstPath)
|
||||
rawTest(t, &sshContext, little, big, littleLFS, bigLFS)
|
||||
mediaTest(t, &sshContext, little, big, littleLFS, bigLFS)
|
||||
|
||||
t.Run("CreateAgitFlowPull", doCreateAgitFlowPull(dstPath, &sshContext, "master", "test/head2"))
|
||||
t.Run("BranchProtectMerge", doBranchProtectPRMerge(&sshContext, dstPath))
|
||||
t.Run("MergeFork", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
t.Run("CreatePRAndMerge", doMergeFork(sshContext, forkedUserCtx, "master", sshContext.Username+":master"))
|
||||
rawTest(t, &forkedUserCtx, little, big, littleLFS, bigLFS)
|
||||
mediaTest(t, &forkedUserCtx, little, big, littleLFS, bigLFS)
|
||||
})
|
||||
|
||||
t.Run("PushCreate", doPushCreate(sshContext, sshURL))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func ensureAnonymousClone(t *testing.T, u *url.URL) {
|
||||
dstLocalPath, err := os.MkdirTemp("", "repo1")
|
||||
assert.NoError(t, err)
|
||||
defer util.RemoveAll(dstLocalPath)
|
||||
t.Run("CloneAnonymous", doGitClone(dstLocalPath, u))
|
||||
}
|
||||
|
||||
func standardCommitAndPushTest(t *testing.T, dstPath string) (little, big string) {
|
||||
t.Run("Standard", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
little, big = commitAndPushTest(t, dstPath, "data-file-")
|
||||
})
|
||||
return little, big
|
||||
}
|
||||
|
||||
func lfsCommitAndPushTest(t *testing.T, dstPath string) (littleLFS, bigLFS string) {
|
||||
t.Run("LFS", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
prefix := "lfs-data-file-"
|
||||
err := git.NewCommand(git.DefaultContext, "lfs").AddArguments("install").Run(&git.RunOpts{Dir: dstPath})
|
||||
assert.NoError(t, err)
|
||||
_, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("track", prefix+"*").RunStdString(&git.RunOpts{Dir: dstPath})
|
||||
assert.NoError(t, err)
|
||||
err = git.AddChanges(dstPath, false, ".gitattributes")
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = git.CommitChangesWithArgs(dstPath, git.AllowLFSFiltersArgs(), git.CommitChangesOptions{
|
||||
Committer: &git.Signature{
|
||||
Email: "user2@example.com",
|
||||
Name: "User Two",
|
||||
When: time.Now(),
|
||||
},
|
||||
Author: &git.Signature{
|
||||
Email: "user2@example.com",
|
||||
Name: "User Two",
|
||||
When: time.Now(),
|
||||
},
|
||||
Message: fmt.Sprintf("Testing commit @ %v", time.Now()),
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
littleLFS, bigLFS = commitAndPushTest(t, dstPath, prefix)
|
||||
|
||||
t.Run("Locks", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
lockTest(t, dstPath)
|
||||
})
|
||||
})
|
||||
return littleLFS, bigLFS
|
||||
}
|
||||
|
||||
func commitAndPushTest(t *testing.T, dstPath, prefix string) (little, big string) {
|
||||
t.Run("PushCommit", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
t.Run("Little", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
little = doCommitAndPush(t, littleSize, dstPath, prefix)
|
||||
})
|
||||
t.Run("Big", func(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping test in short mode.")
|
||||
return
|
||||
}
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
big = doCommitAndPush(t, bigSize, dstPath, prefix)
|
||||
})
|
||||
})
|
||||
return little, big
|
||||
}
|
||||
|
||||
func rawTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS string) {
|
||||
t.Run("Raw", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
username := ctx.Username
|
||||
reponame := ctx.Reponame
|
||||
|
||||
session := loginUser(t, username)
|
||||
|
||||
// Request raw paths
|
||||
req := NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", little))
|
||||
resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
|
||||
assert.Equal(t, littleSize, resp.Length)
|
||||
|
||||
if setting.LFS.StartServer {
|
||||
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", littleLFS))
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.NotEqual(t, littleSize, resp.Body.Len())
|
||||
assert.LessOrEqual(t, resp.Body.Len(), 1024)
|
||||
if resp.Body.Len() != littleSize && resp.Body.Len() <= 1024 {
|
||||
assert.Contains(t, resp.Body.String(), lfs.MetaFileIdentifier)
|
||||
}
|
||||
}
|
||||
|
||||
if !testing.Short() {
|
||||
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", big))
|
||||
resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
|
||||
assert.Equal(t, bigSize, resp.Length)
|
||||
|
||||
if setting.LFS.StartServer {
|
||||
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", bigLFS))
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.NotEqual(t, bigSize, resp.Body.Len())
|
||||
if resp.Body.Len() != bigSize && resp.Body.Len() <= 1024 {
|
||||
assert.Contains(t, resp.Body.String(), lfs.MetaFileIdentifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func mediaTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS string) {
|
||||
t.Run("Media", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
username := ctx.Username
|
||||
reponame := ctx.Reponame
|
||||
|
||||
session := loginUser(t, username)
|
||||
|
||||
// Request media paths
|
||||
req := NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", little))
|
||||
resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
|
||||
assert.Equal(t, littleSize, resp.Length)
|
||||
|
||||
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", littleLFS))
|
||||
resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
|
||||
assert.Equal(t, littleSize, resp.Length)
|
||||
|
||||
if !testing.Short() {
|
||||
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", big))
|
||||
resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
|
||||
assert.Equal(t, bigSize, resp.Length)
|
||||
|
||||
if setting.LFS.StartServer {
|
||||
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", bigLFS))
|
||||
resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
|
||||
assert.Equal(t, bigSize, resp.Length)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func lockTest(t *testing.T, repoPath string) {
|
||||
lockFileTest(t, "README.md", repoPath)
|
||||
}
|
||||
|
||||
func lockFileTest(t *testing.T, filename, repoPath string) {
|
||||
_, _, err := git.NewCommand(git.DefaultContext, "lfs").AddArguments("locks").RunStdString(&git.RunOpts{Dir: repoPath})
|
||||
assert.NoError(t, err)
|
||||
_, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("lock", filename).RunStdString(&git.RunOpts{Dir: repoPath})
|
||||
assert.NoError(t, err)
|
||||
_, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("locks").RunStdString(&git.RunOpts{Dir: repoPath})
|
||||
assert.NoError(t, err)
|
||||
_, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("unlock", filename).RunStdString(&git.RunOpts{Dir: repoPath})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func doCommitAndPush(t *testing.T, size int, repoPath, prefix string) string {
|
||||
name, err := generateCommitWithNewData(size, repoPath, "user2@example.com", "User Two", prefix)
|
||||
assert.NoError(t, err)
|
||||
_, _, err = git.NewCommand(git.DefaultContext, "push", "origin", "master").RunStdString(&git.RunOpts{Dir: repoPath}) // Push
|
||||
assert.NoError(t, err)
|
||||
return name
|
||||
}
|
||||
|
||||
func generateCommitWithNewData(size int, repoPath, email, fullName, prefix string) (string, error) {
|
||||
// Generate random file
|
||||
bufSize := 4 * 1024
|
||||
if bufSize > size {
|
||||
bufSize = size
|
||||
}
|
||||
|
||||
buffer := make([]byte, bufSize)
|
||||
|
||||
tmpFile, err := os.CreateTemp(repoPath, prefix)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer tmpFile.Close()
|
||||
written := 0
|
||||
for written < size {
|
||||
n := size - written
|
||||
if n > bufSize {
|
||||
n = bufSize
|
||||
}
|
||||
_, err := rand.Read(buffer[:n])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
n, err = tmpFile.Write(buffer[:n])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
written += n
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Commit
|
||||
// Now here we should explicitly allow lfs filters to run
|
||||
globalArgs := git.AllowLFSFiltersArgs()
|
||||
err = git.AddChangesWithArgs(repoPath, globalArgs, false, filepath.Base(tmpFile.Name()))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = git.CommitChangesWithArgs(repoPath, globalArgs, git.CommitChangesOptions{
|
||||
Committer: &git.Signature{
|
||||
Email: email,
|
||||
Name: fullName,
|
||||
When: time.Now(),
|
||||
},
|
||||
Author: &git.Signature{
|
||||
Email: email,
|
||||
Name: fullName,
|
||||
When: time.Now(),
|
||||
},
|
||||
Message: fmt.Sprintf("Testing commit @ %v", time.Now()),
|
||||
})
|
||||
return filepath.Base(tmpFile.Name()), err
|
||||
}
|
||||
|
||||
func doBranchProtectPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
t.Run("CreateBranchProtected", doGitCreateBranch(dstPath, "protected"))
|
||||
t.Run("PushProtectedBranch", doGitPushTestRepository(dstPath, "origin", "protected"))
|
||||
|
||||
ctx := NewAPITestContext(t, baseCtx.Username, baseCtx.Reponame)
|
||||
t.Run("ProtectProtectedBranchNoWhitelist", doProtectBranch(ctx, "protected", "", ""))
|
||||
t.Run("GenerateCommit", func(t *testing.T) {
|
||||
_, err := generateCommitWithNewData(littleSize, dstPath, "user2@example.com", "User Two", "branch-data-file-")
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("FailToPushToProtectedBranch", doGitPushTestRepositoryFail(dstPath, "origin", "protected"))
|
||||
t.Run("PushToUnprotectedBranch", doGitPushTestRepository(dstPath, "origin", "protected:unprotected"))
|
||||
var pr api.PullRequest
|
||||
var err error
|
||||
t.Run("CreatePullRequest", func(t *testing.T) {
|
||||
pr, err = doAPICreatePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, "protected", "unprotected")(t)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("GenerateCommit", func(t *testing.T) {
|
||||
_, err := generateCommitWithNewData(littleSize, dstPath, "user2@example.com", "User Two", "branch-data-file-")
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("PushToUnprotectedBranch", doGitPushTestRepository(dstPath, "origin", "protected:unprotected-2"))
|
||||
var pr2 api.PullRequest
|
||||
t.Run("CreatePullRequest", func(t *testing.T) {
|
||||
pr2, err = doAPICreatePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, "unprotected", "unprotected-2")(t)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("MergePR2", doAPIMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr2.Index))
|
||||
t.Run("MergePR", doAPIMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index))
|
||||
t.Run("PullProtected", doGitPull(dstPath, "origin", "protected"))
|
||||
|
||||
t.Run("ProtectProtectedBranchUnprotectedFilePaths", doProtectBranch(ctx, "protected", "", "unprotected-file-*"))
|
||||
t.Run("GenerateCommit", func(t *testing.T) {
|
||||
_, err := generateCommitWithNewData(littleSize, dstPath, "user2@example.com", "User Two", "unprotected-file-")
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("PushUnprotectedFilesToProtectedBranch", doGitPushTestRepository(dstPath, "origin", "protected"))
|
||||
|
||||
t.Run("ProtectProtectedBranchWhitelist", doProtectBranch(ctx, "protected", baseCtx.Username, ""))
|
||||
|
||||
t.Run("CheckoutMaster", doGitCheckoutBranch(dstPath, "master"))
|
||||
t.Run("CreateBranchForced", doGitCreateBranch(dstPath, "toforce"))
|
||||
t.Run("GenerateCommit", func(t *testing.T) {
|
||||
_, err := generateCommitWithNewData(littleSize, dstPath, "user2@example.com", "User Two", "branch-data-file-")
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("FailToForcePushToProtectedBranch", doGitPushTestRepositoryFail(dstPath, "-f", "origin", "toforce:protected"))
|
||||
t.Run("MergeProtectedToToforce", doGitMerge(dstPath, "protected"))
|
||||
t.Run("PushToProtectedBranch", doGitPushTestRepository(dstPath, "origin", "toforce:protected"))
|
||||
t.Run("CheckoutMasterAgain", doGitCheckoutBranch(dstPath, "master"))
|
||||
}
|
||||
}
|
||||
|
||||
func doProtectBranch(ctx APITestContext, branch, userToWhitelist, unprotectedFilePatterns string) func(t *testing.T) {
|
||||
// We are going to just use the owner to set the protection.
|
||||
return func(t *testing.T) {
|
||||
csrf := GetCSRF(t, ctx.Session, fmt.Sprintf("/%s/%s/settings/branches", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame)))
|
||||
|
||||
if userToWhitelist == "" {
|
||||
// Change branch to protected
|
||||
req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/settings/branches/%s", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame), url.PathEscape(branch)), map[string]string{
|
||||
"_csrf": csrf,
|
||||
"protected": "on",
|
||||
"unprotected_file_patterns": unprotectedFilePatterns,
|
||||
})
|
||||
ctx.Session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
} else {
|
||||
user, err := user_model.GetUserByName(db.DefaultContext, userToWhitelist)
|
||||
assert.NoError(t, err)
|
||||
// Change branch to protected
|
||||
req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/settings/branches/%s", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame), url.PathEscape(branch)), map[string]string{
|
||||
"_csrf": csrf,
|
||||
"protected": "on",
|
||||
"enable_push": "whitelist",
|
||||
"enable_whitelist": "on",
|
||||
"whitelist_users": strconv.FormatInt(user.ID, 10),
|
||||
"unprotected_file_patterns": unprotectedFilePatterns,
|
||||
})
|
||||
ctx.Session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
}
|
||||
// Check if master branch has been locked successfully
|
||||
flashCookie := ctx.Session.GetCookie("macaron_flash")
|
||||
assert.NotNil(t, flashCookie)
|
||||
assert.EqualValues(t, "success%3DBranch%2Bprotection%2Bfor%2Bbranch%2B%2527"+url.QueryEscape(branch)+"%2527%2Bhas%2Bbeen%2Bupdated.", flashCookie.Value)
|
||||
}
|
||||
}
|
||||
|
||||
func doMergeFork(ctx, baseCtx 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(ctx, baseCtx.Username, baseCtx.Reponame, baseBranch, headBranch)(t)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
// Ensure the PR page works
|
||||
t.Run("EnsureCanSeePull", doEnsureCanSeePull(baseCtx, pr))
|
||||
|
||||
// Then get the diff string
|
||||
var diffHash string
|
||||
var diffLength int
|
||||
t.Run("GetDiff", func(t *testing.T) {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d.diff", url.PathEscape(baseCtx.Username), url.PathEscape(baseCtx.Reponame), pr.Index))
|
||||
resp := ctx.Session.MakeRequestNilResponseHashSumRecorder(t, req, http.StatusOK)
|
||||
diffHash = string(resp.Hash.Sum(nil))
|
||||
diffLength = resp.Length
|
||||
})
|
||||
|
||||
// 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))
|
||||
t.Run("CheckPR", func(t *testing.T) {
|
||||
oldMergeBase := pr.MergeBase
|
||||
pr2, err := doAPIGetPullRequest(baseCtx, baseCtx.Username, baseCtx.Reponame, pr.Index)(t)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, oldMergeBase, pr2.MergeBase)
|
||||
})
|
||||
t.Run("EnsurDiffNoChange", doEnsureDiffNoChange(baseCtx, pr, diffHash, diffLength))
|
||||
|
||||
// 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("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("EnsureDiffNoChange", doEnsureDiffNoChange(baseCtx, pr, diffHash, diffLength))
|
||||
}
|
||||
}
|
||||
|
||||
func doCreatePRAndSetManuallyMerged(ctx, baseCtx APITestContext, dstPath, baseBranch, headBranch string) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
var (
|
||||
pr api.PullRequest
|
||||
err error
|
||||
lastCommitID string
|
||||
)
|
||||
|
||||
trueBool := true
|
||||
falseBool := false
|
||||
|
||||
t.Run("AllowSetManuallyMergedAndSwitchOffAutodetectManualMerge", doAPIEditRepository(baseCtx, &api.EditRepoOption{
|
||||
HasPullRequests: &trueBool,
|
||||
AllowManualMerge: &trueBool,
|
||||
AutodetectManualMerge: &falseBool,
|
||||
}))
|
||||
|
||||
t.Run("CreateHeadBranch", doGitCreateBranch(dstPath, headBranch))
|
||||
t.Run("PushToHeadBranch", doGitPushTestRepository(dstPath, "origin", headBranch))
|
||||
t.Run("CreateEmptyPullRequest", func(t *testing.T) {
|
||||
pr, err = doAPICreatePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, baseBranch, headBranch)(t)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
lastCommitID = pr.Base.Sha
|
||||
t.Run("ManuallyMergePR", doAPIManuallyMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, lastCommitID, pr.Index))
|
||||
}
|
||||
}
|
||||
|
||||
func doEnsureCanSeePull(ctx APITestContext, pr api.PullRequest) 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)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
func doEnsureDiffNoChange(ctx APITestContext, pr api.PullRequest, diffHash string, diffLength int) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d.diff", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame), pr.Index))
|
||||
resp := ctx.Session.MakeRequestNilResponseHashSumRecorder(t, req, http.StatusOK)
|
||||
actual := string(resp.Hash.Sum(nil))
|
||||
actualLength := resp.Length
|
||||
|
||||
equal := diffHash == actual
|
||||
assert.True(t, equal, "Unexpected change in the diff string: expected hash: %s size: %d but was actually: %s size: %d", hex.EncodeToString([]byte(diffHash)), diffLength, hex.EncodeToString([]byte(actual)), actualLength)
|
||||
}
|
||||
}
|
||||
|
||||
func doPushCreate(ctx APITestContext, u *url.URL) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
// create a context for a currently non-existent repository
|
||||
ctx.Reponame = fmt.Sprintf("repo-tmp-push-create-%s", u.Scheme)
|
||||
u.Path = ctx.GitPath()
|
||||
|
||||
// Create a temporary directory
|
||||
tmpDir, err := os.MkdirTemp("", ctx.Reponame)
|
||||
assert.NoError(t, err)
|
||||
defer util.RemoveAll(tmpDir)
|
||||
|
||||
// Now create local repository to push as our test and set its origin
|
||||
t.Run("InitTestRepository", doGitInitTestRepository(tmpDir))
|
||||
t.Run("AddRemote", doGitAddRemote(tmpDir, "origin", u))
|
||||
|
||||
// Disable "Push To Create" and attempt to push
|
||||
setting.Repository.EnablePushCreateUser = false
|
||||
t.Run("FailToPushAndCreateTestRepository", doGitPushTestRepositoryFail(tmpDir, "origin", "master"))
|
||||
|
||||
// Enable "Push To Create"
|
||||
setting.Repository.EnablePushCreateUser = true
|
||||
|
||||
// Assert that cloning from a non-existent repository does not create it and that it definitely wasn't create above
|
||||
t.Run("FailToCloneFromNonExistentRepository", doGitCloneFail(u))
|
||||
|
||||
// Then "Push To Create"x
|
||||
t.Run("SuccessfullyPushAndCreateTestRepository", doGitPushTestRepository(tmpDir, "origin", "master"))
|
||||
|
||||
// Finally, fetch repo from database and ensure the correct repository has been created
|
||||
repo, err := repo_model.GetRepositoryByOwnerAndName(ctx.Username, ctx.Reponame)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, repo.IsEmpty)
|
||||
assert.True(t, repo.IsPrivate)
|
||||
|
||||
// Now add a remote that is invalid to "Push To Create"
|
||||
invalidCtx := ctx
|
||||
invalidCtx.Reponame = fmt.Sprintf("invalid/repo-tmp-push-create-%s", u.Scheme)
|
||||
u.Path = invalidCtx.GitPath()
|
||||
t.Run("AddInvalidRemote", doGitAddRemote(tmpDir, "invalid", u))
|
||||
|
||||
// Fail to "Push To Create" the invalid
|
||||
t.Run("FailToPushAndCreateInvalidTestRepository", doGitPushTestRepositoryFail(tmpDir, "invalid", "master"))
|
||||
}
|
||||
}
|
||||
|
||||
func doBranchDelete(ctx APITestContext, owner, repo, branch string) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
csrf := GetCSRF(t, ctx.Session, fmt.Sprintf("/%s/%s/branches", url.PathEscape(owner), url.PathEscape(repo)))
|
||||
|
||||
req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/branches/delete?name=%s", url.PathEscape(owner), url.PathEscape(repo), url.QueryEscape(branch)), map[string]string{
|
||||
"_csrf": csrf,
|
||||
})
|
||||
ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
func doAutoPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
ctx := NewAPITestContext(t, baseCtx.Username, baseCtx.Reponame)
|
||||
|
||||
t.Run("CheckoutProtected", doGitCheckoutBranch(dstPath, "protected"))
|
||||
t.Run("PullProtected", doGitPull(dstPath, "origin", "protected"))
|
||||
t.Run("GenerateCommit", func(t *testing.T) {
|
||||
_, err := generateCommitWithNewData(littleSize, dstPath, "user2@example.com", "User Two", "branch-data-file-")
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("PushToUnprotectedBranch", doGitPushTestRepository(dstPath, "origin", "protected:unprotected3"))
|
||||
var pr api.PullRequest
|
||||
var err error
|
||||
t.Run("CreatePullRequest", func(t *testing.T) {
|
||||
pr, err = doAPICreatePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, "protected", "unprotected3")(t)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
// Request repository commits page
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d/commits", baseCtx.Username, baseCtx.Reponame, pr.Index))
|
||||
resp := ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
// Get first commit URL
|
||||
commitURL, exists := doc.doc.Find("#commits-table tbody tr td.sha a").Last().Attr("href")
|
||||
assert.True(t, exists)
|
||||
assert.NotEmpty(t, commitURL)
|
||||
|
||||
commitID := path.Base(commitURL)
|
||||
|
||||
// Call API to add Pending status for commit
|
||||
t.Run("CreateStatus", doAPICreateCommitStatus(ctx, commitID, api.CommitStatusPending))
|
||||
|
||||
// Cancel not existing auto merge
|
||||
ctx.ExpectedCode = http.StatusNotFound
|
||||
t.Run("CancelAutoMergePR", doAPICancelAutoMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index))
|
||||
|
||||
// Add auto merge request
|
||||
ctx.ExpectedCode = http.StatusCreated
|
||||
t.Run("AutoMergePR", doAPIAutoMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index))
|
||||
|
||||
// Can not create schedule twice
|
||||
ctx.ExpectedCode = http.StatusConflict
|
||||
t.Run("AutoMergePRTwice", doAPIAutoMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index))
|
||||
|
||||
// Cancel auto merge request
|
||||
ctx.ExpectedCode = http.StatusNoContent
|
||||
t.Run("CancelAutoMergePR", doAPICancelAutoMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index))
|
||||
|
||||
// Add auto merge request
|
||||
ctx.ExpectedCode = http.StatusCreated
|
||||
t.Run("AutoMergePR", doAPIAutoMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index))
|
||||
|
||||
// Check pr status
|
||||
ctx.ExpectedCode = 0
|
||||
pr, err = doAPIGetPullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)(t)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, pr.HasMerged)
|
||||
|
||||
// Call API to add Failure status for commit
|
||||
t.Run("CreateStatus", doAPICreateCommitStatus(ctx, commitID, api.CommitStatusFailure))
|
||||
|
||||
// Check pr status
|
||||
pr, err = doAPIGetPullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)(t)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, pr.HasMerged)
|
||||
|
||||
// Call API to add Success status for commit
|
||||
t.Run("CreateStatus", doAPICreateCommitStatus(ctx, commitID, api.CommitStatusSuccess))
|
||||
|
||||
// wait to let gitea merge stuff
|
||||
time.Sleep(time.Second)
|
||||
|
||||
// test pr status
|
||||
pr, err = doAPIGetPullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)(t)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, pr.HasMerged)
|
||||
}
|
||||
}
|
||||
|
||||
func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headBranch string) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
// skip this test if git version is low
|
||||
if git.CheckGitVersionAtLeast("2.29") != nil {
|
||||
return
|
||||
}
|
||||
|
||||
gitRepo, err := git.OpenRepository(git.DefaultContext, dstPath)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
defer gitRepo.Close()
|
||||
|
||||
var (
|
||||
pr1, pr2 *issues_model.PullRequest
|
||||
commit string
|
||||
)
|
||||
repo, err := repo_model.GetRepositoryByOwnerAndName(ctx.Username, ctx.Reponame)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
pullNum := unittest.GetCount(t, &issues_model.PullRequest{})
|
||||
|
||||
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)
|
||||
commit, err = gitRepo.GetRefCommitID("HEAD")
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("Push", func(t *testing.T) {
|
||||
err := git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master", "-o", "topic="+headBranch).Run(&git.RunOpts{Dir: dstPath})
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
unittest.AssertCount(t, &issues_model.PullRequest{}, pullNum+1)
|
||||
pr1 = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{
|
||||
HeadRepoID: repo.ID,
|
||||
Flow: issues_model.PullRequestFlowAGit,
|
||||
})
|
||||
if !assert.NotEmpty(t, pr1) {
|
||||
return
|
||||
}
|
||||
prMsg, err := doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr1.Index)(t)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
assert.Equal(t, "user2/"+headBranch, pr1.HeadBranch)
|
||||
assert.Equal(t, false, prMsg.HasMerged)
|
||||
assert.Contains(t, "Testing commit 1", prMsg.Body)
|
||||
assert.Equal(t, commit, prMsg.Head.Sha)
|
||||
|
||||
_, _, err = git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master/test/"+headBranch).RunStdString(&git.RunOpts{Dir: dstPath})
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
unittest.AssertCount(t, &issues_model.PullRequest{}, pullNum+2)
|
||||
pr2 = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{
|
||||
HeadRepoID: repo.ID,
|
||||
Index: pr1.Index + 1,
|
||||
Flow: issues_model.PullRequestFlowAGit,
|
||||
})
|
||||
if !assert.NotEmpty(t, pr2) {
|
||||
return
|
||||
}
|
||||
prMsg, err = doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr2.Index)(t)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
assert.Equal(t, "user2/test/"+headBranch, pr2.HeadBranch)
|
||||
assert.Equal(t, false, prMsg.HasMerged)
|
||||
})
|
||||
|
||||
if pr1 == nil || pr2 == nil {
|
||||
return
|
||||
}
|
||||
|
||||
t.Run("AddCommit2", func(t *testing.T) {
|
||||
err := os.WriteFile(path.Join(dstPath, "test_file"), []byte("## test content \n ## test content 2"), 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 2",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
commit, err = gitRepo.GetRefCommitID("HEAD")
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("Push2", func(t *testing.T) {
|
||||
err := git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master", "-o", "topic="+headBranch).Run(&git.RunOpts{Dir: dstPath})
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
unittest.AssertCount(t, &issues_model.PullRequest{}, pullNum+2)
|
||||
prMsg, err := doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr1.Index)(t)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
assert.Equal(t, false, prMsg.HasMerged)
|
||||
assert.Equal(t, commit, prMsg.Head.Sha)
|
||||
|
||||
_, _, err = git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master/test/"+headBranch).RunStdString(&git.RunOpts{Dir: dstPath})
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
unittest.AssertCount(t, &issues_model.PullRequest{}, pullNum+2)
|
||||
prMsg, err = doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr2.Index)(t)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
assert.Equal(t, false, prMsg.HasMerged)
|
||||
assert.Equal(t, commit, prMsg.Head.Sha)
|
||||
})
|
||||
t.Run("Merge", doAPIMergePullRequest(*ctx, ctx.Username, ctx.Reponame, pr1.Index))
|
||||
t.Run("CheckoutMasterAgain", doGitCheckoutBranch(dstPath, "master"))
|
||||
}
|
||||
}
|
36
tests/integration/goget_test.go
Normal file
36
tests/integration/goget_test.go
Normal file
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGoGet(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/blah/glah/plah?go-get=1")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
expected := fmt.Sprintf(`<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="go-import" content="%[1]s:%[2]s/blah/glah git %[3]sblah/glah.git">
|
||||
<meta name="go-source" content="%[1]s:%[2]s/blah/glah _ %[3]sblah/glah/src/branch/master{/dir} %[3]sblah/glah/src/branch/master{/dir}/{file}#L{line}">
|
||||
</head>
|
||||
<body>
|
||||
go get --insecure %[1]s:%[2]s/blah/glah
|
||||
</body>
|
||||
</html>`, setting.Domain, setting.HTTPPort, setting.AppURL)
|
||||
|
||||
assert.Equal(t, expected, resp.Body.String())
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue