func newRetrieveIndexesTestWithAccess(db *DB, ch swarm.Chunk, storeTimestamp, accessTimestamp int64) func(t *testing.T) {
	return func(t *testing.T) {
		t.Helper()
		item, err := db.retrievalDataIndex.Get(addressToItem(ch.Address()))
		if err != nil {
			t.Fatal(err)
		}
		if accessTimestamp > 0 {
			item, err = db.retrievalAccessIndex.Get(item)
			if err != nil {
				t.Fatal(err)
			}
		}
		validateItem(t, item, ch.Address().Bytes(), ch.Data(), storeTimestamp, accessTimestamp, ch.Stamp())
	}
}
newRetrieveIndexesTestWithAccess returns a test function that validates if the right
chunk values are in the retrieval indexes when access time must be stored.
package localstore
import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"io/ioutil"
	"math/rand"
	"runtime"
	"sort"
	"sync"
	"testing"
	"time"
	"github.com/ethsana/sana/pkg/logging"
	"github.com/ethsana/sana/pkg/postage"
	"github.com/ethsana/sana/pkg/shed"
	"github.com/ethsana/sana/pkg/storage"
	chunktesting "github.com/ethsana/sana/pkg/storage/testing"
	"github.com/ethsana/sana/pkg/swarm"
	"github.com/syndtr/goleveldb/leveldb"
)
func init() {
	if runtime.GOOS == "windows" {
		setNow(func() int64 {
			time.Sleep(time.Microsecond)
			return time.Now().UTC().UnixNano()
		})
	}
}
func TestCacheCapacity(t *testing.T) {
	lo := Options{
		Capacity: 500,
	}
	db := newTestDB(t, &lo)
	if db.cacheCapacity != 500 {
		t.Fatal("could not set cache capacity")
	}
}
func TestDB(t *testing.T) {
	db := newTestDB(t, nil)
	ch := generateTestRandomChunk()
	_, err := db.Put(context.Background(), storage.ModePutUpload, ch)
	if err != nil {
		t.Fatal(err)
	}
	got, err := db.Get(context.Background(), storage.ModeGetRequest, ch.Address())
	if err != nil {
		t.Fatal(err)
	}
	if !got.Address().Equal(ch.Address()) {
		t.Errorf("got address %x, want %x", got.Address(), ch.Address())
	}
	if !bytes.Equal(got.Data(), ch.Data()) {
		t.Errorf("got data %x, want %x", got.Data(), ch.Data())
	}
}
func TestDB_updateGCSem(t *testing.T) {
	updateGCSleep := time.Second
	var count int
	var max int
	var mu sync.Mutex
	t.Cleanup(setTestHookUpdateGC(func() {
		mu.Lock()
		count++
		if count > max {
			max = count
		}
		mu.Unlock()
		time.Sleep(updateGCSleep)
		mu.Lock()
		count--
		mu.Unlock()
	}))
	defer func(m int) { maxParallelUpdateGC = m }(maxParallelUpdateGC)
	maxParallelUpdateGC = 3
	db := newTestDB(t, nil)
	ch := generateTestRandomChunk()
	_, err := db.Put(context.Background(), storage.ModePutUpload, ch)
	if err != nil {
		t.Fatal(err)
	}
	for i := 0; i < 5; i++ {
		_, err = db.Get(context.Background(), storage.ModeGetRequest, ch.Address())
		if err != nil {
			t.Fatal(err)
		}
	}
	if max != maxParallelUpdateGC {
		t.Errorf("got max %v, want %v", max, maxParallelUpdateGC)
	}
}
func newTestDB(t testing.TB, o *Options) *DB {
	t.Helper()
	baseKey := make([]byte, 32)
	if _, err := rand.Read(baseKey); err != nil {
		t.Fatal(err)
	}
	logger := logging.New(ioutil.Discard, 0)
	db, err := New("", baseKey, nil, o, logger)
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() {
		err := db.Close()
		if err != nil {
			t.Error(err)
		}
	})
	return db
}
var (
	generateTestRandomChunk   = chunktesting.GenerateTestRandomChunk
	generateTestRandomChunks  = chunktesting.GenerateTestRandomChunks
	generateTestRandomChunkAt = chunktesting.GenerateTestRandomChunkAt
)
func chunkAddresses(chunks []swarm.Chunk) []swarm.Address {
	addrs := make([]swarm.Address, len(chunks))
	for i, ch := range chunks {
		addrs[i] = ch.Address()
	}
	return addrs
}
var multiChunkTestCases = []struct {
	name  string
	count int
}{
	{
		name:  "one",
		count: 1,
	},
	{
		name:  "two",
		count: 2,
	},
	{
		name:  "eight",
		count: 8,
	},
	{
		name:  "hundred",
		count: 100,
	},
	{
		name:  "thousand",
		count: 1000,
	},
}
func TestGenerateTestRandomChunk(t *testing.T) {
	c1 := generateTestRandomChunk()
	c2 := generateTestRandomChunk()
	addrLen := len(c1.Address().Bytes())
	if addrLen != 32 {
		t.Errorf("first chunk address length %v, want %v", addrLen, 32)
	}
	dataLen := len(c1.Data())
	if dataLen != swarm.ChunkSize+swarm.SpanSize {
		t.Errorf("first chunk data length %v, want %v", dataLen, swarm.ChunkSize)
	}
	addrLen = len(c2.Address().Bytes())
	if addrLen != 32 {
		t.Errorf("second chunk address length %v, want %v", addrLen, 32)
	}
	dataLen = len(c2.Data())
	if dataLen != swarm.ChunkSize+swarm.SpanSize {
		t.Errorf("second chunk data length %v, want %v", dataLen, swarm.ChunkSize)
	}
	if c1.Address().Equal(c2.Address()) {
		t.Error("fake chunks addresses do not differ")
	}
	if bytes.Equal(c1.Data(), c2.Data()) {
		t.Error("fake chunks data bytes do not differ")
	}
}
func newRetrieveIndexesTest(db *DB, chunk swarm.Chunk, storeTimestamp, accessTimestamp int64) func(t *testing.T) {
	return func(t *testing.T) {
		t.Helper()
		item, err := db.retrievalDataIndex.Get(addressToItem(chunk.Address()))
		if err != nil {
			t.Fatal(err)
		}
		validateItem(t, item, chunk.Address().Bytes(), chunk.Data(), storeTimestamp, 0, chunk.Stamp())
		wantErr := leveldb.ErrNotFound
		_, err = db.retrievalAccessIndex.Get(addressToItem(chunk.Address()))
		if !errors.Is(err, wantErr) {
			t.Errorf("got error %v, want %v", err, wantErr)
		}
	}
}