github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/network/bqueue/queue_test.go (about)

     1  package bqueue
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	"github.com/nspcc-dev/neo-go/internal/fakechain"
     8  	"github.com/nspcc-dev/neo-go/pkg/core/block"
     9  	"github.com/stretchr/testify/assert"
    10  	"go.uber.org/zap/zaptest"
    11  )
    12  
    13  func TestBlockQueue(t *testing.T) {
    14  	chain := fakechain.NewFakeChain()
    15  	// notice, it's not yet running
    16  	bq := New(chain, zaptest.NewLogger(t), nil, nil)
    17  	blocks := make([]*block.Block, 11)
    18  	for i := 1; i < 11; i++ {
    19  		blocks[i] = &block.Block{Header: block.Header{Index: uint32(i)}}
    20  	}
    21  	// not the ones expected currently
    22  	for i := 3; i < 5; i++ {
    23  		assert.NoError(t, bq.PutBlock(blocks[i]))
    24  	}
    25  	last, capLeft := bq.LastQueued()
    26  	assert.Equal(t, uint32(0), last)
    27  	assert.Equal(t, CacheSize-2, capLeft)
    28  	// nothing should be put into the blockchain
    29  	assert.Equal(t, uint32(0), chain.BlockHeight())
    30  	assert.Equal(t, 2, bq.length())
    31  	// now added the expected ones (with duplicates)
    32  	for i := 1; i < 5; i++ {
    33  		assert.NoError(t, bq.PutBlock(blocks[i]))
    34  	}
    35  	// but they're still not put into the blockchain, because bq isn't running
    36  	last, capLeft = bq.LastQueued()
    37  	assert.Equal(t, uint32(4), last)
    38  	assert.Equal(t, CacheSize-4, capLeft)
    39  	assert.Equal(t, uint32(0), chain.BlockHeight())
    40  	assert.Equal(t, 4, bq.length())
    41  	// block with too big index is dropped
    42  	assert.NoError(t, bq.PutBlock(&block.Block{Header: block.Header{Index: bq.chain.BlockHeight() + CacheSize + 1}}))
    43  	assert.Equal(t, 4, bq.length())
    44  	go bq.Run()
    45  	// run() is asynchronous, so we need some kind of timeout anyway and this is the simplest one
    46  	assert.Eventually(t, func() bool { return chain.BlockHeight() == 4 }, 4*time.Second, 100*time.Millisecond)
    47  	last, capLeft = bq.LastQueued()
    48  	assert.Equal(t, uint32(4), last)
    49  	assert.Equal(t, CacheSize, capLeft)
    50  	assert.Equal(t, 0, bq.length())
    51  	assert.Equal(t, uint32(4), chain.BlockHeight())
    52  	// put some old blocks
    53  	for i := 1; i < 5; i++ {
    54  		assert.NoError(t, bq.PutBlock(blocks[i]))
    55  	}
    56  	last, capLeft = bq.LastQueued()
    57  	assert.Equal(t, uint32(4), last)
    58  	assert.Equal(t, CacheSize, capLeft)
    59  	assert.Equal(t, 0, bq.length())
    60  	assert.Equal(t, uint32(4), chain.BlockHeight())
    61  	// unexpected blocks with run() active
    62  	assert.NoError(t, bq.PutBlock(blocks[8]))
    63  	assert.Equal(t, 1, bq.length())
    64  	assert.Equal(t, uint32(4), chain.BlockHeight())
    65  	assert.NoError(t, bq.PutBlock(blocks[7]))
    66  	assert.Equal(t, 2, bq.length())
    67  	assert.Equal(t, uint32(4), chain.BlockHeight())
    68  	// sparse put
    69  	assert.NoError(t, bq.PutBlock(blocks[10]))
    70  	assert.Equal(t, 3, bq.length())
    71  	assert.Equal(t, uint32(4), chain.BlockHeight())
    72  	assert.NoError(t, bq.PutBlock(blocks[6]))
    73  	assert.NoError(t, bq.PutBlock(blocks[5]))
    74  	// run() is asynchronous, so we need some kind of timeout anyway and this is the simplest one
    75  	assert.Eventually(t, func() bool { return chain.BlockHeight() == 8 }, 4*time.Second, 100*time.Millisecond)
    76  	last, capLeft = bq.LastQueued()
    77  	assert.Equal(t, uint32(8), last)
    78  	assert.Equal(t, CacheSize-1, capLeft)
    79  	assert.Equal(t, 1, bq.length())
    80  	assert.Equal(t, uint32(8), chain.BlockHeight())
    81  	bq.Discard()
    82  	assert.Equal(t, 0, bq.length())
    83  }
    84  
    85  // length wraps len access for tests to make them thread-safe.
    86  func (bq *Queue) length() int {
    87  	bq.queueLock.Lock()
    88  	defer bq.queueLock.Unlock()
    89  	return bq.len
    90  }