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

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