github.com/ava-labs/avalanchego@v1.11.11/indexer/index_test.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package indexer 5 6 import ( 7 "testing" 8 9 "github.com/stretchr/testify/require" 10 11 "github.com/ava-labs/avalanchego/database/memdb" 12 "github.com/ava-labs/avalanchego/database/versiondb" 13 "github.com/ava-labs/avalanchego/ids" 14 "github.com/ava-labs/avalanchego/snow/snowtest" 15 "github.com/ava-labs/avalanchego/utils" 16 "github.com/ava-labs/avalanchego/utils/logging" 17 "github.com/ava-labs/avalanchego/utils/set" 18 "github.com/ava-labs/avalanchego/utils/timer/mockable" 19 ) 20 21 func TestIndex(t *testing.T) { 22 // Setup 23 pageSize := uint64(64) 24 require := require.New(t) 25 baseDB := memdb.New() 26 db := versiondb.New(baseDB) 27 snowCtx := snowtest.Context(t, snowtest.CChainID) 28 ctx := snowtest.ConsensusContext(snowCtx) 29 30 idx, err := newIndex(db, logging.NoLog{}, mockable.Clock{}) 31 require.NoError(err) 32 33 // Populate "containers" with random IDs/bytes 34 containers := map[ids.ID][]byte{} 35 for i := uint64(0); i < 2*pageSize; i++ { 36 containers[ids.GenerateTestID()] = utils.RandomBytes(32) 37 } 38 39 // Accept each container and after each, make assertions 40 i := uint64(0) 41 for containerID, containerBytes := range containers { 42 require.NoError(idx.Accept(ctx, containerID, containerBytes)) 43 44 lastAcceptedIndex, ok := idx.lastAcceptedIndex() 45 require.True(ok) 46 require.Equal(i, lastAcceptedIndex) 47 require.Equal(i+1, idx.nextAcceptedIndex) 48 49 gotContainer, err := idx.GetContainerByID(containerID) 50 require.NoError(err) 51 require.Equal(containerBytes, gotContainer.Bytes) 52 53 gotIndex, err := idx.GetIndex(containerID) 54 require.NoError(err) 55 require.Equal(i, gotIndex) 56 57 gotContainer, err = idx.GetContainerByIndex(i) 58 require.NoError(err) 59 require.Equal(containerBytes, gotContainer.Bytes) 60 61 gotContainer, err = idx.GetLastAccepted() 62 require.NoError(err) 63 require.Equal(containerBytes, gotContainer.Bytes) 64 65 containers, err := idx.GetContainerRange(i, 1) 66 require.NoError(err) 67 require.Len(containers, 1) 68 require.Equal(containerBytes, containers[0].Bytes) 69 70 containers, err = idx.GetContainerRange(i, 2) 71 require.NoError(err) 72 require.Len(containers, 1) 73 require.Equal(containerBytes, containers[0].Bytes) 74 75 i++ 76 } 77 78 // Create a new index with the same database and ensure contents still there 79 require.NoError(db.Commit()) 80 require.NoError(idx.Close()) 81 db = versiondb.New(baseDB) 82 idx, err = newIndex(db, logging.NoLog{}, mockable.Clock{}) 83 require.NoError(err) 84 85 // Get all of the containers 86 containersList, err := idx.GetContainerRange(0, pageSize) 87 require.NoError(err) 88 require.Len(containersList, int(pageSize)) 89 containersList2, err := idx.GetContainerRange(pageSize, pageSize) 90 require.NoError(err) 91 require.Len(containersList2, int(pageSize)) 92 containersList = append(containersList, containersList2...) 93 94 // Ensure that the data is correct 95 lastTimestamp := int64(0) 96 sawContainers := set.Set[ids.ID]{} 97 for _, container := range containersList { 98 require.False(sawContainers.Contains(container.ID)) // Should only see this container once 99 require.Contains(containers, container.ID) 100 require.Equal(containers[container.ID], container.Bytes) 101 // Timestamps should be non-decreasing 102 require.GreaterOrEqual(container.Timestamp, lastTimestamp) 103 lastTimestamp = container.Timestamp 104 sawContainers.Add(container.ID) 105 } 106 } 107 108 func TestIndexGetContainerByRangeMaxPageSize(t *testing.T) { 109 // Setup 110 require := require.New(t) 111 db := memdb.New() 112 snowCtx := snowtest.Context(t, snowtest.CChainID) 113 ctx := snowtest.ConsensusContext(snowCtx) 114 idx, err := newIndex(db, logging.NoLog{}, mockable.Clock{}) 115 require.NoError(err) 116 117 // Insert [MaxFetchedByRange] + 1 containers 118 for i := uint64(0); i < MaxFetchedByRange+1; i++ { 119 require.NoError(idx.Accept(ctx, ids.GenerateTestID(), utils.RandomBytes(32))) 120 } 121 122 // Page size too large 123 _, err = idx.GetContainerRange(0, MaxFetchedByRange+1) 124 require.ErrorIs(err, errNumToFetchInvalid) 125 126 // Make sure data is right 127 containers, err := idx.GetContainerRange(0, MaxFetchedByRange) 128 require.NoError(err) 129 require.Len(containers, MaxFetchedByRange) 130 131 containers2, err := idx.GetContainerRange(1, MaxFetchedByRange) 132 require.NoError(err) 133 require.Len(containers2, MaxFetchedByRange) 134 135 require.Equal(containers[1], containers2[0]) 136 require.Equal(containers[MaxFetchedByRange-1], containers2[MaxFetchedByRange-2]) 137 138 // Should have last 2 elements 139 containers, err = idx.GetContainerRange(MaxFetchedByRange-1, MaxFetchedByRange) 140 require.NoError(err) 141 require.Len(containers, 2) 142 require.Equal(containers[1], containers2[MaxFetchedByRange-1]) 143 require.Equal(containers[0], containers2[MaxFetchedByRange-2]) 144 } 145 146 func TestDontIndexSameContainerTwice(t *testing.T) { 147 // Setup 148 require := require.New(t) 149 db := memdb.New() 150 snowCtx := snowtest.Context(t, snowtest.CChainID) 151 ctx := snowtest.ConsensusContext(snowCtx) 152 idx, err := newIndex(db, logging.NoLog{}, mockable.Clock{}) 153 require.NoError(err) 154 155 // Accept the same container twice 156 containerID := ids.GenerateTestID() 157 require.NoError(idx.Accept(ctx, containerID, []byte{1, 2, 3})) 158 require.NoError(idx.Accept(ctx, containerID, []byte{4, 5, 6})) 159 _, err = idx.GetContainerByIndex(1) 160 require.ErrorIs(err, errNoContainerAtIndex) 161 gotContainer, err := idx.GetContainerByID(containerID) 162 require.NoError(err) 163 require.Equal([]byte{1, 2, 3}, gotContainer.Bytes) 164 }