basic_test.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. // Copyright 2020 The Gogs 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 lfs
  5. import (
  6. "bytes"
  7. "io"
  8. "io/ioutil"
  9. "net/http"
  10. "net/http/httptest"
  11. "strings"
  12. "testing"
  13. "github.com/stretchr/testify/assert"
  14. "gopkg.in/macaron.v1"
  15. "gogs.io/gogs/internal/db"
  16. "gogs.io/gogs/internal/lfsutil"
  17. )
  18. var _ lfsutil.Storager = (*mockStorage)(nil)
  19. // mockStorage is a in-memory storage for LFS objects.
  20. type mockStorage struct {
  21. buf *bytes.Buffer
  22. }
  23. func (s *mockStorage) Storage() lfsutil.Storage {
  24. return "memory"
  25. }
  26. func (s *mockStorage) Upload(oid lfsutil.OID, rc io.ReadCloser) (int64, error) {
  27. defer rc.Close()
  28. return io.Copy(s.buf, rc)
  29. }
  30. func (s *mockStorage) Download(oid lfsutil.OID, w io.Writer) error {
  31. _, err := io.Copy(w, s.buf)
  32. return err
  33. }
  34. func Test_basicHandler_serveDownload(t *testing.T) {
  35. s := &mockStorage{}
  36. basic := &basicHandler{
  37. defaultStorage: s.Storage(),
  38. storagers: map[lfsutil.Storage]lfsutil.Storager{
  39. s.Storage(): s,
  40. },
  41. }
  42. m := macaron.New()
  43. m.Use(macaron.Renderer())
  44. m.Use(func(c *macaron.Context) {
  45. c.Map(&db.Repository{Name: "repo"})
  46. c.Map(lfsutil.OID("ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f"))
  47. })
  48. m.Get("/", basic.serveDownload)
  49. tests := []struct {
  50. name string
  51. content string
  52. mockLFSStore *db.MockLFSStore
  53. expStatusCode int
  54. expHeader http.Header
  55. expBody string
  56. }{
  57. {
  58. name: "object does not exist",
  59. mockLFSStore: &db.MockLFSStore{
  60. MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) {
  61. return nil, db.ErrLFSObjectNotExist{}
  62. },
  63. },
  64. expStatusCode: http.StatusNotFound,
  65. expHeader: http.Header{
  66. "Content-Type": []string{"application/vnd.git-lfs+json"},
  67. },
  68. expBody: `{"message":"Object does not exist"}` + "\n",
  69. },
  70. {
  71. name: "storage not found",
  72. mockLFSStore: &db.MockLFSStore{
  73. MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) {
  74. return &db.LFSObject{Storage: "bad_storage"}, nil
  75. },
  76. },
  77. expStatusCode: http.StatusInternalServerError,
  78. expHeader: http.Header{
  79. "Content-Type": []string{"application/vnd.git-lfs+json"},
  80. },
  81. expBody: `{"message":"Internal server error"}` + "\n",
  82. },
  83. {
  84. name: "object exists",
  85. content: "Hello world!",
  86. mockLFSStore: &db.MockLFSStore{
  87. MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) {
  88. return &db.LFSObject{
  89. Size: 12,
  90. Storage: s.Storage(),
  91. }, nil
  92. },
  93. },
  94. expStatusCode: http.StatusOK,
  95. expHeader: http.Header{
  96. "Content-Type": []string{"application/octet-stream"},
  97. "Content-Length": []string{"12"},
  98. },
  99. expBody: "Hello world!",
  100. },
  101. }
  102. for _, test := range tests {
  103. t.Run(test.name, func(t *testing.T) {
  104. db.SetMockLFSStore(t, test.mockLFSStore)
  105. s.buf = bytes.NewBufferString(test.content)
  106. r, err := http.NewRequest("GET", "/", nil)
  107. if err != nil {
  108. t.Fatal(err)
  109. }
  110. rr := httptest.NewRecorder()
  111. m.ServeHTTP(rr, r)
  112. resp := rr.Result()
  113. assert.Equal(t, test.expStatusCode, resp.StatusCode)
  114. assert.Equal(t, test.expHeader, resp.Header)
  115. body, err := ioutil.ReadAll(resp.Body)
  116. if err != nil {
  117. t.Fatal(err)
  118. }
  119. assert.Equal(t, test.expBody, string(body))
  120. })
  121. }
  122. }
  123. func Test_basicHandler_serveUpload(t *testing.T) {
  124. s := &mockStorage{buf: &bytes.Buffer{}}
  125. basic := &basicHandler{
  126. defaultStorage: s.Storage(),
  127. storagers: map[lfsutil.Storage]lfsutil.Storager{
  128. s.Storage(): s,
  129. },
  130. }
  131. m := macaron.New()
  132. m.Use(macaron.Renderer())
  133. m.Use(func(c *macaron.Context) {
  134. c.Map(&db.Repository{Name: "repo"})
  135. c.Map(lfsutil.OID("ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f"))
  136. })
  137. m.Put("/", basic.serveUpload)
  138. tests := []struct {
  139. name string
  140. mockLFSStore *db.MockLFSStore
  141. expStatusCode int
  142. expBody string
  143. }{
  144. {
  145. name: "object already exists",
  146. mockLFSStore: &db.MockLFSStore{
  147. MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) {
  148. return &db.LFSObject{}, nil
  149. },
  150. },
  151. expStatusCode: http.StatusOK,
  152. },
  153. {
  154. name: "new object",
  155. mockLFSStore: &db.MockLFSStore{
  156. MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) {
  157. return nil, db.ErrLFSObjectNotExist{}
  158. },
  159. MockCreateObject: func(repoID int64, oid lfsutil.OID, size int64, storage lfsutil.Storage) error {
  160. return nil
  161. },
  162. },
  163. expStatusCode: http.StatusOK,
  164. },
  165. }
  166. for _, test := range tests {
  167. t.Run(test.name, func(t *testing.T) {
  168. db.SetMockLFSStore(t, test.mockLFSStore)
  169. r, err := http.NewRequest("PUT", "/", strings.NewReader("Hello world!"))
  170. if err != nil {
  171. t.Fatal(err)
  172. }
  173. rr := httptest.NewRecorder()
  174. m.ServeHTTP(rr, r)
  175. resp := rr.Result()
  176. assert.Equal(t, test.expStatusCode, resp.StatusCode)
  177. body, err := ioutil.ReadAll(resp.Body)
  178. if err != nil {
  179. t.Fatal(err)
  180. }
  181. assert.Equal(t, test.expBody, string(body))
  182. })
  183. }
  184. }
  185. func Test_basicHandler_serveVerify(t *testing.T) {
  186. m := macaron.New()
  187. m.Use(macaron.Renderer())
  188. m.Use(func(c *macaron.Context) {
  189. c.Map(&db.Repository{Name: "repo"})
  190. })
  191. m.Post("/", (&basicHandler{}).serveVerify)
  192. tests := []struct {
  193. name string
  194. body string
  195. mockLFSStore *db.MockLFSStore
  196. expStatusCode int
  197. expBody string
  198. }{
  199. {
  200. name: "invalid oid",
  201. body: `{"oid": "bad_oid"}`,
  202. expStatusCode: http.StatusBadRequest,
  203. expBody: `{"message":"Invalid oid"}` + "\n",
  204. },
  205. {
  206. name: "object does not exist",
  207. body: `{"oid":"ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f"}`,
  208. mockLFSStore: &db.MockLFSStore{
  209. MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) {
  210. return nil, db.ErrLFSObjectNotExist{}
  211. },
  212. },
  213. expStatusCode: http.StatusNotFound,
  214. expBody: `{"message":"Object does not exist"}` + "\n",
  215. },
  216. {
  217. name: "object size mismatch",
  218. body: `{"oid":"ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f"}`,
  219. mockLFSStore: &db.MockLFSStore{
  220. MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) {
  221. return &db.LFSObject{Size: 12}, nil
  222. },
  223. },
  224. expStatusCode: http.StatusBadRequest,
  225. expBody: `{"message":"Object size mismatch"}` + "\n",
  226. },
  227. {
  228. name: "object exists",
  229. body: `{"oid":"ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f", "size":12}`,
  230. mockLFSStore: &db.MockLFSStore{
  231. MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) {
  232. return &db.LFSObject{Size: 12}, nil
  233. },
  234. },
  235. expStatusCode: http.StatusOK,
  236. },
  237. }
  238. for _, test := range tests {
  239. t.Run(test.name, func(t *testing.T) {
  240. db.SetMockLFSStore(t, test.mockLFSStore)
  241. r, err := http.NewRequest("POST", "/", strings.NewReader(test.body))
  242. if err != nil {
  243. t.Fatal(err)
  244. }
  245. rr := httptest.NewRecorder()
  246. m.ServeHTTP(rr, r)
  247. resp := rr.Result()
  248. assert.Equal(t, test.expStatusCode, resp.StatusCode)
  249. body, err := ioutil.ReadAll(resp.Body)
  250. if err != nil {
  251. t.Fatal(err)
  252. }
  253. assert.Equal(t, test.expBody, string(body))
  254. })
  255. }
  256. }