loading up the forgejo repo on tangled to test page performance
at forgejo 420 lines 15 kB view raw
1// Copyright 2017 The Gitea Authors. All rights reserved. 2// SPDX-License-Identifier: MIT 3 4package integration 5 6import ( 7 "fmt" 8 "net/http" 9 "testing" 10 "time" 11 12 asymkey_model "forgejo.org/models/asymkey" 13 auth_model "forgejo.org/models/auth" 14 "forgejo.org/models/unittest" 15 user_model "forgejo.org/models/user" 16 "forgejo.org/modules/json" 17 "forgejo.org/modules/setting" 18 api "forgejo.org/modules/structs" 19 "forgejo.org/tests" 20 21 "github.com/gobwas/glob" 22 "github.com/stretchr/testify/assert" 23) 24 25func TestAPIAdminCreateAndDeleteSSHKey(t *testing.T) { 26 defer tests.PrepareTestEnv(t)() 27 // user1 is an admin user 28 session := loginUser(t, "user1") 29 keyOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user2"}) 30 31 token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin) 32 urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys", keyOwner.Name) 33 req := NewRequestWithValues(t, "POST", urlStr, map[string]string{ 34 "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment\n", 35 "title": "test-key", 36 }).AddTokenAuth(token) 37 resp := MakeRequest(t, req, http.StatusCreated) 38 39 var newPublicKey api.PublicKey 40 DecodeJSON(t, resp, &newPublicKey) 41 unittest.AssertExistsAndLoadBean(t, &asymkey_model.PublicKey{ 42 ID: newPublicKey.ID, 43 Name: newPublicKey.Title, 44 Fingerprint: newPublicKey.Fingerprint, 45 OwnerID: keyOwner.ID, 46 }) 47 48 req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d", keyOwner.Name, newPublicKey.ID). 49 AddTokenAuth(token) 50 MakeRequest(t, req, http.StatusNoContent) 51 unittest.AssertNotExistsBean(t, &asymkey_model.PublicKey{ID: newPublicKey.ID}) 52} 53 54func TestAPIAdminDeleteMissingSSHKey(t *testing.T) { 55 defer tests.PrepareTestEnv(t)() 56 57 // user1 is an admin user 58 token := getUserToken(t, "user1", auth_model.AccessTokenScopeWriteAdmin) 59 req := NewRequestf(t, "DELETE", "/api/v1/admin/users/user1/keys/%d", unittest.NonexistentID). 60 AddTokenAuth(token) 61 MakeRequest(t, req, http.StatusNotFound) 62} 63 64func TestAPIAdminDeleteUnauthorizedKey(t *testing.T) { 65 defer tests.PrepareTestEnv(t)() 66 adminUsername := "user1" 67 normalUsername := "user2" 68 token := getUserToken(t, adminUsername, auth_model.AccessTokenScopeWriteAdmin) 69 70 urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys", adminUsername) 71 req := NewRequestWithValues(t, "POST", urlStr, map[string]string{ 72 "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment\n", 73 "title": "test-key", 74 }).AddTokenAuth(token) 75 resp := MakeRequest(t, req, http.StatusCreated) 76 var newPublicKey api.PublicKey 77 DecodeJSON(t, resp, &newPublicKey) 78 79 token = getUserToken(t, normalUsername) 80 req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d", adminUsername, newPublicKey.ID). 81 AddTokenAuth(token) 82 MakeRequest(t, req, http.StatusForbidden) 83} 84 85func TestAPISudoUser(t *testing.T) { 86 defer tests.PrepareTestEnv(t)() 87 adminUsername := "user1" 88 normalUsername := "user2" 89 token := getUserToken(t, adminUsername, auth_model.AccessTokenScopeReadUser) 90 91 req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/user?sudo=%s", normalUsername)). 92 AddTokenAuth(token) 93 resp := MakeRequest(t, req, http.StatusOK) 94 var user api.User 95 DecodeJSON(t, resp, &user) 96 97 assert.Equal(t, normalUsername, user.UserName) 98} 99 100func TestAPISudoUserForbidden(t *testing.T) { 101 defer tests.PrepareTestEnv(t)() 102 adminUsername := "user1" 103 normalUsername := "user2" 104 105 token := getUserToken(t, normalUsername, auth_model.AccessTokenScopeReadAdmin) 106 req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/user?sudo=%s", adminUsername)). 107 AddTokenAuth(token) 108 MakeRequest(t, req, http.StatusForbidden) 109} 110 111func TestAPIListUsers(t *testing.T) { 112 defer tests.PrepareTestEnv(t)() 113 adminUsername := "user1" 114 token := getUserToken(t, adminUsername, auth_model.AccessTokenScopeReadAdmin) 115 116 req := NewRequest(t, "GET", "/api/v1/admin/users"). 117 AddTokenAuth(token) 118 resp := MakeRequest(t, req, http.StatusOK) 119 var users []api.User 120 DecodeJSON(t, resp, &users) 121 122 found := false 123 for _, user := range users { 124 if user.UserName == adminUsername { 125 found = true 126 } 127 } 128 assert.True(t, found) 129 numberOfUsers := unittest.GetCount(t, &user_model.User{}, "type = 0") 130 assert.Len(t, users, numberOfUsers) 131} 132 133func TestAPIListUsersNotLoggedIn(t *testing.T) { 134 defer tests.PrepareTestEnv(t)() 135 req := NewRequest(t, "GET", "/api/v1/admin/users") 136 MakeRequest(t, req, http.StatusUnauthorized) 137} 138 139func TestAPIListUsersNonAdmin(t *testing.T) { 140 defer tests.PrepareTestEnv(t)() 141 nonAdminUsername := "user2" 142 token := getUserToken(t, nonAdminUsername) 143 req := NewRequest(t, "GET", "/api/v1/admin/users"). 144 AddTokenAuth(token) 145 MakeRequest(t, req, http.StatusForbidden) 146} 147 148func TestAPICreateUserInvalidEmail(t *testing.T) { 149 defer tests.PrepareTestEnv(t)() 150 adminUsername := "user1" 151 token := getUserToken(t, adminUsername, auth_model.AccessTokenScopeWriteAdmin) 152 req := NewRequestWithValues(t, "POST", "/api/v1/admin/users", map[string]string{ 153 "email": "invalid_email@domain.com\r\n", 154 "full_name": "invalid user", 155 "login_name": "invalidUser", 156 "must_change_password": "true", 157 "password": "password", 158 "send_notify": "true", 159 "source_id": "0", 160 "username": "invalidUser", 161 }).AddTokenAuth(token) 162 MakeRequest(t, req, http.StatusUnprocessableEntity) 163} 164 165func TestAPICreateAndDeleteUser(t *testing.T) { 166 defer tests.PrepareTestEnv(t)() 167 adminUsername := "user1" 168 token := getUserToken(t, adminUsername, auth_model.AccessTokenScopeWriteAdmin) 169 170 req := NewRequestWithValues( 171 t, 172 "POST", 173 "/api/v1/admin/users", 174 map[string]string{ 175 "email": "deleteme@domain.com", 176 "full_name": "delete me", 177 "login_name": "deleteme", 178 "must_change_password": "true", 179 "password": "password", 180 "send_notify": "true", 181 "source_id": "0", 182 "username": "deleteme", 183 }, 184 ).AddTokenAuth(token) 185 MakeRequest(t, req, http.StatusCreated) 186 187 req = NewRequest(t, "DELETE", "/api/v1/admin/users/deleteme"). 188 AddTokenAuth(token) 189 MakeRequest(t, req, http.StatusNoContent) 190} 191 192func TestAPIEditUser(t *testing.T) { 193 defer tests.PrepareTestEnv(t)() 194 adminUsername := "user1" 195 token := getUserToken(t, adminUsername, auth_model.AccessTokenScopeWriteAdmin) 196 urlStr := fmt.Sprintf("/api/v1/admin/users/%s", "user2") 197 198 fullNameToChange := "Full Name User 2" 199 req := NewRequestWithValues(t, "PATCH", urlStr, map[string]string{ 200 "full_name": fullNameToChange, 201 }).AddTokenAuth(token) 202 MakeRequest(t, req, http.StatusOK) 203 user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{LoginName: "user2"}) 204 assert.Equal(t, fullNameToChange, user2.FullName) 205 206 empty := "" 207 req = NewRequestWithJSON(t, "PATCH", urlStr, api.EditUserOption{ 208 Email: &empty, 209 }).AddTokenAuth(token) 210 resp := MakeRequest(t, req, http.StatusBadRequest) 211 212 errMap := make(map[string]any) 213 json.Unmarshal(resp.Body.Bytes(), &errMap) 214 assert.Equal(t, "e-mail invalid [email: ]", errMap["message"].(string)) 215 216 user2 = unittest.AssertExistsAndLoadBean(t, &user_model.User{LoginName: "user2"}) 217 assert.False(t, user2.IsRestricted) 218 bTrue := true 219 req = NewRequestWithJSON(t, "PATCH", urlStr, api.EditUserOption{ 220 Restricted: &bTrue, 221 }).AddTokenAuth(token) 222 MakeRequest(t, req, http.StatusOK) 223 user2 = unittest.AssertExistsAndLoadBean(t, &user_model.User{LoginName: "user2"}) 224 assert.True(t, user2.IsRestricted) 225} 226 227func TestAPIEditUserWithLoginName(t *testing.T) { 228 defer tests.PrepareTestEnv(t)() 229 230 adminUsername := "user1" 231 token := getUserToken(t, adminUsername, auth_model.AccessTokenScopeWriteAdmin) 232 urlStr := fmt.Sprintf("/api/v1/admin/users/%s", "user2") 233 234 loginName := "user2" 235 loginSource := int64(0) 236 237 t.Run("login_name only", func(t *testing.T) { 238 defer tests.PrintCurrentTest(t)() 239 240 req := NewRequestWithJSON(t, "PATCH", urlStr, api.EditUserOption{ 241 LoginName: &loginName, 242 }).AddTokenAuth(token) 243 MakeRequest(t, req, http.StatusUnprocessableEntity) 244 }) 245 246 t.Run("source_id only", func(t *testing.T) { 247 defer tests.PrintCurrentTest(t)() 248 249 req := NewRequestWithJSON(t, "PATCH", urlStr, api.EditUserOption{ 250 SourceID: &loginSource, 251 }).AddTokenAuth(token) 252 MakeRequest(t, req, http.StatusUnprocessableEntity) 253 }) 254 255 t.Run("login_name & source_id", func(t *testing.T) { 256 defer tests.PrintCurrentTest(t)() 257 258 req := NewRequestWithJSON(t, "PATCH", urlStr, api.EditUserOption{ 259 LoginName: &loginName, 260 SourceID: &loginSource, 261 }).AddTokenAuth(token) 262 MakeRequest(t, req, http.StatusOK) 263 }) 264} 265 266func TestAPICreateRepoForUser(t *testing.T) { 267 defer tests.PrepareTestEnv(t)() 268 adminUsername := "user1" 269 token := getUserToken(t, adminUsername, auth_model.AccessTokenScopeWriteAdmin) 270 271 req := NewRequestWithJSON( 272 t, 273 "POST", 274 fmt.Sprintf("/api/v1/admin/users/%s/repos", adminUsername), 275 &api.CreateRepoOption{ 276 Name: "admincreatedrepo", 277 }, 278 ).AddTokenAuth(token) 279 MakeRequest(t, req, http.StatusCreated) 280} 281 282func TestAPIRenameUser(t *testing.T) { 283 defer tests.PrepareTestEnv(t)() 284 adminUsername := "user1" 285 token := getUserToken(t, adminUsername, auth_model.AccessTokenScopeWriteAdmin) 286 urlStr := fmt.Sprintf("/api/v1/admin/users/%s/rename", "user2") 287 req := NewRequestWithValues(t, "POST", urlStr, map[string]string{ 288 // required 289 "new_name": "User2", 290 }).AddTokenAuth(token) 291 MakeRequest(t, req, http.StatusNoContent) 292 293 urlStr = fmt.Sprintf("/api/v1/admin/users/%s/rename", "User2") 294 req = NewRequestWithValues(t, "POST", urlStr, map[string]string{ 295 // required 296 "new_name": "User2-2-2", 297 }).AddTokenAuth(token) 298 MakeRequest(t, req, http.StatusNoContent) 299 300 req = NewRequestWithValues(t, "POST", urlStr, map[string]string{ 301 // required 302 "new_name": "user1", 303 }).AddTokenAuth(token) 304 // the old user name still be used by with a redirect 305 MakeRequest(t, req, http.StatusTemporaryRedirect) 306 307 urlStr = fmt.Sprintf("/api/v1/admin/users/%s/rename", "User2-2-2") 308 req = NewRequestWithValues(t, "POST", urlStr, map[string]string{ 309 // required 310 "new_name": "user1", 311 }).AddTokenAuth(token) 312 MakeRequest(t, req, http.StatusUnprocessableEntity) 313 314 req = NewRequestWithValues(t, "POST", urlStr, map[string]string{ 315 // required 316 "new_name": "user2", 317 }).AddTokenAuth(token) 318 MakeRequest(t, req, http.StatusNoContent) 319} 320 321func TestAPICron(t *testing.T) { 322 defer tests.PrepareTestEnv(t)() 323 324 // user1 is an admin user 325 session := loginUser(t, "user1") 326 327 t.Run("List", func(t *testing.T) { 328 defer tests.PrintCurrentTest(t)() 329 330 token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadAdmin) 331 332 req := NewRequest(t, "GET", "/api/v1/admin/cron"). 333 AddTokenAuth(token) 334 resp := MakeRequest(t, req, http.StatusOK) 335 336 assert.Equal(t, "28", resp.Header().Get("X-Total-Count")) 337 338 var crons []api.Cron 339 DecodeJSON(t, resp, &crons) 340 assert.Len(t, crons, 28) 341 }) 342 343 t.Run("Execute", func(t *testing.T) { 344 defer tests.PrintCurrentTest(t)() 345 346 now := time.Now() 347 token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin) 348 // Archive cleanup is harmless, because in the test environment there are none 349 // and is thus an NOOP operation and therefore doesn't interfere with any other 350 // tests. 351 req := NewRequest(t, "POST", "/api/v1/admin/cron/archive_cleanup"). 352 AddTokenAuth(token) 353 MakeRequest(t, req, http.StatusNoContent) 354 355 // Check for the latest run time for this cron, to ensure it has been run. 356 req = NewRequest(t, "GET", "/api/v1/admin/cron"). 357 AddTokenAuth(token) 358 resp := MakeRequest(t, req, http.StatusOK) 359 360 var crons []api.Cron 361 DecodeJSON(t, resp, &crons) 362 363 for _, cron := range crons { 364 if cron.Name == "archive_cleanup" { 365 assert.True(t, now.Before(cron.Prev)) 366 } 367 } 368 }) 369} 370 371func TestAPICreateUser_NotAllowedEmailDomain(t *testing.T) { 372 defer tests.PrepareTestEnv(t)() 373 374 setting.Service.EmailDomainAllowList = []glob.Glob{glob.MustCompile("example.org")} 375 defer func() { 376 setting.Service.EmailDomainAllowList = []glob.Glob{} 377 }() 378 379 adminUsername := "user1" 380 token := getUserToken(t, adminUsername, auth_model.AccessTokenScopeWriteAdmin) 381 382 req := NewRequestWithValues(t, "POST", "/api/v1/admin/users", map[string]string{ 383 "email": "allowedUser1@example1.org", 384 "login_name": "allowedUser1", 385 "username": "allowedUser1", 386 "password": "allowedUser1_pass", 387 "must_change_password": "true", 388 }).AddTokenAuth(token) 389 resp := MakeRequest(t, req, http.StatusCreated) 390 assert.Equal(t, "the domain of user email allowedUser1@example1.org conflicts with EMAIL_DOMAIN_ALLOWLIST or EMAIL_DOMAIN_BLOCKLIST", resp.Header().Get("X-Gitea-Warning")) 391 392 req = NewRequest(t, "DELETE", "/api/v1/admin/users/allowedUser1").AddTokenAuth(token) 393 MakeRequest(t, req, http.StatusNoContent) 394} 395 396func TestAPIEditUser_NotAllowedEmailDomain(t *testing.T) { 397 defer tests.PrepareTestEnv(t)() 398 399 setting.Service.EmailDomainAllowList = []glob.Glob{glob.MustCompile("example.org")} 400 defer func() { 401 setting.Service.EmailDomainAllowList = []glob.Glob{} 402 }() 403 404 adminUsername := "user1" 405 token := getUserToken(t, adminUsername, auth_model.AccessTokenScopeWriteAdmin) 406 urlStr := fmt.Sprintf("/api/v1/admin/users/%s", "user2") 407 408 newEmail := "user2@example1.com" 409 req := NewRequestWithJSON(t, "PATCH", urlStr, api.EditUserOption{ 410 Email: &newEmail, 411 }).AddTokenAuth(token) 412 resp := MakeRequest(t, req, http.StatusOK) 413 assert.Equal(t, "the domain of user email user2@example1.com conflicts with EMAIL_DOMAIN_ALLOWLIST or EMAIL_DOMAIN_BLOCKLIST", resp.Header().Get("X-Gitea-Warning")) 414 415 originalEmail := "user2@example.com" 416 req = NewRequestWithJSON(t, "PATCH", urlStr, api.EditUserOption{ 417 Email: &originalEmail, 418 }).AddTokenAuth(token) 419 MakeRequest(t, req, http.StatusOK) 420}