github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/module/mempool/stdmap/eject_test.go (about)

     1  package stdmap
     2  
     3  import (
     4  	crand "crypto/rand"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  	"github.com/stretchr/testify/require"
     9  
    10  	"github.com/onflow/flow-go/model/flow"
    11  	"github.com/onflow/flow-go/utils/unittest"
    12  )
    13  
    14  // TestLRUEjector_Track evaluates that tracking a new item adds the item to the ejector table.
    15  func TestLRUEjector_Track(t *testing.T) {
    16  	ejector := NewLRUEjector()
    17  	// ejector's table should be empty
    18  	assert.Len(t, ejector.table, 0)
    19  
    20  	// sequence number of ejector should initially be zero
    21  	assert.Equal(t, ejector.seqNum, uint64(0))
    22  
    23  	// creates adds an item to the ejector
    24  	item := flow.Identifier{0x00}
    25  	ejector.Track(item)
    26  
    27  	// size of ejector's table should be one
    28  	// which indicates that ejector is tracking the item
    29  	assert.Len(t, ejector.table, 1)
    30  
    31  	// item should reside in the ejector's table
    32  	_, ok := ejector.table[item]
    33  	assert.True(t, ok)
    34  
    35  	// sequence number of ejector should be increased by one
    36  	assert.Equal(t, ejector.seqNum, uint64(1))
    37  }
    38  
    39  // TestLRUEjector_Track_Duplicate evaluates that tracking a duplicate item
    40  // does not change the internal state of the ejector.
    41  func TestLRUEjector_Track_Duplicate(t *testing.T) {
    42  	ejector := NewLRUEjector()
    43  
    44  	// creates adds an item to the ejector
    45  	item := flow.Identifier{0x00}
    46  	ejector.Track(item)
    47  
    48  	// size of ejector's table should be one
    49  	// which indicates that ejector is tracking the item
    50  	assert.Len(t, ejector.table, 1)
    51  
    52  	// item should reside in the ejector's table
    53  	_, ok := ejector.table[item]
    54  	assert.True(t, ok)
    55  
    56  	// sequence number of ejector should be increased by one
    57  	assert.Equal(t, ejector.seqNum, uint64(1))
    58  
    59  	// adds the duplicate item
    60  	ejector.Track(item)
    61  
    62  	// internal state of the ejector should be unchaged
    63  	assert.Len(t, ejector.table, 1)
    64  	assert.Equal(t, ejector.seqNum, uint64(1))
    65  	_, ok = ejector.table[item]
    66  	assert.True(t, ok)
    67  }
    68  
    69  // TestLRUEjector_Track_Many evaluates that tracking many items
    70  // changes the state of ejector properly, i.e., items reside on the
    71  // memory, and sequence number changed accordingly.
    72  func TestLRUEjector_Track_Many(t *testing.T) {
    73  	ejector := NewLRUEjector()
    74  
    75  	// creates and tracks 100 items
    76  	size := 100
    77  	items := flow.IdentifierList{}
    78  	for i := 0; i < size; i++ {
    79  		var id flow.Identifier
    80  		_, _ = crand.Read(id[:])
    81  		ejector.Track(id)
    82  		items = append(items, id)
    83  	}
    84  
    85  	// size of ejector's table should be 100
    86  	assert.Len(t, ejector.table, size)
    87  
    88  	// all items should reside in the ejector's table
    89  	for _, id := range items {
    90  		_, ok := ejector.table[id]
    91  		require.True(t, ok)
    92  	}
    93  
    94  	// sequence number of ejector should be increased by size
    95  	assert.Equal(t, ejector.seqNum, uint64(size))
    96  }
    97  
    98  // TestLRUEjector_Untrack_One evaluates that untracking an existing item
    99  // removes it from the ejector state and changes the state accordingly.
   100  func TestLRUEjector_Untrack_One(t *testing.T) {
   101  	ejector := NewLRUEjector()
   102  
   103  	// creates adds an item to the ejector
   104  	item := flow.Identifier{0x00}
   105  	ejector.Track(item)
   106  
   107  	// size of ejector's table should be one
   108  	// which indicates that ejector is tracking the item
   109  	assert.Len(t, ejector.table, 1)
   110  
   111  	// item should reside in the ejector's table
   112  	_, ok := ejector.table[item]
   113  	assert.True(t, ok)
   114  
   115  	// sequence number of ejector should be increased by one
   116  	assert.Equal(t, ejector.seqNum, uint64(1))
   117  
   118  	// untracks the item
   119  	ejector.Untrack(item)
   120  
   121  	// internal state of the ejector should be changed
   122  	assert.Len(t, ejector.table, 0)
   123  
   124  	// sequence number should not be changed
   125  	assert.Equal(t, ejector.seqNum, uint64(1))
   126  
   127  	// item should no longer reside on internal state of ejector
   128  	_, ok = ejector.table[item]
   129  	assert.False(t, ok)
   130  }
   131  
   132  // TestLRUEjector_Untrack_Duplicate evaluates that untracking an item twice
   133  // removes it from the ejector state only once and changes the state safely.
   134  func TestLRUEjector_Untrack_Duplicate(t *testing.T) {
   135  	ejector := NewLRUEjector()
   136  
   137  	// creates and adds two items to the ejector
   138  	item1 := flow.Identifier{0x00}
   139  	item2 := flow.Identifier{0x01}
   140  	ejector.Track(item1)
   141  	ejector.Track(item2)
   142  
   143  	// size of ejector's table should be two
   144  	// which indicates that ejector is tracking the items
   145  	assert.Len(t, ejector.table, 2)
   146  
   147  	// items should reside in the ejector's table
   148  	_, ok := ejector.table[item1]
   149  	assert.True(t, ok)
   150  	_, ok = ejector.table[item2]
   151  	assert.True(t, ok)
   152  
   153  	// sequence number of ejector should be increased by two
   154  	assert.Equal(t, ejector.seqNum, uint64(2))
   155  
   156  	// untracks the item twice
   157  	ejector.Untrack(item1)
   158  	ejector.Untrack(item1)
   159  
   160  	// internal state of the ejector should be changed
   161  	assert.Len(t, ejector.table, 1)
   162  
   163  	// sequence number should not be changed
   164  	assert.Equal(t, ejector.seqNum, uint64(2))
   165  
   166  	// double untracking should only affect the untracked item1
   167  	_, ok = ejector.table[item1]
   168  	assert.False(t, ok)
   169  
   170  	// item 2 should still reside in the memory
   171  	_, ok = ejector.table[item2]
   172  	assert.True(t, ok)
   173  }
   174  
   175  // TestLRUEjector_UntrackEject evaluates that untracking the next ejectable item
   176  // properly changes the next ejectable item in the ejector.
   177  func TestLRUEjector_UntrackEject(t *testing.T) {
   178  	ejector := NewLRUEjector()
   179  
   180  	// creates and tracks 100 items
   181  	size := 100
   182  	backEnd := NewBackend()
   183  
   184  	items := make([]flow.Identifier, size)
   185  
   186  	for i := 0; i < size; i++ {
   187  		mockEntity := unittest.MockEntityFixture()
   188  		require.True(t, backEnd.Add(mockEntity))
   189  
   190  		id := mockEntity.ID()
   191  		ejector.Track(id)
   192  		items[i] = id
   193  	}
   194  
   195  	// untracks the oldest item
   196  	ejector.Untrack(items[0])
   197  
   198  	// next ejectable item should be the second oldest item
   199  	id := ejector.Eject(backEnd)
   200  	assert.Equal(t, id, items[1])
   201  }
   202  
   203  // TestLRUEjector_EjectAll adds many item to the ejector and then ejects them
   204  // all one by one and evaluates an LRU ejection behavior.
   205  func TestLRUEjector_EjectAll(t *testing.T) {
   206  	ejector := NewLRUEjector()
   207  
   208  	// creates and tracks 100 items
   209  	size := 100
   210  	backEnd := NewBackend()
   211  
   212  	items := make([]flow.Identifier, size)
   213  
   214  	for i := 0; i < size; i++ {
   215  		mockEntity := unittest.MockEntityFixture()
   216  		require.True(t, backEnd.Add(mockEntity))
   217  
   218  		id := mockEntity.ID()
   219  		ejector.Track(id)
   220  		items[i] = id
   221  	}
   222  
   223  	require.Equal(t, uint(size), backEnd.Size())
   224  
   225  	// ejects one by one
   226  	for i := 0; i < size; i++ {
   227  		id := ejector.Eject(backEnd)
   228  		require.Equal(t, id, items[i])
   229  	}
   230  }