github.com/ethersphere/bee/v2@v2.2.0/pkg/storer/migration/step_06_test.go (about)

     1  // Copyright 2024 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  	"testing"
    10  
    11  	"github.com/ethersphere/bee/v2/pkg/sharky"
    12  	"github.com/ethersphere/bee/v2/pkg/storage"
    13  	"github.com/ethersphere/bee/v2/pkg/storage/leveldbstore"
    14  	chunktest "github.com/ethersphere/bee/v2/pkg/storage/testing"
    15  	"github.com/ethersphere/bee/v2/pkg/storer/internal/chunkstamp"
    16  	"github.com/ethersphere/bee/v2/pkg/storer/internal/reserve"
    17  	"github.com/ethersphere/bee/v2/pkg/storer/internal/stampindex"
    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  	"github.com/stretchr/testify/require"
    23  )
    24  
    25  type oldAndNewItem[K storage.Item, V storage.Item] struct {
    26  	old K
    27  	new V
    28  }
    29  
    30  func Test_Step_06(t *testing.T) {
    31  	t.Parallel()
    32  
    33  	sharkyDir := t.TempDir()
    34  	sharkyStore, err := sharky.New(&dirFS{basedir: sharkyDir}, 1, swarm.SocMaxChunkSize)
    35  	require.NoError(t, err)
    36  
    37  	lstore, err := leveldbstore.New("", nil)
    38  	require.NoError(t, err)
    39  
    40  	store := transaction.NewStorage(sharkyStore, lstore)
    41  	t.Cleanup(func() {
    42  		err := store.Close()
    43  		require.NoError(t, err)
    44  	})
    45  
    46  	chunks := chunktest.GenerateTestRandomChunks(100)
    47  	ctx := context.Background()
    48  
    49  	batchRadiusItems := make(map[string]oldAndNewItem[*reserve.BatchRadiusItemV1, *reserve.BatchRadiusItem])
    50  	chunkBinItems := make(map[string]oldAndNewItem[*reserve.ChunkBinItemV1, *reserve.ChunkBinItem])
    51  	stampIndexItems := make(map[string]oldAndNewItem[*stampindex.ItemV1, *stampindex.Item])
    52  
    53  	for i, ch := range chunks {
    54  		err = store.Run(ctx, func(s transaction.Store) error {
    55  			b := &reserve.BatchRadiusItemV1{
    56  				Bin:     uint8(i),
    57  				BatchID: ch.Stamp().BatchID(),
    58  				Address: ch.Address(),
    59  				BinID:   uint64(i),
    60  			}
    61  			err := s.IndexStore().Put(b)
    62  			if err != nil {
    63  				return err
    64  			}
    65  			batchRadiusItems[string(b.BatchID)+string(b.Bin)+b.Address.ByteString()] = oldAndNewItem[*reserve.BatchRadiusItemV1, *reserve.BatchRadiusItem]{old: b, new: nil}
    66  
    67  			c := &reserve.ChunkBinItemV1{
    68  				Bin:       uint8(i),
    69  				BinID:     uint64(i),
    70  				Address:   ch.Address(),
    71  				BatchID:   ch.Stamp().BatchID(),
    72  				ChunkType: swarm.ChunkTypeSingleOwner,
    73  			}
    74  			err = s.IndexStore().Put(c)
    75  			if err != nil {
    76  				return err
    77  			}
    78  			chunkBinItems[c.ID()] = oldAndNewItem[*reserve.ChunkBinItemV1, *reserve.ChunkBinItem]{old: c, new: nil}
    79  
    80  			sIdxItem := &stampindex.ItemV1{
    81  				BatchID:          ch.Stamp().BatchID(),
    82  				StampIndex:       ch.Stamp().Index(),
    83  				StampTimestamp:   ch.Stamp().Timestamp(),
    84  				ChunkAddress:     ch.Address(),
    85  				ChunkIsImmutable: true,
    86  			}
    87  			sIdxItem.SetNamespace([]byte("reserve"))
    88  			err = s.IndexStore().Put(sIdxItem)
    89  			if err != nil {
    90  				return err
    91  			}
    92  
    93  			stampIndexItems[sIdxItem.ID()] = oldAndNewItem[*stampindex.ItemV1, *stampindex.Item]{old: sIdxItem, new: nil}
    94  
    95  			return chunkstamp.Store(s.IndexStore(), "reserve", ch)
    96  		})
    97  		require.NoError(t, err)
    98  	}
    99  
   100  	require.NoError(t, err)
   101  	err = localmigration.Step_06(store)()
   102  	require.NoError(t, err)
   103  
   104  	has, err := store.IndexStore().Has(&reserve.EpochItem{})
   105  	if has {
   106  		t.Fatal("epoch item should be deleted")
   107  	}
   108  	require.NoError(t, err)
   109  
   110  	checkBatchRadiusItems(t, store.IndexStore(), len(chunks), batchRadiusItems)
   111  	checkChunkBinItems(t, store.IndexStore(), len(chunks), chunkBinItems)
   112  	checkStampIndex(t, store.IndexStore(), len(chunks), stampIndexItems)
   113  }
   114  
   115  func checkBatchRadiusItems(t *testing.T, s storage.Reader, wantCount int, m map[string]oldAndNewItem[*reserve.BatchRadiusItemV1, *reserve.BatchRadiusItem]) {
   116  	t.Helper()
   117  	count := 0
   118  
   119  	err := s.Iterate(storage.Query{
   120  		Factory: func() storage.Item { return new(reserve.BatchRadiusItem) },
   121  	}, func(result storage.Result) (bool, error) {
   122  		count++
   123  		b := result.Entry.(*reserve.BatchRadiusItem)
   124  		id := string(b.BatchID) + string(b.Bin) + b.Address.ByteString()
   125  		found, ok := m[id]
   126  		require.True(t, ok)
   127  		found.new = b
   128  		m[id] = found
   129  		return false, nil
   130  	})
   131  	require.NoError(t, err)
   132  	assert.Equal(t, wantCount, count)
   133  
   134  	for _, v := range m {
   135  		assert.Equal(t, v.old.Bin, v.new.Bin)
   136  		assert.Equal(t, v.old.BatchID, v.new.BatchID)
   137  		assert.Equal(t, v.old.Address, v.new.Address)
   138  		assert.Equal(t, v.old.BinID, v.new.BinID)
   139  		assert.NotEqual(t, swarm.EmptyAddress.Bytes(), v.new.StampHash)
   140  	}
   141  }
   142  
   143  func checkChunkBinItems(t *testing.T, s storage.Reader, wantCount int, m map[string]oldAndNewItem[*reserve.ChunkBinItemV1, *reserve.ChunkBinItem]) {
   144  	t.Helper()
   145  	count := 0
   146  	err := s.Iterate(storage.Query{
   147  		Factory: func() storage.Item { return new(reserve.ChunkBinItem) },
   148  	}, func(result storage.Result) (bool, error) {
   149  		count++
   150  		b := result.Entry.(*reserve.ChunkBinItem)
   151  		found, ok := m[b.ID()]
   152  		require.True(t, ok)
   153  		found.new = b
   154  		m[b.ID()] = found
   155  		return false, nil
   156  	})
   157  	require.NoError(t, err)
   158  	assert.Equal(t, wantCount, count)
   159  	for _, v := range m {
   160  		assert.Equal(t, v.old.Bin, v.new.Bin)
   161  		assert.Equal(t, v.old.BatchID, v.new.BatchID)
   162  		assert.Equal(t, v.old.Address, v.new.Address)
   163  		assert.Equal(t, v.old.BinID, v.new.BinID)
   164  		assert.Equal(t, v.old.ChunkType, v.new.ChunkType)
   165  		assert.NotEqual(t, swarm.EmptyAddress.Bytes(), v.new.StampHash)
   166  	}
   167  }
   168  
   169  func checkStampIndex(t *testing.T, s storage.Reader, wantCount int, m map[string]oldAndNewItem[*stampindex.ItemV1, *stampindex.Item]) {
   170  	t.Helper()
   171  	count := 0
   172  	err := s.Iterate(storage.Query{
   173  		Factory: func() storage.Item { return new(stampindex.Item) },
   174  	}, func(result storage.Result) (bool, error) {
   175  		count++
   176  		b := result.Entry.(*stampindex.Item)
   177  		found, ok := m[b.ID()]
   178  		require.True(t, ok)
   179  		found.new = b
   180  		m[b.ID()] = found
   181  		return false, nil
   182  	})
   183  	require.NoError(t, err)
   184  	assert.Equal(t, wantCount, count)
   185  	for _, v := range m {
   186  		assert.Equal(t, v.old.Namespace(), v.new.Namespace())
   187  		assert.Equal(t, v.old.BatchID, v.new.BatchID)
   188  		assert.Equal(t, v.old.StampIndex, v.new.StampIndex)
   189  		assert.Equal(t, v.old.StampTimestamp, v.new.StampTimestamp)
   190  		assert.Equal(t, v.old.ChunkAddress, v.new.ChunkAddress)
   191  		assert.NotEqual(t, swarm.EmptyAddress.Bytes(), v.new.StampHash)
   192  	}
   193  }