Commit 12ee9df2 authored by Andreas Bigger's avatar Andreas Bigger

Fix tests to use public log store interface.

parent 9e0702db
...@@ -23,7 +23,7 @@ type logStore struct { ...@@ -23,7 +23,7 @@ type logStore struct {
logList []types.Log logList []types.Log
logMap map[common.Hash][]types.Log logMap map[common.Hash][]types.Log
// Log subscriptions // Log subscription
subscription *Subscription subscription *Subscription
// Client to query for logs // Client to query for logs
...@@ -46,32 +46,50 @@ func NewLogStore(query ethereum.FilterQuery, client ethereum.LogFilterer, log lo ...@@ -46,32 +46,50 @@ func NewLogStore(query ethereum.FilterQuery, client ethereum.LogFilterer, log lo
} }
} }
// Subscribed returns true if the subscription has started.
func (l *logStore) Subscribed() bool {
return l.subscription.Started()
}
// Query returns the log filter query.
func (l *logStore) Query() ethereum.FilterQuery {
return l.query
}
// Client returns the log filter client.
func (l *logStore) Client() ethereum.LogFilterer {
return l.client
}
// GetLogs returns all logs in the log store.
func (l *logStore) GetLogs() []types.Log {
l.mu.Lock()
defer l.mu.Unlock()
return l.logList
}
// GetLogByBlockHash returns all logs in the log store for a given block hash.
func (l *logStore) GetLogByBlockHash(blockHash common.Hash) []types.Log {
l.mu.Lock()
defer l.mu.Unlock()
return l.logMap[blockHash]
}
// Subscribe starts the subscription. // Subscribe starts the subscription.
// This function spawns a new goroutine. // This function spawns a new goroutine.
func (l *logStore) Subscribe() error { func (l *logStore) Subscribe() error {
if l.subscription == nil {
l.log.Error("subscription zeroed out")
return nil
}
err := l.subscription.Subscribe() err := l.subscription.Subscribe()
if err != nil { if err != nil {
l.log.Error("failed to subscribe", "err", err) l.log.Error("failed to subscribe", "err", err)
return err return err
} }
return nil
}
// Start starts the log store.
// This function spawns a new goroutine.
func (l *logStore) Start() {
go l.dispatchLogs() go l.dispatchLogs()
return nil
} }
// Quit stops all log store asynchronous tasks. // Quit stops all log store asynchronous tasks.
func (l *logStore) Quit() { func (l *logStore) Quit() {
if l.subscription != nil { l.subscription.Quit()
l.subscription.Quit()
}
} }
// buildBackoffStrategy builds a [backoff.Strategy]. // buildBackoffStrategy builds a [backoff.Strategy].
...@@ -83,9 +101,10 @@ func (l *logStore) buildBackoffStrategy() backoff.Strategy { ...@@ -83,9 +101,10 @@ func (l *logStore) buildBackoffStrategy() backoff.Strategy {
} }
} }
// resubscribe resubscribes to the log store subscription with a backoff. // resubscribe attempts to re-establish the log store internal
// subscription with a backoff strategy.
func (l *logStore) resubscribe() error { func (l *logStore) resubscribe() error {
l.log.Info("resubscribing to subscription", "id", l.subscription.ID()) l.log.Info("resubscribing")
ctx := context.Background() ctx := context.Background()
backoffStrategy := l.buildBackoffStrategy() backoffStrategy := l.buildBackoffStrategy()
return backoff.DoCtx(ctx, 10, backoffStrategy, func() error { return backoff.DoCtx(ctx, 10, backoffStrategy, func() error {
...@@ -109,20 +128,6 @@ func (l *logStore) insertLog(log types.Log) { ...@@ -109,20 +128,6 @@ func (l *logStore) insertLog(log types.Log) {
l.mu.Unlock() l.mu.Unlock()
} }
// GetLogs returns all logs in the log store.
func (l *logStore) GetLogs() []types.Log {
l.mu.Lock()
defer l.mu.Unlock()
return l.logList
}
// GetLogByBlockHash returns all logs in the log store for a given block hash.
func (l *logStore) GetLogByBlockHash(blockHash common.Hash) []types.Log {
l.mu.Lock()
defer l.mu.Unlock()
return l.logMap[blockHash]
}
// dispatchLogs dispatches logs to the log store. // dispatchLogs dispatches logs to the log store.
// This function is intended to be run as a goroutine. // This function is intended to be run as a goroutine.
func (l *logStore) dispatchLogs() { func (l *logStore) dispatchLogs() {
......
This diff is collapsed.
...@@ -2,17 +2,12 @@ package challenger ...@@ -2,17 +2,12 @@ package challenger
import ( import (
"context" "context"
"errors"
"github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
var (
ErrMissingClient = errors.New("missing client")
)
// SubscriptionId is a unique subscription ID. // SubscriptionId is a unique subscription ID.
type SubscriptionId uint64 type SubscriptionId uint64
...@@ -28,6 +23,8 @@ type Subscription struct { ...@@ -28,6 +23,8 @@ type Subscription struct {
id SubscriptionId id SubscriptionId
// The current subscription // The current subscription
sub ethereum.Subscription sub ethereum.Subscription
// If the subscription is started
started bool
// The query used to create the subscription // The query used to create the subscription
query ethereum.FilterQuery query ethereum.FilterQuery
// The log channel // The log channel
...@@ -43,13 +40,14 @@ type Subscription struct { ...@@ -43,13 +40,14 @@ type Subscription struct {
// NewSubscription creates a new subscription. // NewSubscription creates a new subscription.
func NewSubscription(query ethereum.FilterQuery, client ethereum.LogFilterer, log log.Logger) *Subscription { func NewSubscription(query ethereum.FilterQuery, client ethereum.LogFilterer, log log.Logger) *Subscription {
return &Subscription{ return &Subscription{
id: SubscriptionId(0), id: SubscriptionId(0),
sub: nil, sub: nil,
query: query, started: false,
logs: make(chan types.Log), query: query,
quit: make(chan struct{}), logs: make(chan types.Log),
client: client, quit: make(chan struct{}),
log: log, client: client,
log: log,
} }
} }
...@@ -60,22 +58,19 @@ func (s *Subscription) ID() SubscriptionId { ...@@ -60,22 +58,19 @@ func (s *Subscription) ID() SubscriptionId {
// Started returns true if the subscription has started. // Started returns true if the subscription has started.
func (s *Subscription) Started() bool { func (s *Subscription) Started() bool {
return s.sub != nil return s.started
} }
// Subscribe constructs the subscription. // Subscribe constructs the subscription.
func (s *Subscription) Subscribe() error { func (s *Subscription) Subscribe() error {
s.log.Info("Subscribing to", "query", s.query.Topics, "id", s.id) s.log.Info("Subscribing to", "query", s.query.Topics, "id", s.id)
if s.client == nil {
s.log.Error("missing client")
return ErrMissingClient
}
sub, err := s.client.SubscribeFilterLogs(context.Background(), s.query, s.logs) sub, err := s.client.SubscribeFilterLogs(context.Background(), s.query, s.logs)
if err != nil { if err != nil {
s.log.Error("failed to subscribe to logs", "err", err) s.log.Error("failed to subscribe to logs", "err", err)
return err return err
} }
s.sub = sub s.sub = sub
s.started = true
return nil return nil
} }
...@@ -84,5 +79,6 @@ func (s *Subscription) Quit() { ...@@ -84,5 +79,6 @@ func (s *Subscription) Quit() {
s.log.Info("Quitting subscription", "id", s.id) s.log.Info("Quitting subscription", "id", s.id)
s.sub.Unsubscribe() s.sub.Unsubscribe()
s.quit <- struct{}{} s.quit <- struct{}{}
s.started = false
s.log.Info("Quit subscription", "id", s.id) s.log.Info("Quit subscription", "id", s.id)
} }
...@@ -15,7 +15,6 @@ import ( ...@@ -15,7 +15,6 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
// mockLogFilterClient implements the [ethereum.LogFilter] interface for testing.
type mockLogFilterClient struct{} type mockLogFilterClient struct{}
func (m mockLogFilterClient) FilterLogs(context.Context, ethereum.FilterQuery) ([]types.Log, error) { func (m mockLogFilterClient) FilterLogs(context.Context, ethereum.FilterQuery) ([]types.Log, error) {
...@@ -26,7 +25,12 @@ func (m mockLogFilterClient) SubscribeFilterLogs(context.Context, ethereum.Filte ...@@ -26,7 +25,12 @@ func (m mockLogFilterClient) SubscribeFilterLogs(context.Context, ethereum.Filte
return nil, nil return nil, nil
} }
// FuzzSubscriptionId_Increment tests the Increment method on a [SubscriptionId]. func newSubscription(t *testing.T, client *mockLogFilterClient) (*Subscription, *mockLogFilterClient) {
query := ethereum.FilterQuery{}
log := testlog.Logger(t, log.LvlError)
return NewSubscription(query, client, log), client
}
func FuzzSubscriptionId_Increment(f *testing.F) { func FuzzSubscriptionId_Increment(f *testing.F) {
maxUint64 := uint64(math.MaxUint64) maxUint64 := uint64(math.MaxUint64)
f.Fuzz(func(t *testing.T, id uint64) { f.Fuzz(func(t *testing.T, id uint64) {
...@@ -39,31 +43,20 @@ func FuzzSubscriptionId_Increment(f *testing.F) { ...@@ -39,31 +43,20 @@ func FuzzSubscriptionId_Increment(f *testing.F) {
}) })
} }
// TestSubscription_Subscribe_MissingClient tests the Subscribe func TestSubscription_Subscribe_NilClient_Panics(t *testing.T) {
// method on a [Subscription] fails when the client is missing. defer func() {
func TestSubscription_Subscribe_MissingClient(t *testing.T) { if recover() == nil {
query := ethereum.FilterQuery{} t.Error("expected nil client to panic")
log := testlog.Logger(t, log.LvlError) }
subscription := Subscription{ }()
query: query, subscription, _ := newSubscription(t, nil)
log: log, require.NoError(t, subscription.Subscribe())
}
err := subscription.Subscribe()
require.EqualError(t, err, ErrMissingClient.Error())
} }
// TestSubscription_Subscribe tests the Subscribe method on a [Subscription].
func TestSubscription_Subscribe(t *testing.T) { func TestSubscription_Subscribe(t *testing.T) {
query := ethereum.FilterQuery{} subscription, _ := newSubscription(t, &mockLogFilterClient{})
log := testlog.Logger(t, log.LvlError) require.NoError(t, subscription.Subscribe())
subscription := Subscription{ require.True(t, subscription.Started())
query: query,
client: mockLogFilterClient{},
log: log,
}
require.Nil(t, subscription.logs)
err := subscription.Subscribe()
require.NoError(t, err)
} }
var ErrSubscriptionFailed = errors.New("failed to subscribe to logs") var ErrSubscriptionFailed = errors.New("failed to subscribe to logs")
...@@ -78,10 +71,7 @@ func (m errLogFilterClient) SubscribeFilterLogs(context.Context, ethereum.Filter ...@@ -78,10 +71,7 @@ func (m errLogFilterClient) SubscribeFilterLogs(context.Context, ethereum.Filter
return nil, ErrSubscriptionFailed return nil, ErrSubscriptionFailed
} }
// TestSubscription_Subscribe_Errors tests the Subscribe func TestSubscription_Subscribe_SubscriptionErrors(t *testing.T) {
// method on a [Subscription] errors if the LogFilter client
// returns an error.
func TestSubscription_Subscribe_Errors(t *testing.T) {
query := ethereum.FilterQuery{} query := ethereum.FilterQuery{}
log := testlog.Logger(t, log.LvlError) log := testlog.Logger(t, log.LvlError)
subscription := Subscription{ subscription := Subscription{
...@@ -89,6 +79,5 @@ func TestSubscription_Subscribe_Errors(t *testing.T) { ...@@ -89,6 +79,5 @@ func TestSubscription_Subscribe_Errors(t *testing.T) {
client: errLogFilterClient{}, client: errLogFilterClient{},
log: log, log: log,
} }
err := subscription.Subscribe() require.EqualError(t, subscription.Subscribe(), ErrSubscriptionFailed.Error())
require.EqualError(t, err, ErrSubscriptionFailed.Error())
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment