gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package integration
  4. import (
  5. "bytes"
  6. "net/http"
  7. "path"
  8. "strconv"
  9. "strings"
  10. "testing"
  11. auth_model "code.gitea.io/gitea/models/auth"
  12. git_model "code.gitea.io/gitea/models/git"
  13. repo_model "code.gitea.io/gitea/models/repo"
  14. "code.gitea.io/gitea/models/unittest"
  15. user_model "code.gitea.io/gitea/models/user"
  16. "code.gitea.io/gitea/modules/json"
  17. "code.gitea.io/gitea/modules/lfs"
  18. "code.gitea.io/gitea/modules/setting"
  19. "code.gitea.io/gitea/modules/test"
  20. "code.gitea.io/gitea/tests"
  21. "github.com/stretchr/testify/assert"
  22. )
  23. func TestAPILFSNotStarted(t *testing.T) {
  24. defer tests.PrepareTestEnv(t)()
  25. setting.LFS.StartServer = false
  26. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  27. repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
  28. req := NewRequestf(t, "POST", "/%s/%s.git/info/lfs/objects/batch", user.Name, repo.Name)
  29. MakeRequest(t, req, http.StatusNotFound)
  30. req = NewRequestf(t, "PUT", "/%s/%s.git/info/lfs/objects/oid/10", user.Name, repo.Name)
  31. MakeRequest(t, req, http.StatusNotFound)
  32. req = NewRequestf(t, "GET", "/%s/%s.git/info/lfs/objects/oid/name", user.Name, repo.Name)
  33. MakeRequest(t, req, http.StatusNotFound)
  34. req = NewRequestf(t, "GET", "/%s/%s.git/info/lfs/objects/oid", user.Name, repo.Name)
  35. MakeRequest(t, req, http.StatusNotFound)
  36. req = NewRequestf(t, "POST", "/%s/%s.git/info/lfs/verify", user.Name, repo.Name)
  37. MakeRequest(t, req, http.StatusNotFound)
  38. }
  39. func TestAPILFSMediaType(t *testing.T) {
  40. defer tests.PrepareTestEnv(t)()
  41. setting.LFS.StartServer = true
  42. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  43. repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
  44. req := NewRequestf(t, "POST", "/%s/%s.git/info/lfs/objects/batch", user.Name, repo.Name)
  45. MakeRequest(t, req, http.StatusUnsupportedMediaType)
  46. req = NewRequestf(t, "POST", "/%s/%s.git/info/lfs/verify", user.Name, repo.Name)
  47. MakeRequest(t, req, http.StatusUnsupportedMediaType)
  48. }
  49. func createLFSTestRepository(t *testing.T, name string) *repo_model.Repository {
  50. ctx := NewAPITestContext(t, "user2", "lfs-"+name+"-repo", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
  51. t.Run("CreateRepo", doAPICreateRepository(ctx, false))
  52. repo, err := repo_model.GetRepositoryByOwnerAndName(t.Context(), "user2", "lfs-"+name+"-repo")
  53. assert.NoError(t, err)
  54. return repo
  55. }
  56. func TestAPILFSBatch(t *testing.T) {
  57. defer tests.PrepareTestEnv(t)()
  58. setting.LFS.StartServer = true
  59. repo := createLFSTestRepository(t, "batch")
  60. content := []byte("dummy1")
  61. oid := storeObjectInRepo(t, repo.ID, &content)
  62. defer git_model.RemoveLFSMetaObjectByOid(t.Context(), repo.ID, oid)
  63. session := loginUser(t, "user2")
  64. newRequest := func(t testing.TB, br *lfs.BatchRequest) *RequestWrapper {
  65. return NewRequestWithJSON(t, "POST", "/user2/lfs-batch-repo.git/info/lfs/objects/batch", br).
  66. SetHeader("Accept", lfs.AcceptHeader).
  67. SetHeader("Content-Type", lfs.MediaType)
  68. }
  69. decodeResponse := func(t *testing.T, b *bytes.Buffer) *lfs.BatchResponse {
  70. var br lfs.BatchResponse
  71. assert.NoError(t, json.Unmarshal(b.Bytes(), &br))
  72. return &br
  73. }
  74. t.Run("InvalidJsonRequest", func(t *testing.T) {
  75. defer tests.PrintCurrentTest(t)()
  76. req := newRequest(t, nil)
  77. session.MakeRequest(t, req, http.StatusBadRequest)
  78. })
  79. t.Run("InvalidOperation", func(t *testing.T) {
  80. defer tests.PrintCurrentTest(t)()
  81. req := newRequest(t, &lfs.BatchRequest{
  82. Operation: "dummy",
  83. })
  84. session.MakeRequest(t, req, http.StatusBadRequest)
  85. })
  86. t.Run("InvalidPointer", func(t *testing.T) {
  87. defer tests.PrintCurrentTest(t)()
  88. req := newRequest(t, &lfs.BatchRequest{
  89. Operation: "download",
  90. Objects: []lfs.Pointer{
  91. {Oid: "dummy"},
  92. {Oid: oid, Size: -1},
  93. },
  94. })
  95. resp := session.MakeRequest(t, req, http.StatusOK)
  96. br := decodeResponse(t, resp.Body)
  97. assert.Len(t, br.Objects, 2)
  98. assert.Equal(t, "dummy", br.Objects[0].Oid)
  99. assert.Equal(t, oid, br.Objects[1].Oid)
  100. assert.Equal(t, int64(0), br.Objects[0].Size)
  101. assert.Equal(t, int64(-1), br.Objects[1].Size)
  102. assert.NotNil(t, br.Objects[0].Error)
  103. assert.NotNil(t, br.Objects[1].Error)
  104. assert.Equal(t, http.StatusUnprocessableEntity, br.Objects[0].Error.Code)
  105. assert.Equal(t, http.StatusUnprocessableEntity, br.Objects[1].Error.Code)
  106. assert.Equal(t, "Oid or size are invalid", br.Objects[0].Error.Message)
  107. assert.Equal(t, "Oid or size are invalid", br.Objects[1].Error.Message)
  108. })
  109. t.Run("PointerSizeMismatch", func(t *testing.T) {
  110. defer tests.PrintCurrentTest(t)()
  111. req := newRequest(t, &lfs.BatchRequest{
  112. Operation: "download",
  113. Objects: []lfs.Pointer{
  114. {Oid: oid, Size: 1},
  115. },
  116. })
  117. resp := session.MakeRequest(t, req, http.StatusOK)
  118. br := decodeResponse(t, resp.Body)
  119. assert.Len(t, br.Objects, 1)
  120. assert.NotNil(t, br.Objects[0].Error)
  121. assert.Equal(t, http.StatusUnprocessableEntity, br.Objects[0].Error.Code)
  122. assert.Equal(t, "Object "+oid+" is not 1 bytes", br.Objects[0].Error.Message)
  123. })
  124. t.Run("Download", func(t *testing.T) {
  125. defer tests.PrintCurrentTest(t)()
  126. t.Run("PointerNotInStore", func(t *testing.T) {
  127. defer tests.PrintCurrentTest(t)()
  128. req := newRequest(t, &lfs.BatchRequest{
  129. Operation: "download",
  130. Objects: []lfs.Pointer{
  131. {Oid: "fb8f7d8435968c4f82a726a92395be4d16f2f63116caf36c8ad35c60831ab042", Size: 6},
  132. },
  133. })
  134. resp := session.MakeRequest(t, req, http.StatusOK)
  135. br := decodeResponse(t, resp.Body)
  136. assert.Len(t, br.Objects, 1)
  137. assert.NotNil(t, br.Objects[0].Error)
  138. assert.Equal(t, http.StatusNotFound, br.Objects[0].Error.Code)
  139. })
  140. t.Run("MetaNotFound", func(t *testing.T) {
  141. defer tests.PrintCurrentTest(t)()
  142. p := lfs.Pointer{Oid: "05eeb4eb5be71f2dd291ca39157d6d9effd7d1ea19cbdc8a99411fe2a8f26a00", Size: 6}
  143. contentStore := lfs.NewContentStore()
  144. exist, err := contentStore.Exists(p)
  145. assert.NoError(t, err)
  146. assert.False(t, exist)
  147. err = contentStore.Put(p, bytes.NewReader([]byte("dummy0")))
  148. assert.NoError(t, err)
  149. req := newRequest(t, &lfs.BatchRequest{
  150. Operation: "download",
  151. Objects: []lfs.Pointer{p},
  152. })
  153. resp := session.MakeRequest(t, req, http.StatusOK)
  154. br := decodeResponse(t, resp.Body)
  155. assert.Len(t, br.Objects, 1)
  156. assert.NotNil(t, br.Objects[0].Error)
  157. assert.Equal(t, http.StatusNotFound, br.Objects[0].Error.Code)
  158. })
  159. t.Run("Success", func(t *testing.T) {
  160. defer tests.PrintCurrentTest(t)()
  161. req := newRequest(t, &lfs.BatchRequest{
  162. Operation: "download",
  163. Objects: []lfs.Pointer{
  164. {Oid: oid, Size: 6},
  165. },
  166. })
  167. resp := session.MakeRequest(t, req, http.StatusOK)
  168. br := decodeResponse(t, resp.Body)
  169. assert.Len(t, br.Objects, 1)
  170. assert.Nil(t, br.Objects[0].Error)
  171. assert.Contains(t, br.Objects[0].Actions, "download")
  172. l := br.Objects[0].Actions["download"]
  173. assert.NotNil(t, l)
  174. assert.NotEmpty(t, l.Href)
  175. })
  176. })
  177. t.Run("Upload", func(t *testing.T) {
  178. defer tests.PrintCurrentTest(t)()
  179. t.Run("FileTooBig", func(t *testing.T) {
  180. defer tests.PrintCurrentTest(t)()
  181. defer test.MockVariableValue(&setting.LFS.MaxFileSize, 2)()
  182. req := newRequest(t, &lfs.BatchRequest{
  183. Operation: "upload",
  184. Objects: []lfs.Pointer{
  185. {Oid: "fb8f7d8435968c4f82a726a92395be4d16f2f63116caf36c8ad35c60831ab042", Size: 6},
  186. },
  187. })
  188. resp := session.MakeRequest(t, req, http.StatusOK)
  189. br := decodeResponse(t, resp.Body)
  190. assert.Len(t, br.Objects, 1)
  191. assert.NotNil(t, br.Objects[0].Error)
  192. assert.Equal(t, http.StatusUnprocessableEntity, br.Objects[0].Error.Code)
  193. assert.Equal(t, "Size must be less than or equal to 2", br.Objects[0].Error.Message)
  194. })
  195. t.Run("AddMeta", func(t *testing.T) {
  196. defer tests.PrintCurrentTest(t)()
  197. p := lfs.Pointer{Oid: "05eeb4eb5be71f2dd291ca39157d6d9effd7d1ea19cbdc8a99411fe2a8f26a00", Size: 6}
  198. contentStore := lfs.NewContentStore()
  199. exist, err := contentStore.Exists(p)
  200. assert.NoError(t, err)
  201. assert.True(t, exist)
  202. repo2 := createLFSTestRepository(t, "batch2")
  203. content := []byte("dummy0")
  204. storeObjectInRepo(t, repo2.ID, &content)
  205. meta, err := git_model.GetLFSMetaObjectByOid(t.Context(), repo.ID, p.Oid)
  206. assert.Nil(t, meta)
  207. assert.Equal(t, git_model.ErrLFSObjectNotExist, err)
  208. req := newRequest(t, &lfs.BatchRequest{
  209. Operation: "upload",
  210. Objects: []lfs.Pointer{p},
  211. })
  212. resp := session.MakeRequest(t, req, http.StatusOK)
  213. br := decodeResponse(t, resp.Body)
  214. assert.Len(t, br.Objects, 1)
  215. assert.Nil(t, br.Objects[0].Error)
  216. assert.Empty(t, br.Objects[0].Actions)
  217. meta, err = git_model.GetLFSMetaObjectByOid(t.Context(), repo.ID, p.Oid)
  218. assert.NoError(t, err)
  219. assert.NotNil(t, meta)
  220. // Cleanup
  221. err = contentStore.Delete(p.RelativePath())
  222. assert.NoError(t, err)
  223. })
  224. t.Run("AlreadyExists", func(t *testing.T) {
  225. defer tests.PrintCurrentTest(t)()
  226. req := newRequest(t, &lfs.BatchRequest{
  227. Operation: "upload",
  228. Objects: []lfs.Pointer{
  229. {Oid: oid, Size: 6},
  230. },
  231. })
  232. resp := session.MakeRequest(t, req, http.StatusOK)
  233. br := decodeResponse(t, resp.Body)
  234. assert.Len(t, br.Objects, 1)
  235. assert.Nil(t, br.Objects[0].Error)
  236. assert.Empty(t, br.Objects[0].Actions)
  237. })
  238. t.Run("NewFile", func(t *testing.T) {
  239. defer tests.PrintCurrentTest(t)()
  240. req := newRequest(t, &lfs.BatchRequest{
  241. Operation: "upload",
  242. Objects: []lfs.Pointer{
  243. {Oid: "d6f175817f886ec6fbbc1515326465fa96c3bfd54a4ea06cfd6dbbd8340e0153", Size: 1},
  244. },
  245. })
  246. resp := session.MakeRequest(t, req, http.StatusOK)
  247. br := decodeResponse(t, resp.Body)
  248. assert.Len(t, br.Objects, 1)
  249. assert.Nil(t, br.Objects[0].Error)
  250. assert.Contains(t, br.Objects[0].Actions, "upload")
  251. ul := br.Objects[0].Actions["upload"]
  252. assert.NotNil(t, ul)
  253. assert.NotEmpty(t, ul.Href)
  254. assert.Contains(t, br.Objects[0].Actions, "verify")
  255. vl := br.Objects[0].Actions["verify"]
  256. assert.NotNil(t, vl)
  257. assert.NotEmpty(t, vl.Href)
  258. })
  259. })
  260. }
  261. func TestAPILFSUpload(t *testing.T) {
  262. defer tests.PrepareTestEnv(t)()
  263. setting.LFS.StartServer = true
  264. repo := createLFSTestRepository(t, "upload")
  265. content := []byte("dummy3")
  266. oid := storeObjectInRepo(t, repo.ID, &content)
  267. defer git_model.RemoveLFSMetaObjectByOid(t.Context(), repo.ID, oid)
  268. session := loginUser(t, "user2")
  269. newRequest := func(t testing.TB, p lfs.Pointer, content string) *RequestWrapper {
  270. return NewRequestWithBody(t, "PUT", path.Join("/user2/lfs-upload-repo.git/info/lfs/objects/", p.Oid, strconv.FormatInt(p.Size, 10)), strings.NewReader(content))
  271. }
  272. t.Run("InvalidPointer", func(t *testing.T) {
  273. defer tests.PrintCurrentTest(t)()
  274. req := newRequest(t, lfs.Pointer{Oid: "dummy"}, "")
  275. session.MakeRequest(t, req, http.StatusUnprocessableEntity)
  276. })
  277. t.Run("AlreadyExistsInStore", func(t *testing.T) {
  278. defer tests.PrintCurrentTest(t)()
  279. p := lfs.Pointer{Oid: "83de2e488b89a0aa1c97496b888120a28b0c1e15463a4adb8405578c540f36d4", Size: 6}
  280. contentStore := lfs.NewContentStore()
  281. exist, err := contentStore.Exists(p)
  282. assert.NoError(t, err)
  283. assert.False(t, exist)
  284. err = contentStore.Put(p, bytes.NewReader([]byte("dummy5")))
  285. assert.NoError(t, err)
  286. meta, err := git_model.GetLFSMetaObjectByOid(t.Context(), repo.ID, p.Oid)
  287. assert.Nil(t, meta)
  288. assert.Equal(t, git_model.ErrLFSObjectNotExist, err)
  289. t.Run("InvalidAccess", func(t *testing.T) {
  290. req := newRequest(t, p, "invalid")
  291. session.MakeRequest(t, req, http.StatusUnprocessableEntity)
  292. })
  293. t.Run("ValidAccess", func(t *testing.T) {
  294. req := newRequest(t, p, "dummy5")
  295. session.MakeRequest(t, req, http.StatusOK)
  296. meta, err = git_model.GetLFSMetaObjectByOid(t.Context(), repo.ID, p.Oid)
  297. assert.NoError(t, err)
  298. assert.NotNil(t, meta)
  299. })
  300. // Cleanup
  301. err = contentStore.Delete(p.RelativePath())
  302. assert.NoError(t, err)
  303. })
  304. t.Run("MetaAlreadyExists", func(t *testing.T) {
  305. defer tests.PrintCurrentTest(t)()
  306. req := newRequest(t, lfs.Pointer{Oid: oid, Size: 6}, "")
  307. session.MakeRequest(t, req, http.StatusOK)
  308. })
  309. t.Run("HashMismatch", func(t *testing.T) {
  310. defer tests.PrintCurrentTest(t)()
  311. req := newRequest(t, lfs.Pointer{Oid: "2581dd7bbc1fe44726de4b7dd806a087a978b9c5aec0a60481259e34be09b06a", Size: 1}, "a")
  312. session.MakeRequest(t, req, http.StatusUnprocessableEntity)
  313. })
  314. t.Run("SizeMismatch", func(t *testing.T) {
  315. defer tests.PrintCurrentTest(t)()
  316. req := newRequest(t, lfs.Pointer{Oid: "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", Size: 2}, "a")
  317. session.MakeRequest(t, req, http.StatusUnprocessableEntity)
  318. })
  319. t.Run("Success", func(t *testing.T) {
  320. defer tests.PrintCurrentTest(t)()
  321. p := lfs.Pointer{Oid: "6ccce4863b70f258d691f59609d31b4502e1ba5199942d3bc5d35d17a4ce771d", Size: 5}
  322. req := newRequest(t, p, "gitea")
  323. session.MakeRequest(t, req, http.StatusOK)
  324. contentStore := lfs.NewContentStore()
  325. exist, err := contentStore.Exists(p)
  326. assert.NoError(t, err)
  327. assert.True(t, exist)
  328. meta, err := git_model.GetLFSMetaObjectByOid(t.Context(), repo.ID, p.Oid)
  329. assert.NoError(t, err)
  330. assert.NotNil(t, meta)
  331. })
  332. }
  333. func TestAPILFSVerify(t *testing.T) {
  334. defer tests.PrepareTestEnv(t)()
  335. setting.LFS.StartServer = true
  336. repo := createLFSTestRepository(t, "verify")
  337. content := []byte("dummy3")
  338. oid := storeObjectInRepo(t, repo.ID, &content)
  339. defer git_model.RemoveLFSMetaObjectByOid(t.Context(), repo.ID, oid)
  340. session := loginUser(t, "user2")
  341. newRequest := func(t testing.TB, p *lfs.Pointer) *RequestWrapper {
  342. return NewRequestWithJSON(t, "POST", "/user2/lfs-verify-repo.git/info/lfs/verify", p).
  343. SetHeader("Accept", lfs.AcceptHeader).
  344. SetHeader("Content-Type", lfs.MediaType)
  345. }
  346. t.Run("InvalidJsonRequest", func(t *testing.T) {
  347. defer tests.PrintCurrentTest(t)()
  348. req := newRequest(t, nil)
  349. session.MakeRequest(t, req, http.StatusUnprocessableEntity)
  350. })
  351. t.Run("InvalidPointer", func(t *testing.T) {
  352. defer tests.PrintCurrentTest(t)()
  353. req := newRequest(t, &lfs.Pointer{})
  354. session.MakeRequest(t, req, http.StatusUnprocessableEntity)
  355. })
  356. t.Run("PointerNotExisting", func(t *testing.T) {
  357. defer tests.PrintCurrentTest(t)()
  358. req := newRequest(t, &lfs.Pointer{Oid: "fb8f7d8435968c4f82a726a92395be4d16f2f63116caf36c8ad35c60831ab042", Size: 6})
  359. session.MakeRequest(t, req, http.StatusNotFound)
  360. })
  361. t.Run("Success", func(t *testing.T) {
  362. defer tests.PrintCurrentTest(t)()
  363. req := newRequest(t, &lfs.Pointer{Oid: oid, Size: 6})
  364. session.MakeRequest(t, req, http.StatusOK)
  365. })
  366. }