github.com/iotexproject/iotex-core@v1.14.1-rc1/blockindex/sync_indexers_test.go (about) 1 // Copyright (c) 2023 IoTeX Foundation 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package blockindex 7 8 import ( 9 "context" 10 "strconv" 11 "testing" 12 13 "github.com/golang/mock/gomock" 14 "github.com/stretchr/testify/require" 15 16 "github.com/iotexproject/iotex-core/blockchain/block" 17 "github.com/iotexproject/iotex-core/blockchain/blockdao" 18 "github.com/iotexproject/iotex-core/test/identityset" 19 "github.com/iotexproject/iotex-core/test/mock/mock_blockdao" 20 ) 21 22 func TestSyncIndexers_StartHeight(t *testing.T) { 23 require := require.New(t) 24 ctrl := gomock.NewController(t) 25 26 cases := []struct { 27 name string 28 indexers [][2]uint64 // [startHeight, height] 29 expect uint64 30 }{ 31 {"no indexers", nil, 0}, 32 {"one indexer without start height", [][2]uint64{{0, 100}}, 101}, 33 {"one indexer with start height I", [][2]uint64{{100, 200}}, 201}, 34 {"one indexer with start height II", [][2]uint64{{300, 200}}, 300}, 35 {"two indexers with start height I", [][2]uint64{{100, 200}, {200, 300}}, 201}, 36 {"two indexers with start height II", [][2]uint64{{100, 200}, {400, 300}}, 201}, 37 {"two indexers with start height III", [][2]uint64{{100, 350}, {400, 300}}, 351}, 38 {"two indexers one with start height I", [][2]uint64{{0, 1}, {150, 1}}, 2}, 39 {"two indexers one with start height II", [][2]uint64{{0, 1}, {150, 200}}, 2}, 40 {"two indexers one with start height III", [][2]uint64{{0, 200}, {250, 1}}, 201}, 41 {"two indexers one with start height IV", [][2]uint64{{0, 200}, {150, 1}}, 150}, 42 {"two indexers I", [][2]uint64{{0, 5}, {0, 1}}, 2}, 43 {"two indexers II", [][2]uint64{{0, 5}, {0, 5}}, 6}, 44 {"two indexers III", [][2]uint64{{0, 5}, {0, 6}}, 6}, 45 {"multiple indexers I", [][2]uint64{{0, 5}, {0, 6}, {0, 7}}, 6}, 46 {"multiple indexers II", [][2]uint64{{0, 5}, {10, 6}, {0, 7}}, 6}, 47 {"multiple indexers III", [][2]uint64{{10, 5}, {0, 6}, {0, 7}}, 7}, 48 } 49 50 for _, c := range cases { 51 t.Run(c.name, func(t *testing.T) { 52 var indexers []blockdao.BlockIndexer 53 for _, indexer := range c.indexers { 54 if indexer[0] > 0 { 55 mockIndexerWithStart := mock_blockdao.NewMockBlockIndexerWithStart(ctrl) 56 mockIndexerWithStart.EXPECT().Start(gomock.Any()).Return(nil).Times(1) 57 mockIndexerWithStart.EXPECT().StartHeight().Return(indexer[0]).Times(1) 58 mockIndexerWithStart.EXPECT().Height().Return(indexer[1], nil).Times(1) 59 indexers = append(indexers, mockIndexerWithStart) 60 } else { 61 mockIndexer := mock_blockdao.NewMockBlockIndexer(ctrl) 62 mockIndexer.EXPECT().Start(gomock.Any()).Return(nil).Times(1) 63 mockIndexer.EXPECT().Height().Return(indexer[1], nil).Times(1) 64 indexers = append(indexers, mockIndexer) 65 } 66 } 67 ig := NewSyncIndexers(indexers...) 68 err := ig.Start(context.Background()) 69 require.NoError(err) 70 height := ig.StartHeight() 71 require.Equal(c.expect, height) 72 }) 73 } 74 75 } 76 77 func TestSyncIndexers_Height(t *testing.T) { 78 require := require.New(t) 79 ctrl := gomock.NewController(t) 80 defer ctrl.Finish() 81 82 cases := []struct { 83 heights []uint64 84 expect uint64 85 }{ 86 {[]uint64{}, 0}, 87 {[]uint64{100}, 100}, 88 {[]uint64{100, 100}, 100}, 89 {[]uint64{90, 100}, 90}, 90 {[]uint64{100, 90}, 90}, 91 {[]uint64{100, 100, 100}, 100}, 92 {[]uint64{90, 100, 100}, 90}, 93 {[]uint64{90, 80, 100}, 80}, 94 {[]uint64{90, 80, 70}, 70}, 95 } 96 97 for i := range cases { 98 name := strconv.FormatUint(uint64(i), 10) 99 t.Run(name, func(t *testing.T) { 100 var indexers []blockdao.BlockIndexer 101 for _, height := range cases[i].heights { 102 mockIndexer := mock_blockdao.NewMockBlockIndexer(ctrl) 103 mockIndexer.EXPECT().Height().Return(height, nil).Times(1) 104 indexers = append(indexers, mockIndexer) 105 } 106 ig := NewSyncIndexers(indexers...) 107 height, err := ig.Height() 108 require.NoError(err) 109 require.Equal(cases[i].expect, height) 110 }) 111 } 112 } 113 114 func TestSyncIndexers_PutBlock(t *testing.T) { 115 require := require.New(t) 116 ctrl := gomock.NewController(t) 117 defer ctrl.Finish() 118 119 cases := []struct { 120 indexers [][2]uint64 // [startHeight, height] 121 blocks []uint64 // blocks to put 122 expectBlocks [][]uint64 // expect blocks to put on every indexer 123 }{ 124 { 125 [][2]uint64{}, 126 []uint64{100}, 127 [][]uint64{}, 128 }, 129 { 130 [][2]uint64{{100, 10}}, 131 []uint64{10, 20, 90, 100, 101}, 132 [][]uint64{{100, 101}}, 133 }, 134 { 135 [][2]uint64{{100, 210}}, 136 []uint64{10, 20, 90, 100, 101, 210, 211}, 137 [][]uint64{{211}}, 138 }, 139 { 140 [][2]uint64{{0, 200}, {250, 1}}, 141 []uint64{1, 2, 201, 249, 250, 251}, 142 [][]uint64{{201, 249, 250, 251}, {250, 251}}, 143 }, 144 { 145 [][2]uint64{{0, 250}, {250, 250}}, 146 []uint64{1, 2, 201, 249, 250, 251, 252}, 147 [][]uint64{{251, 252}, {251, 252}}, 148 }, 149 { 150 [][2]uint64{{0, 200}, {250, 1}, {300, 1}}, 151 []uint64{1, 2, 201, 249, 250, 251, 300, 301}, 152 [][]uint64{{201, 249, 250, 251, 300, 301}, {250, 251, 300, 301}, {300, 301}}, 153 }, 154 { 155 [][2]uint64{{0, 250}, {250, 250}, {300, 250}}, 156 []uint64{1, 2, 201, 249, 250, 251, 300, 301}, 157 [][]uint64{{251, 300, 301}, {251, 300, 301}, {300, 301}}, 158 }, 159 { 160 [][2]uint64{{0, 300}, {250, 300}, {300, 300}}, 161 []uint64{1, 2, 201, 249, 250, 251, 300, 301}, 162 [][]uint64{{301}, {301}, {301}}, 163 }, 164 { 165 [][2]uint64{{0, 400}, {250, 400}, {300, 400}}, 166 []uint64{1, 2, 201, 249, 250, 251, 300, 301, 400, 401}, 167 [][]uint64{{401}, {401}, {401}}, 168 }, 169 } 170 171 for _, c := range cases { 172 t.Run("", func(t *testing.T) { 173 var indexers []blockdao.BlockIndexer 174 putBlocks := make([][]uint64, len(c.indexers)) 175 indexersHeight := make([]uint64, len(c.indexers)) 176 for id, indexer := range c.indexers { 177 idx := id 178 indexersHeight[idx] = indexer[1] 179 if indexer[0] > 0 { 180 mockIndexerWithStart := mock_blockdao.NewMockBlockIndexerWithStart(ctrl) 181 mockIndexerWithStart.EXPECT().Start(gomock.Any()).Return(nil).Times(1) 182 mockIndexerWithStart.EXPECT().StartHeight().Return(indexer[0]).Times(1) 183 mockIndexerWithStart.EXPECT().Height().DoAndReturn(func() (uint64, error) { 184 return indexersHeight[idx], nil 185 }).AnyTimes() 186 mockIndexerWithStart.EXPECT().PutBlock(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, blk *block.Block) error { 187 putBlocks[idx] = append(putBlocks[idx], blk.Height()) 188 indexersHeight[idx] = blk.Height() 189 return nil 190 }).Times(len(c.expectBlocks[idx])) 191 indexers = append(indexers, mockIndexerWithStart) 192 } else { 193 mockIndexer := mock_blockdao.NewMockBlockIndexer(ctrl) 194 mockIndexer.EXPECT().Start(gomock.Any()).Return(nil).Times(1) 195 mockIndexer.EXPECT().Height().DoAndReturn(func() (uint64, error) { 196 return indexersHeight[idx], nil 197 }).AnyTimes() 198 mockIndexer.EXPECT().PutBlock(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, blk *block.Block) error { 199 putBlocks[idx] = append(putBlocks[idx], blk.Height()) 200 indexersHeight[idx] = blk.Height() 201 return nil 202 }).Times(len(c.expectBlocks[idx])) 203 indexers = append(indexers, mockIndexer) 204 } 205 } 206 ig := NewSyncIndexers(indexers...) 207 err := ig.Start(context.Background()) 208 require.NoError(err) 209 for _, blkHeight := range c.blocks { 210 blk, err := block.NewBuilder(block.RunnableActions{}).SetHeight(blkHeight).SignAndBuild(identityset.PrivateKey(0)) 211 require.NoError(err) 212 err = ig.PutBlock(context.Background(), &blk) 213 require.NoError(err) 214 } 215 require.Equal(c.expectBlocks, putBlocks) 216 }) 217 } 218 }