github.com/koko1123/flow-go-1@v0.29.6/module/mempool/queue/queue_test.go (about)

     1  package queue
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/stretchr/testify/assert"
     7  	"github.com/stretchr/testify/require"
     8  
     9  	"github.com/koko1123/flow-go-1/module/mempool/entity"
    10  	"github.com/koko1123/flow-go-1/utils/unittest"
    11  )
    12  
    13  func TestQueue(t *testing.T) {
    14  
    15  	/* Input queue:
    16  	  g-b
    17  	     \
    18  	f--d--c-a
    19  	  /
    20  	 e
    21  
    22  	*/
    23  
    24  	a := unittest.ExecutableBlockFixture(nil)
    25  	c := unittest.ExecutableBlockFixtureWithParent(nil, a.Block.Header)
    26  	b := unittest.ExecutableBlockFixtureWithParent(nil, c.Block.Header)
    27  	d := unittest.ExecutableBlockFixtureWithParent(nil, c.Block.Header)
    28  	e := unittest.ExecutableBlockFixtureWithParent(nil, d.Block.Header)
    29  	f := unittest.ExecutableBlockFixtureWithParent(nil, d.Block.Header)
    30  	g := unittest.ExecutableBlockFixtureWithParent(nil, b.Block.Header)
    31  
    32  	dBroken := unittest.ExecutableBlockFixtureWithParent(nil, c.Block.Header)
    33  	dBroken.Block.Header.Height += 2 //change height
    34  
    35  	queue := NewQueue(a)
    36  
    37  	t.Run("Adding", func(t *testing.T) {
    38  		stored, _ := queue.TryAdd(b) //parent not stored yet
    39  		size := queue.Size()
    40  		height := queue.Height()
    41  		assert.False(t, stored)
    42  		assert.Equal(t, 1, size)
    43  		assert.Equal(t, uint64(0), height)
    44  
    45  		stored, new := queue.TryAdd(c)
    46  		size = queue.Size()
    47  		height = queue.Height()
    48  		assert.True(t, stored)
    49  		assert.True(t, new)
    50  		assert.Equal(t, 2, size)
    51  		assert.Equal(t, uint64(1), height)
    52  
    53  		stored, new = queue.TryAdd(b)
    54  		size = queue.Size()
    55  		height = queue.Height()
    56  		assert.True(t, stored)
    57  		assert.True(t, new)
    58  		assert.Equal(t, 3, size)
    59  		assert.Equal(t, uint64(2), height)
    60  
    61  		stored, new = queue.TryAdd(b) //repeat
    62  		size = queue.Size()
    63  		height = queue.Height()
    64  		assert.True(t, stored)
    65  		assert.False(t, new)
    66  		assert.Equal(t, 3, size)
    67  		assert.Equal(t, uint64(2), height)
    68  
    69  		stored, _ = queue.TryAdd(f) //parent not stored yet
    70  		assert.False(t, stored)
    71  
    72  		stored, new = queue.TryAdd(d)
    73  		size = queue.Size()
    74  		height = queue.Height()
    75  		assert.True(t, stored)
    76  		assert.True(t, new)
    77  		assert.Equal(t, 4, size)
    78  		assert.Equal(t, uint64(2), height)
    79  
    80  		stored, _ = queue.TryAdd(dBroken) // wrong height
    81  		assert.False(t, stored)
    82  
    83  		stored, new = queue.TryAdd(e)
    84  		size = queue.Size()
    85  		height = queue.Height()
    86  		assert.True(t, stored)
    87  		assert.True(t, new)
    88  		assert.Equal(t, 5, size)
    89  		assert.Equal(t, uint64(3), height)
    90  
    91  		stored, new = queue.TryAdd(f)
    92  		size = queue.Size()
    93  		height = queue.Height()
    94  		assert.True(t, stored)
    95  		assert.True(t, new)
    96  		assert.Equal(t, 6, size)
    97  		assert.Equal(t, uint64(3), height)
    98  
    99  		stored, new = queue.TryAdd(g)
   100  		size = queue.Size()
   101  		height = queue.Height()
   102  		assert.True(t, stored)
   103  		assert.True(t, new)
   104  		assert.Equal(t, 7, size)
   105  		assert.Equal(t, uint64(3), height)
   106  	})
   107  
   108  	t.Run("Dismounting", func(t *testing.T) {
   109  		// dismount queue
   110  		blockA, queuesA := queue.Dismount()
   111  		assert.Equal(t, a, blockA)
   112  		require.Len(t, queuesA, 1)
   113  		assert.Equal(t, 6, queuesA[0].Size())
   114  		assert.Equal(t, uint64(2), queuesA[0].Height())
   115  
   116  		blockC, queuesC := queuesA[0].Dismount()
   117  		assert.Equal(t, c, blockC)
   118  		require.Len(t, queuesC, 2)
   119  
   120  		// order of children is not guaranteed
   121  		var queueD *Queue
   122  		var queueB *Queue
   123  		if queuesC[0].Head.Item == d {
   124  			queueD = queuesC[0]
   125  			queueB = queuesC[1]
   126  		} else {
   127  			queueD = queuesC[1]
   128  			queueB = queuesC[0]
   129  		}
   130  		assert.Equal(t, d, queueD.Head.Item)
   131  		sizeD := queueD.Size()
   132  		heightD := queueD.Height()
   133  		sizeB := queueB.Size()
   134  		heightB := queueB.Height()
   135  
   136  		assert.Equal(t, 3, sizeD)
   137  		assert.Equal(t, uint64(1), heightD)
   138  		assert.Equal(t, 2, sizeB)
   139  		assert.Equal(t, uint64(1), heightB)
   140  
   141  		blockD, queuesD := queueD.Dismount()
   142  		assert.Equal(t, d, blockD)
   143  		assert.Len(t, queuesD, 2)
   144  	})
   145  
   146  	t.Run("Process all", func(t *testing.T) {
   147  		// Dismounting iteratively all queues should yield all nodes/blocks only once
   148  		// and in the proper order (parents are always evaluated first)
   149  		blocksInOrder := make([]*entity.ExecutableBlock, 0)
   150  
   151  		executionHeads := make(chan *Queue, 10)
   152  		executionHeads <- queue
   153  
   154  		for len(executionHeads) > 0 {
   155  			currentHead := <-executionHeads
   156  			block, newQueues := currentHead.Dismount()
   157  			blocksInOrder = append(blocksInOrder, block.(*entity.ExecutableBlock))
   158  			for _, newQueue := range newQueues {
   159  				executionHeads <- newQueue
   160  			}
   161  		}
   162  
   163  		// Couldn't find ready assertion for subset in order, so lets
   164  		// map nodes by their index and check if order is as expected
   165  		indices := make(map[*entity.ExecutableBlock]int)
   166  
   167  		for i, block := range blocksInOrder {
   168  			indices[block] = i
   169  		}
   170  
   171  		// a -> c -> b -> g
   172  		assert.Less(t, indices[a], indices[c])
   173  		assert.Less(t, indices[c], indices[b])
   174  		assert.Less(t, indices[b], indices[g])
   175  
   176  		// a -> c -> d -> f
   177  		assert.Less(t, indices[a], indices[c])
   178  		assert.Less(t, indices[c], indices[d])
   179  		assert.Less(t, indices[d], indices[f])
   180  
   181  		// a -> c -> d -> e
   182  		assert.Less(t, indices[a], indices[c])
   183  		assert.Less(t, indices[c], indices[d])
   184  		assert.Less(t, indices[d], indices[e])
   185  	})
   186  
   187  	//t.Run("Attaching", func(t *testing.T) {
   188  	//	queue := NewQueue(a)
   189  	//
   190  	//	added, new := queue.TryAdd(c)
   191  	//	assert.True(t, added)
   192  	//	assert.True(t, new)
   193  	//	assert.Equal(t, 2, queue.Size())
   194  	//	assert.Equal(t, uint64(1), queue.Height())
   195  	//
   196  	//	queueB := NewQueue(b)
   197  	//	added, new = queueB.TryAdd(g)
   198  	//	assert.True(t, added)
   199  	//	assert.True(t, new)
   200  	//
   201  	//	assert.Equal(t, 2, queueB.Size())
   202  	//	assert.Equal(t, uint64(1), queueB.Height())
   203  	//
   204  	//	queueF := NewQueue(f)
   205  	//
   206  	//	err := queue.Attach(queueF) // node D is missing
   207  	//	assert.Error(t, err)
   208  	//
   209  	//	err = queue.Attach(queueB)
   210  	//	assert.NoError(t, err)
   211  	//	assert.Equal(t, 4, queue.Size())
   212  	//	assert.Equal(t, uint64(3), queue.Height())
   213  	//
   214  	//	added, new = queue.TryAdd(d)
   215  	//	assert.True(t, added)
   216  	//	assert.True(t, new)
   217  	//	assert.Equal(t, 5, queue.Size())
   218  	//	assert.Equal(t, uint64(3), queue.Height())
   219  	//
   220  	//	err = queue.Attach(queueF) // node D is now in the queue
   221  	//	assert.NoError(t, err)
   222  	//	assert.Equal(t, 6, queue.Size())
   223  	//	assert.Equal(t, uint64(3), queue.Height())
   224  	//})
   225  
   226  	// Creating queue:
   227  	//    f--d--c-a
   228  	// Addingan element should be an idempotent operation:
   229  	//   * adding c a second time
   230  	//   * Dequeueing single head:
   231  	//     we should only get one child queue f--d--c
   232  	t.Run("Adding_Idempotent", func(t *testing.T) {
   233  		queue := NewQueue(a)
   234  		add, new := queue.TryAdd(c)
   235  		assert.True(t, add)
   236  		assert.True(t, new)
   237  
   238  		add, new = queue.TryAdd(d)
   239  		assert.True(t, add)
   240  		assert.True(t, new)
   241  
   242  		add, new = queue.TryAdd(f)
   243  		assert.True(t, add)
   244  		assert.True(t, new)
   245  
   246  		assert.Equal(t, 4, queue.Size())
   247  		assert.Equal(t, uint64(3), queue.Height())
   248  
   249  		// adding c a second time
   250  		add, new = queue.TryAdd(c)
   251  		assert.True(t, add)
   252  		assert.False(t, new)
   253  
   254  		// Dequeueing a
   255  		head, childQueues := queue.Dismount()
   256  		assert.Equal(t, a, head)
   257  		assert.Equal(t, 1, len(childQueues), "There should only be a single child queue")
   258  		assert.Equal(t, c.ID(), childQueues[0].Head.Item.ID())
   259  	})
   260  
   261  	// Testing attaching overlapping queues:
   262  	// queue A:
   263  	//   g-b
   264  	//      \
   265  	//       c
   266  	// queue B:
   267  	//    d--c-a
   268  	// attach queueA to queueB: we expect an error as the queues have nodes in common
   269  	//t.Run("Attaching_partially_overlapped_queue", func(t *testing.T) {
   270  	//	queueA := NewQueue(c)
   271  	//	add, new := queueA.TryAdd(b)
   272  	//	assert.True(t, add)
   273  	//	assert.True(t, new)
   274  	//
   275  	//	add, new = queueA.TryAdd(g)
   276  	//	assert.True(t, add)
   277  	//	assert.True(t, new)
   278  	//
   279  	//	queueB := NewQueue(a)
   280  	//	add, new = queueB.TryAdd(c)
   281  	//	assert.True(t, add)
   282  	//	assert.True(t, new)
   283  	//
   284  	//	add, new = queueB.TryAdd(d)
   285  	//	assert.True(t, add)
   286  	//	assert.True(t, new)
   287  	//
   288  	//	err := queueB.Attach(queueA)
   289  	//	assert.Error(t, err)
   290  	//})
   291  
   292  }