package buffer import ( "math/rand" "strconv" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/thrasher-corp/gocryptotrader/common" "github.com/thrasher-corp/gocryptotrader/common/key" "github.com/thrasher-corp/gocryptotrader/config" "github.com/thrasher-corp/gocryptotrader/currency" "github.com/thrasher-corp/gocryptotrader/exchanges/asset" "github.com/thrasher-corp/gocryptotrader/exchanges/orderbook" ) var ( itemArray = [][]orderbook.Level{ {{Price: 1000, Amount: 1, ID: 1000}}, {{Price: 2000, Amount: 1, ID: 2000}}, {{Price: 3000, Amount: 1, ID: 3000}}, {{Price: 3000, Amount: 2, ID: 4000}}, {{Price: 4000, Amount: 0, ID: 6000}}, {{Price: 5000, Amount: 1, ID: 5000}}, } offset = common.Counter{} ) const exchangeName = "exchangeTest" // getExclusivePair returns a currency pair with a unique ID for testing as books are centralised and changes will affect other tests func getExclusivePair() (currency.Pair, error) { return currency.NewPairFromStrings(currency.BTC.String(), currency.USDT.String()+strconv.FormatInt(offset.IncrementAndGet(), 10)) } func createSnapshot(pair currency.Pair) (holder *Orderbook, asks, bids orderbook.Levels, err error) { asks = orderbook.Levels{{Price: 4000, Amount: 1, ID: 6}} bids = orderbook.Levels{{Price: 4000, Amount: 1, ID: 6}} book := &orderbook.Book{ Exchange: exchangeName, Asks: asks, Bids: bids, Asset: asset.Spot, Pair: pair, PriceDuplication: true, LastUpdated: time.Now(), LastUpdateID: 69420, ValidateOrderbook: true, } newBook := make(map[key.PairAsset]*orderbookHolder) ch := make(chan any) go func(<-chan any) { // reader for range ch { continue } }(ch) holder = &Orderbook{ exchangeName: exchangeName, dataHandler: ch, ob: newBook, } err = holder.LoadSnapshot(book) return holder, asks, bids, err } // BenchmarkBufferPerformance demonstrates buffer more performant than multi // process calls // 890016 1688 ns/op 416 B/op 3 allocs/op func BenchmarkBufferPerformance(b *testing.B) { cp, err := getExclusivePair() require.NoError(b, err) holder, asks, bids, err := createSnapshot(cp) require.NoError(b, err) holder.bufferEnabled = true update := &orderbook.Update{ Bids: bids, Asks: asks, Pair: cp, UpdateTime: time.Now(), Asset: asset.Spot, } for b.Loop() { randomIndex := rand.Intn(4) //nolint:gosec // no need to import crypo/rand for testing update.Asks = itemArray[randomIndex] update.Bids = itemArray[randomIndex] require.NoError(b, holder.Update(update)) } } // BenchmarkBufferSortingPerformance benchmark // // 613964 2093 ns/op 440 B/op 4 allocs/op func BenchmarkBufferSortingPerformance(b *testing.B) { cp, err := getExclusivePair() require.NoError(b, err) holder, asks, bids, err := createSnapshot(cp) require.NoError(b, err) holder.bufferEnabled = true holder.sortBuffer = true update := &orderbook.Update{ Bids: bids, Asks: asks, Pair: cp, UpdateTime: time.Now(), Asset: asset.Spot, } for b.Loop() { randomIndex := rand.Intn(4) //nolint:gosec // no need to import crypo/rand for testing update.Asks = itemArray[randomIndex] update.Bids = itemArray[randomIndex] require.NoError(b, holder.Update(update)) } } // BenchmarkBufferSortingPerformance benchmark // 914500 1599 ns/op 440 B/op 4 allocs/op func BenchmarkBufferSortingByIDPerformance(b *testing.B) { cp, err := getExclusivePair() require.NoError(b, err) holder, asks, bids, err := createSnapshot(cp) require.NoError(b, err) holder.bufferEnabled = true holder.sortBuffer = true holder.sortBufferByUpdateIDs = true update := &orderbook.Update{ Bids: bids, Asks: asks, Pair: cp, UpdateTime: time.Now(), Asset: asset.Spot, } for b.Loop() { randomIndex := rand.Intn(4) //nolint:gosec // no need to import crypo/rand for testing update.Asks = itemArray[randomIndex] update.Bids = itemArray[randomIndex] require.NoError(b, holder.Update(update)) } } // BenchmarkNoBufferPerformance demonstrates orderbook process more performant // than buffer // 122659 12792 ns/op 972 B/op 7 allocs/op PRIOR // 1225924 1028 ns/op 240 B/op 2 allocs/op CURRENT func BenchmarkNoBufferPerformance(b *testing.B) { cp, err := getExclusivePair() require.NoError(b, err) obl, asks, bids, err := createSnapshot(cp) require.NoError(b, err) update := &orderbook.Update{ Bids: bids, Asks: asks, Pair: cp, UpdateTime: time.Now(), Asset: asset.Spot, } for b.Loop() { randomIndex := rand.Intn(4) //nolint:gosec // no need to import crypo/rand for testing update.Asks = itemArray[randomIndex] update.Bids = itemArray[randomIndex] require.NoError(b, obl.Update(update)) } } // TestHittingTheBuffer logic test func TestHittingTheBuffer(t *testing.T) { t.Parallel() cp, err := getExclusivePair() require.NoError(t, err) holder, _, _, err := createSnapshot(cp) require.NoError(t, err) holder.bufferEnabled = true holder.obBufferLimit = 5 for i := range itemArray { asks := itemArray[i] bids := itemArray[i] err = holder.Update(&orderbook.Update{ Bids: bids, Asks: asks, Pair: cp, UpdateTime: time.Now(), Asset: asset.Spot, }) require.NoError(t, err) } book := holder.ob[key.PairAsset{Base: cp.Base.Item, Quote: cp.Quote.Item, Asset: asset.Spot}] askLen, err := book.ob.GetAskLength() require.NoError(t, err) assert.Equal(t, 3, askLen) bidLen, err := book.ob.GetBidLength() require.NoError(t, err) assert.Equal(t, 3, bidLen) } // TestInsertWithIDs logic test func TestInsertWithIDs(t *testing.T) { t.Parallel() cp, err := getExclusivePair() require.NoError(t, err) holder, _, _, err := createSnapshot(cp) require.NoError(t, err) holder.bufferEnabled = true holder.obBufferLimit = 5 for i := range itemArray { asks := itemArray[i] if asks[0].Amount <= 0 { continue } bids := itemArray[i] err = holder.Update(&orderbook.Update{ Bids: bids, Asks: asks, Pair: cp, UpdateTime: time.Now(), Asset: asset.Spot, Action: orderbook.UpdateOrInsertAction, }) require.NoError(t, err) } book := holder.ob[key.PairAsset{Base: cp.Base.Item, Quote: cp.Quote.Item, Asset: asset.Spot}] askLen, err := book.ob.GetAskLength() require.NoError(t, err) assert.Equal(t, 6, askLen) bidLen, err := book.ob.GetBidLength() require.NoError(t, err) assert.Equal(t, 6, bidLen) holder.obBufferLimit = 1 err = holder.Update(&orderbook.Update{ UpdateTime: time.Now(), Asset: asset.Spot, Pair: cp, }) assert.ErrorIs(t, err, orderbook.ErrEmptyUpdate) } // TestSortIDs logic test func TestSortIDs(t *testing.T) { t.Parallel() cp, err := getExclusivePair() require.NoError(t, err) holder, _, _, err := createSnapshot(cp) require.NoError(t, err) holder.bufferEnabled = true holder.sortBufferByUpdateIDs = true holder.sortBuffer = true holder.obBufferLimit = 5 for i := range itemArray { asks := itemArray[i] bids := itemArray[i] err = holder.Update(&orderbook.Update{ Bids: bids, Asks: asks, Pair: cp, UpdateID: int64(i), Asset: asset.Spot, UpdateTime: time.Now(), }) require.NoError(t, err) } book := holder.ob[key.PairAsset{Base: cp.Base.Item, Quote: cp.Quote.Item, Asset: asset.Spot}] askLen, err := book.ob.GetAskLength() require.NoError(t, err) assert.Equal(t, 3, askLen) bidLen, err := book.ob.GetBidLength() require.NoError(t, err) assert.Equal(t, 3, bidLen) } // TestOutOfOrderIDs logic test func TestOutOfOrderIDs(t *testing.T) { t.Parallel() cp, err := getExclusivePair() require.NoError(t, err) holder, _, _, err := createSnapshot(cp) require.NoError(t, err) outOFOrderIDs := []int64{2, 1, 5, 3, 4, 6, 7} assert.Equal(t, 1000., itemArray[0][0].Price) holder.bufferEnabled = true holder.sortBuffer = true holder.obBufferLimit = 5 for i := range itemArray { asks := itemArray[i] err = holder.Update(&orderbook.Update{ Asks: asks, Pair: cp, UpdateID: outOFOrderIDs[i], Asset: asset.Spot, UpdateTime: time.Now(), }) require.NoError(t, err) } book := holder.ob[key.PairAsset{Base: cp.Base.Item, Quote: cp.Quote.Item, Asset: asset.Spot}] cpy, err := book.ob.Retrieve() require.NoError(t, err) // Index 1 since index 0 is price 7000 assert.Equal(t, 2000., cpy.Asks[1].Price) } func TestOrderbookLastUpdateID(t *testing.T) { t.Parallel() cp, err := getExclusivePair() require.NoError(t, err) holder, _, _, err := createSnapshot(cp) require.NoError(t, err) assert.Equal(t, 1000., itemArray[0][0].Price) // this update invalidates the book err = holder.Update(&orderbook.Update{ Asks: orderbook.Levels{{Price: 999999}}, Pair: cp, UpdateID: -1, Asset: asset.Spot, UpdateTime: time.Now(), ExpectedChecksum: 1337, GenerateChecksum: func(*orderbook.Book) uint32 { return 1336 }, }) require.ErrorIs(t, err, orderbook.ErrOrderbookInvalid) cp, err = getExclusivePair() require.NoError(t, err) holder, _, _, err = createSnapshot(cp) require.NoError(t, err) for i := range itemArray { asks := itemArray[i] err = holder.Update(&orderbook.Update{ Asks: asks, Pair: cp, UpdateID: int64(i) + 1 + 69420, Asset: asset.Spot, UpdateTime: time.Now(), SkipOutOfOrderLastUpdateID: true, ExpectedChecksum: 1337, GenerateChecksum: func(*orderbook.Book) uint32 { return 1337 }, }) require.NoError(t, err) } // out of order err = holder.Update(&orderbook.Update{ Asks: orderbook.Levels{{Price: 999999}}, Pair: cp, UpdateID: 1, Asset: asset.Spot, SkipOutOfOrderLastUpdateID: true, }) require.NoError(t, err, "Out of sequence Update must not error") ob, err := holder.GetOrderbook(cp, asset.Spot) require.NoError(t, err, "GetOrderbook must not error") assert.Equal(t, int64(len(itemArray)+69420), ob.LastUpdateID, "Out of sequence Update should not change LastUpdateID") } // TestRunUpdateWithoutSnapshot logic test func TestRunUpdateWithoutSnapshot(t *testing.T) { t.Parallel() cp, err := getExclusivePair() require.NoError(t, err) var holder Orderbook asks := []orderbook.Level{{Price: 4000, Amount: 1, ID: 8}} bids := []orderbook.Level{{Price: 5999, Amount: 1, ID: 8}, {Price: 4000, Amount: 1, ID: 9}} holder.exchangeName = exchangeName err = holder.Update(&orderbook.Update{ Bids: bids, Asks: asks, Pair: cp, UpdateTime: time.Now(), Asset: asset.Spot, }) require.ErrorIs(t, err, orderbook.ErrDepthNotFound) } // TestRunUpdateWithoutAnyUpdates logic test func TestRunUpdateWithoutAnyUpdates(t *testing.T) { t.Parallel() cp, err := getExclusivePair() require.NoError(t, err) holder, _, _, err := createSnapshot(cp) require.NoError(t, err) holder.exchangeName = exchangeName err = holder.Update(&orderbook.Update{ Bids: orderbook.Levels{}, Asks: orderbook.Levels{}, Pair: cp, UpdateTime: time.Now(), Asset: asset.Spot, }) require.ErrorIs(t, err, orderbook.ErrEmptyUpdate) } // TestRunSnapshotWithNoData logic test func TestRunSnapshotWithNoData(t *testing.T) { t.Parallel() cp, err := getExclusivePair() require.NoError(t, err) var obl Orderbook obl.ob = make(map[key.PairAsset]*orderbookHolder) obl.dataHandler = make(chan any, 1) var snapShot1 orderbook.Book snapShot1.Asset = asset.Spot snapShot1.Pair = cp snapShot1.Exchange = "test" obl.exchangeName = "test" snapShot1.LastUpdated = time.Now() require.NoError(t, obl.LoadSnapshot(&snapShot1)) } // TestLoadSnapshot logic test func TestLoadSnapshot(t *testing.T) { t.Parallel() cp, err := getExclusivePair() require.NoError(t, err) var obl Orderbook obl.dataHandler = make(chan any, 100) obl.ob = make(map[key.PairAsset]*orderbookHolder) err = obl.LoadSnapshot(&orderbook.Book{Asks: orderbook.Levels{{Amount: 1}}, ValidateOrderbook: true}) require.ErrorIs(t, err, orderbook.ErrPriceZero) err = obl.LoadSnapshot(&orderbook.Book{Asks: orderbook.Levels{{Amount: 1}}}) require.ErrorIs(t, err, common.ErrExchangeNameNotSet) err = obl.LoadSnapshot(&orderbook.Book{Asks: orderbook.Levels{{Amount: 1}}, Exchange: "test", Pair: cp, Asset: asset.Spot}) require.ErrorIs(t, err, orderbook.ErrLastUpdatedNotSet) var snapShot1 orderbook.Book snapShot1.Exchange = "SnapshotWithOverride" asks := []orderbook.Level{{Price: 4000, Amount: 1, ID: 8}} bids := []orderbook.Level{{Price: 4000, Amount: 1, ID: 9}} snapShot1.Asks = asks snapShot1.Bids = bids snapShot1.Asset = asset.Spot snapShot1.Pair = cp snapShot1.LastUpdated = time.Now() require.NoError(t, obl.LoadSnapshot(&snapShot1)) } // TestFlushBuffer logic test func TestFlushBuffer(t *testing.T) { t.Parallel() cp, err := getExclusivePair() require.NoError(t, err) obl, _, _, err := createSnapshot(cp) require.NoError(t, err, "createSnapshot must not error") require.NotEmpty(t, obl.ob, "createSnapshot must not return empty") k := key.PairAsset{Base: cp.Base.Item, Quote: cp.Quote.Item, Asset: asset.Spot} holder, ok := obl.ob[k] require.Truef(t, ok, "createSnapshot must return a orderbook for %v", k) holder.buffer = make([]orderbook.Update, 0, 10) holder.buffer = append(holder.buffer, orderbook.Update{}) obl.FlushBuffer() assert.Empty(t, holder.buffer, "FlushBuffer should empty buffer") assert.Equal(t, 10, cap(holder.buffer), "FlushBuffer should leave the buffer cap to avoid reallocs") } // TestInsertingSnapShots logic test func TestInsertingSnapShots(t *testing.T) { t.Parallel() cp, err := getExclusivePair() require.NoError(t, err) var holder Orderbook holder.dataHandler = make(chan any, 100) holder.ob = make(map[key.PairAsset]*orderbookHolder) var snapShot1 orderbook.Book snapShot1.Exchange = "WSORDERBOOKTEST1" asks := []orderbook.Level{ {Price: 6000, Amount: 1, ID: 1}, {Price: 6001, Amount: 0.5, ID: 2}, {Price: 6002, Amount: 2, ID: 3}, {Price: 6003, Amount: 3, ID: 4}, {Price: 6004, Amount: 5, ID: 5}, {Price: 6005, Amount: 2, ID: 6}, {Price: 6006, Amount: 1.5, ID: 7}, {Price: 6007, Amount: 0.5, ID: 8}, {Price: 6008, Amount: 23, ID: 9}, {Price: 6009, Amount: 9, ID: 10}, {Price: 6010, Amount: 7, ID: 11}, } bids := []orderbook.Level{ {Price: 5999, Amount: 1, ID: 12}, {Price: 5998, Amount: 0.5, ID: 13}, {Price: 5997, Amount: 2, ID: 14}, {Price: 5996, Amount: 3, ID: 15}, {Price: 5995, Amount: 5, ID: 16}, {Price: 5994, Amount: 2, ID: 17}, {Price: 5993, Amount: 1.5, ID: 18}, {Price: 5992, Amount: 0.5, ID: 19}, {Price: 5991, Amount: 23, ID: 20}, {Price: 5990, Amount: 9, ID: 21}, {Price: 5989, Amount: 7, ID: 22}, } snapShot1.Asks = asks snapShot1.Bids = bids snapShot1.Asset = asset.Spot snapShot1.Pair = cp snapShot1.LastUpdated = time.Now() require.NoError(t, holder.LoadSnapshot(&snapShot1)) var snapShot2 orderbook.Book snapShot2.Exchange = "WSORDERBOOKTEST2" asks = []orderbook.Level{ {Price: 51, Amount: 1, ID: 1}, {Price: 52, Amount: 0.5, ID: 2}, {Price: 53, Amount: 2, ID: 3}, {Price: 54, Amount: 3, ID: 4}, {Price: 55, Amount: 5, ID: 5}, {Price: 56, Amount: 2, ID: 6}, {Price: 57, Amount: 1.5, ID: 7}, {Price: 58, Amount: 0.5, ID: 8}, {Price: 59, Amount: 23, ID: 9}, {Price: 50, Amount: 9, ID: 10}, {Price: 60, Amount: 7, ID: 11}, } bids = []orderbook.Level{ {Price: 49, Amount: 1, ID: 12}, {Price: 48, Amount: 0.5, ID: 13}, {Price: 47, Amount: 2, ID: 14}, {Price: 46, Amount: 3, ID: 15}, {Price: 45, Amount: 5, ID: 16}, {Price: 44, Amount: 2, ID: 17}, {Price: 43, Amount: 1.5, ID: 18}, {Price: 42, Amount: 0.5, ID: 19}, {Price: 41, Amount: 23, ID: 20}, {Price: 40, Amount: 9, ID: 21}, {Price: 39, Amount: 7, ID: 22}, } snapShot2.Asks = asks snapShot2.Asks.SortAsks() snapShot2.Bids = bids snapShot2.Bids.SortBids() snapShot2.Asset = asset.Spot snapShot2.Pair, err = getExclusivePair() require.NoError(t, err) snapShot2.LastUpdated = time.Now() require.NoError(t, holder.LoadSnapshot(&snapShot2)) var snapShot3 orderbook.Book snapShot3.Exchange = "WSORDERBOOKTEST3" asks = []orderbook.Level{ {Price: 511, Amount: 1, ID: 1}, {Price: 52, Amount: 0.5, ID: 2}, {Price: 53, Amount: 2, ID: 3}, {Price: 54, Amount: 3, ID: 4}, {Price: 55, Amount: 5, ID: 5}, {Price: 56, Amount: 2, ID: 6}, {Price: 57, Amount: 1.5, ID: 7}, {Price: 58, Amount: 0.5, ID: 8}, {Price: 59, Amount: 23, ID: 9}, {Price: 50, Amount: 9, ID: 10}, {Price: 60, Amount: 7, ID: 11}, } bids = []orderbook.Level{ {Price: 49, Amount: 1, ID: 12}, {Price: 48, Amount: 0.5, ID: 13}, {Price: 47, Amount: 2, ID: 14}, {Price: 46, Amount: 3, ID: 15}, {Price: 45, Amount: 5, ID: 16}, {Price: 44, Amount: 2, ID: 17}, {Price: 43, Amount: 1.5, ID: 18}, {Price: 42, Amount: 0.5, ID: 19}, {Price: 41, Amount: 23, ID: 20}, {Price: 40, Amount: 9, ID: 21}, {Price: 39, Amount: 7, ID: 22}, } snapShot3.Asks = asks snapShot3.Asks.SortAsks() snapShot3.Bids = bids snapShot3.Bids.SortBids() snapShot3.Asset = asset.Futures snapShot3.Pair, err = getExclusivePair() require.NoError(t, err) snapShot3.LastUpdated = time.Now() require.NoError(t, holder.LoadSnapshot(&snapShot3)) ob, err := holder.GetOrderbook(snapShot1.Pair, snapShot1.Asset) require.NoError(t, err) assert.Equal(t, snapShot1.Asks[0], ob.Asks[0]) ob, err = holder.GetOrderbook(snapShot2.Pair, snapShot2.Asset) require.NoError(t, err) assert.Equal(t, snapShot2.Asks[0], ob.Asks[0]) ob, err = holder.GetOrderbook(snapShot3.Pair, snapShot3.Asset) require.NoError(t, err) assert.Equal(t, snapShot3.Asks[0], ob.Asks[0]) } func TestGetOrderbook(t *testing.T) { t.Parallel() cp, err := getExclusivePair() require.NoError(t, err) holder, _, _, err := createSnapshot(cp) require.NoError(t, err) _, err = holder.GetOrderbook(currency.EMPTYPAIR, asset.Spot) require.ErrorIs(t, err, currency.ErrCurrencyPairEmpty) _, err = holder.GetOrderbook(cp, 0) require.ErrorIs(t, err, asset.ErrInvalidAsset) ob, err := holder.GetOrderbook(cp, asset.Spot) require.NoError(t, err) bufferOb := holder.ob[key.PairAsset{Base: cp.Base.Item, Quote: cp.Quote.Item, Asset: asset.Spot}] b, err := bufferOb.ob.Retrieve() require.NoError(t, err) askLen, err := bufferOb.ob.GetAskLength() require.NoError(t, err) bidLen, err := bufferOb.ob.GetBidLength() require.NoError(t, err) assert.Equal(t, askLen, len(ob.Asks), "ask length mismatch") assert.Equal(t, bidLen, len(ob.Bids), "bid length mismatch") assert.Equal(t, b.Asset, ob.Asset, "asset mismatch") assert.Equal(t, b.Exchange, ob.Exchange, "exchange name mismatch") assert.Equal(t, b.LastUpdateID, ob.LastUpdateID, "last update ID mismatch") assert.Equal(t, b.PriceDuplication, ob.PriceDuplication, "price duplication mismatch") assert.Equal(t, b.Pair, ob.Pair, "pair mismatch") } func TestLastUpdateID(t *testing.T) { t.Parallel() cp, err := getExclusivePair() require.NoError(t, err) holder, _, _, err := createSnapshot(cp) require.NoError(t, err) _, err = holder.LastUpdateID(currency.EMPTYPAIR, asset.Spot) require.ErrorIs(t, err, currency.ErrCurrencyPairEmpty) _, err = holder.LastUpdateID(cp, 0) require.ErrorIs(t, err, asset.ErrInvalidAsset) _, err = holder.LastUpdateID(cp, asset.FutureCombo) require.ErrorIs(t, err, orderbook.ErrDepthNotFound) ob, err := holder.LastUpdateID(cp, asset.Spot) require.NoError(t, err) require.Equal(t, int64(69420), ob) } func TestSetup(t *testing.T) { t.Parallel() w := Orderbook{} err := w.Setup(nil, nil, nil) require.ErrorIs(t, err, errExchangeConfigNil) exchangeConfig := &config.Exchange{} err = w.Setup(exchangeConfig, nil, nil) require.ErrorIs(t, err, errBufferConfigNil) bufferConf := &Config{} err = w.Setup(exchangeConfig, bufferConf, nil) require.ErrorIs(t, err, errUnsetDataHandler) exchangeConfig.Orderbook.WebsocketBufferEnabled = true err = w.Setup(exchangeConfig, bufferConf, make(chan any)) require.ErrorIs(t, err, errIssueBufferEnabledButNoLimit) exchangeConfig.Orderbook.WebsocketBufferLimit = 1337 exchangeConfig.Orderbook.WebsocketBufferEnabled = true exchangeConfig.Name = "test" bufferConf.SortBuffer = true bufferConf.SortBufferByUpdateIDs = true err = w.Setup(exchangeConfig, bufferConf, make(chan any)) require.NoError(t, err) require.Equal(t, 1337, w.obBufferLimit) require.True(t, w.bufferEnabled) require.True(t, w.sortBuffer) require.True(t, w.sortBufferByUpdateIDs) require.Equal(t, "test", w.exchangeName) } func TestInvalidateOrderbook(t *testing.T) { t.Parallel() cp, err := getExclusivePair() require.NoError(t, err) w := &Orderbook{} err = w.Setup(&config.Exchange{Name: "test"}, &Config{}, make(chan any, 2)) require.NoError(t, err) var snapShot1 orderbook.Book snapShot1.Exchange = "Snapshooooot" asks := []orderbook.Level{{Price: 4000, Amount: 1, ID: 8}} bids := []orderbook.Level{{Price: 4000, Amount: 1, ID: 9}} snapShot1.Asks = asks snapShot1.Bids = bids snapShot1.Asset = asset.Spot snapShot1.Pair = cp snapShot1.LastUpdated = time.Now() err = w.InvalidateOrderbook(cp, asset.Spot) if err == nil { t.Fatal("book not loaded error cannot be nil") } _, err = w.GetOrderbook(cp, asset.Spot) require.ErrorIs(t, err, orderbook.ErrDepthNotFound) require.NoError(t, w.LoadSnapshot(&snapShot1)) require.NoError(t, w.InvalidateOrderbook(cp, asset.Spot)) _, err = w.GetOrderbook(cp, asset.Spot) require.ErrorIs(t, err, orderbook.ErrOrderbookInvalid) }