frostfs-node/pkg/services/object/ape/request_test.go

338 lines
9.3 KiB
Go

package ape
import (
"context"
"fmt"
"testing"
objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
aperequest "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/ape/request"
checksumtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum/test"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
usertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user/test"
nativeschema "git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
"github.com/stretchr/testify/require"
)
const (
testOwnerID = "FPPtmAi9TCX329"
)
func TestObjectProperties(t *testing.T) {
for _, test := range []struct {
name string
container string
object *string
header *headerObjectSDKParams
}{
{
name: "fully filled header",
container: containerID,
object: stringPtr(objectID),
header: &headerObjectSDKParams{
majorVersion: 1,
minorVersion: 1,
owner: usertest.ID(),
epoch: 3,
payloadSize: 1000,
typ: objectSDK.TypeRegular,
payloadChecksum: checksumtest.Checksum(),
payloadHomomorphicHash: checksumtest.Checksum(),
attributes: []struct {
key string
val string
}{
{
key: "attr1",
val: "val1",
},
{
key: "attr2",
val: "val2",
},
},
},
},
{
name: "partially filled header",
container: containerID,
header: &headerObjectSDKParams{
majorVersion: 1,
minorVersion: 1,
owner: usertest.ID(),
epoch: 3,
attributes: []struct {
key string
val string
}{
{
key: "attr1",
val: "val1",
},
},
},
},
{
name: "only address paramaters set in header",
container: containerID,
object: stringPtr(objectID),
},
{
name: "only container set in header",
container: containerID,
},
} {
t.Run(test.name, func(t *testing.T) {
cnr := newContainerIDSDK(t, test.container)
obj := newObjectIDSDK(t, test.object)
header := newHeaderObjectSDK(cnr, obj, test.header)
var testCnrOwner user.ID
require.NoError(t, testCnrOwner.DecodeString(testOwnerID))
props := objectProperties(cnr, obj, testCnrOwner, header.ToV2().GetHeader())
require.Equal(t, test.container, props[nativeschema.PropertyKeyObjectContainerID])
require.Equal(t, testOwnerID, props[nativeschema.PropertyKeyContainerOwnerID])
if obj != nil {
require.Equal(t, *test.object, props[nativeschema.PropertyKeyObjectID])
}
if test.header != nil {
require.Equal(t,
fmt.Sprintf("v%d.%d", test.header.majorVersion, test.header.minorVersion),
props[nativeschema.PropertyKeyObjectVersion],
)
require.Equal(t, test.header.owner.EncodeToString(), props[nativeschema.PropertyKeyObjectOwnerID])
require.Equal(t, fmt.Sprintf("%d", test.header.epoch), props[nativeschema.PropertyKeyObjectCreationEpoch])
require.Equal(t, fmt.Sprintf("%d", test.header.payloadSize), props[nativeschema.PropertyKeyObjectPayloadLength])
require.Equal(t, test.header.typ.String(), props[nativeschema.PropertyKeyObjectType])
require.Equal(t, test.header.payloadChecksum.String(), props[nativeschema.PropertyKeyObjectPayloadHash])
require.Equal(t, test.header.payloadHomomorphicHash.String(), props[nativeschema.PropertyKeyObjectHomomorphicHash])
for _, attr := range test.header.attributes {
require.Equal(t, attr.val, props[attr.key])
}
}
})
}
}
func TestNewAPERequest(t *testing.T) {
tests := []struct {
name string
methods []string
namespace string
container string
object *string
header testHeader
expectErr error
}{
{
name: "oid required requests",
methods: methodsRequiredOID,
namespace: namespace,
container: containerID,
object: stringPtr(objectID),
header: testHeader{
headerObjSDK: &headerObjectSDKParams{
majorVersion: 1,
minorVersion: 1,
owner: usertest.ID(),
epoch: 3,
payloadSize: 1000,
typ: objectSDK.TypeRegular,
payloadChecksum: checksumtest.Checksum(),
payloadHomomorphicHash: checksumtest.Checksum(),
},
fromHeaderProvider: true,
},
},
{
name: "oid required requests but header cannot be found locally",
methods: methodsRequiredOID,
namespace: namespace,
container: containerID,
object: stringPtr(objectID),
header: testHeader{},
},
{
name: "oid required requests missed oid",
methods: methodsRequiredOID,
namespace: namespace,
container: containerID,
object: nil,
header: testHeader{},
expectErr: errMissingOID,
},
{
name: "response for oid required requests",
methods: methodsRequiredOID,
namespace: namespace,
container: containerID,
object: stringPtr(objectID),
header: testHeader{
headerObjSDK: &headerObjectSDKParams{
majorVersion: 1,
minorVersion: 1,
owner: usertest.ID(),
epoch: 3,
payloadSize: 1000,
typ: objectSDK.TypeRegular,
payloadChecksum: checksumtest.Checksum(),
payloadHomomorphicHash: checksumtest.Checksum(),
},
fromRequestResponseHeader: true,
},
},
{
name: "oid not required methods request",
methods: methodsOptionalOID,
namespace: namespace,
container: containerID,
object: nil,
header: testHeader{
headerObjSDK: &headerObjectSDKParams{
majorVersion: 6,
minorVersion: 66,
owner: usertest.ID(),
epoch: 3,
typ: objectSDK.TypeLock,
},
fromRequestResponseHeader: true,
},
},
{
name: "oid not required methods request but no header",
methods: methodsOptionalOID,
namespace: namespace,
container: containerID,
object: nil,
header: testHeader{},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
for _, method := range test.methods {
t.Run(method, func(t *testing.T) {
cnr := newContainerIDSDK(t, test.container)
obj := newObjectIDSDK(t, test.object)
var testCnrOwner user.ID
require.NoError(t, testCnrOwner.DecodeString(testOwnerID))
prm := Prm{
Namespace: test.namespace,
Method: method,
Container: cnr,
Object: obj,
Role: role,
SenderKey: senderKey,
ContainerOwner: testCnrOwner,
}
headerSource := newHeaderProviderMock()
var headerObjSDK *objectSDK.Object
if test.header.headerObjSDK != nil {
headerObjSDK = newHeaderObjectSDK(cnr, obj, test.header.headerObjSDK)
if test.header.fromHeaderProvider {
require.NotNil(t, obj, "oid is required if a header is expected to be found in header provider")
headerSource.addHeader(cnr, *obj, headerObjSDK)
} else if test.header.fromRequestResponseHeader {
prm.Header = headerObjSDK.ToV2().GetHeader()
}
}
c := checkerImpl{
headerProvider: headerSource,
}
r, err := c.newAPERequest(context.TODO(), prm)
if test.expectErr != nil {
require.Error(t, err)
require.ErrorIs(t, err, test.expectErr)
return
}
expectedRequest := aperequest.NewRequest(
method,
aperequest.NewResource(
resourceName(cnr, obj, prm.Namespace),
objectProperties(cnr, obj, testCnrOwner, func() *objectV2.Header {
if headerObjSDK != nil {
return headerObjSDK.ToV2().GetHeader()
}
return prm.Header
}())),
map[string]string{
nativeschema.PropertyKeyActorPublicKey: prm.SenderKey,
nativeschema.PropertyKeyActorRole: prm.Role,
},
)
require.Equal(t, expectedRequest, r)
})
}
})
}
}
func TestResourceName(t *testing.T) {
for _, test := range []struct {
name string
namespace string
container string
object *string
expected string
}{
{
name: "non-root namespace, CID",
namespace: namespace,
container: containerID,
expected: fmt.Sprintf("native:object/%s/%s/*", namespace, containerID),
},
{
name: "non-root namespace, CID, OID",
namespace: namespace,
container: containerID,
object: stringPtr(objectID),
expected: fmt.Sprintf("native:object/%s/%s/%s", namespace, containerID, objectID),
},
{
name: "empty namespace, CID",
namespace: "",
container: containerID,
expected: fmt.Sprintf("native:object//%s/*", containerID),
},
{
name: "empty namespace, CID, OID",
namespace: "",
container: containerID,
object: stringPtr(objectID),
expected: fmt.Sprintf("native:object//%s/%s", containerID, objectID),
},
{
name: "root namespace, CID",
namespace: "root",
container: containerID,
expected: fmt.Sprintf("native:object//%s/*", containerID),
},
{
name: "root namespace, CID, OID",
namespace: "root",
container: containerID,
object: stringPtr(objectID),
expected: fmt.Sprintf("native:object//%s/%s", containerID, objectID),
},
} {
t.Run(test.name, func(t *testing.T) {
cnr := newContainerIDSDK(t, test.container)
obj := newObjectIDSDK(t, test.object)
require.Equal(t, test.expected, resourceName(cnr, obj, test.namespace))
})
}
}