github.com/ethersphere/bee/v2@v2.2.0/pkg/storer/mock/mockstorer.go (about) 1 // Copyright 2023 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package mockstorer 6 7 import ( 8 "context" 9 "sync" 10 "time" 11 12 "github.com/ethersphere/bee/v2/pkg/pusher" 13 storage "github.com/ethersphere/bee/v2/pkg/storage" 14 "github.com/ethersphere/bee/v2/pkg/storage/inmemchunkstore" 15 storer "github.com/ethersphere/bee/v2/pkg/storer" 16 "github.com/ethersphere/bee/v2/pkg/swarm" 17 "go.uber.org/atomic" 18 ) 19 20 // now returns the current time.Time; used in testing. 21 var now = time.Now 22 23 type mockStorer struct { 24 chunkStore storage.ChunkStore 25 mu sync.Mutex 26 pins []swarm.Address 27 sessionID atomic.Uint64 28 activeSessions map[uint64]*storer.SessionInfo 29 chunkPushC chan *pusher.Op 30 debugInfo storer.Info 31 } 32 33 type putterSession struct { 34 chunkStore storage.Putter 35 done func(swarm.Address) error 36 } 37 38 func (p *putterSession) Put(ctx context.Context, ch swarm.Chunk) error { 39 return p.chunkStore.Put(ctx, ch) 40 } 41 42 func (p *putterSession) Done(address swarm.Address) error { 43 if p.done != nil { 44 return p.done(address) 45 } 46 return nil 47 } 48 49 func (p *putterSession) Cleanup() error { return nil } 50 51 // New returns a mock storer implementation that is designed to be used for the 52 // unit tests. 53 func New() *mockStorer { 54 return &mockStorer{ 55 chunkStore: inmemchunkstore.New(), 56 chunkPushC: make(chan *pusher.Op), 57 activeSessions: make(map[uint64]*storer.SessionInfo), 58 } 59 } 60 61 func NewWithChunkStore(cs storage.ChunkStore) *mockStorer { 62 return &mockStorer{ 63 chunkStore: cs, 64 chunkPushC: make(chan *pusher.Op), 65 activeSessions: make(map[uint64]*storer.SessionInfo), 66 } 67 } 68 69 func NewWithDebugInfo(info storer.Info) *mockStorer { 70 st := New() 71 st.debugInfo = info 72 return st 73 } 74 75 func (m *mockStorer) Upload(_ context.Context, pin bool, tagID uint64) (storer.PutterSession, error) { 76 return &putterSession{ 77 chunkStore: m.chunkStore, 78 done: func(address swarm.Address) error { 79 m.mu.Lock() 80 defer m.mu.Unlock() 81 82 if pin { 83 m.pins = append(m.pins, address) 84 } 85 if session, ok := m.activeSessions[tagID]; ok { 86 session.Address = address 87 } 88 return nil 89 }, 90 }, nil 91 } 92 93 func (m *mockStorer) NewSession() (storer.SessionInfo, error) { 94 session := &storer.SessionInfo{ 95 TagID: m.sessionID.Inc(), 96 StartedAt: now().UnixNano(), 97 } 98 99 m.mu.Lock() 100 defer m.mu.Unlock() 101 m.activeSessions[session.TagID] = session 102 103 return *session, nil 104 } 105 106 func (m *mockStorer) Session(tagID uint64) (storer.SessionInfo, error) { 107 m.mu.Lock() 108 defer m.mu.Unlock() 109 110 session, ok := m.activeSessions[tagID] 111 if !ok { 112 return storer.SessionInfo{}, storage.ErrNotFound 113 } 114 return *session, nil 115 } 116 117 func (m *mockStorer) DeleteSession(tagID uint64) error { 118 m.mu.Lock() 119 defer m.mu.Unlock() 120 121 if _, ok := m.activeSessions[tagID]; !ok { 122 return storage.ErrNotFound 123 } 124 delete(m.activeSessions, tagID) 125 return nil 126 } 127 128 func (m *mockStorer) ListSessions(offset, limit int) ([]storer.SessionInfo, error) { 129 m.mu.Lock() 130 defer m.mu.Unlock() 131 132 sessions := []storer.SessionInfo{} 133 for _, v := range m.activeSessions { 134 sessions = append(sessions, *v) 135 } 136 return sessions, nil 137 } 138 139 func (m *mockStorer) DeletePin(_ context.Context, address swarm.Address) error { 140 m.mu.Lock() 141 defer m.mu.Unlock() 142 143 for idx, p := range m.pins { 144 if p.Equal(address) { 145 m.pins = append(m.pins[:idx], m.pins[idx+1:]...) 146 break 147 } 148 } 149 return nil 150 } 151 152 func (m *mockStorer) Pins() ([]swarm.Address, error) { 153 m.mu.Lock() 154 defer m.mu.Unlock() 155 156 pins := make([]swarm.Address, 0, len(m.pins)) 157 for _, p := range m.pins { 158 pins = append(pins, p.Clone()) 159 } 160 return pins, nil 161 } 162 163 func (m *mockStorer) HasPin(address swarm.Address) (bool, error) { 164 m.mu.Lock() 165 defer m.mu.Unlock() 166 for _, p := range m.pins { 167 if p.Equal(address) { 168 return true, nil 169 } 170 } 171 return false, nil 172 } 173 174 func (m *mockStorer) NewCollection(ctx context.Context) (storer.PutterSession, error) { 175 return &putterSession{ 176 chunkStore: m.chunkStore, 177 done: func(address swarm.Address) error { 178 m.mu.Lock() 179 defer m.mu.Unlock() 180 181 m.pins = append(m.pins, address) 182 return nil 183 }, 184 }, nil 185 } 186 187 func (m *mockStorer) Lookup() storage.Getter { 188 return m.chunkStore 189 } 190 191 func (m *mockStorer) Cache() storage.Putter { 192 return m.chunkStore 193 } 194 195 func (m *mockStorer) DirectUpload() storer.PutterSession { 196 return &putterSession{chunkStore: storage.PutterFunc( 197 func(ctx context.Context, ch swarm.Chunk) error { 198 op := &pusher.Op{Chunk: ch, Err: make(chan error, 1), Direct: true} 199 select { 200 case <-ctx.Done(): 201 return ctx.Err() 202 case m.chunkPushC <- op: 203 return nil 204 } 205 }), 206 } 207 } 208 209 func (m *mockStorer) Download(_ bool) storage.Getter { 210 return m.chunkStore 211 } 212 213 func (m *mockStorer) PusherFeed() <-chan *pusher.Op { 214 return m.chunkPushC 215 } 216 217 func (m *mockStorer) ChunkStore() storage.ReadOnlyChunkStore { 218 return m.chunkStore 219 } 220 221 func (m *mockStorer) StorageRadius() uint8 { return 0 } 222 223 func (m *mockStorer) IsWithinStorageRadius(_ swarm.Address) bool { return true } 224 225 func (m *mockStorer) DebugInfo(_ context.Context) (storer.Info, error) { 226 return m.debugInfo, nil 227 }