1package mock 2 3import ( 4 "context" 5 "io" 6 7 "github.com/restic/restic/internal/errors" 8 "github.com/restic/restic/internal/restic" 9) 10 11// Backend implements a mock backend. 12type Backend struct { 13 CloseFn func() error 14 IsNotExistFn func(err error) bool 15 SaveFn func(ctx context.Context, h restic.Handle, rd restic.RewindReader) error 16 OpenReaderFn func(ctx context.Context, h restic.Handle, length int, offset int64) (io.ReadCloser, error) 17 StatFn func(ctx context.Context, h restic.Handle) (restic.FileInfo, error) 18 ListFn func(ctx context.Context, t restic.FileType, fn func(restic.FileInfo) error) error 19 RemoveFn func(ctx context.Context, h restic.Handle) error 20 TestFn func(ctx context.Context, h restic.Handle) (bool, error) 21 DeleteFn func(ctx context.Context) error 22 LocationFn func() string 23} 24 25// NewBackend returns new mock Backend instance 26func NewBackend() *Backend { 27 be := &Backend{} 28 return be 29} 30 31// Close the backend. 32func (m *Backend) Close() error { 33 if m.CloseFn == nil { 34 return nil 35 } 36 37 return m.CloseFn() 38} 39 40// Location returns a location string. 41func (m *Backend) Location() string { 42 if m.LocationFn == nil { 43 return "" 44 } 45 46 return m.LocationFn() 47} 48 49// IsNotExist returns true if the error is caused by a missing file. 50func (m *Backend) IsNotExist(err error) bool { 51 if m.IsNotExistFn == nil { 52 return false 53 } 54 55 return m.IsNotExistFn(err) 56} 57 58// Save data in the backend. 59func (m *Backend) Save(ctx context.Context, h restic.Handle, rd restic.RewindReader) error { 60 if m.SaveFn == nil { 61 return errors.New("not implemented") 62 } 63 64 return m.SaveFn(ctx, h, rd) 65} 66 67// Load runs fn with a reader that yields the contents of the file at h at the 68// given offset. 69func (m *Backend) Load(ctx context.Context, h restic.Handle, length int, offset int64, fn func(rd io.Reader) error) error { 70 rd, err := m.openReader(ctx, h, length, offset) 71 if err != nil { 72 return err 73 } 74 err = fn(rd) 75 if err != nil { 76 _ = rd.Close() // ignore secondary errors closing the reader 77 return err 78 } 79 return rd.Close() 80} 81 82func (m *Backend) openReader(ctx context.Context, h restic.Handle, length int, offset int64) (io.ReadCloser, error) { 83 if m.OpenReaderFn == nil { 84 return nil, errors.New("not implemented") 85 } 86 87 return m.OpenReaderFn(ctx, h, length, offset) 88} 89 90// Stat an object in the backend. 91func (m *Backend) Stat(ctx context.Context, h restic.Handle) (restic.FileInfo, error) { 92 if m.StatFn == nil { 93 return restic.FileInfo{}, errors.New("not implemented") 94 } 95 96 return m.StatFn(ctx, h) 97} 98 99// List items of type t. 100func (m *Backend) List(ctx context.Context, t restic.FileType, fn func(restic.FileInfo) error) error { 101 if m.ListFn == nil { 102 return nil 103 } 104 105 return m.ListFn(ctx, t, fn) 106} 107 108// Remove data from the backend. 109func (m *Backend) Remove(ctx context.Context, h restic.Handle) error { 110 if m.RemoveFn == nil { 111 return errors.New("not implemented") 112 } 113 114 return m.RemoveFn(ctx, h) 115} 116 117// Test for the existence of a specific item. 118func (m *Backend) Test(ctx context.Context, h restic.Handle) (bool, error) { 119 if m.TestFn == nil { 120 return false, errors.New("not implemented") 121 } 122 123 return m.TestFn(ctx, h) 124} 125 126// Delete all data. 127func (m *Backend) Delete(ctx context.Context) error { 128 if m.DeleteFn == nil { 129 return errors.New("not implemented") 130 } 131 132 return m.DeleteFn(ctx) 133} 134 135// Make sure that Backend implements the backend interface. 136var _ restic.Backend = &Backend{} 137