package container_test import ( "crypto/sha256" "fmt" "math/rand" "testing" "github.com/nspcc-dev/neofs-api-go/v2/acl" "github.com/nspcc-dev/neofs-api-go/v2/container" grpc "github.com/nspcc-dev/neofs-api-go/v2/container/grpc" "github.com/nspcc-dev/neofs-api-go/v2/refs" "github.com/stretchr/testify/require" goproto "google.golang.org/protobuf/proto" ) func TestAttribute_StableMarshal(t *testing.T) { attributeFrom := generateAttribute("key", "value") t.Run("non empty", func(t *testing.T) { wire, err := attributeFrom.StableMarshal(nil) require.NoError(t, err) attributeTo := new(container.Attribute) require.NoError(t, attributeTo.Unmarshal(wire)) require.Equal(t, attributeFrom, attributeTo) }) } func TestContainer_StableMarshal(t *testing.T) { cnrFrom := generateContainer("nonce") t.Run("non empty", func(t *testing.T) { wire, err := cnrFrom.StableMarshal(nil) require.NoError(t, err) cnrTo := new(container.Container) require.NoError(t, cnrTo.Unmarshal(wire)) require.Equal(t, cnrFrom, cnrTo) }) } func TestPutRequestBody_StableMarshal(t *testing.T) { requestFrom := generatePutRequestBody("nonce") transport := new(grpc.PutRequest_Body) t.Run("non empty", func(t *testing.T) { wire, err := requestFrom.StableMarshal(nil) require.NoError(t, err) err = goproto.Unmarshal(wire, transport) require.NoError(t, err) requestTo := container.PutRequestBodyFromGRPCMessage(transport) require.Equal(t, requestFrom, requestTo) }) } func TestPutResponseBody_StableMarshal(t *testing.T) { responseFrom := generatePutResponseBody("Container ID") transport := new(grpc.PutResponse_Body) t.Run("non empty", func(t *testing.T) { wire, err := responseFrom.StableMarshal(nil) require.NoError(t, err) err = goproto.Unmarshal(wire, transport) require.NoError(t, err) responseTo := container.PutResponseBodyFromGRPCMessage(transport) require.Equal(t, responseFrom, responseTo) }) } func TestDeleteRequestBody_StableMarshal(t *testing.T) { requestFrom := generateDeleteRequestBody("Container ID") transport := new(grpc.DeleteRequest_Body) t.Run("non empty", func(t *testing.T) { wire, err := requestFrom.StableMarshal(nil) require.NoError(t, err) err = goproto.Unmarshal(wire, transport) require.NoError(t, err) requestTo := container.DeleteRequestBodyFromGRPCMessage(transport) require.Equal(t, requestFrom, requestTo) }) } func TestDeleteResponseBody_StableMarshal(t *testing.T) { responseFrom := generateDeleteResponseBody() transport := new(grpc.DeleteResponse_Body) t.Run("non empty", func(t *testing.T) { wire, err := responseFrom.StableMarshal(nil) require.NoError(t, err) err = goproto.Unmarshal(wire, transport) require.NoError(t, err) responseTo := container.DeleteResponseBodyFromGRPCMessage(transport) require.Equal(t, responseFrom, responseTo) }) } func TestGetRequestBody_StableMarshal(t *testing.T) { requestFrom := generateGetRequestBody("Container ID") transport := new(grpc.GetRequest_Body) t.Run("non empty", func(t *testing.T) { wire, err := requestFrom.StableMarshal(nil) require.NoError(t, err) err = goproto.Unmarshal(wire, transport) require.NoError(t, err) requestTo := container.GetRequestBodyFromGRPCMessage(transport) require.Equal(t, requestFrom, requestTo) }) } func TestGetResponseBody_StableMarshal(t *testing.T) { responseFrom := generateGetResponseBody("nonce") transport := new(grpc.GetResponse_Body) t.Run("non empty", func(t *testing.T) { wire, err := responseFrom.StableMarshal(nil) require.NoError(t, err) err = goproto.Unmarshal(wire, transport) require.NoError(t, err) responseTo := container.GetResponseBodyFromGRPCMessage(transport) require.Equal(t, responseFrom, responseTo) }) } func TestListRequestBody_StableMarshal(t *testing.T) { requestFrom := generateListRequestBody("Owner ID") transport := new(grpc.ListRequest_Body) t.Run("non empty", func(t *testing.T) { wire, err := requestFrom.StableMarshal(nil) require.NoError(t, err) err = goproto.Unmarshal(wire, transport) require.NoError(t, err) requestTo := container.ListRequestBodyFromGRPCMessage(transport) require.Equal(t, requestFrom, requestTo) }) } func TestListResponseBody_StableMarshal(t *testing.T) { responseFrom := generateListResponseBody(3) transport := new(grpc.ListResponse_Body) t.Run("non empty", func(t *testing.T) { wire, err := responseFrom.StableMarshal(nil) require.NoError(t, err) err = goproto.Unmarshal(wire, transport) require.NoError(t, err) responseTo := container.ListResponseBodyFromGRPCMessage(transport) require.Equal(t, responseFrom, responseTo) }) } func TestSetEACLRequestBody_StableMarshal(t *testing.T) { requestFrom := generateSetEACLRequestBody(4, "Filter Key", "Filter Value") transport := new(grpc.SetExtendedACLRequest_Body) t.Run("non empty", func(t *testing.T) { wire, err := requestFrom.StableMarshal(nil) require.NoError(t, err) err = goproto.Unmarshal(wire, transport) require.NoError(t, err) requestTo := container.SetExtendedACLRequestBodyFromGRPCMessage(transport) require.Equal(t, requestFrom, requestTo) }) } func TestSetEACLResponseBody_StableMarshal(t *testing.T) { responseFrom := generateSetEACLResponseBody() transport := new(grpc.SetExtendedACLResponse_Body) t.Run("non empty", func(t *testing.T) { wire, err := responseFrom.StableMarshal(nil) require.NoError(t, err) err = goproto.Unmarshal(wire, transport) require.NoError(t, err) responseTo := container.SetExtendedACLResponseBodyFromGRPCMessage(transport) require.Equal(t, responseFrom, responseTo) }) } func TestGetEACLRequestBody_StableMarshal(t *testing.T) { requestFrom := generateGetEACLRequestBody("Container ID") transport := new(grpc.GetExtendedACLRequest_Body) t.Run("non empty", func(t *testing.T) { wire, err := requestFrom.StableMarshal(nil) require.NoError(t, err) err = goproto.Unmarshal(wire, transport) require.NoError(t, err) requestTo := container.GetExtendedACLRequestBodyFromGRPCMessage(transport) require.Equal(t, requestFrom, requestTo) }) } func TestGetEACLResponseBody_StableMarshal(t *testing.T) { responseFrom := generateGetEACLResponseBody(3, "Filter Key", "Filter Value") transport := new(grpc.GetExtendedACLResponse_Body) t.Run("non empty", func(t *testing.T) { wire, err := responseFrom.StableMarshal(nil) require.NoError(t, err) err = goproto.Unmarshal(wire, transport) require.NoError(t, err) responseTo := container.GetExtendedACLResponseBodyFromGRPCMessage(transport) require.Equal(t, responseFrom, responseTo) }) } func TestUsedSpaceAnnouncement_StableMarshal(t *testing.T) { from := generateAnnouncement() transport := new(grpc.AnnounceUsedSpaceRequest_Body_Announcement) t.Run("non empty", func(t *testing.T) { wire, err := from.StableMarshal(nil) require.NoError(t, err) err = goproto.Unmarshal(wire, transport) require.NoError(t, err) to := container.UsedSpaceAnnouncementFromGRPCMessage(transport) require.Equal(t, from, to) }) } func TestAnnounceUsedSpaceRequestBody_StableMarshal(t *testing.T) { requestFrom := generateAnnounceRequestBody(10) transport := new(grpc.AnnounceUsedSpaceRequest_Body) t.Run("non empty", func(t *testing.T) { wire, err := requestFrom.StableMarshal(nil) require.NoError(t, err) err = goproto.Unmarshal(wire, transport) require.NoError(t, err) requestTo := container.AnnounceUsedSpaceRequestBodyFromGRPCMessage(transport) require.Equal(t, requestFrom, requestTo) }) } func TestAnnounceUsedSpaceResponseBody_StableMarshal(t *testing.T) { responseFrom := generateAnnounceResponseBody() transport := new(grpc.AnnounceUsedSpaceResponse_Body) t.Run("non empty", func(t *testing.T) { wire, err := responseFrom.StableMarshal(nil) require.NoError(t, err) err = goproto.Unmarshal(wire, transport) require.NoError(t, err) responseTo := container.AnnounceUsedSpaceResponseBodyFromGRPCMessage(transport) require.Equal(t, responseFrom, responseTo) }) } func generateAttribute(k, v string) *container.Attribute { attr := new(container.Attribute) attr.SetKey(k) attr.SetValue(v) return attr } func generateContainer(n string) *container.Container { owner := new(refs.OwnerID) owner.SetValue([]byte("Owner ID")) version := new(refs.Version) version.SetMajor(2) version.SetMinor(0) // todo: add placement rule cnr := new(container.Container) cnr.SetOwnerID(owner) cnr.SetVersion(version) cnr.SetAttributes([]*container.Attribute{ generateAttribute("one", "two"), generateAttribute("three", "four"), }) cnr.SetBasicACL(100) cnr.SetNonce([]byte(n)) return cnr } func generateSignature(k, v string) *refs.Signature { sig := new(refs.Signature) sig.SetKey([]byte(k)) sig.SetSign([]byte(v)) return sig } func generatePutRequestBody(n string) *container.PutRequestBody { req := new(container.PutRequestBody) req.SetContainer(generateContainer(n)) req.SetSignature(generateSignature("public key", "signature")) return req } func generatePutResponseBody(id string) *container.PutResponseBody { cid := new(refs.ContainerID) cid.SetValue([]byte(id)) resp := new(container.PutResponseBody) resp.SetContainerID(cid) return resp } func generateDeleteRequestBody(id string) *container.DeleteRequestBody { cid := new(refs.ContainerID) cid.SetValue([]byte(id)) req := new(container.DeleteRequestBody) req.SetContainerID(cid) req.SetSignature(generateSignature("public key", "signature")) return req } func generateDeleteResponseBody() *container.DeleteResponseBody { return new(container.DeleteResponseBody) } func generateGetRequestBody(id string) *container.GetRequestBody { cid := new(refs.ContainerID) cid.SetValue([]byte(id)) req := new(container.GetRequestBody) req.SetContainerID(cid) return req } func generateGetResponseBody(n string) *container.GetResponseBody { resp := new(container.GetResponseBody) resp.SetContainer(generateContainer(n)) return resp } func generateListRequestBody(id string) *container.ListRequestBody { owner := new(refs.OwnerID) owner.SetValue([]byte(id)) req := new(container.ListRequestBody) req.SetOwnerID(owner) return req } func generateListResponseBody(n int) *container.ListResponseBody { resp := new(container.ListResponseBody) ids := make([]*refs.ContainerID, n) for i := 0; i < n; i++ { cid := new(refs.ContainerID) cid.SetValue([]byte(fmt.Sprintf("Container ID %d", n+1))) ids[i] = cid } resp.SetContainerIDs(ids) return resp } func generateEACL(n int, k, v string) *acl.Table { target := new(acl.Target) target.SetRole(acl.RoleUser) keys := make([][]byte, n) for i := 0; i < n; i++ { s := fmt.Sprintf("Public Key %d", i+1) keys[i] = []byte(s) } filter := new(acl.HeaderFilter) filter.SetHeaderType(acl.HeaderTypeObject) filter.SetMatchType(acl.MatchTypeStringEqual) filter.SetKey(k) filter.SetValue(v) record := new(acl.Record) record.SetOperation(acl.OperationHead) record.SetAction(acl.ActionDeny) record.SetTargets([]*acl.Target{target}) record.SetFilters([]*acl.HeaderFilter{filter}) table := new(acl.Table) cid := new(refs.ContainerID) cid.SetValue([]byte("Container ID")) table.SetContainerID(cid) table.SetRecords([]*acl.Record{record}) return table } func generateSetEACLRequestBody(n int, k, v string) *container.SetExtendedACLRequestBody { req := new(container.SetExtendedACLRequestBody) req.SetEACL(generateEACL(n, k, v)) req.SetSignature(generateSignature("public key", "signature")) return req } func generateSetEACLResponseBody() *container.SetExtendedACLResponseBody { return new(container.SetExtendedACLResponseBody) } func generateGetEACLRequestBody(id string) *container.GetExtendedACLRequestBody { cid := new(refs.ContainerID) cid.SetValue([]byte(id)) req := new(container.GetExtendedACLRequestBody) req.SetContainerID(cid) return req } func generateGetEACLResponseBody(n int, k, v string) *container.GetExtendedACLResponseBody { resp := new(container.GetExtendedACLResponseBody) resp.SetEACL(generateEACL(n, k, v)) resp.SetSignature(generateSignature("public key", "signature")) return resp } func generateAnnouncement() *container.UsedSpaceAnnouncement { buf := make([]byte, sha256.Size) rand.Read(buf) cid := new(refs.ContainerID) cid.SetValue(buf) a := new(container.UsedSpaceAnnouncement) a.SetEpoch(rand.Uint64()) a.SetContainerID(cid) a.SetUsedSpace(rand.Uint64()) return a } func generateAnnounceRequestBody(n int) *container.AnnounceUsedSpaceRequestBody { resp := new(container.AnnounceUsedSpaceRequestBody) announcements := make([]*container.UsedSpaceAnnouncement, 0, n) for i := 0; i < n; i++ { announcements = append(announcements, generateAnnouncement()) } resp.SetAnnouncements(announcements) return resp } func generateAnnounceResponseBody() *container.AnnounceUsedSpaceResponseBody { return new(container.AnnounceUsedSpaceResponseBody) }