diff options
Diffstat (limited to 'internal/route/lfs/basic_test.go')
-rw-r--r-- | internal/route/lfs/basic_test.go | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/internal/route/lfs/basic_test.go b/internal/route/lfs/basic_test.go new file mode 100644 index 00000000..db2fbe61 --- /dev/null +++ b/internal/route/lfs/basic_test.go @@ -0,0 +1,288 @@ +// Copyright 2020 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package lfs + +import ( + "bytes" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "gopkg.in/macaron.v1" + + "gogs.io/gogs/internal/db" + "gogs.io/gogs/internal/lfsutil" +) + +var _ lfsutil.Storager = (*mockStorage)(nil) + +// mockStorage is a in-memory storage for LFS objects. +type mockStorage struct { + buf *bytes.Buffer +} + +func (s *mockStorage) Storage() lfsutil.Storage { + return "memory" +} + +func (s *mockStorage) Upload(oid lfsutil.OID, rc io.ReadCloser) (int64, error) { + defer rc.Close() + return io.Copy(s.buf, rc) +} + +func (s *mockStorage) Download(oid lfsutil.OID, w io.Writer) error { + _, err := io.Copy(w, s.buf) + return err +} + +func Test_basicHandler_serveDownload(t *testing.T) { + s := &mockStorage{} + basic := &basicHandler{ + defaultStorage: s.Storage(), + storagers: map[lfsutil.Storage]lfsutil.Storager{ + s.Storage(): s, + }, + } + + m := macaron.New() + m.Use(macaron.Renderer()) + m.Use(func(c *macaron.Context) { + c.Map(&db.Repository{Name: "repo"}) + c.Map(lfsutil.OID("ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f")) + }) + m.Get("/", basic.serveDownload) + + tests := []struct { + name string + content string + mockLFSStore *db.MockLFSStore + expStatusCode int + expHeader http.Header + expBody string + }{ + { + name: "object does not exist", + mockLFSStore: &db.MockLFSStore{ + MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) { + return nil, db.ErrLFSObjectNotExist{} + }, + }, + expStatusCode: http.StatusNotFound, + expHeader: http.Header{ + "Content-Type": []string{"application/vnd.git-lfs+json"}, + }, + expBody: `{"message":"Object does not exist"}` + "\n", + }, + { + name: "storage not found", + mockLFSStore: &db.MockLFSStore{ + MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) { + return &db.LFSObject{Storage: "bad_storage"}, nil + }, + }, + expStatusCode: http.StatusInternalServerError, + expHeader: http.Header{ + "Content-Type": []string{"application/vnd.git-lfs+json"}, + }, + expBody: `{"message":"Internal server error"}` + "\n", + }, + + { + name: "object exists", + content: "Hello world!", + mockLFSStore: &db.MockLFSStore{ + MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) { + return &db.LFSObject{ + Size: 12, + Storage: s.Storage(), + }, nil + }, + }, + expStatusCode: http.StatusOK, + expHeader: http.Header{ + "Content-Type": []string{"application/octet-stream"}, + "Content-Length": []string{"12"}, + }, + expBody: "Hello world!", + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + db.SetMockLFSStore(t, test.mockLFSStore) + + s.buf = bytes.NewBufferString(test.content) + + r, err := http.NewRequest("GET", "/", nil) + if err != nil { + t.Fatal(err) + } + + rr := httptest.NewRecorder() + m.ServeHTTP(rr, r) + + resp := rr.Result() + assert.Equal(t, test.expStatusCode, resp.StatusCode) + assert.Equal(t, test.expHeader, resp.Header) + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, test.expBody, string(body)) + }) + } +} + +func Test_basicHandler_serveUpload(t *testing.T) { + s := &mockStorage{buf: &bytes.Buffer{}} + basic := &basicHandler{ + defaultStorage: s.Storage(), + storagers: map[lfsutil.Storage]lfsutil.Storager{ + s.Storage(): s, + }, + } + + m := macaron.New() + m.Use(macaron.Renderer()) + m.Use(func(c *macaron.Context) { + c.Map(&db.Repository{Name: "repo"}) + c.Map(lfsutil.OID("ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f")) + }) + m.Put("/", basic.serveUpload) + + tests := []struct { + name string + mockLFSStore *db.MockLFSStore + expStatusCode int + expBody string + }{ + { + name: "object already exists", + mockLFSStore: &db.MockLFSStore{ + MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) { + return &db.LFSObject{}, nil + }, + }, + expStatusCode: http.StatusOK, + }, + { + name: "new object", + mockLFSStore: &db.MockLFSStore{ + MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) { + return nil, db.ErrLFSObjectNotExist{} + }, + MockCreateObject: func(repoID int64, oid lfsutil.OID, size int64, storage lfsutil.Storage) error { + return nil + }, + }, + expStatusCode: http.StatusOK, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + db.SetMockLFSStore(t, test.mockLFSStore) + + r, err := http.NewRequest("PUT", "/", strings.NewReader("Hello world!")) + if err != nil { + t.Fatal(err) + } + + rr := httptest.NewRecorder() + m.ServeHTTP(rr, r) + + resp := rr.Result() + assert.Equal(t, test.expStatusCode, resp.StatusCode) + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, test.expBody, string(body)) + }) + } +} + +func Test_basicHandler_serveVerify(t *testing.T) { + m := macaron.New() + m.Use(macaron.Renderer()) + m.Use(func(c *macaron.Context) { + c.Map(&db.Repository{Name: "repo"}) + }) + m.Post("/", (&basicHandler{}).serveVerify) + + tests := []struct { + name string + body string + mockLFSStore *db.MockLFSStore + expStatusCode int + expBody string + }{ + { + name: "invalid oid", + body: `{"oid": "bad_oid"}`, + expStatusCode: http.StatusBadRequest, + expBody: `{"message":"Invalid oid"}` + "\n", + }, + { + name: "object does not exist", + body: `{"oid":"ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f"}`, + mockLFSStore: &db.MockLFSStore{ + MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) { + return nil, db.ErrLFSObjectNotExist{} + }, + }, + expStatusCode: http.StatusNotFound, + expBody: `{"message":"Object does not exist"}` + "\n", + }, + { + name: "object size mismatch", + body: `{"oid":"ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f"}`, + mockLFSStore: &db.MockLFSStore{ + MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) { + return &db.LFSObject{Size: 12}, nil + }, + }, + expStatusCode: http.StatusBadRequest, + expBody: `{"message":"Object size mismatch"}` + "\n", + }, + + { + name: "object exists", + body: `{"oid":"ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f", "size":12}`, + mockLFSStore: &db.MockLFSStore{ + MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) { + return &db.LFSObject{Size: 12}, nil + }, + }, + expStatusCode: http.StatusOK, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + db.SetMockLFSStore(t, test.mockLFSStore) + + r, err := http.NewRequest("POST", "/", strings.NewReader(test.body)) + if err != nil { + t.Fatal(err) + } + + rr := httptest.NewRecorder() + m.ServeHTTP(rr, r) + + resp := rr.Result() + assert.Equal(t, test.expStatusCode, resp.StatusCode) + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, test.expBody, string(body)) + }) + } +} |