package main import ( "context" "crypto/ecdsa" "errors" "testing" "github.com/nspcc-dev/neofs-api-go/v2/acl" "github.com/nspcc-dev/neofs-api-go/v2/container" containerGRPC "github.com/nspcc-dev/neofs-api-go/v2/container/grpc" "github.com/nspcc-dev/neofs-api-go/v2/refs" "github.com/nspcc-dev/neofs-api-go/v2/session" "github.com/nspcc-dev/neofs-api-go/v2/signature" "github.com/nspcc-dev/neofs-crypto/test" "github.com/stretchr/testify/require" "google.golang.org/grpc" ) type testGRPCClient struct { server containerGRPC.ContainerServiceServer } type testGRPCServer struct { key *ecdsa.PrivateKey putResp *container.PutResponse getResp *container.GetResponse delResp *container.DeleteResponse listResp *container.ListResponse sEaclResp *container.SetExtendedACLResponse gEaclResp *container.GetExtendedACLResponse announceResp *container.AnnounceUsedSpaceResponse err error } func (s *testGRPCClient) Put(ctx context.Context, in *containerGRPC.PutRequest, opts ...grpc.CallOption) (*containerGRPC.PutResponse, error) { return s.server.Put(ctx, in) } func (s *testGRPCClient) Delete(ctx context.Context, in *containerGRPC.DeleteRequest, opts ...grpc.CallOption) (*containerGRPC.DeleteResponse, error) { return s.server.Delete(ctx, in) } func (s *testGRPCClient) Get(ctx context.Context, in *containerGRPC.GetRequest, opts ...grpc.CallOption) (*containerGRPC.GetResponse, error) { return s.server.Get(ctx, in) } func (s *testGRPCClient) List(ctx context.Context, in *containerGRPC.ListRequest, opts ...grpc.CallOption) (*containerGRPC.ListResponse, error) { return s.server.List(ctx, in) } func (s *testGRPCClient) SetExtendedACL(ctx context.Context, in *containerGRPC.SetExtendedACLRequest, opts ...grpc.CallOption) (*containerGRPC.SetExtendedACLResponse, error) { return s.server.SetExtendedACL(ctx, in) } func (s *testGRPCClient) GetExtendedACL(ctx context.Context, in *containerGRPC.GetExtendedACLRequest, opts ...grpc.CallOption) (*containerGRPC.GetExtendedACLResponse, error) { return s.server.GetExtendedACL(ctx, in) } func (s *testGRPCClient) AnnounceUsedSpace(ctx context.Context, in *containerGRPC.AnnounceUsedSpaceRequest, opts ...grpc.CallOption) (*containerGRPC.AnnounceUsedSpaceResponse, error) { return s.server.AnnounceUsedSpace(ctx, in) } func (s *testGRPCServer) Put(_ context.Context, req *containerGRPC.PutRequest) (*containerGRPC.PutResponse, error) { if s.err != nil { return nil, s.err } // verify request structure if err := signature.VerifyServiceMessage( container.PutRequestFromGRPCMessage(req), ); err != nil { return nil, err } // sign response structure if err := signature.SignServiceMessage(s.key, s.putResp); err != nil { return nil, err } return container.PutResponseToGRPCMessage(s.putResp), nil } func (s *testGRPCServer) Delete(_ context.Context, req *containerGRPC.DeleteRequest) (*containerGRPC.DeleteResponse, error) { if s.err != nil { return nil, s.err } // verify request structure if err := signature.VerifyServiceMessage( container.DeleteRequestFromGRPCMessage(req), ); err != nil { return nil, err } // sign response structure if err := signature.SignServiceMessage(s.key, s.delResp); err != nil { return nil, err } return container.DeleteResponseToGRPCMessage(s.delResp), nil } func (s *testGRPCServer) Get(_ context.Context, req *containerGRPC.GetRequest) (*containerGRPC.GetResponse, error) { if s.err != nil { return nil, s.err } // verify request structure if err := signature.VerifyServiceMessage( container.GetRequestFromGRPCMessage(req), ); err != nil { return nil, err } // sign response structure if err := signature.SignServiceMessage(s.key, s.getResp); err != nil { return nil, err } return container.GetResponseToGRPCMessage(s.getResp), nil } func (s *testGRPCServer) List(_ context.Context, req *containerGRPC.ListRequest) (*containerGRPC.ListResponse, error) { if s.err != nil { return nil, s.err } // verify request structure if err := signature.VerifyServiceMessage( container.ListRequestFromGRPCMessage(req), ); err != nil { return nil, err } // sign response structure if err := signature.SignServiceMessage(s.key, s.listResp); err != nil { return nil, err } return container.ListResponseToGRPCMessage(s.listResp), nil } func (s *testGRPCServer) SetExtendedACL(_ context.Context, req *containerGRPC.SetExtendedACLRequest) (*containerGRPC.SetExtendedACLResponse, error) { if s.err != nil { return nil, s.err } // verify request structure if err := signature.VerifyServiceMessage( container.SetExtendedACLRequestFromGRPCMessage(req), ); err != nil { return nil, err } // sign response structure if err := signature.SignServiceMessage(s.key, s.sEaclResp); err != nil { return nil, err } return container.SetExtendedACLResponseToGRPCMessage(s.sEaclResp), nil } func (s *testGRPCServer) GetExtendedACL(_ context.Context, req *containerGRPC.GetExtendedACLRequest) (*containerGRPC.GetExtendedACLResponse, error) { if s.err != nil { return nil, s.err } // verify request structure if err := signature.VerifyServiceMessage( container.GetExtendedACLRequestFromGRPCMessage(req), ); err != nil { return nil, err } // sign response structure if err := signature.SignServiceMessage(s.key, s.gEaclResp); err != nil { return nil, err } return container.GetExtendedACLResponseToGRPCMessage(s.gEaclResp), nil } func (s *testGRPCServer) AnnounceUsedSpace(_ context.Context, req *containerGRPC.AnnounceUsedSpaceRequest) (*containerGRPC.AnnounceUsedSpaceResponse, error) { if s.err != nil { return nil, s.err } // verify request structure if err := signature.VerifyServiceMessage( container.AnnounceUsedSpaceRequestFromGRPCMessage(req), ); err != nil { return nil, err } // sign response structure if err := signature.SignServiceMessage(s.key, s.announceResp); err != nil { return nil, err } return container.AnnounceUsedSpaceResponseToGRPCMessage(s.announceResp), nil } func testPutRequest() *container.PutRequest { cnr := new(container.Container) cnr.SetBasicACL(1) body := new(container.PutRequestBody) body.SetContainer(cnr) meta := new(session.RequestMetaHeader) meta.SetTTL(1) req := new(container.PutRequest) req.SetBody(body) req.SetMetaHeader(meta) return req } func testPutResponse() *container.PutResponse { cid := new(refs.ContainerID) cid.SetValue([]byte{1, 2, 3}) body := new(container.PutResponseBody) body.SetContainerID(cid) meta := new(session.ResponseMetaHeader) meta.SetTTL(1) meta.SetXHeaders([]*session.XHeader{}) // w/o this require.Equal fails due to nil and []T{} difference resp := new(container.PutResponse) resp.SetBody(body) resp.SetMetaHeader(meta) return resp } func testGetRequest() *container.GetRequest { cid := new(refs.ContainerID) cid.SetValue([]byte{1, 2, 3}) body := new(container.GetRequestBody) body.SetContainerID(cid) meta := new(session.RequestMetaHeader) meta.SetTTL(1) req := new(container.GetRequest) req.SetBody(body) req.SetMetaHeader(meta) return req } func testGetResponse() *container.GetResponse { cnr := new(container.Container) cnr.SetAttributes([]*container.Attribute{}) // w/o this require.Equal fails due to nil and []T{} difference body := new(container.GetResponseBody) body.SetContainer(cnr) meta := new(session.ResponseMetaHeader) meta.SetTTL(1) meta.SetXHeaders([]*session.XHeader{}) // w/o this require.Equal fails due to nil and []T{} difference resp := new(container.GetResponse) resp.SetBody(body) resp.SetMetaHeader(meta) return resp } func testDelRequest() *container.DeleteRequest { cid := new(refs.ContainerID) cid.SetValue([]byte{1, 2, 3}) body := new(container.DeleteRequestBody) body.SetContainerID(cid) meta := new(session.RequestMetaHeader) meta.SetTTL(1) req := new(container.DeleteRequest) req.SetBody(body) req.SetMetaHeader(meta) return req } func testDelResponse() *container.DeleteResponse { body := new(container.DeleteResponseBody) meta := new(session.ResponseMetaHeader) meta.SetTTL(1) meta.SetXHeaders([]*session.XHeader{}) // w/o this require.Equal fails due to nil and []T{} difference resp := new(container.DeleteResponse) resp.SetBody(body) resp.SetMetaHeader(meta) return resp } func testListRequest() *container.ListRequest { ownerID := new(refs.OwnerID) ownerID.SetValue([]byte{1, 2, 3}) body := new(container.ListRequestBody) body.SetOwnerID(ownerID) meta := new(session.RequestMetaHeader) meta.SetTTL(1) req := new(container.ListRequest) req.SetBody(body) req.SetMetaHeader(meta) return req } func testListResponse() *container.ListResponse { cid := new(refs.ContainerID) cid.SetValue([]byte{1, 2, 3}) body := new(container.ListResponseBody) body.SetContainerIDs([]*refs.ContainerID{cid}) meta := new(session.ResponseMetaHeader) meta.SetTTL(1) meta.SetXHeaders([]*session.XHeader{}) // w/o this require.Equal fails due to nil and []T{} difference resp := new(container.ListResponse) resp.SetBody(body) resp.SetMetaHeader(meta) return resp } func testSetEACLRequest() *container.SetExtendedACLRequest { cid := new(refs.ContainerID) cid.SetValue([]byte{1, 2, 3}) eacl := new(acl.Table) eacl.SetContainerID(cid) body := new(container.SetExtendedACLRequestBody) body.SetEACL(eacl) meta := new(session.RequestMetaHeader) meta.SetTTL(1) req := new(container.SetExtendedACLRequest) req.SetBody(body) req.SetMetaHeader(meta) return req } func testSetEACLResponse() *container.SetExtendedACLResponse { body := new(container.SetExtendedACLResponseBody) meta := new(session.ResponseMetaHeader) meta.SetTTL(1) meta.SetXHeaders([]*session.XHeader{}) // w/o this require.Equal fails due to nil and []T{} difference resp := new(container.SetExtendedACLResponse) resp.SetBody(body) resp.SetMetaHeader(meta) return resp } func testGetEACLRequest() *container.GetExtendedACLRequest { cid := new(refs.ContainerID) cid.SetValue([]byte{1, 2, 3}) body := new(container.GetExtendedACLRequestBody) body.SetContainerID(cid) meta := new(session.RequestMetaHeader) meta.SetTTL(1) req := new(container.GetExtendedACLRequest) req.SetBody(body) req.SetMetaHeader(meta) return req } func testGetEACLResponse() *container.GetExtendedACLResponse { cid := new(refs.ContainerID) cid.SetValue([]byte{1, 2, 3}) eacl := new(acl.Table) eacl.SetContainerID(cid) eacl.SetRecords([]*acl.Record{}) // w/o this require.Equal fails due to nil and []T{} difference body := new(container.GetExtendedACLResponseBody) body.SetEACL(eacl) meta := new(session.ResponseMetaHeader) meta.SetTTL(1) meta.SetXHeaders([]*session.XHeader{}) // w/o this require.Equal fails due to nil and []T{} difference resp := new(container.GetExtendedACLResponse) resp.SetBody(body) resp.SetMetaHeader(meta) return resp } func testAnnounceRequest() *container.AnnounceUsedSpaceRequest { cid1 := new(refs.ContainerID) cid1.SetValue([]byte{1, 2, 3}) cid2 := new(refs.ContainerID) cid2.SetValue([]byte{4, 5, 6}) a1 := new(container.UsedSpaceAnnouncement) a1.SetUsedSpace(10) a1.SetContainerID(cid1) a2 := new(container.UsedSpaceAnnouncement) a2.SetUsedSpace(20) a2.SetContainerID(cid2) announcements := []*container.UsedSpaceAnnouncement{a1, a2} body := new(container.AnnounceUsedSpaceRequestBody) body.SetAnnouncements(announcements) meta := new(session.RequestMetaHeader) meta.SetTTL(1) req := new(container.AnnounceUsedSpaceRequest) req.SetBody(body) req.SetMetaHeader(meta) return req } func testAnnounceResponse() *container.AnnounceUsedSpaceResponse { body := new(container.AnnounceUsedSpaceResponseBody) meta := new(session.ResponseMetaHeader) meta.SetTTL(1) meta.SetXHeaders([]*session.XHeader{}) // w/o this require.Equal fails due to nil and []T{} difference resp := new(container.AnnounceUsedSpaceResponse) resp.SetBody(body) resp.SetMetaHeader(meta) return resp } func TestGRPCClient_Put(t *testing.T) { ctx := context.TODO() cliKey := test.DecodeKey(0) srvKey := test.DecodeKey(1) t.Run("gRPC server error", func(t *testing.T) { srvErr := errors.New("test server error") srv := &testGRPCServer{ err: srvErr, } cli := &testGRPCClient{ server: srv, } c, err := container.NewClient(container.WithGRPCServiceClient(cli)) require.NoError(t, err) resp, err := c.Put(ctx, new(container.PutRequest)) require.True(t, errors.Is(err, srvErr)) require.Nil(t, resp) }) t.Run("invalid request structure", func(t *testing.T) { req := testPutRequest() require.Error(t, signature.VerifyServiceMessage(req)) c, err := container.NewClient( container.WithGRPCServiceClient( &testGRPCClient{ server: new(testGRPCServer), }, ), ) require.NoError(t, err) resp, err := c.Put(ctx, req) require.Error(t, err) require.Nil(t, resp) }) t.Run("correct response", func(t *testing.T) { req := testPutRequest() require.NoError(t, signature.SignServiceMessage(cliKey, req)) resp := testPutResponse() c, err := container.NewClient( container.WithGRPCServiceClient( &testGRPCClient{ server: &testGRPCServer{ key: srvKey, putResp: resp, }, }, ), ) require.NoError(t, err) r, err := c.Put(ctx, req) require.NoError(t, err) require.NoError(t, signature.VerifyServiceMessage(r)) require.Equal(t, resp.GetBody(), r.GetBody()) require.Equal(t, resp.GetMetaHeader(), r.GetMetaHeader()) }) } func TestGRPCClient_Get(t *testing.T) { ctx := context.TODO() cliKey := test.DecodeKey(0) srvKey := test.DecodeKey(1) t.Run("gRPC server error", func(t *testing.T) { srvErr := errors.New("test server error") srv := &testGRPCServer{ err: srvErr, } cli := &testGRPCClient{ server: srv, } c, err := container.NewClient(container.WithGRPCServiceClient(cli)) require.NoError(t, err) resp, err := c.Get(ctx, new(container.GetRequest)) require.True(t, errors.Is(err, srvErr)) require.Nil(t, resp) }) t.Run("invalid request structure", func(t *testing.T) { req := testGetRequest() require.Error(t, signature.VerifyServiceMessage(req)) c, err := container.NewClient( container.WithGRPCServiceClient( &testGRPCClient{ server: new(testGRPCServer), }, ), ) require.NoError(t, err) resp, err := c.Get(ctx, req) require.Error(t, err) require.Nil(t, resp) }) t.Run("correct response", func(t *testing.T) { req := testGetRequest() require.NoError(t, signature.SignServiceMessage(cliKey, req)) resp := testGetResponse() c, err := container.NewClient( container.WithGRPCServiceClient( &testGRPCClient{ server: &testGRPCServer{ key: srvKey, getResp: resp, }, }, ), ) require.NoError(t, err) r, err := c.Get(ctx, req) require.NoError(t, err) require.NoError(t, signature.VerifyServiceMessage(r)) require.Equal(t, resp.GetBody(), r.GetBody()) require.Equal(t, resp.GetMetaHeader(), r.GetMetaHeader()) }) } func TestGRPCClient_Delete(t *testing.T) { ctx := context.TODO() cliKey := test.DecodeKey(0) srvKey := test.DecodeKey(1) t.Run("gRPC server error", func(t *testing.T) { srvErr := errors.New("test server error") srv := &testGRPCServer{ err: srvErr, } cli := &testGRPCClient{ server: srv, } c, err := container.NewClient(container.WithGRPCServiceClient(cli)) require.NoError(t, err) resp, err := c.Delete(ctx, new(container.DeleteRequest)) require.True(t, errors.Is(err, srvErr)) require.Nil(t, resp) }) t.Run("invalid request structure", func(t *testing.T) { req := testDelRequest() require.Error(t, signature.VerifyServiceMessage(req)) c, err := container.NewClient( container.WithGRPCServiceClient( &testGRPCClient{ server: new(testGRPCServer), }, ), ) require.NoError(t, err) resp, err := c.Delete(ctx, req) require.Error(t, err) require.Nil(t, resp) }) t.Run("correct response", func(t *testing.T) { req := testDelRequest() require.NoError(t, signature.SignServiceMessage(cliKey, req)) resp := testDelResponse() c, err := container.NewClient( container.WithGRPCServiceClient( &testGRPCClient{ server: &testGRPCServer{ key: srvKey, delResp: resp, }, }, ), ) require.NoError(t, err) r, err := c.Delete(ctx, req) require.NoError(t, err) require.NoError(t, signature.VerifyServiceMessage(r)) require.Equal(t, resp.GetBody(), r.GetBody()) require.Equal(t, resp.GetMetaHeader(), r.GetMetaHeader()) }) } func TestGRPCClient_List(t *testing.T) { ctx := context.TODO() cliKey := test.DecodeKey(0) srvKey := test.DecodeKey(1) t.Run("gRPC server error", func(t *testing.T) { srvErr := errors.New("test server error") srv := &testGRPCServer{ err: srvErr, } cli := &testGRPCClient{ server: srv, } c, err := container.NewClient(container.WithGRPCServiceClient(cli)) require.NoError(t, err) resp, err := c.List(ctx, new(container.ListRequest)) require.True(t, errors.Is(err, srvErr)) require.Nil(t, resp) }) t.Run("invalid request structure", func(t *testing.T) { req := testListRequest() require.Error(t, signature.VerifyServiceMessage(req)) c, err := container.NewClient( container.WithGRPCServiceClient( &testGRPCClient{ server: new(testGRPCServer), }, ), ) require.NoError(t, err) resp, err := c.List(ctx, req) require.Error(t, err) require.Nil(t, resp) }) t.Run("correct response", func(t *testing.T) { req := testListRequest() require.NoError(t, signature.SignServiceMessage(cliKey, req)) resp := testListResponse() c, err := container.NewClient( container.WithGRPCServiceClient( &testGRPCClient{ server: &testGRPCServer{ key: srvKey, listResp: resp, }, }, ), ) require.NoError(t, err) r, err := c.List(ctx, req) require.NoError(t, err) require.NoError(t, signature.VerifyServiceMessage(r)) require.Equal(t, resp.GetBody(), r.GetBody()) require.Equal(t, resp.GetMetaHeader(), r.GetMetaHeader()) }) } func TestGRPCClient_SetEACL(t *testing.T) { ctx := context.TODO() cliKey := test.DecodeKey(0) srvKey := test.DecodeKey(1) t.Run("gRPC server error", func(t *testing.T) { srvErr := errors.New("test server error") srv := &testGRPCServer{ err: srvErr, } cli := &testGRPCClient{ server: srv, } c, err := container.NewClient(container.WithGRPCServiceClient(cli)) require.NoError(t, err) resp, err := c.SetExtendedACL(ctx, new(container.SetExtendedACLRequest)) require.True(t, errors.Is(err, srvErr)) require.Nil(t, resp) }) t.Run("invalid request structure", func(t *testing.T) { req := testSetEACLRequest() require.Error(t, signature.VerifyServiceMessage(req)) c, err := container.NewClient( container.WithGRPCServiceClient( &testGRPCClient{ server: new(testGRPCServer), }, ), ) require.NoError(t, err) resp, err := c.SetExtendedACL(ctx, req) require.Error(t, err) require.Nil(t, resp) }) t.Run("correct response", func(t *testing.T) { req := testSetEACLRequest() require.NoError(t, signature.SignServiceMessage(cliKey, req)) resp := testSetEACLResponse() c, err := container.NewClient( container.WithGRPCServiceClient( &testGRPCClient{ server: &testGRPCServer{ key: srvKey, sEaclResp: resp, }, }, ), ) require.NoError(t, err) r, err := c.SetExtendedACL(ctx, req) require.NoError(t, err) require.NoError(t, signature.VerifyServiceMessage(r)) require.Equal(t, resp.GetBody(), r.GetBody()) require.Equal(t, resp.GetMetaHeader(), r.GetMetaHeader()) }) } func TestGRPCClient_GetEACL(t *testing.T) { ctx := context.TODO() cliKey := test.DecodeKey(0) srvKey := test.DecodeKey(1) t.Run("gRPC server error", func(t *testing.T) { srvErr := errors.New("test server error") srv := &testGRPCServer{ err: srvErr, } cli := &testGRPCClient{ server: srv, } c, err := container.NewClient(container.WithGRPCServiceClient(cli)) require.NoError(t, err) resp, err := c.GetExtendedACL(ctx, new(container.GetExtendedACLRequest)) require.True(t, errors.Is(err, srvErr)) require.Nil(t, resp) }) t.Run("invalid request structure", func(t *testing.T) { req := testGetEACLRequest() require.Error(t, signature.VerifyServiceMessage(req)) c, err := container.NewClient( container.WithGRPCServiceClient( &testGRPCClient{ server: new(testGRPCServer), }, ), ) require.NoError(t, err) resp, err := c.GetExtendedACL(ctx, req) require.Error(t, err) require.Nil(t, resp) }) t.Run("correct response", func(t *testing.T) { req := testGetEACLRequest() require.NoError(t, signature.SignServiceMessage(cliKey, req)) resp := testGetEACLResponse() c, err := container.NewClient( container.WithGRPCServiceClient( &testGRPCClient{ server: &testGRPCServer{ key: srvKey, gEaclResp: resp, }, }, ), ) require.NoError(t, err) r, err := c.GetExtendedACL(ctx, req) require.NoError(t, err) require.NoError(t, signature.VerifyServiceMessage(r)) require.Equal(t, resp.GetBody(), r.GetBody()) require.Equal(t, resp.GetMetaHeader(), r.GetMetaHeader()) }) } func TestGRPCClient_AnnounceUsedSpace(t *testing.T) { ctx := context.TODO() cliKey := test.DecodeKey(0) srvKey := test.DecodeKey(1) t.Run("gRPC server error", func(t *testing.T) { srvErr := errors.New("test server error") srv := &testGRPCServer{ err: srvErr, } cli := &testGRPCClient{ server: srv, } c, err := container.NewClient(container.WithGRPCServiceClient(cli)) require.NoError(t, err) resp, err := c.AnnounceUsedSpace(ctx, new(container.AnnounceUsedSpaceRequest)) require.True(t, errors.Is(err, srvErr)) require.Nil(t, resp) }) t.Run("invalid request structure", func(t *testing.T) { req := testAnnounceRequest() require.Error(t, signature.VerifyServiceMessage(req)) c, err := container.NewClient( container.WithGRPCServiceClient( &testGRPCClient{ server: new(testGRPCServer), }, ), ) require.NoError(t, err) resp, err := c.AnnounceUsedSpace(ctx, req) require.Error(t, err) require.Nil(t, resp) }) t.Run("correct response", func(t *testing.T) { req := testAnnounceRequest() require.NoError(t, signature.SignServiceMessage(cliKey, req)) resp := testAnnounceResponse() c, err := container.NewClient( container.WithGRPCServiceClient( &testGRPCClient{ server: &testGRPCServer{ key: srvKey, announceResp: resp, }, }, ), ) require.NoError(t, err) r, err := c.AnnounceUsedSpace(ctx, req) require.NoError(t, err) require.NoError(t, signature.VerifyServiceMessage(r)) require.Equal(t, resp.GetBody(), r.GetBody()) require.Equal(t, resp.GetMetaHeader(), r.GetMetaHeader()) }) }