2024-05-07 09:45:13 +00:00
|
|
|
package getsvc
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"crypto/rand"
|
|
|
|
"fmt"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
|
|
|
|
coreContainer "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/policy"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object_manager/placement"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
|
|
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
|
|
|
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/erasurecode"
|
|
|
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/transformer"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
type containerStorage struct {
|
|
|
|
cnt *container.Container
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cs *containerStorage) Get(cid.ID) (*coreContainer.Container, error) {
|
|
|
|
coreCnt := coreContainer.Container{
|
|
|
|
Value: *cs.cnt,
|
|
|
|
}
|
|
|
|
return &coreCnt, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cs *containerStorage) DeletionInfo(cid.ID) (*coreContainer.DelInfo, error) {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGetRangeEC(t *testing.T) {
|
|
|
|
var dataCount uint32 = 3
|
|
|
|
var parityCount uint32 = 1
|
|
|
|
cnr := container.Container{}
|
|
|
|
p := netmap.PlacementPolicy{}
|
|
|
|
p.SetContainerBackupFactor(1)
|
|
|
|
x := netmap.ReplicaDescriptor{}
|
|
|
|
x.SetECDataCount(dataCount)
|
|
|
|
x.SetECParityCount(parityCount)
|
|
|
|
p.AddReplicas(x)
|
|
|
|
cnr.SetPlacementPolicy(p)
|
|
|
|
|
|
|
|
var idCnr cid.ID
|
|
|
|
container.CalculateID(&idCnr, cnr)
|
|
|
|
|
|
|
|
ns, as := testNodeMatrix(t, []int{4})
|
|
|
|
|
|
|
|
testGetRange := func(t *testing.T, svc *Service, addr oid.Address, from, to uint64, payload []byte) {
|
|
|
|
w := NewSimpleObjectWriter()
|
|
|
|
rngPrm := newRngPrm(false, w, from, to-from)
|
|
|
|
rngPrm.WithAddress(addr)
|
|
|
|
|
|
|
|
err := svc.GetRange(context.Background(), rngPrm)
|
|
|
|
require.NoError(t, err)
|
|
|
|
if from == to {
|
|
|
|
require.Nil(t, w.Object().Payload())
|
|
|
|
} else {
|
|
|
|
require.Equal(t, payload[from:to], w.Object().Payload())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
newSvc := func(b *testPlacementBuilder, c *testClientCache) *Service {
|
|
|
|
const curEpoch = 13
|
|
|
|
|
|
|
|
return &Service{
|
|
|
|
log: test.NewLogger(t),
|
|
|
|
localStorage: newTestStorage(),
|
|
|
|
traverserGenerator: &testTraverserGenerator{
|
|
|
|
c: cnr,
|
|
|
|
b: map[uint64]placement.Builder{
|
|
|
|
curEpoch: b,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
epochSource: testEpochReceiver(curEpoch),
|
|
|
|
remoteStorageConstructor: c,
|
|
|
|
keyStore: &testKeyStorage{},
|
|
|
|
containerSource: &containerStorage{
|
|
|
|
cnt: &cnr,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const totalSize = 5
|
|
|
|
obj, parts := objectECChain(t, &idCnr, &cnr, totalSize, totalSize)
|
|
|
|
require.Len(t, parts, int(dataCount+parityCount))
|
|
|
|
require.Len(t, obj.Payload(), totalSize)
|
|
|
|
|
|
|
|
addr := object.AddressOf(obj)
|
|
|
|
builder := &testPlacementBuilder{
|
|
|
|
vectors: map[string][][]netmap.NodeInfo{
|
|
|
|
addr.EncodeToString(): ns,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
clients := map[string]*testClient{}
|
|
|
|
for i, part := range parts {
|
|
|
|
builder.vectors[object.AddressOf(part).EncodeToString()] = ns
|
|
|
|
|
|
|
|
tc := newTestClient()
|
|
|
|
|
|
|
|
ecInfo := objectSDK.NewECInfo()
|
|
|
|
|
|
|
|
chunk := objectSDK.ECChunk{}
|
|
|
|
chunk.Total = uint32(len(parts))
|
|
|
|
chunk.Index = uint32(i)
|
|
|
|
id, _ := part.ID()
|
|
|
|
idv2 := refs.ObjectID{}
|
|
|
|
id.WriteToV2(&idv2)
|
|
|
|
chunk.ID = idv2
|
|
|
|
|
|
|
|
ecInfo.AddChunk(chunk)
|
|
|
|
errECInfo := objectSDK.NewECInfoError(ecInfo)
|
|
|
|
|
|
|
|
tc.addResult(addr, nil, errECInfo)
|
|
|
|
tc.addResult(object.AddressOf(part), part, nil)
|
|
|
|
|
|
|
|
clients[as[0][i]] = tc
|
|
|
|
}
|
|
|
|
|
|
|
|
svc := newSvc(builder, &testClientCache{
|
|
|
|
clients: clients,
|
|
|
|
})
|
|
|
|
|
2024-08-30 16:20:55 +00:00
|
|
|
for from := range totalSize - 1 {
|
2024-05-07 09:45:13 +00:00
|
|
|
for to := from; to < totalSize; to++ {
|
|
|
|
t.Run(fmt.Sprintf("from=%d,to=%d", from, to), func(t *testing.T) {
|
|
|
|
testGetRange(t, svc, addr, uint64(from), uint64(to), obj.Payload())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func objectECChain(t *testing.T, cnrId *cid.ID, cnr *container.Container, singleSize, totalSize uint64) (*objectSDK.Object, []*objectSDK.Object) {
|
|
|
|
pk, err := keys.NewPrivateKey()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
tt := new(testTarget)
|
|
|
|
p := transformer.NewPayloadSizeLimiter(transformer.Params{
|
|
|
|
Key: &pk.PrivateKey,
|
|
|
|
NextTargetInit: func() transformer.ObjectWriter { return tt },
|
|
|
|
NetworkState: testEpochReceiver(1),
|
|
|
|
MaxSize: singleSize,
|
|
|
|
})
|
|
|
|
|
|
|
|
payload := make([]byte, totalSize)
|
|
|
|
_, err = rand.Read(payload)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
ver := version.Current()
|
|
|
|
hdr := objectSDK.New()
|
|
|
|
hdr.SetContainerID(*cnrId)
|
|
|
|
hdr.SetType(objectSDK.TypeRegular)
|
|
|
|
hdr.SetVersion(&ver)
|
|
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
require.NoError(t, p.WriteHeader(ctx, hdr))
|
|
|
|
|
|
|
|
_, err = p.Write(ctx, payload)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
_, err = p.Close(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.Len(t, tt.objects, 1)
|
|
|
|
|
|
|
|
c, err := erasurecode.NewConstructor(policy.ECDataCount(cnr.PlacementPolicy()), policy.ECParityCount(cnr.PlacementPolicy()))
|
|
|
|
require.NoError(t, err)
|
|
|
|
parts, err := c.Split(tt.objects[0], &pk.PrivateKey)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
return tt.objects[0], parts
|
|
|
|
}
|