diff --git a/pkg/storage/segments/mock_store.go b/pkg/storage/segments/mock_store.go new file mode 100644 index 000000000..4dacd5d83 --- /dev/null +++ b/pkg/storage/segments/mock_store.go @@ -0,0 +1,105 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: storj.io/storj/pkg/storage/segments (interfaces: Store) + +// Package segments is a generated GoMock package. +package segments + +import ( + context "context" + io "io" + reflect "reflect" + time "time" + + gomock "github.com/golang/mock/gomock" + paths "storj.io/storj/pkg/paths" + ranger "storj.io/storj/pkg/ranger" +) + +// MockStore is a mock of Store interface +type MockStore struct { + ctrl *gomock.Controller + recorder *MockStoreMockRecorder +} + +// MockStoreMockRecorder is the mock recorder for MockStore +type MockStoreMockRecorder struct { + mock *MockStore +} + +// NewMockStore creates a new mock instance +func NewMockStore(ctrl *gomock.Controller) *MockStore { + mock := &MockStore{ctrl: ctrl} + mock.recorder = &MockStoreMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockStore) EXPECT() *MockStoreMockRecorder { + return m.recorder +} + +// Meta mocks base method +func (m *MockStore) Meta(ctx context.Context, path paths.Path) (Meta, error) { + ret := m.ctrl.Call(m, "Meta", ctx, path) + ret0, _ := ret[0].(Meta) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Meta indicates an expected call of Meta +func (mr *MockStoreMockRecorder) Meta(ctx, path interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Meta", reflect.TypeOf((*MockStore)(nil).Meta), ctx, path) +} + +// Get mocks base method +func (m *MockStore) Get(ctx context.Context, path paths.Path) (ranger.Ranger, Meta, error) { + ret := m.ctrl.Call(m, "Get", ctx, path) + ret0, _ := ret[0].(ranger.Ranger) + ret1, _ := ret[1].(Meta) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// Get indicates an expected call of Get +func (mr *MockStoreMockRecorder) Get(ctx, path interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockStore)(nil).Get), ctx, path) +} + +// Put mocks base method +func (m *MockStore) Put(ctx context.Context, path paths.Path, data io.Reader, metadata []byte, expiration time.Time) (Meta, error) { + ret := m.ctrl.Call(m, "Put", ctx, path, data, metadata, expiration) + ret0, _ := ret[0].(Meta) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Put indicates an expected call of Put +func (mr *MockStoreMockRecorder) Put(ctx, path, data, metadata, expiration interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockStore)(nil).Put), ctx, path, data, metadata, expiration) +} + +// Delete mocks base method +func (m *MockStore) Delete(ctx context.Context, path paths.Path) error { + ret := m.ctrl.Call(m, "Delete", ctx, path) + ret0, _ := ret[0].(error) + return ret0 +} + +// Delete indicates an expected call of Delete +func (mr *MockStoreMockRecorder) Delete(ctx, path interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockStore)(nil).Delete), ctx, path) +} + +// List mocks base method +func (m *MockStore) List(ctx context.Context, prefix, startAfter, endBefore paths.Path, recursive bool, limit int, metaFlags uint32) ([]ListItem, bool, error) { + ret := m.ctrl.Call(m, "List", ctx, prefix, startAfter, endBefore, recursive, limit, metaFlags) + ret0, _ := ret[0].([]ListItem) + ret1, _ := ret[1].(bool) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// List indicates an expected call of List +func (mr *MockStoreMockRecorder) List(ctx, prefix, startAfter, endBefore, recursive, limit, metaFlags interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockStore)(nil).List), ctx, prefix, startAfter, endBefore, recursive, limit, metaFlags) +} diff --git a/pkg/storage/streams/store_test.go b/pkg/storage/streams/store_test.go new file mode 100644 index 000000000..1d2609659 --- /dev/null +++ b/pkg/storage/streams/store_test.go @@ -0,0 +1,330 @@ +// Copyright (C) 2018 Storj Labs, Inc. +// See LICENSE for copying information. + +package streams + +import ( + "context" + "fmt" + "io" + "strings" + "testing" + "time" + + proto "github.com/gogo/protobuf/proto" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + "storj.io/storj/pkg/paths" + "storj.io/storj/pkg/pb" + ranger "storj.io/storj/pkg/ranger" + "storj.io/storj/pkg/storage/segments" +) + +var ( + ctx = context.Background() +) + +func TestStreamStoreMeta(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockSegmentStore := segments.NewMockStore(ctrl) + + md := pb.MetaStreamInfo{ + NumberOfSegments: 2, + SegmentsSize: 10, + LastSegmentSize: 0, + Metadata: []byte{}, + } + lastSegmentMetadata, err := proto.Marshal(&md) + if err != nil { + t.Fatal(err) + } + + staticTime := time.Now() + segmentMeta := segments.Meta{ + Modified: staticTime, + Expiration: staticTime, + Size: 10, + Data: lastSegmentMetadata, + } + streamMeta, err := convertMeta(segmentMeta) + if err != nil { + t.Fatal(err) + } + + for i, test := range []struct { + // input for test function + path string + // output for mock function + segmentMeta segments.Meta + segmentError error + // assert on output of test function + streamMeta Meta + streamError error + }{ + {"bucket", segmentMeta, nil, streamMeta, nil}, + } { + errTag := fmt.Sprintf("Test case #%d", i) + + mockSegmentStore.EXPECT(). + Meta(gomock.Any(), gomock.Any()). + Return(test.segmentMeta, test.segmentError) + + streamStore, err := NewStreamStore(mockSegmentStore, 10, "key", 10, 0) + if err != nil { + t.Fatal(err) + } + + meta, err := streamStore.Meta(ctx, paths.New(test.path)) + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, test.streamMeta, meta, errTag) + } +} + +func TestStreamStorePut(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockSegmentStore := segments.NewMockStore(ctrl) + + staticTime := time.Now() + segmentMeta := segments.Meta{ + Modified: staticTime, + Expiration: staticTime, + Size: 10, + Data: []byte{}, + } + + streamMeta := Meta{ + Modified: segmentMeta.Modified, + Expiration: segmentMeta.Expiration, + Size: 14, + Data: []byte("metadata"), + } + + for i, test := range []struct { + // input for test function + path string + data io.Reader + metadata []byte + expiration time.Time + // output for mock function + segmentMeta segments.Meta + segmentError error + // assert on output of test function + streamMeta Meta + streamError error + }{ + {"bucket", strings.NewReader("data"), []byte("metadata"), staticTime, segmentMeta, nil, streamMeta, nil}, + } { + errTag := fmt.Sprintf("Test case #%d", i) + + mockSegmentStore.EXPECT(). + Put(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). + Return(test.segmentMeta, test.segmentError). + Times(2). + Do(func(ctx context.Context, path paths.Path, data io.Reader, metadata []byte, expiration time.Time) { + for { + buf := make([]byte, 4) + _, err := data.Read(buf) + if err == io.EOF { + break + } + } + }) + + streamStore, err := NewStreamStore(mockSegmentStore, 10, "key", 10, 0) + if err != nil { + t.Fatal(err) + } + + meta, err := streamStore.Put(ctx, paths.New(test.path), test.data, test.metadata, test.expiration) + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, test.streamMeta, meta, errTag) + } +} + +type stubRanger struct { + len int64 + closer io.ReadCloser +} + +func (r stubRanger) Size() int64 { + return r.len +} +func (r stubRanger) Range(ctx context.Context, offset, length int64) (io.ReadCloser, error) { + return r.closer, nil +} + +type readCloserStub struct{} + +func (r readCloserStub) Read(p []byte) (n int, err error) { return 10, nil } +func (r readCloserStub) Close() error { return nil } + +func TestStreamStoreGet(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockSegmentStore := segments.NewMockStore(ctrl) + + staticTime := time.Now() + + segmentRanger := stubRanger{ + len: 10, + closer: readCloserStub{}, + } + + segmentMeta := segments.Meta{ + Modified: staticTime, + Expiration: staticTime, + Size: 10, + Data: []byte{}, + } + + streamRanger := ranger.ByteRanger(nil) + + streamMeta := Meta{ + Modified: staticTime, + Expiration: staticTime, + Size: 0, + Data: nil, + } + + for i, test := range []struct { + // input for test function + path string + // output for mock function + segmentRanger ranger.Ranger + segmentMeta segments.Meta + segmentError error + // assert on output of test function + streamRanger ranger.Ranger + streamMeta Meta + streamError error + }{ + {"bucket", segmentRanger, segmentMeta, nil, streamRanger, streamMeta, nil}, + } { + errTag := fmt.Sprintf("Test case #%d", i) + + calls := []*gomock.Call{ + mockSegmentStore.EXPECT(). + Meta(gomock.Any(), gomock.Any()). + Return(test.segmentMeta, test.segmentError), + } + + gomock.InOrder(calls...) + + streamStore, err := NewStreamStore(mockSegmentStore, 10, "key", 10, 0) + if err != nil { + t.Fatal(err) + } + + ranger, meta, err := streamStore.Get(ctx, paths.New(test.path)) + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, test.streamRanger, ranger, errTag) + assert.Equal(t, test.streamMeta, meta, errTag) + } +} + +func TestStreamStoreDelete(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockSegmentStore := segments.NewMockStore(ctrl) + + staticTime := time.Now() + segmentMeta := segments.Meta{ + Modified: staticTime, + Expiration: staticTime, + Size: 10, + Data: []byte{}, + } + + for i, test := range []struct { + // input for test function + path string + // output for mock functions + segmentMeta segments.Meta + segmentError error + // assert on output of test function + streamError error + }{ + {"bucket", segmentMeta, nil, nil}, + } { + errTag := fmt.Sprintf("Test case #%d", i) + + mockSegmentStore.EXPECT(). + Meta(gomock.Any(), gomock.Any()). + Return(test.segmentMeta, test.segmentError) + mockSegmentStore.EXPECT(). + Delete(gomock.Any(), gomock.Any()). + Return(test.segmentError) + + streamStore, err := NewStreamStore(mockSegmentStore, 10, "key", 10, 0) + if err != nil { + t.Fatal(err) + } + + err = streamStore.Delete(ctx, paths.New(test.path)) + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, test.streamError, err, errTag) + } +} +func TestStreamStoreList(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockSegmentStore := segments.NewMockStore(ctrl) + + for i, test := range []struct { + // input for test function + prefix string + startAfter string + endBefore string + recursive bool + limit int + metaFlags uint32 + // output for mock function + segments []segments.ListItem + segmentMore bool + segmentError error + // assert on output of test function + streamItems []ListItem + streamMore bool + streamError error + }{ + {"bucket", "", "", false, 1, 0, []segments.ListItem{}, false, nil, []ListItem{}, false, nil}, + } { + errTag := fmt.Sprintf("Test case #%d", i) + + mockSegmentStore.EXPECT(). + List(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). + Return(test.segments, test.segmentMore, test.segmentError) + + streamStore, err := NewStreamStore(mockSegmentStore, 10, "key", 10, 0) + if err != nil { + t.Fatal(err) + } + + items, more, err := streamStore.List(ctx, paths.New(test.prefix), paths.New(test.startAfter), paths.New(test.endBefore), test.recursive, test.limit, test.metaFlags) + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, test.streamItems, items, errTag) + assert.Equal(t, test.streamMore, more, errTag) + } +}