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.

lfs_getobject_test.go 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. // Copyright 2019 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. "archive/zip"
  7. "bytes"
  8. "io"
  9. "net/http"
  10. "net/http/httptest"
  11. "testing"
  12. "code.gitea.io/gitea/models"
  13. repo_model "code.gitea.io/gitea/models/repo"
  14. "code.gitea.io/gitea/modules/git"
  15. "code.gitea.io/gitea/modules/json"
  16. "code.gitea.io/gitea/modules/lfs"
  17. "code.gitea.io/gitea/modules/setting"
  18. "code.gitea.io/gitea/routers/web"
  19. gzipp "github.com/klauspost/compress/gzip"
  20. "github.com/stretchr/testify/assert"
  21. )
  22. func storeObjectInRepo(t *testing.T, repositoryID int64, content *[]byte) string {
  23. pointer, err := lfs.GeneratePointer(bytes.NewReader(*content))
  24. assert.NoError(t, err)
  25. _, err = models.NewLFSMetaObject(&models.LFSMetaObject{Pointer: pointer, RepositoryID: repositoryID})
  26. assert.NoError(t, err)
  27. contentStore := lfs.NewContentStore()
  28. exist, err := contentStore.Exists(pointer)
  29. assert.NoError(t, err)
  30. if !exist {
  31. err := contentStore.Put(pointer, bytes.NewReader(*content))
  32. assert.NoError(t, err)
  33. }
  34. return pointer.Oid
  35. }
  36. func storeAndGetLfs(t *testing.T, content *[]byte, extraHeader *http.Header, expectedStatus int) *httptest.ResponseRecorder {
  37. repo, err := repo_model.GetRepositoryByOwnerAndName("user2", "repo1")
  38. assert.NoError(t, err)
  39. oid := storeObjectInRepo(t, repo.ID, content)
  40. defer models.RemoveLFSMetaObjectByOid(repo.ID, oid)
  41. session := loginUser(t, "user2")
  42. // Request OID
  43. req := NewRequest(t, "GET", "/user2/repo1.git/info/lfs/objects/"+oid+"/test")
  44. req.Header.Set("Accept-Encoding", "gzip")
  45. if extraHeader != nil {
  46. for key, values := range *extraHeader {
  47. for _, value := range values {
  48. req.Header.Add(key, value)
  49. }
  50. }
  51. }
  52. resp := session.MakeRequest(t, req, expectedStatus)
  53. return resp
  54. }
  55. func checkResponseTestContentEncoding(t *testing.T, content *[]byte, resp *httptest.ResponseRecorder, expectGzip bool) {
  56. contentEncoding := resp.Header().Get("Content-Encoding")
  57. if !expectGzip || !setting.EnableGzip {
  58. assert.NotContains(t, contentEncoding, "gzip")
  59. result := resp.Body.Bytes()
  60. assert.Equal(t, *content, result)
  61. } else {
  62. assert.Contains(t, contentEncoding, "gzip")
  63. gzippReader, err := gzipp.NewReader(resp.Body)
  64. assert.NoError(t, err)
  65. result, err := io.ReadAll(gzippReader)
  66. assert.NoError(t, err)
  67. assert.Equal(t, *content, result)
  68. }
  69. }
  70. func TestGetLFSSmall(t *testing.T) {
  71. defer prepareTestEnv(t)()
  72. git.CheckLFSVersion()
  73. if !setting.LFS.StartServer {
  74. t.Skip()
  75. return
  76. }
  77. content := []byte("A very small file\n")
  78. resp := storeAndGetLfs(t, &content, nil, http.StatusOK)
  79. checkResponseTestContentEncoding(t, &content, resp, false)
  80. }
  81. func TestGetLFSLarge(t *testing.T) {
  82. defer prepareTestEnv(t)()
  83. git.CheckLFSVersion()
  84. if !setting.LFS.StartServer {
  85. t.Skip()
  86. return
  87. }
  88. content := make([]byte, web.GzipMinSize*10)
  89. for i := range content {
  90. content[i] = byte(i % 256)
  91. }
  92. resp := storeAndGetLfs(t, &content, nil, http.StatusOK)
  93. checkResponseTestContentEncoding(t, &content, resp, true)
  94. }
  95. func TestGetLFSGzip(t *testing.T) {
  96. defer prepareTestEnv(t)()
  97. git.CheckLFSVersion()
  98. if !setting.LFS.StartServer {
  99. t.Skip()
  100. return
  101. }
  102. b := make([]byte, web.GzipMinSize*10)
  103. for i := range b {
  104. b[i] = byte(i % 256)
  105. }
  106. outputBuffer := bytes.NewBuffer([]byte{})
  107. gzippWriter := gzipp.NewWriter(outputBuffer)
  108. gzippWriter.Write(b)
  109. gzippWriter.Close()
  110. content := outputBuffer.Bytes()
  111. resp := storeAndGetLfs(t, &content, nil, http.StatusOK)
  112. checkResponseTestContentEncoding(t, &content, resp, false)
  113. }
  114. func TestGetLFSZip(t *testing.T) {
  115. defer prepareTestEnv(t)()
  116. git.CheckLFSVersion()
  117. if !setting.LFS.StartServer {
  118. t.Skip()
  119. return
  120. }
  121. b := make([]byte, web.GzipMinSize*10)
  122. for i := range b {
  123. b[i] = byte(i % 256)
  124. }
  125. outputBuffer := bytes.NewBuffer([]byte{})
  126. zipWriter := zip.NewWriter(outputBuffer)
  127. fileWriter, err := zipWriter.Create("default")
  128. assert.NoError(t, err)
  129. fileWriter.Write(b)
  130. zipWriter.Close()
  131. content := outputBuffer.Bytes()
  132. resp := storeAndGetLfs(t, &content, nil, http.StatusOK)
  133. checkResponseTestContentEncoding(t, &content, resp, false)
  134. }
  135. func TestGetLFSRangeNo(t *testing.T) {
  136. defer prepareTestEnv(t)()
  137. git.CheckLFSVersion()
  138. if !setting.LFS.StartServer {
  139. t.Skip()
  140. return
  141. }
  142. content := []byte("123456789\n")
  143. resp := storeAndGetLfs(t, &content, nil, http.StatusOK)
  144. assert.Equal(t, content, resp.Body.Bytes())
  145. }
  146. func TestGetLFSRange(t *testing.T) {
  147. defer prepareTestEnv(t)()
  148. git.CheckLFSVersion()
  149. if !setting.LFS.StartServer {
  150. t.Skip()
  151. return
  152. }
  153. content := []byte("123456789\n")
  154. tests := []struct {
  155. in string
  156. out string
  157. status int
  158. }{
  159. {"bytes=0-0", "1", http.StatusPartialContent},
  160. {"bytes=0-1", "12", http.StatusPartialContent},
  161. {"bytes=1-1", "2", http.StatusPartialContent},
  162. {"bytes=1-3", "234", http.StatusPartialContent},
  163. {"bytes=1-", "23456789\n", http.StatusPartialContent},
  164. // end-range smaller than start-range is ignored
  165. {"bytes=1-0", "23456789\n", http.StatusPartialContent},
  166. {"bytes=0-10", "123456789\n", http.StatusPartialContent},
  167. // end-range bigger than length-1 is ignored
  168. {"bytes=0-11", "123456789\n", http.StatusPartialContent},
  169. {"bytes=11-", "Requested Range Not Satisfiable", http.StatusRequestedRangeNotSatisfiable},
  170. // incorrect header value cause whole header to be ignored
  171. {"bytes=-", "123456789\n", http.StatusOK},
  172. {"foobar", "123456789\n", http.StatusOK},
  173. }
  174. for _, tt := range tests {
  175. t.Run(tt.in, func(t *testing.T) {
  176. h := http.Header{
  177. "Range": []string{tt.in},
  178. }
  179. resp := storeAndGetLfs(t, &content, &h, tt.status)
  180. if tt.status == http.StatusPartialContent || tt.status == http.StatusOK {
  181. assert.Equal(t, tt.out, resp.Body.String())
  182. } else {
  183. var er lfs.ErrorResponse
  184. err := json.Unmarshal(resp.Body.Bytes(), &er)
  185. assert.NoError(t, err)
  186. assert.Equal(t, tt.out, er.Message)
  187. }
  188. })
  189. }
  190. }