gw <-> po contracts tests #692
@@ -14,7 +14,7 @@ require (
|
|||||||
github.com/tech/sendico/pkg v0.1.0
|
github.com/tech/sendico/pkg v0.1.0
|
||||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||||
go.uber.org/zap v1.27.1
|
go.uber.org/zap v1.27.1
|
||||||
google.golang.org/grpc v1.79.1
|
google.golang.org/grpc v1.79.2
|
||||||
google.golang.org/protobuf v1.36.11
|
google.golang.org/protobuf v1.36.11
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -212,8 +212,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
|||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
@@ -492,6 +492,9 @@ func transferFromReceipt(req *chainv1.SubmitTransferRequest, receipt *connectorv
|
|||||||
transfer.Destination = req.GetDestination()
|
transfer.Destination = req.GetDestination()
|
||||||
transfer.RequestedAmount = req.GetAmount()
|
transfer.RequestedAmount = req.GetAmount()
|
||||||
transfer.NetAmount = req.GetAmount()
|
transfer.NetAmount = req.GetAmount()
|
||||||
|
transfer.IntentRef = strings.TrimSpace(req.GetIntentRef())
|
||||||
|
transfer.OperationRef = strings.TrimSpace(req.GetOperationRef())
|
||||||
|
transfer.PaymentRef = strings.TrimSpace(req.GetPaymentRef())
|
||||||
}
|
}
|
||||||
if receipt != nil {
|
if receipt != nil {
|
||||||
transfer.TransferRef = strings.TrimSpace(receipt.GetOperationId())
|
transfer.TransferRef = strings.TrimSpace(receipt.GetOperationId())
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
||||||
connectorv1 "github.com/tech/sendico/pkg/proto/connector/v1"
|
connectorv1 "github.com/tech/sendico/pkg/proto/connector/v1"
|
||||||
chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1"
|
chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
@@ -13,6 +14,11 @@ import (
|
|||||||
|
|
||||||
type stubConnectorClient struct {
|
type stubConnectorClient struct {
|
||||||
listReq *connectorv1.ListAccountsRequest
|
listReq *connectorv1.ListAccountsRequest
|
||||||
|
getReq *connectorv1.GetOperationRequest
|
||||||
|
|
||||||
|
submitReq *connectorv1.SubmitOperationRequest
|
||||||
|
submitResp *connectorv1.SubmitOperationResponse
|
||||||
|
getResp *connectorv1.GetOperationResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stubConnectorClient) GetCapabilities(ctx context.Context, in *connectorv1.GetCapabilitiesRequest, opts ...grpc.CallOption) (*connectorv1.GetCapabilitiesResponse, error) {
|
func (s *stubConnectorClient) GetCapabilities(ctx context.Context, in *connectorv1.GetCapabilitiesRequest, opts ...grpc.CallOption) (*connectorv1.GetCapabilitiesResponse, error) {
|
||||||
@@ -37,10 +43,18 @@ func (s *stubConnectorClient) GetBalance(ctx context.Context, in *connectorv1.Ge
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *stubConnectorClient) SubmitOperation(ctx context.Context, in *connectorv1.SubmitOperationRequest, opts ...grpc.CallOption) (*connectorv1.SubmitOperationResponse, error) {
|
func (s *stubConnectorClient) SubmitOperation(ctx context.Context, in *connectorv1.SubmitOperationRequest, opts ...grpc.CallOption) (*connectorv1.SubmitOperationResponse, error) {
|
||||||
|
s.submitReq = in
|
||||||
|
if s.submitResp != nil {
|
||||||
|
return s.submitResp, nil
|
||||||
|
}
|
||||||
return &connectorv1.SubmitOperationResponse{}, nil
|
return &connectorv1.SubmitOperationResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stubConnectorClient) GetOperation(ctx context.Context, in *connectorv1.GetOperationRequest, opts ...grpc.CallOption) (*connectorv1.GetOperationResponse, error) {
|
func (s *stubConnectorClient) GetOperation(ctx context.Context, in *connectorv1.GetOperationRequest, opts ...grpc.CallOption) (*connectorv1.GetOperationResponse, error) {
|
||||||
|
s.getReq = in
|
||||||
|
if s.getResp != nil {
|
||||||
|
return s.getResp, nil
|
||||||
|
}
|
||||||
return &connectorv1.GetOperationResponse{}, nil
|
return &connectorv1.GetOperationResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,3 +80,84 @@ func TestListManagedWallets_ForwardsOrganizationRef(t *testing.T) {
|
|||||||
require.Equal(t, "owner-1", stub.listReq.GetOwnerRefFilter().GetValue())
|
require.Equal(t, "owner-1", stub.listReq.GetOwnerRefFilter().GetValue())
|
||||||
require.Equal(t, connectorv1.AccountKind_CHAIN_MANAGED_WALLET, stub.listReq.GetKind())
|
require.Equal(t, connectorv1.AccountKind_CHAIN_MANAGED_WALLET, stub.listReq.GetKind())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTransferFromReceipt_PreservesRequestReferences(t *testing.T) {
|
||||||
|
req := &chainv1.SubmitTransferRequest{
|
||||||
|
IdempotencyKey: "idem-1",
|
||||||
|
OrganizationRef: "org-1",
|
||||||
|
SourceWalletRef: "wallet-src",
|
||||||
|
Amount: &moneyv1.Money{Amount: "12.34", Currency: "USDT"},
|
||||||
|
IntentRef: "intent-1",
|
||||||
|
OperationRef: "payment-1:hop_2_settlement_fx_convert",
|
||||||
|
PaymentRef: "payment-1",
|
||||||
|
}
|
||||||
|
receipt := &connectorv1.OperationReceipt{
|
||||||
|
OperationId: "payment-1:hop_2_settlement_fx_convert",
|
||||||
|
ProviderRef: "provider-1",
|
||||||
|
Status: connectorv1.OperationStatus_OPERATION_WAITING,
|
||||||
|
}
|
||||||
|
|
||||||
|
transfer := transferFromReceipt(req, receipt)
|
||||||
|
require.NotNil(t, transfer)
|
||||||
|
require.Equal(t, "payment-1:hop_2_settlement_fx_convert", transfer.GetTransferRef())
|
||||||
|
require.Equal(t, "intent-1", transfer.GetIntentRef())
|
||||||
|
require.Equal(t, "payment-1:hop_2_settlement_fx_convert", transfer.GetOperationRef())
|
||||||
|
require.Equal(t, "payment-1", transfer.GetPaymentRef())
|
||||||
|
require.Equal(t, chainv1.TransferStatus_TRANSFER_WAITING, transfer.GetStatus())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSubmitTransfer_ForwardsOperationAndIntentReferences(t *testing.T) {
|
||||||
|
stub := &stubConnectorClient{
|
||||||
|
submitResp: &connectorv1.SubmitOperationResponse{
|
||||||
|
Receipt: &connectorv1.OperationReceipt{
|
||||||
|
OperationId: "payment-1:hop_2_settlement_fx_convert",
|
||||||
|
Status: connectorv1.OperationStatus_OPERATION_WAITING,
|
||||||
|
ProviderRef: "provider-1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
client := NewWithClient(Config{}, stub)
|
||||||
|
|
||||||
|
resp, err := client.SubmitTransfer(context.Background(), &chainv1.SubmitTransferRequest{
|
||||||
|
IdempotencyKey: "idem-1",
|
||||||
|
OrganizationRef: "org-1",
|
||||||
|
SourceWalletRef: "wallet-src",
|
||||||
|
Destination: &chainv1.TransferDestination{
|
||||||
|
Destination: &chainv1.TransferDestination_ManagedWalletRef{
|
||||||
|
ManagedWalletRef: "wallet-dst",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Amount: &moneyv1.Money{Amount: "12.34", Currency: "USDT"},
|
||||||
|
IntentRef: "intent-1",
|
||||||
|
OperationRef: "payment-1:hop_2_settlement_fx_convert",
|
||||||
|
PaymentRef: "payment-1",
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, stub.submitReq)
|
||||||
|
require.NotNil(t, stub.submitReq.GetOperation())
|
||||||
|
require.Equal(t, "intent-1", stub.submitReq.GetOperation().GetIntentRef())
|
||||||
|
require.Equal(t, "payment-1:hop_2_settlement_fx_convert", stub.submitReq.GetOperation().GetOperationRef())
|
||||||
|
require.NotNil(t, resp.GetTransfer())
|
||||||
|
require.Equal(t, "payment-1:hop_2_settlement_fx_convert", resp.GetTransfer().GetTransferRef())
|
||||||
|
require.Equal(t, "payment-1:hop_2_settlement_fx_convert", resp.GetTransfer().GetOperationRef())
|
||||||
|
require.Equal(t, "intent-1", resp.GetTransfer().GetIntentRef())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetTransfer_UsesTransferRefAsOperationID(t *testing.T) {
|
||||||
|
stub := &stubConnectorClient{
|
||||||
|
getResp: &connectorv1.GetOperationResponse{
|
||||||
|
Operation: &connectorv1.Operation{
|
||||||
|
OperationId: "transfer-1",
|
||||||
|
Status: connectorv1.OperationStatus_OPERATION_PROCESSING,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
client := NewWithClient(Config{}, stub)
|
||||||
|
|
||||||
|
resp, err := client.GetTransfer(context.Background(), &chainv1.GetTransferRequest{TransferRef: "transfer-1"})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, stub.getReq)
|
||||||
|
require.Equal(t, "transfer-1", stub.getReq.GetOperationId())
|
||||||
|
require.NotNil(t, resp.GetTransfer())
|
||||||
|
require.Equal(t, "transfer-1", resp.GetTransfer().GetTransferRef())
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ require (
|
|||||||
github.com/tech/sendico/pkg v0.1.0
|
github.com/tech/sendico/pkg v0.1.0
|
||||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||||
go.uber.org/zap v1.27.1
|
go.uber.org/zap v1.27.1
|
||||||
google.golang.org/grpc v1.79.1
|
google.golang.org/grpc v1.79.2
|
||||||
google.golang.org/protobuf v1.36.11
|
google.golang.org/protobuf v1.36.11
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -357,8 +357,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
|||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
144
api/gateway/mntx/client/client_test.go
Normal file
144
api/gateway/mntx/client/client_test.go
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
connectorv1 "github.com/tech/sendico/pkg/proto/connector/v1"
|
||||||
|
mntxv1 "github.com/tech/sendico/pkg/proto/gateway/mntx/v1"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
type stubConnectorClient struct {
|
||||||
|
submitReq *connectorv1.SubmitOperationRequest
|
||||||
|
getReq *connectorv1.GetOperationRequest
|
||||||
|
|
||||||
|
submitResp *connectorv1.SubmitOperationResponse
|
||||||
|
getResp *connectorv1.GetOperationResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stubConnectorClient) SubmitOperation(_ context.Context, in *connectorv1.SubmitOperationRequest, _ ...grpc.CallOption) (*connectorv1.SubmitOperationResponse, error) {
|
||||||
|
s.submitReq = in
|
||||||
|
if s.submitResp != nil {
|
||||||
|
return s.submitResp, nil
|
||||||
|
}
|
||||||
|
return &connectorv1.SubmitOperationResponse{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stubConnectorClient) GetOperation(_ context.Context, in *connectorv1.GetOperationRequest, _ ...grpc.CallOption) (*connectorv1.GetOperationResponse, error) {
|
||||||
|
s.getReq = in
|
||||||
|
if s.getResp != nil {
|
||||||
|
return s.getResp, nil
|
||||||
|
}
|
||||||
|
return &connectorv1.GetOperationResponse{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateCardPayout_UsesOperationRefIdentity(t *testing.T) {
|
||||||
|
stub := &stubConnectorClient{
|
||||||
|
submitResp: &connectorv1.SubmitOperationResponse{
|
||||||
|
Receipt: &connectorv1.OperationReceipt{
|
||||||
|
OperationId: "payment-1:hop_4_card_payout_send",
|
||||||
|
Status: connectorv1.OperationStatus_OPERATION_WAITING,
|
||||||
|
ProviderRef: "provider-1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
client := &gatewayClient{client: stub, cfg: Config{}}
|
||||||
|
|
||||||
|
resp, err := client.CreateCardPayout(context.Background(), &mntxv1.CardPayoutRequest{
|
||||||
|
PayoutId: "payout-legacy-id",
|
||||||
|
OperationRef: "payment-1:hop_4_card_payout_send",
|
||||||
|
IdempotencyKey: "",
|
||||||
|
AmountMinor: 12345,
|
||||||
|
Currency: "RUB",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("CreateCardPayout returned error: %v", err)
|
||||||
|
}
|
||||||
|
if resp.GetPayout() == nil {
|
||||||
|
t.Fatal("expected payout")
|
||||||
|
}
|
||||||
|
if got, want := resp.GetPayout().GetPayoutId(), "payment-1:hop_4_card_payout_send"; got != want {
|
||||||
|
t.Fatalf("payout_id mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
if stub.submitReq == nil || stub.submitReq.GetOperation() == nil {
|
||||||
|
t.Fatal("expected submitted operation")
|
||||||
|
}
|
||||||
|
if got, want := stub.submitReq.GetOperation().GetOperationRef(), "payment-1:hop_4_card_payout_send"; got != want {
|
||||||
|
t.Fatalf("operation_ref mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
if got, want := stub.submitReq.GetOperation().GetIdempotencyKey(), "payment-1:hop_4_card_payout_send"; got != want {
|
||||||
|
t.Fatalf("idempotency_key mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetCardPayoutStatus_UsesPayoutIDAsOperationID(t *testing.T) {
|
||||||
|
stub := &stubConnectorClient{
|
||||||
|
getResp: &connectorv1.GetOperationResponse{
|
||||||
|
Operation: &connectorv1.Operation{
|
||||||
|
OperationId: "payment-2:hop_4_card_payout_send",
|
||||||
|
Status: connectorv1.OperationStatus_OPERATION_PROCESSING,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
client := &gatewayClient{client: stub, cfg: Config{}}
|
||||||
|
|
||||||
|
resp, err := client.GetCardPayoutStatus(context.Background(), &mntxv1.GetCardPayoutStatusRequest{
|
||||||
|
PayoutId: "payment-2:hop_4_card_payout_send",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetCardPayoutStatus returned error: %v", err)
|
||||||
|
}
|
||||||
|
if stub.getReq == nil {
|
||||||
|
t.Fatal("expected get operation request")
|
||||||
|
}
|
||||||
|
if got, want := stub.getReq.GetOperationId(), "payment-2:hop_4_card_payout_send"; got != want {
|
||||||
|
t.Fatalf("operation_id mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
if resp.GetPayout() == nil {
|
||||||
|
t.Fatal("expected payout")
|
||||||
|
}
|
||||||
|
if got, want := resp.GetPayout().GetPayoutId(), "payment-2:hop_4_card_payout_send"; got != want {
|
||||||
|
t.Fatalf("payout_id mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateCardTokenPayout_UsesOperationRefWhenReceiptOperationIDMissing(t *testing.T) {
|
||||||
|
stub := &stubConnectorClient{
|
||||||
|
submitResp: &connectorv1.SubmitOperationResponse{
|
||||||
|
Receipt: &connectorv1.OperationReceipt{
|
||||||
|
OperationId: "",
|
||||||
|
Status: connectorv1.OperationStatus_OPERATION_PROCESSING,
|
||||||
|
ProviderRef: "provider-2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
client := &gatewayClient{client: stub, cfg: Config{}}
|
||||||
|
|
||||||
|
resp, err := client.CreateCardTokenPayout(context.Background(), &mntxv1.CardTokenPayoutRequest{
|
||||||
|
PayoutId: "legacy-payout-id",
|
||||||
|
OperationRef: "payment-3:hop_4_card_payout_send_2",
|
||||||
|
IdempotencyKey: "",
|
||||||
|
AmountMinor: 777,
|
||||||
|
Currency: "RUB",
|
||||||
|
CardToken: "tok_123",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("CreateCardTokenPayout returned error: %v", err)
|
||||||
|
}
|
||||||
|
if stub.submitReq == nil || stub.submitReq.GetOperation() == nil {
|
||||||
|
t.Fatal("expected submitted operation")
|
||||||
|
}
|
||||||
|
if got, want := stub.submitReq.GetOperation().GetOperationRef(), "payment-3:hop_4_card_payout_send_2"; got != want {
|
||||||
|
t.Fatalf("operation_ref mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
if got, want := stub.submitReq.GetOperation().GetIdempotencyKey(), "payment-3:hop_4_card_payout_send_2"; got != want {
|
||||||
|
t.Fatalf("idempotency_key mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
if resp.GetPayout() == nil {
|
||||||
|
t.Fatal("expected payout")
|
||||||
|
}
|
||||||
|
if got, want := resp.GetPayout().GetPayoutId(), "payment-3:hop_4_card_payout_send_2"; got != want {
|
||||||
|
t.Fatalf("payout_id mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@ require (
|
|||||||
github.com/tech/sendico/pkg v0.1.0
|
github.com/tech/sendico/pkg v0.1.0
|
||||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||||
go.uber.org/zap v1.27.1
|
go.uber.org/zap v1.27.1
|
||||||
google.golang.org/grpc v1.79.1
|
google.golang.org/grpc v1.79.2
|
||||||
google.golang.org/protobuf v1.36.11
|
google.golang.org/protobuf v1.36.11
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -212,8 +212,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
|||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
@@ -441,6 +441,8 @@ func operationFromTransfer(req *chainv1.SubmitTransferRequest) (*connectorv1.Ope
|
|||||||
From: &connectorv1.OperationParty{Ref: &connectorv1.OperationParty_Account{Account: &connectorv1.AccountRef{ConnectorId: chainConnectorID, AccountId: strings.TrimSpace(req.GetSourceWalletRef())}}},
|
From: &connectorv1.OperationParty{Ref: &connectorv1.OperationParty_Account{Account: &connectorv1.AccountRef{ConnectorId: chainConnectorID, AccountId: strings.TrimSpace(req.GetSourceWalletRef())}}},
|
||||||
Money: req.GetAmount(),
|
Money: req.GetAmount(),
|
||||||
Params: structFromMap(params),
|
Params: structFromMap(params),
|
||||||
|
IntentRef: strings.TrimSpace(req.GetIntentRef()),
|
||||||
|
OperationRef: strings.TrimSpace(req.GetOperationRef()),
|
||||||
}
|
}
|
||||||
to, err := destinationToParty(req.GetDestination())
|
to, err := destinationToParty(req.GetDestination())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -490,6 +492,9 @@ func transferFromReceipt(req *chainv1.SubmitTransferRequest, receipt *connectorv
|
|||||||
transfer.Destination = req.GetDestination()
|
transfer.Destination = req.GetDestination()
|
||||||
transfer.RequestedAmount = req.GetAmount()
|
transfer.RequestedAmount = req.GetAmount()
|
||||||
transfer.NetAmount = req.GetAmount()
|
transfer.NetAmount = req.GetAmount()
|
||||||
|
transfer.IntentRef = strings.TrimSpace(req.GetIntentRef())
|
||||||
|
transfer.OperationRef = strings.TrimSpace(req.GetOperationRef())
|
||||||
|
transfer.PaymentRef = strings.TrimSpace(req.GetPaymentRef())
|
||||||
}
|
}
|
||||||
if receipt != nil {
|
if receipt != nil {
|
||||||
transfer.TransferRef = strings.TrimSpace(receipt.GetOperationId())
|
transfer.TransferRef = strings.TrimSpace(receipt.GetOperationId())
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
||||||
connectorv1 "github.com/tech/sendico/pkg/proto/connector/v1"
|
connectorv1 "github.com/tech/sendico/pkg/proto/connector/v1"
|
||||||
chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1"
|
chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
@@ -13,6 +14,11 @@ import (
|
|||||||
|
|
||||||
type stubConnectorClient struct {
|
type stubConnectorClient struct {
|
||||||
listReq *connectorv1.ListAccountsRequest
|
listReq *connectorv1.ListAccountsRequest
|
||||||
|
getReq *connectorv1.GetOperationRequest
|
||||||
|
|
||||||
|
submitReq *connectorv1.SubmitOperationRequest
|
||||||
|
submitResp *connectorv1.SubmitOperationResponse
|
||||||
|
getResp *connectorv1.GetOperationResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stubConnectorClient) GetCapabilities(ctx context.Context, in *connectorv1.GetCapabilitiesRequest, opts ...grpc.CallOption) (*connectorv1.GetCapabilitiesResponse, error) {
|
func (s *stubConnectorClient) GetCapabilities(ctx context.Context, in *connectorv1.GetCapabilitiesRequest, opts ...grpc.CallOption) (*connectorv1.GetCapabilitiesResponse, error) {
|
||||||
@@ -37,10 +43,18 @@ func (s *stubConnectorClient) GetBalance(ctx context.Context, in *connectorv1.Ge
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *stubConnectorClient) SubmitOperation(ctx context.Context, in *connectorv1.SubmitOperationRequest, opts ...grpc.CallOption) (*connectorv1.SubmitOperationResponse, error) {
|
func (s *stubConnectorClient) SubmitOperation(ctx context.Context, in *connectorv1.SubmitOperationRequest, opts ...grpc.CallOption) (*connectorv1.SubmitOperationResponse, error) {
|
||||||
|
s.submitReq = in
|
||||||
|
if s.submitResp != nil {
|
||||||
|
return s.submitResp, nil
|
||||||
|
}
|
||||||
return &connectorv1.SubmitOperationResponse{}, nil
|
return &connectorv1.SubmitOperationResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stubConnectorClient) GetOperation(ctx context.Context, in *connectorv1.GetOperationRequest, opts ...grpc.CallOption) (*connectorv1.GetOperationResponse, error) {
|
func (s *stubConnectorClient) GetOperation(ctx context.Context, in *connectorv1.GetOperationRequest, opts ...grpc.CallOption) (*connectorv1.GetOperationResponse, error) {
|
||||||
|
s.getReq = in
|
||||||
|
if s.getResp != nil {
|
||||||
|
return s.getResp, nil
|
||||||
|
}
|
||||||
return &connectorv1.GetOperationResponse{}, nil
|
return &connectorv1.GetOperationResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,3 +80,84 @@ func TestListManagedWallets_ForwardsOrganizationRef(t *testing.T) {
|
|||||||
require.Equal(t, "owner-1", stub.listReq.GetOwnerRefFilter().GetValue())
|
require.Equal(t, "owner-1", stub.listReq.GetOwnerRefFilter().GetValue())
|
||||||
require.Equal(t, connectorv1.AccountKind_CHAIN_MANAGED_WALLET, stub.listReq.GetKind())
|
require.Equal(t, connectorv1.AccountKind_CHAIN_MANAGED_WALLET, stub.listReq.GetKind())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTransferFromReceipt_PreservesRequestReferences(t *testing.T) {
|
||||||
|
req := &chainv1.SubmitTransferRequest{
|
||||||
|
IdempotencyKey: "idem-1",
|
||||||
|
OrganizationRef: "org-1",
|
||||||
|
SourceWalletRef: "wallet-src",
|
||||||
|
Amount: &moneyv1.Money{Amount: "12.34", Currency: "USDT"},
|
||||||
|
IntentRef: "intent-1",
|
||||||
|
OperationRef: "payment-1:hop_1_crypto_send",
|
||||||
|
PaymentRef: "payment-1",
|
||||||
|
}
|
||||||
|
receipt := &connectorv1.OperationReceipt{
|
||||||
|
OperationId: "payment-1:hop_1_crypto_send",
|
||||||
|
ProviderRef: "provider-1",
|
||||||
|
Status: connectorv1.OperationStatus_OPERATION_WAITING,
|
||||||
|
}
|
||||||
|
|
||||||
|
transfer := transferFromReceipt(req, receipt)
|
||||||
|
require.NotNil(t, transfer)
|
||||||
|
require.Equal(t, "payment-1:hop_1_crypto_send", transfer.GetTransferRef())
|
||||||
|
require.Equal(t, "intent-1", transfer.GetIntentRef())
|
||||||
|
require.Equal(t, "payment-1:hop_1_crypto_send", transfer.GetOperationRef())
|
||||||
|
require.Equal(t, "payment-1", transfer.GetPaymentRef())
|
||||||
|
require.Equal(t, chainv1.TransferStatus_TRANSFER_WAITING, transfer.GetStatus())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSubmitTransfer_ForwardsOperationAndIntentReferences(t *testing.T) {
|
||||||
|
stub := &stubConnectorClient{
|
||||||
|
submitResp: &connectorv1.SubmitOperationResponse{
|
||||||
|
Receipt: &connectorv1.OperationReceipt{
|
||||||
|
OperationId: "payment-1:hop_1_crypto_send",
|
||||||
|
Status: connectorv1.OperationStatus_OPERATION_WAITING,
|
||||||
|
ProviderRef: "provider-1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
client := NewWithClient(Config{}, stub)
|
||||||
|
|
||||||
|
resp, err := client.SubmitTransfer(context.Background(), &chainv1.SubmitTransferRequest{
|
||||||
|
IdempotencyKey: "idem-1",
|
||||||
|
OrganizationRef: "org-1",
|
||||||
|
SourceWalletRef: "wallet-src",
|
||||||
|
Destination: &chainv1.TransferDestination{
|
||||||
|
Destination: &chainv1.TransferDestination_ManagedWalletRef{
|
||||||
|
ManagedWalletRef: "wallet-dst",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Amount: &moneyv1.Money{Amount: "12.34", Currency: "USDT"},
|
||||||
|
IntentRef: "intent-1",
|
||||||
|
OperationRef: "payment-1:hop_1_crypto_send",
|
||||||
|
PaymentRef: "payment-1",
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, stub.submitReq)
|
||||||
|
require.NotNil(t, stub.submitReq.GetOperation())
|
||||||
|
require.Equal(t, "intent-1", stub.submitReq.GetOperation().GetIntentRef())
|
||||||
|
require.Equal(t, "payment-1:hop_1_crypto_send", stub.submitReq.GetOperation().GetOperationRef())
|
||||||
|
require.NotNil(t, resp.GetTransfer())
|
||||||
|
require.Equal(t, "payment-1:hop_1_crypto_send", resp.GetTransfer().GetTransferRef())
|
||||||
|
require.Equal(t, "payment-1:hop_1_crypto_send", resp.GetTransfer().GetOperationRef())
|
||||||
|
require.Equal(t, "intent-1", resp.GetTransfer().GetIntentRef())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetTransfer_UsesTransferRefAsOperationID(t *testing.T) {
|
||||||
|
stub := &stubConnectorClient{
|
||||||
|
getResp: &connectorv1.GetOperationResponse{
|
||||||
|
Operation: &connectorv1.Operation{
|
||||||
|
OperationId: "transfer-1",
|
||||||
|
Status: connectorv1.OperationStatus_OPERATION_PROCESSING,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
client := NewWithClient(Config{}, stub)
|
||||||
|
|
||||||
|
resp, err := client.GetTransfer(context.Background(), &chainv1.GetTransferRequest{TransferRef: "transfer-1"})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, stub.getReq)
|
||||||
|
require.Equal(t, "transfer-1", stub.getReq.GetOperationId())
|
||||||
|
require.NotNil(t, resp.GetTransfer())
|
||||||
|
require.Equal(t, "transfer-1", resp.GetTransfer().GetTransferRef())
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ require (
|
|||||||
github.com/tech/sendico/pkg v0.1.0
|
github.com/tech/sendico/pkg v0.1.0
|
||||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||||
go.uber.org/zap v1.27.1
|
go.uber.org/zap v1.27.1
|
||||||
google.golang.org/grpc v1.79.1
|
google.golang.org/grpc v1.79.2
|
||||||
google.golang.org/protobuf v1.36.11
|
google.golang.org/protobuf v1.36.11
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -375,8 +375,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 h1:
|
|||||||
google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171/go.mod h1:M5krXqk4GhBKvB596udGL3UyjL4I1+cTbK0orROM9ng=
|
google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171/go.mod h1:M5krXqk4GhBKvB596udGL3UyjL4I1+cTbK0orROM9ng=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
Reference in New Issue
Block a user