284 lines
6.9 KiB
Go
284 lines
6.9 KiB
Go
package storagegroup_test
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"strconv"
|
|
"testing"
|
|
|
|
objectV2 "github.com/TrueCloudLab/frostfs-api-go/v2/object"
|
|
"github.com/TrueCloudLab/frostfs-api-go/v2/refs"
|
|
storagegroupV2 "github.com/TrueCloudLab/frostfs-api-go/v2/storagegroup"
|
|
storagegroupV2test "github.com/TrueCloudLab/frostfs-api-go/v2/storagegroup/test"
|
|
"github.com/TrueCloudLab/frostfs-sdk-go/checksum"
|
|
checksumtest "github.com/TrueCloudLab/frostfs-sdk-go/checksum/test"
|
|
objectSDK "github.com/TrueCloudLab/frostfs-sdk-go/object"
|
|
oid "github.com/TrueCloudLab/frostfs-sdk-go/object/id"
|
|
oidtest "github.com/TrueCloudLab/frostfs-sdk-go/object/id/test"
|
|
"github.com/TrueCloudLab/frostfs-sdk-go/storagegroup"
|
|
storagegrouptest "github.com/TrueCloudLab/frostfs-sdk-go/storagegroup/test"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestStorageGroup(t *testing.T) {
|
|
var sg storagegroup.StorageGroup
|
|
|
|
sz := uint64(13)
|
|
sg.SetValidationDataSize(sz)
|
|
require.Equal(t, sz, sg.ValidationDataSize())
|
|
|
|
cs := checksumtest.Checksum()
|
|
sg.SetValidationDataHash(cs)
|
|
cs2, set := sg.ValidationDataHash()
|
|
|
|
require.True(t, set)
|
|
require.Equal(t, cs, cs2)
|
|
|
|
exp := uint64(33)
|
|
sg.SetExpirationEpoch(exp)
|
|
require.Equal(t, exp, sg.ExpirationEpoch())
|
|
|
|
members := []oid.ID{oidtest.ID(), oidtest.ID()}
|
|
sg.SetMembers(members)
|
|
require.Equal(t, members, sg.Members())
|
|
}
|
|
|
|
func TestStorageGroup_ReadFromV2(t *testing.T) {
|
|
t.Run("from zero", func(t *testing.T) {
|
|
var (
|
|
x storagegroup.StorageGroup
|
|
v2 storagegroupV2.StorageGroup
|
|
)
|
|
|
|
require.Error(t, x.ReadFromV2(v2))
|
|
})
|
|
|
|
t.Run("from non-zero", func(t *testing.T) {
|
|
var (
|
|
x storagegroup.StorageGroup
|
|
v2 = storagegroupV2test.GenerateStorageGroup(false)
|
|
)
|
|
|
|
// https://github.com/nspcc-dev/neofs-api-go/issues/394
|
|
v2.SetMembers(generateOIDList())
|
|
|
|
size := v2.GetValidationDataSize()
|
|
epoch := v2.GetExpirationEpoch()
|
|
mm := v2.GetMembers()
|
|
hashV2 := v2.GetValidationHash()
|
|
|
|
require.NoError(t, x.ReadFromV2(*v2))
|
|
|
|
require.Equal(t, epoch, x.ExpirationEpoch())
|
|
require.Equal(t, size, x.ValidationDataSize())
|
|
|
|
var hash checksum.Checksum
|
|
require.NoError(t, hash.ReadFromV2(*hashV2))
|
|
h, set := x.ValidationDataHash()
|
|
require.True(t, set)
|
|
require.Equal(t, hash, h)
|
|
|
|
var oidV2 refs.ObjectID
|
|
|
|
for i, m := range mm {
|
|
x.Members()[i].WriteToV2(&oidV2)
|
|
require.Equal(t, m, oidV2)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestStorageGroupEncoding(t *testing.T) {
|
|
sg := storagegrouptest.StorageGroup()
|
|
|
|
t.Run("binary", func(t *testing.T) {
|
|
data, err := sg.Marshal()
|
|
require.NoError(t, err)
|
|
|
|
var sg2 storagegroup.StorageGroup
|
|
require.NoError(t, sg2.Unmarshal(data))
|
|
|
|
require.Equal(t, sg, sg2)
|
|
})
|
|
|
|
t.Run("json", func(t *testing.T) {
|
|
data, err := sg.MarshalJSON()
|
|
require.NoError(t, err)
|
|
|
|
var sg2 storagegroup.StorageGroup
|
|
require.NoError(t, sg2.UnmarshalJSON(data))
|
|
|
|
require.Equal(t, sg, sg2)
|
|
})
|
|
}
|
|
|
|
func TestStorageGroup_WriteToV2(t *testing.T) {
|
|
t.Run("zero to v2", func(t *testing.T) {
|
|
var (
|
|
x storagegroup.StorageGroup
|
|
v2 storagegroupV2.StorageGroup
|
|
)
|
|
|
|
x.WriteToV2(&v2)
|
|
|
|
require.Nil(t, v2.GetValidationHash())
|
|
require.Nil(t, v2.GetMembers())
|
|
require.Zero(t, v2.GetValidationDataSize())
|
|
require.Zero(t, v2.GetExpirationEpoch())
|
|
})
|
|
|
|
t.Run("non-zero to v2", func(t *testing.T) {
|
|
var (
|
|
x = storagegrouptest.StorageGroup()
|
|
v2 storagegroupV2.StorageGroup
|
|
)
|
|
|
|
x.WriteToV2(&v2)
|
|
|
|
require.Equal(t, x.ExpirationEpoch(), v2.GetExpirationEpoch())
|
|
require.Equal(t, x.ValidationDataSize(), v2.GetValidationDataSize())
|
|
|
|
var hash checksum.Checksum
|
|
require.NoError(t, hash.ReadFromV2(*v2.GetValidationHash()))
|
|
|
|
h, set := x.ValidationDataHash()
|
|
require.True(t, set)
|
|
require.Equal(t, h, hash)
|
|
|
|
var oidV2 refs.ObjectID
|
|
|
|
for i, m := range x.Members() {
|
|
m.WriteToV2(&oidV2)
|
|
require.Equal(t, oidV2, v2.GetMembers()[i])
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestNew(t *testing.T) {
|
|
t.Run("default values", func(t *testing.T) {
|
|
var sg storagegroup.StorageGroup
|
|
|
|
// check initial values
|
|
require.Nil(t, sg.Members())
|
|
_, set := sg.ValidationDataHash()
|
|
require.False(t, set)
|
|
require.Zero(t, sg.ExpirationEpoch())
|
|
require.Zero(t, sg.ValidationDataSize())
|
|
})
|
|
}
|
|
|
|
func generateOIDList() []refs.ObjectID {
|
|
const size = 3
|
|
|
|
mmV2 := make([]refs.ObjectID, size)
|
|
for i := 0; i < size; i++ {
|
|
oidV2 := make([]byte, sha256.Size)
|
|
oidV2[i] = byte(i)
|
|
|
|
mmV2[i].SetValue(oidV2)
|
|
}
|
|
|
|
return mmV2
|
|
}
|
|
|
|
func TestStorageGroup_SetMembers_DoubleSetting(t *testing.T) {
|
|
var sg storagegroup.StorageGroup
|
|
|
|
mm := []oid.ID{oidtest.ID(), oidtest.ID(), oidtest.ID()} // cap is 3 at least
|
|
sg.SetMembers(mm)
|
|
|
|
// the previous cap is more that a new length;
|
|
// slicing should not lead to `out of range`
|
|
// and apply update correctly
|
|
sg.SetMembers(mm[:1])
|
|
}
|
|
|
|
func TestStorageGroupFromObject(t *testing.T) {
|
|
sg := storagegrouptest.StorageGroup()
|
|
|
|
var o objectSDK.Object
|
|
|
|
var expAttr objectSDK.Attribute
|
|
expAttr.SetKey(objectV2.SysAttributeExpEpoch)
|
|
expAttr.SetValue(strconv.FormatUint(sg.ExpirationEpoch(), 10))
|
|
|
|
sgRaw, err := sg.Marshal()
|
|
require.NoError(t, err)
|
|
|
|
o.SetPayload(sgRaw)
|
|
o.SetType(objectSDK.TypeStorageGroup)
|
|
|
|
t.Run("correct object", func(t *testing.T) {
|
|
o.SetAttributes(objectSDK.Attribute{}, expAttr, objectSDK.Attribute{})
|
|
|
|
var sg2 storagegroup.StorageGroup
|
|
require.NoError(t, storagegroup.ReadFromObject(&sg2, o))
|
|
require.Equal(t, sg, sg2)
|
|
})
|
|
|
|
t.Run("incorrect exp attr", func(t *testing.T) {
|
|
var sg2 storagegroup.StorageGroup
|
|
|
|
expAttr.SetValue(strconv.FormatUint(sg.ExpirationEpoch()+1, 10))
|
|
o.SetAttributes(expAttr)
|
|
|
|
require.Error(t, storagegroup.ReadFromObject(&sg2, o))
|
|
})
|
|
|
|
t.Run("incorrect object type", func(t *testing.T) {
|
|
var sg2 storagegroup.StorageGroup
|
|
|
|
o.SetType(objectSDK.TypeTombstone)
|
|
require.Error(t, storagegroup.ReadFromObject(&sg2, o))
|
|
})
|
|
}
|
|
|
|
func TestStorageGroupToObject(t *testing.T) {
|
|
sg := storagegrouptest.StorageGroup()
|
|
|
|
sgRaw, err := sg.Marshal()
|
|
require.NoError(t, err)
|
|
|
|
t.Run("empty object", func(t *testing.T) {
|
|
var o objectSDK.Object
|
|
storagegroup.WriteToObject(sg, &o)
|
|
|
|
exp, found := expFromObj(t, o)
|
|
require.True(t, found)
|
|
|
|
require.Equal(t, sgRaw, o.Payload())
|
|
require.Equal(t, sg.ExpirationEpoch(), exp)
|
|
require.Equal(t, objectSDK.TypeStorageGroup, o.Type())
|
|
})
|
|
|
|
t.Run("obj already has exp attr", func(t *testing.T) {
|
|
var o objectSDK.Object
|
|
|
|
var attr objectSDK.Attribute
|
|
attr.SetKey(objectV2.SysAttributeExpEpoch)
|
|
attr.SetValue(strconv.FormatUint(sg.ExpirationEpoch()+1, 10))
|
|
|
|
o.SetAttributes(objectSDK.Attribute{}, attr, objectSDK.Attribute{})
|
|
|
|
storagegroup.WriteToObject(sg, &o)
|
|
|
|
exp, found := expFromObj(t, o)
|
|
require.True(t, found)
|
|
|
|
require.Equal(t, sgRaw, o.Payload())
|
|
require.Equal(t, sg.ExpirationEpoch(), exp)
|
|
require.Equal(t, objectSDK.TypeStorageGroup, o.Type())
|
|
})
|
|
}
|
|
|
|
func expFromObj(t *testing.T, o objectSDK.Object) (uint64, bool) {
|
|
for _, attr := range o.Attributes() {
|
|
if attr.Key() == objectV2.SysAttributeExpEpoch {
|
|
exp, err := strconv.ParseUint(attr.Value(), 10, 64)
|
|
require.NoError(t, err)
|
|
|
|
return exp, true
|
|
}
|
|
}
|
|
|
|
return 0, false
|
|
}
|