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.

277 lines
8.0 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. req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos", &api.CreateRepoOption{
  66. AutoInit: true,
  67. Description: "Temporary repo",
  68. Name: "repo-tmp-17",
  69. Private: false,
  70. Gitignores: "",
  71. License: "WTFPL",
  72. Readme: "Default",
  73. })
  74. session.MakeRequest(t, req, http.StatusCreated)
  75. })
  76. u.Path = "user2/repo-tmp-17.git"
  77. u.User = url.UserPassword("user2", userPassword)
  78. t.Run("Clone", func(t *testing.T) {
  79. err = git.Clone(u.String(), dstPath, git.CloneRepoOptions{})
  80. assert.NoError(t, err)
  81. assert.True(t, com.IsExist(filepath.Join(dstPath, "README.md")))
  82. })
  83. t.Run("PushCommit", func(t *testing.T) {
  84. t.Run("Little", func(t *testing.T) {
  85. commitAndPush(t, littleSize, dstPath)
  86. })
  87. t.Run("Big", func(t *testing.T) {
  88. commitAndPush(t, bigSize, dstPath)
  89. })
  90. })
  91. })
  92. t.Run("LFS", func(t *testing.T) {
  93. t.Run("PushCommit", func(t *testing.T) {
  94. //Setup git LFS
  95. _, err = git.NewCommand("lfs").AddArguments("install").RunInDir(dstPath)
  96. assert.NoError(t, err)
  97. _, err = git.NewCommand("lfs").AddArguments("track", "data-file-*").RunInDir(dstPath)
  98. assert.NoError(t, err)
  99. err = git.AddChanges(dstPath, false, ".gitattributes")
  100. assert.NoError(t, err)
  101. t.Run("Little", func(t *testing.T) {
  102. commitAndPush(t, littleSize, dstPath)
  103. })
  104. t.Run("Big", func(t *testing.T) {
  105. commitAndPush(t, bigSize, dstPath)
  106. })
  107. })
  108. t.Run("Locks", func(t *testing.T) {
  109. lockTest(t, u.String(), dstPath)
  110. })
  111. })
  112. })
  113. t.Run("SSH", func(t *testing.T) {
  114. //Setup remote link
  115. u.Scheme = "ssh"
  116. u.User = url.User("git")
  117. u.Host = fmt.Sprintf("%s:%d", setting.SSH.ListenHost, setting.SSH.ListenPort)
  118. u.Path = "user2/repo-tmp-18.git"
  119. //Setup key
  120. keyFile := filepath.Join(setting.AppDataPath, "my-testing-key")
  121. err := exec.Command("ssh-keygen", "-f", keyFile, "-t", "rsa", "-N", "").Run()
  122. assert.NoError(t, err)
  123. defer os.RemoveAll(keyFile)
  124. defer os.RemoveAll(keyFile + ".pub")
  125. session := loginUser(t, "user1")
  126. keyOwner := models.AssertExistsAndLoadBean(t, &models.User{Name: "user2"}).(*models.User)
  127. urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys", keyOwner.Name)
  128. dataPubKey, err := ioutil.ReadFile(keyFile + ".pub")
  129. assert.NoError(t, err)
  130. req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
  131. "key": string(dataPubKey),
  132. "title": "test-key",
  133. })
  134. session.MakeRequest(t, req, http.StatusCreated)
  135. //Setup ssh wrapper
  136. os.Setenv("GIT_SSH_COMMAND",
  137. "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i "+
  138. filepath.Join(setting.AppWorkPath, keyFile))
  139. os.Setenv("GIT_SSH_VARIANT", "ssh")
  140. //Setup clone folder
  141. dstPath, err := ioutil.TempDir("", "repo-tmp-18")
  142. assert.NoError(t, err)
  143. defer os.RemoveAll(dstPath)
  144. t.Run("Standard", func(t *testing.T) {
  145. t.Run("CreateRepo", func(t *testing.T) {
  146. session := loginUser(t, "user2")
  147. req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos", &api.CreateRepoOption{
  148. AutoInit: true,
  149. Description: "Temporary repo",
  150. Name: "repo-tmp-18",
  151. Private: false,
  152. Gitignores: "",
  153. License: "WTFPL",
  154. Readme: "Default",
  155. })
  156. session.MakeRequest(t, req, http.StatusCreated)
  157. })
  158. //TODO get url from api
  159. t.Run("Clone", func(t *testing.T) {
  160. _, err = git.NewCommand("clone").AddArguments(u.String(), dstPath).Run()
  161. assert.NoError(t, err)
  162. assert.True(t, com.IsExist(filepath.Join(dstPath, "README.md")))
  163. })
  164. //time.Sleep(5 * time.Minute)
  165. t.Run("PushCommit", func(t *testing.T) {
  166. t.Run("Little", func(t *testing.T) {
  167. commitAndPush(t, littleSize, dstPath)
  168. })
  169. t.Run("Big", func(t *testing.T) {
  170. commitAndPush(t, bigSize, dstPath)
  171. })
  172. })
  173. })
  174. t.Run("LFS", func(t *testing.T) {
  175. t.Run("PushCommit", func(t *testing.T) {
  176. //Setup git LFS
  177. _, err = git.NewCommand("lfs").AddArguments("install").RunInDir(dstPath)
  178. assert.NoError(t, err)
  179. _, err = git.NewCommand("lfs").AddArguments("track", "data-file-*").RunInDir(dstPath)
  180. assert.NoError(t, err)
  181. err = git.AddChanges(dstPath, false, ".gitattributes")
  182. assert.NoError(t, err)
  183. t.Run("Little", func(t *testing.T) {
  184. commitAndPush(t, littleSize, dstPath)
  185. })
  186. t.Run("Big", func(t *testing.T) {
  187. commitAndPush(t, bigSize, dstPath)
  188. })
  189. })
  190. t.Run("Locks", func(t *testing.T) {
  191. lockTest(t, u.String(), dstPath)
  192. })
  193. })
  194. })
  195. })
  196. }
  197. func lockTest(t *testing.T, remote, repoPath string) {
  198. _, err := git.NewCommand("remote").AddArguments("set-url", "origin", remote).RunInDir(repoPath) //TODO add test ssh git-lfs-creds
  199. assert.NoError(t, err)
  200. _, err = git.NewCommand("lfs").AddArguments("locks").RunInDir(repoPath)
  201. assert.NoError(t, err)
  202. _, err = git.NewCommand("lfs").AddArguments("lock", "README.md").RunInDir(repoPath)
  203. assert.NoError(t, err)
  204. _, err = git.NewCommand("lfs").AddArguments("locks").RunInDir(repoPath)
  205. assert.NoError(t, err)
  206. _, err = git.NewCommand("lfs").AddArguments("unlock", "README.md").RunInDir(repoPath)
  207. assert.NoError(t, err)
  208. }
  209. func commitAndPush(t *testing.T, size int, repoPath string) {
  210. err := generateCommitWithNewData(size, repoPath, "user2@example.com", "User Two")
  211. assert.NoError(t, err)
  212. _, err = git.NewCommand("push").RunInDir(repoPath) //Push
  213. assert.NoError(t, err)
  214. }
  215. func generateCommitWithNewData(size int, repoPath, email, fullName string) error {
  216. //Generate random file
  217. data := make([]byte, size)
  218. _, err := rand.Read(data)
  219. if err != nil {
  220. return err
  221. }
  222. tmpFile, err := ioutil.TempFile(repoPath, "data-file-")
  223. if err != nil {
  224. return err
  225. }
  226. defer tmpFile.Close()
  227. _, err = tmpFile.Write(data)
  228. if err != nil {
  229. return err
  230. }
  231. //Commit
  232. err = git.AddChanges(repoPath, false, filepath.Base(tmpFile.Name()))
  233. if err != nil {
  234. return err
  235. }
  236. err = git.CommitChanges(repoPath, git.CommitChangesOptions{
  237. Committer: &git.Signature{
  238. Email: email,
  239. Name: fullName,
  240. When: time.Now(),
  241. },
  242. Author: &git.Signature{
  243. Email: email,
  244. Name: fullName,
  245. When: time.Now(),
  246. },
  247. Message: fmt.Sprintf("Testing commit @ %v", time.Now()),
  248. })
  249. return err
  250. }