mirror of
https://github.com/go-gitea/gitea.git
synced 2026-05-06 04:01:05 +09:00
Add a build-time conversion step that transforms the existing Swagger 2.0 spec into an OpenAPI 3.0 spec. The OAS3 spec is served alongside the existing Swagger 2.0 spec, enabling API clients that require OAS3 to generate code directly from Gitea's API. This is not to be an answer to how gitea handles OAS3 long term, but a way to use what we have to move a step forward. --------- Signed-off-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com> Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
372 lines
15 KiB
Go
372 lines
15 KiB
Go
// Copyright 2017 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package integration
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
"testing"
|
|
|
|
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
|
auth_model "code.gitea.io/gitea/models/auth"
|
|
"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/modules/test"
|
|
"code.gitea.io/gitea/modules/translation"
|
|
"code.gitea.io/gitea/tests"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestUser(t *testing.T) {
|
|
defer tests.PrepareTestEnv(t)()
|
|
t.Run("ViewUser", testViewUser)
|
|
t.Run("RenameInvalidUsername", testRenameInvalidUsername)
|
|
t.Run("RenameReservedUsername", testRenameReservedUsername)
|
|
t.Run("ViewLimitedAndPrivateUserAndRename", testViewLimitedAndPrivateUserAndRename)
|
|
t.Run("ExportUserGPGKeys", testExportUserGPGKeys)
|
|
t.Run("GetUserRss", testGetUserRss)
|
|
t.Run("ListStopWatches", testUserListStopWatches)
|
|
t.Run("LocationMapLink", testUserLocationMapLink)
|
|
t.Run("RenameUsername", testRenameUsername)
|
|
}
|
|
|
|
func testViewUser(t *testing.T) {
|
|
req := NewRequest(t, "GET", "/user2")
|
|
MakeRequest(t, req, http.StatusOK)
|
|
|
|
req = NewRequest(t, "GET", "/user2.keys")
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
|
assert.Equal(t, `# Gitea isn't a key server. The keys are exported as the user uploaded and might not have been fully verified.
|
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDWVj0fQ5N8wNc0LVNA41wDLYJ89ZIbejrPfg/avyj3u/ZohAKsQclxG4Ju0VirduBFF9EOiuxoiFBRr3xRpqzpsZtnMPkWVWb+akZwBFAx8p+jKdy4QXR/SZqbVobrGwip2UjSrri1CtBxpJikojRIZfCnDaMOyd9Jp6KkujvniFzUWdLmCPxUE9zhTaPu0JsEP7MW0m6yx7ZUhHyfss+NtqmFTaDO+QlMR7L2QkDliN2Jl3Xa3PhuWnKJfWhdAq1Cw4oraKUOmIgXLkuiuxVQ6mD3AiFupkmfqdHq6h+uHHmyQqv3gU+/sD8GbGAhf6ftqhTsXjnv1Aj4R8NoDf9BS6KRkzkeun5UisSzgtfQzjOMEiJtmrep2ZQrMGahrXa+q4VKr0aKJfm+KlLfwm/JztfsBcqQWNcTURiCFqz+fgZw0Ey/de0eyMzldYTdXXNRYCKjs9bvBK+6SSXRM7AhftfQ0ZuoW5+gtinPrnmoOaSCEJbAiEiTO/BzOHgowiM=
|
|
`, resp.Body.String())
|
|
|
|
_ = db.TruncateBeans(t.Context(), &asymkey_model.PublicKey{})
|
|
_ = db.Insert(t.Context(), &asymkey_model.PublicKey{
|
|
OwnerID: 2,
|
|
Name: "key-1",
|
|
Content: "ssh-rsa AAAA",
|
|
Type: asymkey_model.KeyTypeUser,
|
|
}, &asymkey_model.PublicKey{
|
|
OwnerID: 2,
|
|
Name: "key-2",
|
|
Content: "principal",
|
|
Type: asymkey_model.KeyTypePrincipal,
|
|
})
|
|
req = NewRequest(t, "GET", "/user2.keys")
|
|
resp = MakeRequest(t, req, http.StatusOK)
|
|
assert.Equal(t, `# Gitea isn't a key server. The keys are exported as the user uploaded and might not have been fully verified.
|
|
ssh-rsa AAAA
|
|
`, resp.Body.String())
|
|
}
|
|
|
|
func testRenameUsername(t *testing.T) {
|
|
session := loginUser(t, "user2")
|
|
req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{
|
|
"name": "newUsername",
|
|
"email": "user2@example.com",
|
|
"language": "en-US",
|
|
})
|
|
session.MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "newUsername"})
|
|
unittest.AssertNotExistsBean(t, &user_model.User{Name: "user2"})
|
|
}
|
|
|
|
func testViewLimitedAndPrivateUserAndRename(t *testing.T) {
|
|
// user 22 is a limited visibility org
|
|
org22 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 22})
|
|
req := NewRequest(t, "GET", "/"+org22.Name)
|
|
MakeRequest(t, req, http.StatusNotFound)
|
|
|
|
session := loginUser(t, "user1")
|
|
oldName := org22.Name
|
|
newName := "org22_renamed"
|
|
req = NewRequestWithValues(t, "POST", "/org/"+oldName+"/settings/rename", map[string]string{
|
|
"org_name": oldName,
|
|
"new_org_name": newName,
|
|
})
|
|
session.MakeRequest(t, req, http.StatusOK)
|
|
|
|
unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: newName})
|
|
unittest.AssertNotExistsBean(t, &user_model.User{Name: oldName})
|
|
|
|
req = NewRequest(t, "GET", "/"+oldName)
|
|
MakeRequest(t, req, http.StatusNotFound) // anonymous user cannot visit limited visibility org via old name
|
|
req = NewRequest(t, "GET", "/"+oldName)
|
|
session.MakeRequest(t, req, http.StatusTemporaryRedirect) // login user can visit limited visibility org via old name
|
|
|
|
// org 23 is a private visibility org
|
|
org23 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 23})
|
|
req = NewRequest(t, "GET", "/"+org23.Name)
|
|
MakeRequest(t, req, http.StatusNotFound)
|
|
|
|
oldName = org23.Name
|
|
newName = "org23_renamed"
|
|
req = NewRequestWithValues(t, "POST", "/org/"+oldName+"/settings/rename", map[string]string{
|
|
"org_name": oldName,
|
|
"new_org_name": newName,
|
|
})
|
|
session.MakeRequest(t, req, http.StatusOK)
|
|
|
|
unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: newName})
|
|
unittest.AssertNotExistsBean(t, &user_model.User{Name: oldName})
|
|
|
|
req = NewRequest(t, "GET", "/"+oldName)
|
|
MakeRequest(t, req, http.StatusNotFound) // anonymous user cannot visit limited visibility org via old name
|
|
req = NewRequest(t, "GET", "/"+oldName)
|
|
session.MakeRequest(t, req, http.StatusTemporaryRedirect) // login user can visit limited visibility org via old name
|
|
|
|
// user 31 is a private visibility user
|
|
user31 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 31})
|
|
req = NewRequest(t, "GET", "/"+user31.Name)
|
|
MakeRequest(t, req, http.StatusNotFound)
|
|
|
|
oldName = user31.Name
|
|
newName = "user31_renamed"
|
|
session2 := loginUser(t, oldName)
|
|
req = NewRequestWithValues(t, "POST", "/user/settings", map[string]string{
|
|
"name": newName,
|
|
"visibility": "2", // private
|
|
})
|
|
session2.MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: newName})
|
|
unittest.AssertNotExistsBean(t, &user_model.User{Name: oldName})
|
|
|
|
req = NewRequest(t, "GET", "/"+oldName)
|
|
MakeRequest(t, req, http.StatusNotFound) // anonymous user cannot visit private visibility user via old name
|
|
req = NewRequest(t, "GET", "/"+oldName)
|
|
session.MakeRequest(t, req, http.StatusTemporaryRedirect) // login user2 can visit private visibility user via old name
|
|
}
|
|
|
|
func testRenameInvalidUsername(t *testing.T) {
|
|
invalidUsernames := []string{
|
|
"%2f*",
|
|
"%2f.",
|
|
"%2f..",
|
|
"%00",
|
|
"thisHas ASpace",
|
|
"p<A>tho>lo<gical",
|
|
".",
|
|
"..",
|
|
".well-known",
|
|
".abc",
|
|
"abc.",
|
|
"a..bc",
|
|
"a...bc",
|
|
"a.-bc",
|
|
"a._bc",
|
|
"a_-bc",
|
|
"a/bc",
|
|
"☁️",
|
|
"-",
|
|
"--diff",
|
|
"-im-here",
|
|
"a space",
|
|
}
|
|
|
|
session := loginUser(t, "user2")
|
|
for _, invalidUsername := range invalidUsernames {
|
|
t.Logf("Testing username %s", invalidUsername)
|
|
|
|
req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{
|
|
"name": invalidUsername,
|
|
"email": "user2@example.com",
|
|
})
|
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
|
assert.Contains(t,
|
|
htmlDoc.doc.Find(".ui.negative.message").Text(),
|
|
translation.NewLocale("en-US").TrString("form.username_error"),
|
|
)
|
|
|
|
unittest.AssertNotExistsBean(t, &user_model.User{Name: invalidUsername})
|
|
}
|
|
}
|
|
|
|
func testRenameReservedUsername(t *testing.T) {
|
|
// ".", "..", ".well-known" are also reserved but invalid as form input.
|
|
reservedNames := []string{
|
|
"api",
|
|
"openapi3.v1.json",
|
|
"swagger.v1.json",
|
|
}
|
|
patternNotAllowedNames := []string{
|
|
"name.keys",
|
|
}
|
|
|
|
session := loginUser(t, "user2")
|
|
locale := translation.NewLocale("en-US")
|
|
check := func(name, msgKey string) {
|
|
req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{
|
|
"name": name,
|
|
"email": "user2@example.com",
|
|
"language": "en-US",
|
|
})
|
|
resp := session.MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
req = NewRequest(t, "GET", test.RedirectURL(resp))
|
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
|
actualMsg := strings.TrimSpace(htmlDoc.doc.Find(".ui.negative.message").Text())
|
|
assert.Equal(t, locale.TrString(msgKey, name), actualMsg)
|
|
unittest.AssertNotExistsBean(t, &user_model.User{Name: name})
|
|
}
|
|
for _, name := range reservedNames {
|
|
check(name, "user.form.name_reserved")
|
|
}
|
|
for _, name := range patternNotAllowedNames {
|
|
check(name, "user.form.name_pattern_not_allowed")
|
|
}
|
|
}
|
|
|
|
func testExportUserGPGKeys(t *testing.T) {
|
|
testExportUserGPGKeys := func(t *testing.T, user, expected string) {
|
|
session := loginUser(t, user)
|
|
t.Logf("Testing username %s export gpg keys", user)
|
|
req := NewRequest(t, "GET", "/"+user+".gpg")
|
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
|
assert.Equal(t, expected, resp.Body.String())
|
|
}
|
|
|
|
// Export empty key list
|
|
testExportUserGPGKeys(t, "user1", `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
Comment: Gitea isn't a key server. The keys are exported as the user uploaded and might not have been fully verified.
|
|
Note: This user hasn't uploaded any GPG keys.
|
|
|
|
|
|
=twTO
|
|
-----END PGP PUBLIC KEY BLOCK-----`)
|
|
// Import key
|
|
// User1 <user1@example.com>
|
|
session := loginUser(t, "user1")
|
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteUser)
|
|
testCreateGPGKey(t, session.MakeRequest, token, http.StatusCreated, `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
|
|
mQENBFyy/VUBCADJ7zbM20Z1RWmFoVgp5WkQfI2rU1Vj9cQHes9i42wVLLtcbPeo
|
|
QzubgzvMPITDy7nfWxgSf83E23DoHQ1ACFbQh/6eFSRrjsusp3YQ/08NSfPPbcu8
|
|
0M5G+VGwSfzS5uEcwBVQmHyKdcOZIERTNMtYZx1C3bjLD1XVJHvWz9D72Uq4qeO3
|
|
8SR+lzp5n6ppUakcmRnxt3nGRBj1+hEGkdgzyPo93iy+WioegY2lwCA9xMEo5dah
|
|
BmYxWx51zyiXYlReTaxlyb3/nuSUt8IcW3Q8zjdtJj4Nu8U1SpV8EdaA1I9IPbHW
|
|
510OSLmD3XhqHH5m6mIxL1YoWxk3V7gpDROtABEBAAG0GVVzZXIxIDx1c2VyMUBl
|
|
eGFtcGxlLmNvbT6JAU4EEwEIADgWIQTQEbrYxmXsp1z3j7z9+v0I6RSEHwUCXLL9
|
|
VQIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRD9+v0I6RSEH22YCACFqL5+
|
|
6M0m18AMC/pumcpnnmvAS1GrrKTF8nOROA1augZwp1WCNuKw2R6uOJIHANrYECSn
|
|
u7+j6GBP2gbIW8mSAzS6HWCs7GGiPpVtT4wcu8wljUI6BxjpyZtoEkriyBjt6HfK
|
|
rkegbkuySoJvjq4IcO5D1LB1JWgsUjMYQJj/ZpBIzVtjG9QtFSOiT1Hct4PoZHdC
|
|
nsdSgyCkwRZXG+u3kT/wP9F663ba4o16vYlz3dCGo66lF2tyoG3qcyZ1OUzUrnuv
|
|
96ytAzT6XIhrE0nVoBprMxFF5zExotJD3bHjcGBFNLf944bhjKee3U6t9+OsfJVC
|
|
l7N5xxIawCuTQdbfuQENBFyy/VUBCADe61yGEoTwKfsOKIhxLaNoRmD883O0tiWt
|
|
soO/HPj9dPQLTOiwXgSgSCd8C+LNxGKct87wgFozpah4tDLC6c0nALuHJ0SLbkfz
|
|
55aRhLeOOcrAydatDp72GroXzqpZ0xZBk5wjIWdgEol2GmVRM8QGbeuakU/HVz5y
|
|
lPzxUUocgdbSi3GE3zbzijQzVJdyL/kw/KP7pKT/PPKKJ2C5NQDLy0XGKEHddXGR
|
|
EWKkVlRalxq/TjfaMR0bi3MpezBsQmp99ATPO/d7trayZUxQHRtXzGFiOXfDHATr
|
|
qN730sODjqvU+mpc/SHCRwh9qWDjZRHSuKU5YDBjb5jIQJivZsQ/ABEBAAGJATYE
|
|
GAEIACAWIQTQEbrYxmXsp1z3j7z9+v0I6RSEHwUCXLL9VQIbDAAKCRD9+v0I6RSE
|
|
H7WoB/4tXl+97rQ6owPCGSVp1Xbwt2521V7COgsOFRVTRTryEWxRW8mm0S7wQvax
|
|
C0TLXKur6NVYQMn01iyL+FZzRpEWNuYF3f9QeeLJ/+l2DafESNhNTy17+RPmacK6
|
|
21dccpqchByVw/UMDeHSyjQLiG2lxzt8Gfx2gHmSbrq3aWovTGyz6JTffZvfy/n2
|
|
0Hm437OBPazO0gZyXhdV2PE5RSUfvAgm44235tcV5EV0d32TJDfv61+Vr2GUbah6
|
|
7XhJ1v6JYuh8kaYaEz8OpZDeh7f6Ho6PzJrsy/TKTKhGgZNINj1iaPFyOkQgKR5M
|
|
GrE0MHOxUbc9tbtyk0F1SuzREUBH
|
|
=DDXw
|
|
-----END PGP PUBLIC KEY BLOCK-----`)
|
|
// Export new key
|
|
testExportUserGPGKeys(t, "user1", `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
Comment: Gitea isn't a key server. The keys are exported as the user uploaded and might not have been fully verified.
|
|
|
|
xsBNBFyy/VUBCADJ7zbM20Z1RWmFoVgp5WkQfI2rU1Vj9cQHes9i42wVLLtcbPeo
|
|
QzubgzvMPITDy7nfWxgSf83E23DoHQ1ACFbQh/6eFSRrjsusp3YQ/08NSfPPbcu8
|
|
0M5G+VGwSfzS5uEcwBVQmHyKdcOZIERTNMtYZx1C3bjLD1XVJHvWz9D72Uq4qeO3
|
|
8SR+lzp5n6ppUakcmRnxt3nGRBj1+hEGkdgzyPo93iy+WioegY2lwCA9xMEo5dah
|
|
BmYxWx51zyiXYlReTaxlyb3/nuSUt8IcW3Q8zjdtJj4Nu8U1SpV8EdaA1I9IPbHW
|
|
510OSLmD3XhqHH5m6mIxL1YoWxk3V7gpDROtABEBAAHNGVVzZXIxIDx1c2VyMUBl
|
|
eGFtcGxlLmNvbT7CwI4EEwEIADgWIQTQEbrYxmXsp1z3j7z9+v0I6RSEHwUCXLL9
|
|
VQIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRD9+v0I6RSEH22YCACFqL5+
|
|
6M0m18AMC/pumcpnnmvAS1GrrKTF8nOROA1augZwp1WCNuKw2R6uOJIHANrYECSn
|
|
u7+j6GBP2gbIW8mSAzS6HWCs7GGiPpVtT4wcu8wljUI6BxjpyZtoEkriyBjt6HfK
|
|
rkegbkuySoJvjq4IcO5D1LB1JWgsUjMYQJj/ZpBIzVtjG9QtFSOiT1Hct4PoZHdC
|
|
nsdSgyCkwRZXG+u3kT/wP9F663ba4o16vYlz3dCGo66lF2tyoG3qcyZ1OUzUrnuv
|
|
96ytAzT6XIhrE0nVoBprMxFF5zExotJD3bHjcGBFNLf944bhjKee3U6t9+OsfJVC
|
|
l7N5xxIawCuTQdbfzsBNBFyy/VUBCADe61yGEoTwKfsOKIhxLaNoRmD883O0tiWt
|
|
soO/HPj9dPQLTOiwXgSgSCd8C+LNxGKct87wgFozpah4tDLC6c0nALuHJ0SLbkfz
|
|
55aRhLeOOcrAydatDp72GroXzqpZ0xZBk5wjIWdgEol2GmVRM8QGbeuakU/HVz5y
|
|
lPzxUUocgdbSi3GE3zbzijQzVJdyL/kw/KP7pKT/PPKKJ2C5NQDLy0XGKEHddXGR
|
|
EWKkVlRalxq/TjfaMR0bi3MpezBsQmp99ATPO/d7trayZUxQHRtXzGFiOXfDHATr
|
|
qN730sODjqvU+mpc/SHCRwh9qWDjZRHSuKU5YDBjb5jIQJivZsQ/ABEBAAHCwHYE
|
|
GAEIACAWIQTQEbrYxmXsp1z3j7z9+v0I6RSEHwUCXLL9VQIbDAAKCRD9+v0I6RSE
|
|
H7WoB/4tXl+97rQ6owPCGSVp1Xbwt2521V7COgsOFRVTRTryEWxRW8mm0S7wQvax
|
|
C0TLXKur6NVYQMn01iyL+FZzRpEWNuYF3f9QeeLJ/+l2DafESNhNTy17+RPmacK6
|
|
21dccpqchByVw/UMDeHSyjQLiG2lxzt8Gfx2gHmSbrq3aWovTGyz6JTffZvfy/n2
|
|
0Hm437OBPazO0gZyXhdV2PE5RSUfvAgm44235tcV5EV0d32TJDfv61+Vr2GUbah6
|
|
7XhJ1v6JYuh8kaYaEz8OpZDeh7f6Ho6PzJrsy/TKTKhGgZNINj1iaPFyOkQgKR5M
|
|
GrE0MHOxUbc9tbtyk0F1SuzREUBH
|
|
=WFf5
|
|
-----END PGP PUBLIC KEY BLOCK-----`)
|
|
}
|
|
|
|
func testGetUserRss(t *testing.T) {
|
|
user34 := "the_34-user.with.all.allowedChars"
|
|
req := NewRequestf(t, "GET", "/%s.rss", user34)
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
|
if assert.Equal(t, "application/rss+xml;charset=utf-8", resp.Header().Get("Content-Type")) {
|
|
rssDoc := NewHTMLParser(t, resp.Body).Find("channel")
|
|
title, _ := rssDoc.ChildrenFiltered("title").Html()
|
|
assert.Equal(t, "Feed of "the_1-user.with.all.allowedChars"", title)
|
|
description, _ := rssDoc.ChildrenFiltered("description").Html()
|
|
assert.Equal(t, "<p dir="auto">some <a href="https://commonmark.org/" rel="nofollow">commonmark</a>!</p>\n", description)
|
|
}
|
|
|
|
req = NewRequestf(t, "GET", "/non-existent-user.rss")
|
|
MakeRequest(t, req, http.StatusNotFound)
|
|
|
|
session := loginUser(t, "user2")
|
|
req = NewRequestf(t, "GET", "/non-existent-user.rss")
|
|
session.MakeRequest(t, req, http.StatusNotFound)
|
|
}
|
|
|
|
func testUserListStopWatches(t *testing.T) {
|
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
|
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
|
|
|
session := loginUser(t, owner.Name)
|
|
req := NewRequest(t, "GET", "/user/stopwatches")
|
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
|
apiWatches := DecodeJSON(t, resp, []*api.StopWatch{})
|
|
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.Equal(t, stopwatch.CreatedUnix.AsTime().Unix(), apiWatches[0].Created.Unix())
|
|
assert.Equal(t, issue.Index, apiWatches[0].IssueIndex)
|
|
assert.Equal(t, issue.Title, apiWatches[0].IssueTitle)
|
|
assert.Equal(t, repo.Name, apiWatches[0].RepoName)
|
|
assert.Equal(t, repo.OwnerName, apiWatches[0].RepoOwnerName)
|
|
assert.Positive(t, apiWatches[0].Seconds)
|
|
}
|
|
}
|
|
|
|
func testUserLocationMapLink(t *testing.T) {
|
|
defer test.MockVariableValue(&setting.Service.UserLocationMapURL, "https://example/foo/")()
|
|
|
|
session := loginUser(t, "user2")
|
|
req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{
|
|
"name": "user2",
|
|
"email": "user@example.com",
|
|
"language": "en-US",
|
|
"location": "A/b",
|
|
})
|
|
session.MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
req = NewRequest(t, "GET", "/user2/")
|
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
|
AssertHTMLElement(t, htmlDoc, `a[href="https://example/foo/A%2Fb"]`, true)
|
|
}
|