From 8eb591d668817ee0e438522845bb3e9ff1b574c8 Mon Sep 17 00:00:00 2001 From: Dmitrii Stepanov Date: Fri, 5 Jul 2024 12:06:28 +0300 Subject: [PATCH] [#1231] policer: Add EC node-off unit test Signed-off-by: Dmitrii Stepanov --- pkg/services/policer/ec_test.go | 145 ++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/pkg/services/policer/ec_test.go b/pkg/services/policer/ec_test.go index 9492787dc..e230153f9 100644 --- a/pkg/services/policer/ec_test.go +++ b/pkg/services/policer/ec_test.go @@ -563,3 +563,148 @@ func TestECChunkRestore(t *testing.T) { require.NoError(t, err) require.EqualValues(t, string(expectedData), string(actualData), "invalid restored objects") } + +func TestECChunkRestoreNodeOff(t *testing.T) { + // node0 has chunk0, node1 has chunk1, node2 has chunk2, node3 is out of netmap + t.Parallel() + + payload := make([]byte, 64) + rand.Read(payload) + parentAddress := oidtest.Address() + parentObject := objectSDK.New() + parentObject.SetContainerID(parentAddress.Container()) + parentObject.SetPayload(payload) + parentObject.SetPayloadSize(64) + objectSDK.CalculateAndSetPayloadChecksum(parentObject) + err := objectSDK.CalculateAndSetID(parentObject) + require.NoError(t, err) + id, _ := parentObject.ID() + parentAddress.SetObject(id) + + chunkIDs := make([]oid.ID, 4) + c, err := erasurecode.NewConstructor(3, 1) + require.NoError(t, err) + key, err := keys.NewPrivateKey() + require.NoError(t, err) + chunks, err := c.Split(parentObject, &key.PrivateKey) + require.NoError(t, err) + for i, ch := range chunks { + chunkIDs[i], _ = ch.ID() + } + + var policy netmapSDK.PlacementPolicy + require.NoError(t, policy.DecodeString("EC 3.1")) + + cnr := &container.Container{} + cnr.Value.Init() + cnr.Value.SetPlacementPolicy(policy) + containerSrc := containerSrc{ + get: func(id cid.ID) (*container.Container, error) { + if id.Equals(parentAddress.Container()) { + return cnr, nil + } + return nil, new(apistatus.ContainerNotFound) + }, + } + + nodes := make([]netmapSDK.NodeInfo, 3) + for i := range nodes { + nodes[i].SetPublicKey([]byte{byte(i)}) + } + + placementBuilder := func(cnr cid.ID, obj *oid.ID, p netmapSDK.PlacementPolicy) ([][]netmapSDK.NodeInfo, error) { + if cnr.Equals(parentAddress.Container()) && obj.Equals(parentAddress.Object()) { + return [][]netmapSDK.NodeInfo{nodes}, nil + } + return nil, errors.New("unexpected placement build") + } + remoteHeadFn := func(_ context.Context, ni netmapSDK.NodeInfo, a oid.Address, raw bool) (*objectSDK.Object, error) { + require.True(t, raw, "remote header for parent object must be called with raw flag") + index := int(ni.PublicKey()[0]) + require.True(t, index == 1 || index == 2, "invalid node to get parent header") + require.True(t, a == parentAddress, "invalid address to get remote header") + if index == 1 { + ei := objectSDK.NewECInfo() + var ch objectSDK.ECChunk + ch.SetID(chunkIDs[1]) + ch.Index = uint32(1) + ch.Total = 4 + ei.AddChunk(ch) + return nil, objectSDK.NewECInfoError(ei) + } + if index == 2 { + ei := objectSDK.NewECInfo() + var ch objectSDK.ECChunk + ch.SetID(chunkIDs[2]) + ch.Index = uint32(2) + ch.Total = 4 + ei.AddChunk(ch) + return nil, objectSDK.NewECInfoError(ei) + } + + return nil, new(apistatus.ObjectNotFound) + } + + localHeadFn := func(_ context.Context, a oid.Address) (*objectSDK.Object, error) { + require.True(t, a == parentAddress, "invalid address to get remote header") + ei := objectSDK.NewECInfo() + var ch objectSDK.ECChunk + ch.SetID(chunkIDs[0]) + ch.Index = uint32(0) + ch.Total = 4 + ei.AddChunk(ch) + return nil, objectSDK.NewECInfoError(ei) + } + + var replicatedObj []*objectSDK.Object + p := New( + WithContainerSource(containerSrc), + WithPlacementBuilder(placementBuilderFunc(placementBuilder)), + WithNetmapKeys(announcedKeysFunc(func(k []byte) bool { + return bytes.Equal(k, nodes[0].PublicKey()) + })), + WithRemoteObjectHeaderFunc(remoteHeadFn), + WithLocalObjectHeaderFunc(localHeadFn), + WithReplicator(&testReplicator{ + handleLocalPutTask: func(ctx context.Context, task replicator.Task) { + if task.Obj != nil { + replicatedObj = append(replicatedObj, task.Obj) + } + }, + }), + WithLocalObjectGetFunc(func(ctx context.Context, a oid.Address) (*objectSDK.Object, error) { + require.True(t, a.Container() == parentAddress.Container() && a.Object() == chunkIDs[0], "invalid local object request") + return chunks[0], nil + }), + WithRemoteObjectGetFunc(func(ctx context.Context, ni netmapSDK.NodeInfo, a oid.Address) (*objectSDK.Object, error) { + index := ni.PublicKey()[0] + return chunks[index], nil + }), + WithPool(testPool(t)), + WithKeyStorage(util.NewKeyStorage(&key.PrivateKey, nil, nil)), + ) + + var chunkAddress oid.Address + chunkAddress.SetContainer(parentAddress.Container()) + chunkAddress.SetObject(chunkIDs[0]) + objInfo := objectcore.Info{ + Address: chunkAddress, + Type: objectSDK.TypeRegular, + ECInfo: &objectcore.ECInfo{ + ParentID: parentAddress.Object(), + Index: 0, + Total: 4, + }, + } + err = p.processObject(context.Background(), objInfo) + require.NoError(t, err) + + require.Equal(t, 1, len(replicatedObj), "invalid replicated objects count") + chunks[3].SetSignature(nil) + expectedData, err := chunks[3].MarshalJSON() + require.NoError(t, err) + replicatedObj[0].SetSignature(nil) + actualData, err := replicatedObj[0].MarshalJSON() + require.NoError(t, err) + require.EqualValues(t, string(expectedData), string(actualData), "invalid restored objects") +}