github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/module/mempool/herocache/transactions_test.go (about) 1 package herocache_test 2 3 import ( 4 "sync" 5 "testing" 6 "time" 7 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 11 "github.com/onflow/flow-go/model/flow" 12 "github.com/onflow/flow-go/module/mempool/herocache" 13 "github.com/onflow/flow-go/module/metrics" 14 "github.com/onflow/flow-go/utils/unittest" 15 ) 16 17 func TestTransactionPool(t *testing.T) { 18 tx1 := unittest.TransactionBodyFixture() 19 tx2 := unittest.TransactionBodyFixture() 20 21 transactions := herocache.NewTransactions(1000, unittest.Logger(), metrics.NewNoopCollector()) 22 23 t.Run("should be able to add first", func(t *testing.T) { 24 added := transactions.Add(&tx1) 25 assert.True(t, added) 26 }) 27 28 t.Run("should be able to add second", func(t *testing.T) { 29 added := transactions.Add(&tx2) 30 assert.True(t, added) 31 }) 32 33 t.Run("should be able to get size", func(t *testing.T) { 34 size := transactions.Size() 35 assert.EqualValues(t, 2, size) 36 }) 37 38 t.Run("should be able to get first", func(t *testing.T) { 39 actual, exists := transactions.ByID(tx1.ID()) 40 assert.True(t, exists) 41 assert.Equal(t, &tx1, actual) 42 }) 43 44 t.Run("should be able to remove second", func(t *testing.T) { 45 ok := transactions.Remove(tx2.ID()) 46 assert.True(t, ok) 47 }) 48 49 t.Run("should be able to retrieve all", func(t *testing.T) { 50 items := transactions.All() 51 assert.Len(t, items, 1) 52 assert.Equal(t, &tx1, items[0]) 53 }) 54 55 t.Run("should be able to clear", func(t *testing.T) { 56 assert.True(t, transactions.Size() > 0) 57 transactions.Clear() 58 assert.Equal(t, uint(0), transactions.Size()) 59 }) 60 } 61 62 // TestConcurrentWriteAndRead checks correctness of transactions mempool under concurrent read and write. 63 func TestConcurrentWriteAndRead(t *testing.T) { 64 total := 100 65 txs := unittest.TransactionBodyListFixture(total) 66 transactions := herocache.NewTransactions(uint32(total), unittest.Logger(), metrics.NewNoopCollector()) 67 68 wg := sync.WaitGroup{} 69 wg.Add(total) 70 71 // storing all transactions 72 for i := 0; i < total; i++ { 73 go func(tx flow.TransactionBody) { 74 require.True(t, transactions.Add(&tx)) 75 76 wg.Done() 77 }(txs[i]) 78 } 79 80 unittest.RequireReturnsBefore(t, wg.Wait, 100*time.Millisecond, "could not write all transactions on time") 81 require.Equal(t, transactions.Size(), uint(total)) 82 83 wg.Add(total) 84 // reading all transactions 85 for i := 0; i < total; i++ { 86 go func(tx flow.TransactionBody) { 87 actual, ok := transactions.ByID(tx.ID()) 88 require.True(t, ok) 89 require.Equal(t, tx, *actual) 90 91 wg.Done() 92 }(txs[i]) 93 } 94 unittest.RequireReturnsBefore(t, wg.Wait, 100*time.Millisecond, "could not read all transactions on time") 95 } 96 97 // TestAllReturnsInOrder checks All method of the HeroCache-based transactions mempool returns all 98 // transactions in the same order as they are returned. 99 func TestAllReturnsInOrder(t *testing.T) { 100 total := 100 101 txs := unittest.TransactionBodyListFixture(total) 102 transactions := herocache.NewTransactions(uint32(total), unittest.Logger(), metrics.NewNoopCollector()) 103 104 // storing all transactions 105 for i := 0; i < total; i++ { 106 require.True(t, transactions.Add(&txs[i])) 107 tx, ok := transactions.ByID(txs[i].ID()) 108 require.True(t, ok) 109 require.Equal(t, txs[i], *tx) 110 } 111 112 // all transactions must be retrieved in the same order as they are added 113 all := transactions.All() 114 for i := 0; i < total; i++ { 115 require.Equal(t, txs[i], *all[i]) 116 } 117 }