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.

280 lines
8.2 KiB

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