You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package integrations
  5. import (
  6. "context"
  7. "crypto/rand"
  8. "fmt"
  9. "io/ioutil"
  10. "net"
  11. "net/http"
  12. "net/url"
  13. "os"
  14. "path/filepath"
  15. "testing"
  16. "time"
  17. "code.gitea.io/git"
  18. "code.gitea.io/gitea/models"
  19. "code.gitea.io/gitea/modules/setting"
  20. api "code.gitea.io/sdk/gitea"
  21. "github.com/Unknwon/com"
  22. "github.com/stretchr/testify/assert"
  23. )
  24. const (
  25. littleSize = 1024 //1ko
  26. bigSize = 128 * 1024 * 1024 //128Mo
  27. )
  28. func onGiteaRun(t *testing.T, callback func(*testing.T, *url.URL)) {
  29. prepareTestEnv(t)
  30. s := http.Server{
  31. Handler: mac,
  32. }
  33. u, err := url.Parse(setting.AppURL)
  34. assert.NoError(t, err)
  35. listener, err := net.Listen("tcp", u.Host)
  36. assert.NoError(t, err)
  37. defer func() {
  38. ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
  39. s.Shutdown(ctx)
  40. cancel()
  41. }()
  42. go s.Serve(listener)
  43. //Started by config go ssh.Listen(setting.SSH.ListenHost, setting.SSH.ListenPort, setting.SSH.ServerCiphers, setting.SSH.ServerKeyExchanges, setting.SSH.ServerMACs)
  44. callback(t, u)
  45. }
  46. func TestGit(t *testing.T) {
  47. onGiteaRun(t, func(t *testing.T, u *url.URL) {
  48. u.Path = "user2/repo1.git"
  49. t.Run("HTTP", func(t *testing.T) {
  50. dstPath, err := ioutil.TempDir("", "repo-tmp-17")
  51. assert.NoError(t, err)
  52. defer os.RemoveAll(dstPath)
  53. t.Run("Standard", func(t *testing.T) {
  54. t.Run("CloneNoLogin", func(t *testing.T) {
  55. dstLocalPath, err := ioutil.TempDir("", "repo1")
  56. assert.NoError(t, err)
  57. defer os.RemoveAll(dstLocalPath)
  58. err = git.Clone(u.String(), dstLocalPath, git.CloneRepoOptions{})
  59. assert.NoError(t, err)
  60. assert.True(t, com.IsExist(filepath.Join(dstLocalPath, "README.md")))
  61. })
  62. t.Run("CreateRepo", func(t *testing.T) {
  63. session := loginUser(t, "user2")
  64. req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos", &api.CreateRepoOption{
  65. AutoInit: true,
  66. Description: "Temporary repo",
  67. Name: "repo-tmp-17",
  68. Private: false,
  69. Gitignores: "",
  70. License: "WTFPL",
  71. Readme: "Default",
  72. })
  73. session.MakeRequest(t, req, http.StatusCreated)
  74. })
  75. u.Path = "user2/repo-tmp-17.git"
  76. u.User = url.UserPassword("user2", userPassword)
  77. t.Run("Clone", func(t *testing.T) {
  78. err = git.Clone(u.String(), dstPath, git.CloneRepoOptions{})
  79. assert.NoError(t, err)
  80. assert.True(t, com.IsExist(filepath.Join(dstPath, "README.md")))
  81. })
  82. t.Run("PushCommit", func(t *testing.T) {
  83. t.Run("Little", func(t *testing.T) {
  84. commitAndPush(t, littleSize, dstPath)
  85. })
  86. t.Run("Big", func(t *testing.T) {
  87. commitAndPush(t, bigSize, dstPath)
  88. })
  89. })
  90. })
  91. t.Run("LFS", func(t *testing.T) {
  92. t.Run("PushCommit", func(t *testing.T) {
  93. //Setup git LFS
  94. _, err = git.NewCommand("lfs").AddArguments("install").RunInDir(dstPath)
  95. assert.NoError(t, err)
  96. _, err = git.NewCommand("lfs").AddArguments("track", "data-file-*").RunInDir(dstPath)
  97. assert.NoError(t, err)
  98. err = git.AddChanges(dstPath, false, ".gitattributes")
  99. assert.NoError(t, err)
  100. t.Run("Little", func(t *testing.T) {
  101. commitAndPush(t, littleSize, dstPath)
  102. })
  103. t.Run("Big", func(t *testing.T) {
  104. commitAndPush(t, bigSize, dstPath)
  105. })
  106. })
  107. t.Run("Locks", func(t *testing.T) {
  108. lockTest(t, u.String(), dstPath)
  109. })
  110. })
  111. })
  112. t.Run("SSH", func(t *testing.T) {
  113. //Setup remote link
  114. u.Scheme = "ssh"
  115. u.User = url.User("git")
  116. u.Host = fmt.Sprintf("%s:%d", setting.SSH.ListenHost, setting.SSH.ListenPort)
  117. u.Path = "user2/repo-tmp-18.git"
  118. //Setup key
  119. keyFile := filepath.Join(setting.AppDataPath, "my-testing-key")
  120. _, _, err := com.ExecCmd("ssh-keygen", "-f", keyFile, "-t", "rsa", "-N", "")
  121. assert.NoError(t, err)
  122. defer os.RemoveAll(keyFile)
  123. defer os.RemoveAll(keyFile + ".pub")
  124. session := loginUser(t, "user1")
  125. keyOwner := models.AssertExistsAndLoadBean(t, &models.User{Name: "user2"}).(*models.User)
  126. urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys", keyOwner.Name)
  127. dataPubKey, err := ioutil.ReadFile(keyFile + ".pub")
  128. assert.NoError(t, err)
  129. req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
  130. "key": string(dataPubKey),
  131. "title": "test-key",
  132. })
  133. session.MakeRequest(t, req, http.StatusCreated)
  134. //Setup ssh wrapper
  135. sshWrapper, err := ioutil.TempFile(setting.AppDataPath, "tmp-ssh-wrapper")
  136. sshWrapper.WriteString("#!/bin/sh\n\n")
  137. sshWrapper.WriteString("ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i \"" + filepath.Join(setting.AppWorkPath, keyFile) + "\" $* \n\n")
  138. err = sshWrapper.Chmod(os.ModePerm)
  139. assert.NoError(t, err)
  140. sshWrapper.Close()
  141. defer os.RemoveAll(sshWrapper.Name())
  142. //Setup clone folder
  143. dstPath, err := ioutil.TempDir("", "repo-tmp-18")
  144. assert.NoError(t, err)
  145. defer os.RemoveAll(dstPath)
  146. t.Run("Standard", func(t *testing.T) {
  147. t.Run("CreateRepo", func(t *testing.T) {
  148. session := loginUser(t, "user2")
  149. req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos", &api.CreateRepoOption{
  150. AutoInit: true,
  151. Description: "Temporary repo",
  152. Name: "repo-tmp-18",
  153. Private: false,
  154. Gitignores: "",
  155. License: "WTFPL",
  156. Readme: "Default",
  157. })
  158. session.MakeRequest(t, req, http.StatusCreated)
  159. })
  160. //TODO get url from api
  161. t.Run("Clone", func(t *testing.T) {
  162. _, err = git.NewCommand("clone").AddArguments("--config", "core.sshCommand="+filepath.Join(setting.AppWorkPath, sshWrapper.Name()), u.String(), dstPath).Run()
  163. assert.NoError(t, err)
  164. assert.True(t, com.IsExist(filepath.Join(dstPath, "README.md")))
  165. })
  166. //time.Sleep(5 * time.Minute)
  167. t.Run("PushCommit", func(t *testing.T) {
  168. t.Run("Little", func(t *testing.T) {
  169. commitAndPush(t, littleSize, dstPath)
  170. })
  171. t.Run("Big", func(t *testing.T) {
  172. commitAndPush(t, bigSize, dstPath)
  173. })
  174. })
  175. })
  176. t.Run("LFS", func(t *testing.T) {
  177. os.Setenv("GIT_SSH_COMMAND", filepath.Join(setting.AppWorkPath, sshWrapper.Name())) //TODO remove when fixed https://github.com/git-lfs/git-lfs/issues/2215
  178. defer os.Unsetenv("GIT_SSH_COMMAND")
  179. t.Run("PushCommit", func(t *testing.T) {
  180. //Setup git LFS
  181. _, err = git.NewCommand("lfs").AddArguments("install").RunInDir(dstPath)
  182. assert.NoError(t, err)
  183. _, err = git.NewCommand("lfs").AddArguments("track", "data-file-*").RunInDir(dstPath)
  184. assert.NoError(t, err)
  185. err = git.AddChanges(dstPath, false, ".gitattributes")
  186. assert.NoError(t, err)
  187. t.Run("Little", func(t *testing.T) {
  188. commitAndPush(t, littleSize, dstPath)
  189. })
  190. t.Run("Big", func(t *testing.T) {
  191. commitAndPush(t, bigSize, dstPath)
  192. })
  193. })
  194. /* Failed without #3152. TODO activate with fix.
  195. t.Run("Locks", func(t *testing.T) {
  196. lockTest(t, u.String(), dstPath)
  197. })
  198. */
  199. })
  200. })
  201. })
  202. }
  203. func lockTest(t *testing.T, remote, repoPath string) {
  204. _, err := git.NewCommand("remote").AddArguments("set-url", "origin", remote).RunInDir(repoPath) //TODO add test ssh git-lfs-creds
  205. assert.NoError(t, err)
  206. _, err = git.NewCommand("lfs").AddArguments("locks").RunInDir(repoPath)
  207. assert.NoError(t, err)
  208. _, err = git.NewCommand("lfs").AddArguments("lock", "README.md").RunInDir(repoPath)
  209. assert.NoError(t, err)
  210. _, err = git.NewCommand("lfs").AddArguments("locks").RunInDir(repoPath)
  211. assert.NoError(t, err)
  212. _, err = git.NewCommand("lfs").AddArguments("unlock", "README.md").RunInDir(repoPath)
  213. assert.NoError(t, err)
  214. }
  215. func commitAndPush(t *testing.T, size int, repoPath string) {
  216. err := generateCommitWithNewData(size, repoPath, "user2@example.com", "User Two")
  217. assert.NoError(t, err)
  218. _, err = git.NewCommand("push").RunInDir(repoPath) //Push
  219. assert.NoError(t, err)
  220. }
  221. func generateCommitWithNewData(size int, repoPath, email, fullName string) error {
  222. //Generate random file
  223. data := make([]byte, size)
  224. _, err := rand.Read(data)
  225. if err != nil {
  226. return err
  227. }
  228. tmpFile, err := ioutil.TempFile(repoPath, "data-file-")
  229. if err != nil {
  230. return err
  231. }
  232. defer tmpFile.Close()
  233. _, err = tmpFile.Write(data)
  234. if err != nil {
  235. return err
  236. }
  237. //Commit
  238. err = git.AddChanges(repoPath, false, filepath.Base(tmpFile.Name()))
  239. if err != nil {
  240. return err
  241. }
  242. err = git.CommitChanges(repoPath, git.CommitChangesOptions{
  243. Committer: &git.Signature{
  244. Email: email,
  245. Name: fullName,
  246. When: time.Now(),
  247. },
  248. Author: &git.Signature{
  249. Email: email,
  250. Name: fullName,
  251. When: time.Now(),
  252. },
  253. Message: fmt.Sprintf("Testing commit @ %v", time.Now()),
  254. })
  255. return err
  256. }