Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

api_repo_lfs_test.go 13KB

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