github.com/ethersphere/bee/v2@v2.2.0/pkg/storer/migration/reserveRepair_test.go (about) 1 // Copyright 2023 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package migration_test 6 7 import ( 8 "context" 9 "errors" 10 "testing" 11 12 "github.com/ethersphere/bee/v2/pkg/log" 13 "github.com/ethersphere/bee/v2/pkg/storage" 14 chunktest "github.com/ethersphere/bee/v2/pkg/storage/testing" 15 "github.com/ethersphere/bee/v2/pkg/storer/internal" 16 "github.com/ethersphere/bee/v2/pkg/storer/internal/chunkstamp" 17 "github.com/ethersphere/bee/v2/pkg/storer/internal/reserve" 18 "github.com/ethersphere/bee/v2/pkg/storer/internal/transaction" 19 localmigration "github.com/ethersphere/bee/v2/pkg/storer/migration" 20 "github.com/ethersphere/bee/v2/pkg/swarm" 21 "github.com/stretchr/testify/assert" 22 ) 23 24 func TestReserveRepair(t *testing.T) { 25 t.Parallel() 26 27 store := internal.NewInmemStorage() 28 baseAddr := swarm.RandAddress(t) 29 stepFn := localmigration.ReserveRepairer(store, func(_ swarm.Chunk) swarm.ChunkType { 30 return swarm.ChunkTypeContentAddressed 31 }, log.Noop) 32 33 var chunksPO = make([][]swarm.Chunk, 5) 34 var chunksPerPO uint64 = 2 35 36 for i := uint8(0); i < swarm.MaxBins; i++ { 37 err := store.Run(context.Background(), func(s transaction.Store) error { 38 return s.IndexStore().Put(&reserve.BinItem{Bin: i, BinID: 10}) 39 }) 40 assert.NoError(t, err) 41 } 42 43 for b := 0; b < 5; b++ { 44 for i := uint64(0); i < chunksPerPO; i++ { 45 ch := chunktest.GenerateTestRandomChunkAt(t, baseAddr, b) 46 stampHash, err := ch.Stamp().Hash() 47 if err != nil { 48 t.Fatal(err) 49 } 50 cb := &reserve.ChunkBinItem{ 51 Bin: uint8(b), 52 // Assign 0 binID to all items to see if migration fixes this 53 BinID: 0, 54 Address: ch.Address(), 55 BatchID: ch.Stamp().BatchID(), 56 ChunkType: swarm.ChunkTypeContentAddressed, 57 StampHash: stampHash, 58 } 59 err = store.Run(context.Background(), func(s transaction.Store) error { 60 return s.IndexStore().Put(cb) 61 }) 62 if err != nil { 63 t.Fatal(err) 64 } 65 66 br := &reserve.BatchRadiusItem{ 67 BatchID: ch.Stamp().BatchID(), 68 Bin: uint8(b), 69 Address: ch.Address(), 70 BinID: 0, 71 StampHash: stampHash, 72 } 73 err = store.Run(context.Background(), func(s transaction.Store) error { 74 return s.IndexStore().Put(br) 75 }) 76 if err != nil { 77 t.Fatal(err) 78 } 79 80 if b < 2 { 81 // simulate missing chunkstore entries 82 continue 83 } 84 85 err = store.Run(context.Background(), func(s transaction.Store) error { 86 err := chunkstamp.Store(s.IndexStore(), "reserve", ch) 87 if err != nil { 88 return err 89 } 90 return s.ChunkStore().Put(context.Background(), ch) 91 }) 92 if err != nil { 93 t.Fatal(err) 94 } 95 96 chunksPO[b] = append(chunksPO[b], ch) 97 } 98 } 99 100 assert.NoError(t, stepFn()) 101 102 binIDs := make(map[uint8][]uint64) 103 cbCount := 0 104 err := store.IndexStore().Iterate( 105 storage.Query{Factory: func() storage.Item { return &reserve.ChunkBinItem{} }}, 106 func(res storage.Result) (stop bool, err error) { 107 cb := res.Entry.(*reserve.ChunkBinItem) 108 if cb.ChunkType != swarm.ChunkTypeContentAddressed { 109 return false, errors.New("chunk type should be content addressed") 110 } 111 binIDs[cb.Bin] = append(binIDs[cb.Bin], cb.BinID) 112 cbCount++ 113 return false, nil 114 }, 115 ) 116 assert.NoError(t, err) 117 118 for b := 0; b < 5; b++ { 119 if b < 2 { 120 if _, found := binIDs[uint8(b)]; found { 121 t.Fatalf("bin %d should not have any binIDs", b) 122 } 123 continue 124 } 125 assert.Len(t, binIDs[uint8(b)], 2) 126 for idx, binID := range binIDs[uint8(b)] { 127 assert.Equal(t, uint64(idx+1), binID) 128 129 item := &reserve.BinItem{Bin: uint8(b)} 130 _ = store.IndexStore().Get(item) 131 assert.Equal(t, item.BinID, uint64(2)) 132 } 133 } 134 135 brCount := 0 136 err = store.IndexStore().Iterate( 137 storage.Query{Factory: func() storage.Item { return &reserve.BatchRadiusItem{} }}, 138 func(res storage.Result) (stop bool, err error) { 139 br := res.Entry.(*reserve.BatchRadiusItem) 140 if br.Bin < 2 { 141 return false, errors.New("bin should be >= 2") 142 } 143 brCount++ 144 return false, nil 145 }, 146 ) 147 assert.NoError(t, err) 148 149 assert.Equal(t, cbCount, brCount) 150 151 has, err := store.IndexStore().Has(&reserve.EpochItem{}) 152 if has { 153 t.Fatal("epoch item should be deleted") 154 } 155 assert.NoError(t, err) 156 }