loading up the forgejo repo on tangled to test page performance
at forgejo 291 lines 10 kB view raw
1// Copyright The Forgejo Authors 2// SPDX-License-Identifier: MIT 3 4package integration 5 6import ( 7 "context" 8 "errors" 9 "fmt" 10 "net" 11 "net/http" 12 "net/url" 13 "os" 14 "os/exec" 15 "path/filepath" 16 "strconv" 17 "testing" 18 "time" 19 20 asymkey_model "forgejo.org/models/asymkey" 21 auth_model "forgejo.org/models/auth" 22 "forgejo.org/models/db" 23 repo_model "forgejo.org/models/repo" 24 "forgejo.org/models/unit" 25 "forgejo.org/models/unittest" 26 user_model "forgejo.org/models/user" 27 "forgejo.org/modules/git" 28 "forgejo.org/modules/optional" 29 "forgejo.org/modules/setting" 30 api "forgejo.org/modules/structs" 31 "forgejo.org/modules/test" 32 "forgejo.org/services/migrations" 33 mirror_service "forgejo.org/services/mirror" 34 repo_service "forgejo.org/services/repository" 35 "forgejo.org/tests" 36 37 "github.com/stretchr/testify/assert" 38 "github.com/stretchr/testify/require" 39) 40 41func TestAPIPushMirror(t *testing.T) { 42 onGiteaRun(t, testAPIPushMirror) 43} 44 45func testAPIPushMirror(t *testing.T, u *url.URL) { 46 defer test.MockVariableValue(&setting.Migrations.AllowLocalNetworks, true)() 47 defer test.MockVariableValue(&setting.Mirror.Enabled, true)() 48 defer test.MockProtect(&mirror_service.AddPushMirrorRemote)() 49 defer test.MockProtect(&repo_model.DeletePushMirrors)() 50 51 require.NoError(t, migrations.Init()) 52 53 user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) 54 srcRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) 55 owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: srcRepo.OwnerID}) 56 session := loginUser(t, user.Name) 57 token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll) 58 urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/push_mirrors", owner.Name, srcRepo.Name) 59 60 mirrorRepo, err := repo_service.CreateRepositoryDirectly(db.DefaultContext, user, user, repo_service.CreateRepoOptions{ 61 Name: "test-push-mirror", 62 }) 63 require.NoError(t, err) 64 remoteAddress := fmt.Sprintf("%s%s/%s", u.String(), url.PathEscape(user.Name), url.PathEscape(mirrorRepo.Name)) 65 66 deletePushMirrors := repo_model.DeletePushMirrors 67 deletePushMirrorsError := errors.New("deletePushMirrorsError") 68 deletePushMirrorsFail := func(ctx context.Context, opts repo_model.PushMirrorOptions) error { 69 return deletePushMirrorsError 70 } 71 72 addPushMirrorRemote := mirror_service.AddPushMirrorRemote 73 addPushMirrorRemoteError := errors.New("addPushMirrorRemoteError") 74 addPushMirrorRemoteFail := func(ctx context.Context, m *repo_model.PushMirror, addr string) error { 75 return addPushMirrorRemoteError 76 } 77 78 for _, testCase := range []struct { 79 name string 80 message string 81 status int 82 mirrorCount int 83 setup func() 84 }{ 85 { 86 name: "success", 87 status: http.StatusOK, 88 mirrorCount: 1, 89 setup: func() { 90 mirror_service.AddPushMirrorRemote = addPushMirrorRemote 91 repo_model.DeletePushMirrors = deletePushMirrors 92 }, 93 }, 94 { 95 name: "fail to add and delete", 96 message: deletePushMirrorsError.Error(), 97 status: http.StatusInternalServerError, 98 mirrorCount: 1, 99 setup: func() { 100 mirror_service.AddPushMirrorRemote = addPushMirrorRemoteFail 101 repo_model.DeletePushMirrors = deletePushMirrorsFail 102 }, 103 }, 104 { 105 name: "fail to add", 106 message: addPushMirrorRemoteError.Error(), 107 status: http.StatusInternalServerError, 108 mirrorCount: 0, 109 setup: func() { 110 mirror_service.AddPushMirrorRemote = addPushMirrorRemoteFail 111 repo_model.DeletePushMirrors = deletePushMirrors 112 }, 113 }, 114 } { 115 t.Run(testCase.name, func(t *testing.T) { 116 testCase.setup() 117 req := NewRequestWithJSON(t, "POST", urlStr, &api.CreatePushMirrorOption{ 118 RemoteAddress: remoteAddress, 119 Interval: "8h", 120 }).AddTokenAuth(token) 121 122 resp := MakeRequest(t, req, testCase.status) 123 if testCase.message != "" { 124 err := api.APIError{} 125 DecodeJSON(t, resp, &err) 126 assert.Equal(t, testCase.message, err.Message) 127 } 128 129 req = NewRequest(t, "GET", urlStr).AddTokenAuth(token) 130 resp = MakeRequest(t, req, http.StatusOK) 131 var pushMirrors []*api.PushMirror 132 DecodeJSON(t, resp, &pushMirrors) 133 if assert.Len(t, pushMirrors, testCase.mirrorCount) && testCase.mirrorCount > 0 { 134 pushMirror := pushMirrors[0] 135 assert.Equal(t, remoteAddress, pushMirror.RemoteAddress) 136 137 repo_model.DeletePushMirrors = deletePushMirrors 138 req = NewRequest(t, "DELETE", fmt.Sprintf("%s/%s", urlStr, pushMirror.RemoteName)).AddTokenAuth(token) 139 MakeRequest(t, req, http.StatusNoContent) 140 } 141 }) 142 } 143} 144 145func TestAPIPushMirrorSSH(t *testing.T) { 146 _, err := exec.LookPath("ssh") 147 if err != nil { 148 t.Skip("SSH executable not present") 149 } 150 151 onGiteaRun(t, func(t *testing.T, _ *url.URL) { 152 defer test.MockVariableValue(&setting.Migrations.AllowLocalNetworks, true)() 153 defer test.MockVariableValue(&setting.Mirror.Enabled, true)() 154 defer test.MockVariableValue(&setting.SSH.RootPath, t.TempDir())() 155 require.NoError(t, migrations.Init()) 156 157 user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) 158 srcRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) 159 assert.False(t, srcRepo.HasWiki()) 160 session := loginUser(t, user.Name) 161 token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) 162 pushToRepo, _, f := tests.CreateDeclarativeRepoWithOptions(t, user, tests.DeclarativeRepoOptions{ 163 Name: optional.Some("push-mirror-test"), 164 AutoInit: optional.Some(false), 165 EnabledUnits: optional.Some([]unit.Type{unit.TypeCode}), 166 }) 167 defer f() 168 169 sshURL := fmt.Sprintf("ssh://%s@%s/%s.git", setting.SSH.User, net.JoinHostPort(setting.SSH.ListenHost, strconv.Itoa(setting.SSH.ListenPort)), pushToRepo.FullName()) 170 171 t.Run("Mutual exclusive", func(t *testing.T) { 172 defer tests.PrintCurrentTest(t)() 173 174 req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/push_mirrors", srcRepo.FullName()), &api.CreatePushMirrorOption{ 175 RemoteAddress: sshURL, 176 Interval: "8h", 177 UseSSH: true, 178 RemoteUsername: "user", 179 RemotePassword: "password", 180 }).AddTokenAuth(token) 181 resp := MakeRequest(t, req, http.StatusBadRequest) 182 183 var apiError api.APIError 184 DecodeJSON(t, resp, &apiError) 185 assert.Equal(t, "'use_ssh' is mutually exclusive with 'remote_username' and 'remote_passoword'", apiError.Message) 186 }) 187 188 t.Run("SSH not available", func(t *testing.T) { 189 defer tests.PrintCurrentTest(t)() 190 defer test.MockVariableValue(&git.HasSSHExecutable, false)() 191 192 req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/push_mirrors", srcRepo.FullName()), &api.CreatePushMirrorOption{ 193 RemoteAddress: sshURL, 194 Interval: "8h", 195 UseSSH: true, 196 }).AddTokenAuth(token) 197 resp := MakeRequest(t, req, http.StatusBadRequest) 198 199 var apiError api.APIError 200 DecodeJSON(t, resp, &apiError) 201 assert.Equal(t, "SSH authentication not available.", apiError.Message) 202 }) 203 204 t.Run("Normal", func(t *testing.T) { 205 var pushMirror *repo_model.PushMirror 206 t.Run("Adding", func(t *testing.T) { 207 defer tests.PrintCurrentTest(t)() 208 209 req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/push_mirrors", srcRepo.FullName()), &api.CreatePushMirrorOption{ 210 RemoteAddress: sshURL, 211 Interval: "8h", 212 UseSSH: true, 213 }).AddTokenAuth(token) 214 MakeRequest(t, req, http.StatusOK) 215 216 pushMirror = unittest.AssertExistsAndLoadBean(t, &repo_model.PushMirror{RepoID: srcRepo.ID}) 217 assert.NotEmpty(t, pushMirror.PrivateKey) 218 assert.NotEmpty(t, pushMirror.PublicKey) 219 }) 220 221 publickey := pushMirror.GetPublicKey() 222 t.Run("Publickey", func(t *testing.T) { 223 defer tests.PrintCurrentTest(t)() 224 225 req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/push_mirrors", srcRepo.FullName())).AddTokenAuth(token) 226 resp := MakeRequest(t, req, http.StatusOK) 227 228 var pushMirrors []*api.PushMirror 229 DecodeJSON(t, resp, &pushMirrors) 230 assert.Len(t, pushMirrors, 1) 231 assert.Equal(t, publickey, pushMirrors[0].PublicKey) 232 }) 233 234 t.Run("Add deploy key", func(t *testing.T) { 235 defer tests.PrintCurrentTest(t)() 236 237 req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/keys", pushToRepo.FullName()), &api.CreateKeyOption{ 238 Title: "push mirror key", 239 Key: publickey, 240 ReadOnly: false, 241 }).AddTokenAuth(token) 242 MakeRequest(t, req, http.StatusCreated) 243 244 unittest.AssertExistsAndLoadBean(t, &asymkey_model.DeployKey{Name: "push mirror key", RepoID: pushToRepo.ID}) 245 }) 246 247 t.Run("Synchronize", func(t *testing.T) { 248 defer tests.PrintCurrentTest(t)() 249 250 req := NewRequest(t, "POST", fmt.Sprintf("/api/v1/repos/%s/push_mirrors-sync", srcRepo.FullName())).AddTokenAuth(token) 251 MakeRequest(t, req, http.StatusOK) 252 }) 253 254 t.Run("Check mirrored content", func(t *testing.T) { 255 defer tests.PrintCurrentTest(t)() 256 sha := "1032bbf17fbc0d9c95bb5418dabe8f8c99278700" 257 258 req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/commits?limit=1", srcRepo.FullName())).AddTokenAuth(token) 259 resp := MakeRequest(t, req, http.StatusOK) 260 261 var commitList []*api.Commit 262 DecodeJSON(t, resp, &commitList) 263 264 assert.Len(t, commitList, 1) 265 assert.Equal(t, sha, commitList[0].SHA) 266 267 assert.Eventually(t, func() bool { 268 req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/commits?limit=1", srcRepo.FullName())).AddTokenAuth(token) 269 resp := MakeRequest(t, req, http.StatusOK) 270 271 var commitList []*api.Commit 272 DecodeJSON(t, resp, &commitList) 273 274 return len(commitList) != 0 && commitList[0].SHA == sha 275 }, time.Second*30, time.Second) 276 }) 277 278 t.Run("Check known host keys", func(t *testing.T) { 279 defer tests.PrintCurrentTest(t)() 280 281 knownHosts, err := os.ReadFile(filepath.Join(setting.SSH.RootPath, "known_hosts")) 282 require.NoError(t, err) 283 284 publicKey, err := os.ReadFile(setting.SSH.ServerHostKeys[0] + ".pub") 285 require.NoError(t, err) 286 287 assert.Contains(t, string(knownHosts), string(publicKey)) 288 }) 289 }) 290 }) 291}