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  }