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  }