waku-org/go-waku

View on GitHub
waku/v2/protocol/rln/group_manager/dynamic/mock_client.go

Summary

Maintainability
A
0 mins
Test Coverage
B
88%
package dynamic

import (
    "context"
    "encoding/json"
    "math/big"
    "os"
    "sort"
    "sync/atomic"
    "testing"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/ethclient"
)

type ErrCount struct {
    err   error
    count int
}

type MockClient struct {
    ethclient.Client
    blockChain     MockBlockChain
    latestBlockNum atomic.Int64
    errOnBlock     map[int64]*ErrCount
}

func (c *MockClient) SetLatestBlockNumber(num int64) {
    c.latestBlockNum.Store(num)
}

func (c *MockClient) Close() {

}
func (c *MockClient) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) {
    return types.NewBlock(&types.Header{Number: big.NewInt(c.latestBlockNum.Load())}, nil, nil, nil, nil), nil
}
func NewMockClient(t *testing.T, blockFile string) *MockClient {
    blockChain := MockBlockChain{}
    data, err := os.ReadFile(blockFile)
    if err != nil {
        t.Fatal(err)
    }
    if err := json.Unmarshal(data, &blockChain); err != nil {
        t.Fatal(err)
    }
    return &MockClient{blockChain: blockChain, errOnBlock: map[int64]*ErrCount{}}
}

func (c *MockClient) SetErrorOnBlock(blockNum int64, err error, count int) {
    c.errOnBlock[blockNum] = &ErrCount{err: err, count: count}
}

func (c *MockClient) getFromAndToRange(query ethereum.FilterQuery) (int64, int64) {
    var fromBlock int64
    if query.FromBlock == nil {
        fromBlock = 0
    } else {
        fromBlock = query.FromBlock.Int64()
    }

    var toBlock int64
    if query.ToBlock == nil {
        toBlock = 0
    } else {
        toBlock = query.ToBlock.Int64()
    }
    return fromBlock, toBlock
}
func (c *MockClient) FilterLogs(ctx context.Context, query ethereum.FilterQuery) (allTxLogs []types.Log, err error) {
    fromBlock, toBlock := c.getFromAndToRange(query)
    for block, details := range c.blockChain.Blocks {
        if block >= fromBlock && block <= toBlock {
            if txLogs := details.getLogs(uint64(block), query.Addresses, query.Topics[0]); len(txLogs) != 0 {
                allTxLogs = append(allTxLogs, txLogs...)
            }
            if errCount, ok := c.errOnBlock[block]; ok && errCount.count != 0 {
                errCount.count--
                return nil, errCount.err
            }
        }
    }
    sort.Slice(allTxLogs, func(i, j int) bool {
        return allTxLogs[i].BlockNumber < allTxLogs[j].BlockNumber ||
            (allTxLogs[i].BlockNumber == allTxLogs[j].BlockNumber && allTxLogs[i].Index < allTxLogs[j].Index)
    })
    return allTxLogs, nil
}

func (c *MockClient) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (ethereum.Subscription, error) {
    for {
        next := c.latestBlockNum.Load() + 1
        if c.blockChain.Blocks[next] != nil {
            ch <- &types.Header{Number: big.NewInt(next)}
            c.latestBlockNum.Store(next)
        } else {
            break
        }
    }
    return testNoopSub{}, nil
}

type testNoopSub struct {
}

func (testNoopSub) Unsubscribe() {

}

// Err returns the subscription error channel. The error channel receives
// a value if there is an issue with the subscription (e.g. the network connection
// delivering the events has been closed). Only one value will ever be sent.
// The error channel is closed by Unsubscribe.
func (testNoopSub) Err() <-chan error {
    ch := make(chan error)
    return ch
}