mirror of
https://github.com/hanzo-fi/payments.git
synced 2026-10-30 20:31:20 +00:00
1495 lines
52 KiB
Go
1495 lines
52 KiB
Go
package workflow
|
|
|
|
import (
|
|
"context"
|
|
"math/big"
|
|
"time"
|
|
|
|
"github.com/hanzo-fi/go-libs/v5/pkg/types/pointer"
|
|
"github.com/hanzo-fi/payments/internal/connectors/engine/activities"
|
|
"github.com/hanzo-fi/payments/pkg/domain/models"
|
|
"github.com/google/uuid"
|
|
"github.com/pkg/errors"
|
|
"github.com/stretchr/testify/mock"
|
|
"go.temporal.io/sdk/temporal"
|
|
"go.temporal.io/sdk/workflow"
|
|
)
|
|
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_Success() {
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, webhook models.Webhook) error {
|
|
return nil
|
|
})
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, req activities.TranslateWebhookRequest) (*models.TranslateWebhookResponse, error) {
|
|
return &models.TranslateWebhookResponse{
|
|
Responses: []models.WebhookResponse{
|
|
{
|
|
Account: &s.pspAccount,
|
|
ExternalAccount: &s.pspAccount,
|
|
Payment: &s.pspPayment,
|
|
Balance: &models.PSPBalance{
|
|
AccountReference: s.pspAccount.Reference,
|
|
CreatedAt: time.Time{},
|
|
Amount: big.NewInt(100),
|
|
Asset: "EUR/2",
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
})
|
|
s.env.OnWorkflow(RunStoreWebhookTranslation, mock.Anything, mock.Anything).Once().Return(func(ctx workflow.Context, req StoreWebhookTranslation) error {
|
|
s.Equal(s.connectorID, req.ConnectorID)
|
|
s.NotNil(req.Account)
|
|
s.Equal(s.accountID.Reference, req.Account.Reference)
|
|
s.NotNil(req.ExternalAccount)
|
|
s.Equal(s.accountID.Reference, req.ExternalAccount.Reference)
|
|
s.NotNil(req.Payment)
|
|
s.Equal(s.paymentPayoutID.Reference, req.Payment.Reference)
|
|
s.NotNil(req.Balance)
|
|
s.Equal(s.pspBalance.AccountReference, req.Balance.AccountReference)
|
|
return nil
|
|
})
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
Webhook: models.Webhook{
|
|
ID: "test",
|
|
ConnectorID: s.connectorID,
|
|
QueryValues: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Headers: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Body: []byte(`{}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.NoError(err)
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_NoResponses_Success() {
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, webhook models.Webhook) error {
|
|
return nil
|
|
})
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, req activities.TranslateWebhookRequest) (*models.TranslateWebhookResponse, error) {
|
|
return &models.TranslateWebhookResponse{
|
|
Responses: []models.WebhookResponse{},
|
|
}, nil
|
|
})
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
Webhook: models.Webhook{
|
|
ID: "test",
|
|
ConnectorID: s.connectorID,
|
|
QueryValues: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Headers: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Body: []byte(`{}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.NoError(err)
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_StorageWebhooksStore_Error() {
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(
|
|
temporal.NewNonRetryableApplicationError("error-test", "error-test", errors.New("error-test")),
|
|
)
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
Webhook: models.Webhook{
|
|
ID: "test",
|
|
ConnectorID: s.connectorID,
|
|
QueryValues: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Headers: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Body: []byte(`{}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.Error(err)
|
|
s.ErrorContains(err, "error-test")
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_PluginTranslateWebhook_Error() {
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(nil)
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(nil,
|
|
temporal.NewNonRetryableApplicationError("error-test", "error-test", errors.New("error-test")),
|
|
)
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
Webhook: models.Webhook{
|
|
ID: "test",
|
|
ConnectorID: s.connectorID,
|
|
QueryValues: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Headers: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Body: []byte(`{}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.Error(err)
|
|
s.ErrorContains(err, "error-test")
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_RunStoreWebhookTranslation_Error() {
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(nil)
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, req activities.TranslateWebhookRequest) (*models.TranslateWebhookResponse, error) {
|
|
return &models.TranslateWebhookResponse{
|
|
Responses: []models.WebhookResponse{
|
|
{
|
|
Account: &s.pspAccount,
|
|
ExternalAccount: &s.pspAccount,
|
|
Payment: &s.pspPayment,
|
|
},
|
|
},
|
|
}, nil
|
|
})
|
|
s.env.OnWorkflow(RunStoreWebhookTranslation, mock.Anything, mock.Anything).Once().Return(
|
|
temporal.NewNonRetryableApplicationError("error-test", "error-test", errors.New("error-test")),
|
|
)
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
Webhook: models.Webhook{
|
|
ID: "test",
|
|
ConnectorID: s.connectorID,
|
|
QueryValues: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Headers: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Body: []byte(`{}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.Error(err)
|
|
s.ErrorContains(err, "error-test")
|
|
}
|
|
|
|
// DataReadyToFetch webhook tests
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_DataReadyToFetch_Success() {
|
|
connectionID := "test-connection-id"
|
|
psuID := uuid.New()
|
|
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(nil)
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, req activities.TranslateWebhookRequest) (*models.TranslateWebhookResponse, error) {
|
|
return &models.TranslateWebhookResponse{
|
|
Responses: []models.WebhookResponse{
|
|
{
|
|
DataReadyToFetch: &models.PSPDataReadyToFetch{
|
|
PSUID: &psuID,
|
|
ConnectionID: &connectionID,
|
|
FromPayload: []byte(`{"test": "data"}`),
|
|
DataToFetch: []models.OpenBankingDataToFetch{
|
|
models.OpenBankingDataToFetchAccountsAndBalances,
|
|
models.OpenBankingDataToFetchPayments,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingConnectionsGetFromConnectionIDActivity, mock.Anything, mock.Anything, mock.Anything).Return(func(ctx context.Context, connectorID models.ConnectorID, connectionID string) (*activities.StorageOpenBankingConnectionsGetFromConnectionIDResult, error) {
|
|
return &activities.StorageOpenBankingConnectionsGetFromConnectionIDResult{
|
|
Connection: &models.OpenBankingConnection{
|
|
ConnectionID: connectionID,
|
|
ConnectorID: s.connectorID,
|
|
CreatedAt: time.Now(),
|
|
Status: models.ConnectionStatusActive,
|
|
},
|
|
PSUID: psuID,
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingForwardedUsersGetActivity, mock.Anything, mock.Anything, mock.Anything).Return(func(ctx context.Context, psuID uuid.UUID, connectorID models.ConnectorID) (*models.OpenBankingForwardedUser, error) {
|
|
return &models.OpenBankingForwardedUser{
|
|
ConnectorID: connectorID,
|
|
AccessToken: &models.Token{
|
|
Token: "test-token",
|
|
ExpiresAt: time.Now().Add(time.Hour),
|
|
},
|
|
}, nil
|
|
})
|
|
s.env.OnWorkflow(RunFetchOpenBankingData, mock.Anything, mock.Anything, mock.Anything).Once().Return(func(ctx workflow.Context, req FetchOpenBankingData, tasks []models.ConnectorTaskTree) error {
|
|
s.Equal(psuID, req.PsuID)
|
|
s.Equal(connectionID, req.ConnectionID)
|
|
s.Equal(s.connectorID, req.ConnectorID)
|
|
s.NotNil(req.FromPayload)
|
|
s.Equal(connectionID, req.FromPayload.ID)
|
|
return nil
|
|
})
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URL: "https://example.com/webhook",
|
|
URLPath: "/webhook",
|
|
Webhook: models.Webhook{
|
|
ID: "test-webhook",
|
|
ConnectorID: s.connectorID,
|
|
Body: []byte(`{"test": "data"}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.NoError(err)
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_DataReadyToFetch_EmptyDataToFetch_Success() {
|
|
connectionID := "test-connection-id"
|
|
psuID := uuid.New()
|
|
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(nil)
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, req activities.TranslateWebhookRequest) (*models.TranslateWebhookResponse, error) {
|
|
return &models.TranslateWebhookResponse{
|
|
Responses: []models.WebhookResponse{
|
|
{
|
|
DataReadyToFetch: &models.PSPDataReadyToFetch{
|
|
PSUID: &psuID,
|
|
ConnectionID: &connectionID,
|
|
FromPayload: []byte(`{"test": "data"}`),
|
|
DataToFetch: []models.OpenBankingDataToFetch{}, // Empty array
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingConnectionsGetFromConnectionIDActivity, mock.Anything, mock.Anything, mock.Anything).Return(func(ctx context.Context, connectorID models.ConnectorID, connectionID string) (*activities.StorageOpenBankingConnectionsGetFromConnectionIDResult, error) {
|
|
return &activities.StorageOpenBankingConnectionsGetFromConnectionIDResult{
|
|
Connection: &models.OpenBankingConnection{
|
|
ConnectionID: connectionID,
|
|
ConnectorID: s.connectorID,
|
|
CreatedAt: time.Now(),
|
|
Status: models.ConnectionStatusActive,
|
|
},
|
|
PSUID: psuID,
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingForwardedUsersGetActivity, mock.Anything, mock.Anything, mock.Anything).Return(func(ctx context.Context, psuID uuid.UUID, connectorID models.ConnectorID) (*models.OpenBankingForwardedUser, error) {
|
|
return &models.OpenBankingForwardedUser{
|
|
ConnectorID: connectorID,
|
|
AccessToken: &models.Token{
|
|
Token: "test-token",
|
|
ExpiresAt: time.Now().Add(time.Hour),
|
|
},
|
|
}, nil
|
|
})
|
|
s.env.OnWorkflow(RunFetchOpenBankingData, mock.Anything, mock.Anything, mock.Anything).Once().Return(func(ctx workflow.Context, req FetchOpenBankingData, tasks []models.ConnectorTaskTree) error {
|
|
s.Equal(psuID, req.PsuID)
|
|
s.Equal(connectionID, req.ConnectionID)
|
|
s.Equal(s.connectorID, req.ConnectorID)
|
|
s.NotNil(req.FromPayload)
|
|
s.Equal(connectionID, req.FromPayload.ID)
|
|
s.Equal([]models.OpenBankingDataToFetch{}, req.DataToFetch)
|
|
// The actual error handling for empty DataToFetch is tested in fetch_open_banking_data tests
|
|
// Here we just verify the webhook processing works correctly
|
|
return nil
|
|
})
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URL: "https://example.com/webhook",
|
|
URLPath: "/webhook",
|
|
Webhook: models.Webhook{
|
|
ID: "test-webhook",
|
|
ConnectorID: s.connectorID,
|
|
Body: []byte(`{"test": "data"}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.NoError(err)
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_DataReadyToFetch_AccountsAndBalancesSimultaneously_Success() {
|
|
connectionID := "test-connection-id"
|
|
psuID := uuid.New()
|
|
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(nil)
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, req activities.TranslateWebhookRequest) (*models.TranslateWebhookResponse, error) {
|
|
return &models.TranslateWebhookResponse{
|
|
Responses: []models.WebhookResponse{
|
|
{
|
|
DataReadyToFetch: &models.PSPDataReadyToFetch{
|
|
PSUID: &psuID,
|
|
ConnectionID: &connectionID,
|
|
FromPayload: []byte(`{"test": "data"}`),
|
|
DataToFetch: []models.OpenBankingDataToFetch{
|
|
models.OpenBankingDataToFetchAccountsAndBalances,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingConnectionsGetFromConnectionIDActivity, mock.Anything, mock.Anything, mock.Anything).Return(func(ctx context.Context, connectorID models.ConnectorID, connectionID string) (*activities.StorageOpenBankingConnectionsGetFromConnectionIDResult, error) {
|
|
return &activities.StorageOpenBankingConnectionsGetFromConnectionIDResult{
|
|
Connection: &models.OpenBankingConnection{
|
|
ConnectionID: connectionID,
|
|
ConnectorID: s.connectorID,
|
|
CreatedAt: time.Now(),
|
|
Status: models.ConnectionStatusActive,
|
|
},
|
|
PSUID: psuID,
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingForwardedUsersGetActivity, mock.Anything, mock.Anything, mock.Anything).Return(func(ctx context.Context, psuID uuid.UUID, connectorID models.ConnectorID) (*models.OpenBankingForwardedUser, error) {
|
|
return &models.OpenBankingForwardedUser{
|
|
ConnectorID: connectorID,
|
|
AccessToken: &models.Token{
|
|
Token: "test-token",
|
|
ExpiresAt: time.Now().Add(time.Hour),
|
|
},
|
|
}, nil
|
|
})
|
|
s.env.OnWorkflow(RunFetchOpenBankingData, mock.Anything, mock.Anything, mock.Anything).Once().Return(func(ctx workflow.Context, req FetchOpenBankingData, tasks []models.ConnectorTaskTree) error {
|
|
s.Equal(psuID, req.PsuID)
|
|
s.Equal(connectionID, req.ConnectionID)
|
|
s.Equal(s.connectorID, req.ConnectorID)
|
|
s.NotNil(req.FromPayload)
|
|
s.Equal(connectionID, req.FromPayload.ID)
|
|
s.Equal([]models.OpenBankingDataToFetch{models.OpenBankingDataToFetchAccountsAndBalances}, req.DataToFetch)
|
|
return nil
|
|
})
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URL: "https://example.com/webhook",
|
|
URLPath: "/webhook",
|
|
Webhook: models.Webhook{
|
|
ID: "test-webhook",
|
|
ConnectorID: s.connectorID,
|
|
Body: []byte(`{"test": "data"}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.NoError(err)
|
|
}
|
|
|
|
// UserLinkSessionFinished webhook tests
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_UserLinkSessionFinished_Success() {
|
|
attemptID := uuid.New()
|
|
status := models.OpenBankingConnectionAttemptStatusCompleted
|
|
errorMsg := "test error"
|
|
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(nil)
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, req activities.TranslateWebhookRequest) (*models.TranslateWebhookResponse, error) {
|
|
return &models.TranslateWebhookResponse{
|
|
Responses: []models.WebhookResponse{
|
|
{
|
|
UserLinkSessionFinished: &models.PSPUserLinkSessionFinished{
|
|
AttemptID: attemptID,
|
|
Status: status,
|
|
Error: &errorMsg,
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingConnectionAttemptsUpdateStatusActivity, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Once().Return(nil)
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
Webhook: models.Webhook{
|
|
ID: "test",
|
|
ConnectorID: s.connectorID,
|
|
QueryValues: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Headers: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Body: []byte(`{}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.NoError(err)
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_UserLinkSessionFinished_UpdateStatus_Error() {
|
|
attemptID := uuid.New()
|
|
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(nil)
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, req activities.TranslateWebhookRequest) (*models.TranslateWebhookResponse, error) {
|
|
return &models.TranslateWebhookResponse{
|
|
Responses: []models.WebhookResponse{
|
|
{
|
|
UserLinkSessionFinished: &models.PSPUserLinkSessionFinished{
|
|
AttemptID: attemptID,
|
|
Status: models.OpenBankingConnectionAttemptStatusCompleted,
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingConnectionAttemptsUpdateStatusActivity, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Once().Return(
|
|
temporal.NewNonRetryableApplicationError("error-test", "error-test", errors.New("error-test")),
|
|
)
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
Webhook: models.Webhook{
|
|
ID: "test",
|
|
ConnectorID: s.connectorID,
|
|
QueryValues: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Headers: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Body: []byte(`{}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.Error(err)
|
|
s.ErrorContains(err, "error-test")
|
|
}
|
|
|
|
// UserConnectionPendingDisconnect webhook tests
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_UserConnectionPendingDisconnect_Success() {
|
|
connectionID := "test-connection-id"
|
|
psuID := uuid.New()
|
|
reason := "test reason"
|
|
at := time.Now()
|
|
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(nil)
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, req activities.TranslateWebhookRequest) (*models.TranslateWebhookResponse, error) {
|
|
return &models.TranslateWebhookResponse{
|
|
Responses: []models.WebhookResponse{
|
|
{
|
|
UserConnectionPendingDisconnect: &models.PSPUserConnectionPendingDisconnect{
|
|
ConnectionID: connectionID,
|
|
At: at,
|
|
Reason: &reason,
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingConnectionsGetFromConnectionIDActivity, mock.Anything, mock.Anything, mock.Anything).Return(func(ctx context.Context, connectorID models.ConnectorID, connectionID string) (*activities.StorageOpenBankingConnectionsGetFromConnectionIDResult, error) {
|
|
return &activities.StorageOpenBankingConnectionsGetFromConnectionIDResult{
|
|
Connection: &models.OpenBankingConnection{
|
|
ConnectionID: connectionID,
|
|
ConnectorID: s.connectorID,
|
|
Status: models.ConnectionStatusActive,
|
|
},
|
|
PSUID: psuID,
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOutboxEventsInsertActivity, mock.Anything, mock.Anything).Once().Return(nil)
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
Webhook: models.Webhook{
|
|
ID: "test",
|
|
ConnectorID: s.connectorID,
|
|
QueryValues: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Headers: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Body: []byte(`{}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.NoError(err)
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_UserConnectionPendingDisconnect_StoragePSUOpenBankingConnectionsGetFromConnectionID_Error() {
|
|
connectionID := "test-connection-id"
|
|
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(nil)
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, req activities.TranslateWebhookRequest) (*models.TranslateWebhookResponse, error) {
|
|
return &models.TranslateWebhookResponse{
|
|
Responses: []models.WebhookResponse{
|
|
{
|
|
UserConnectionPendingDisconnect: &models.PSPUserConnectionPendingDisconnect{
|
|
ConnectionID: connectionID,
|
|
At: time.Now(),
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingConnectionsGetFromConnectionIDActivity, mock.Anything, mock.Anything, mock.Anything).Return(
|
|
(*activities.StorageOpenBankingConnectionsGetFromConnectionIDResult)(nil), temporal.NewNonRetryableApplicationError("error-test", "error-test", errors.New("error-test")),
|
|
)
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
Webhook: models.Webhook{
|
|
ID: "test",
|
|
ConnectorID: s.connectorID,
|
|
QueryValues: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Headers: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Body: []byte(`{}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.Error(err)
|
|
s.ErrorContains(err, "error-test")
|
|
}
|
|
|
|
// Balance webhook tests
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_Balance_Success() {
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(nil)
|
|
createdAt := time.Now()
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, req activities.TranslateWebhookRequest) (*models.TranslateWebhookResponse, error) {
|
|
return &models.TranslateWebhookResponse{
|
|
Responses: []models.WebhookResponse{
|
|
{
|
|
Balance: &models.PSPBalance{
|
|
AccountReference: s.pspAccount.Reference,
|
|
Amount: big.NewInt(100),
|
|
Asset: "EUR/2",
|
|
CreatedAt: createdAt,
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageAccountsGetActivity, mock.Anything, mock.Anything).Once().Return(
|
|
&s.account, nil)
|
|
s.env.OnActivity(activities.StorageBalancesStoreActivity, mock.Anything, mock.Anything).Once().Return(
|
|
nil,
|
|
)
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
Webhook: models.Webhook{
|
|
ID: "test",
|
|
ConnectorID: s.connectorID,
|
|
QueryValues: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Headers: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Body: []byte(`{}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.NoError(err)
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_Balance_StorageAccountsGet_Error() {
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(nil)
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, req activities.TranslateWebhookRequest) (*models.TranslateWebhookResponse, error) {
|
|
return &models.TranslateWebhookResponse{
|
|
Responses: []models.WebhookResponse{
|
|
{
|
|
Balance: &models.PSPBalance{
|
|
AccountReference: s.pspAccount.Reference,
|
|
Amount: big.NewInt(100),
|
|
Asset: "EUR/2",
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageAccountsGetActivity, mock.Anything, mock.Anything).Once().Return(
|
|
(*models.Account)(nil), temporal.NewNonRetryableApplicationError("error-test", "error-test", errors.New("error-test")),
|
|
)
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
Webhook: models.Webhook{
|
|
ID: "test",
|
|
ConnectorID: s.connectorID,
|
|
QueryValues: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Headers: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Body: []byte(`{}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.Error(err)
|
|
s.ErrorContains(err, "error-test")
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_Balance_TranslateBalance_Error() {
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(nil)
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, req activities.TranslateWebhookRequest) (*models.TranslateWebhookResponse, error) {
|
|
return &models.TranslateWebhookResponse{
|
|
Responses: []models.WebhookResponse{
|
|
{
|
|
Balance: &models.PSPBalance{
|
|
AccountReference: s.pspAccount.Reference,
|
|
Amount: big.NewInt(100),
|
|
Asset: "EUR/2",
|
|
|
|
// I do not pass CreatedAt to fail validation
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
})
|
|
|
|
s.env.OnActivity(
|
|
activities.StorageAccountsGetActivity, mock.Anything, mock.Anything).Return(&s.account, nil)
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
Webhook: models.Webhook{
|
|
ID: "test",
|
|
ConnectorID: s.connectorID,
|
|
QueryValues: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Headers: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Body: []byte(`{}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.Error(err)
|
|
s.ErrorContains(err, "failed to translate balances")
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_Balance_Store_Error() {
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(nil)
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, req activities.TranslateWebhookRequest) (*models.TranslateWebhookResponse, error) {
|
|
return &models.TranslateWebhookResponse{
|
|
Responses: []models.WebhookResponse{
|
|
{
|
|
Balance: &models.PSPBalance{
|
|
AccountReference: s.pspAccount.Reference,
|
|
Amount: big.NewInt(100),
|
|
Asset: "EUR/2",
|
|
CreatedAt: time.Now(),
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageAccountsGetActivity, mock.Anything, mock.Anything).Once().Return(
|
|
&s.account, nil)
|
|
s.env.OnActivity(activities.StorageBalancesStoreActivity, mock.Anything, mock.Anything).Once().Return(
|
|
temporal.NewNonRetryableApplicationError("error-test", "STORAGE", errors.New("error-test")),
|
|
)
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
Webhook: models.Webhook{
|
|
ID: "test",
|
|
ConnectorID: s.connectorID,
|
|
QueryValues: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Headers: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Body: []byte(`{}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.Error(err)
|
|
s.ErrorContains(err, "error-test")
|
|
}
|
|
|
|
// UserConnectionDisconnected webhook tests
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_UserConnectionDisconnected_Success() {
|
|
connectionID := "test-connection-id"
|
|
psuID := uuid.New()
|
|
reason := "test reason"
|
|
at := time.Now()
|
|
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(nil)
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, req activities.TranslateWebhookRequest) (*models.TranslateWebhookResponse, error) {
|
|
return &models.TranslateWebhookResponse{
|
|
Responses: []models.WebhookResponse{
|
|
{
|
|
UserConnectionDisconnected: &models.PSPUserConnectionDisconnected{
|
|
ConnectionID: connectionID,
|
|
At: at,
|
|
ErrorType: models.ConnectionDisconnectedErrorTypeUserActionNeeded,
|
|
Reason: &reason,
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingConnectionsGetFromConnectionIDActivity, mock.Anything, mock.Anything, mock.Anything).Return(func(ctx context.Context, connectorID models.ConnectorID, connectionID string) (*activities.StorageOpenBankingConnectionsGetFromConnectionIDResult, error) {
|
|
return &activities.StorageOpenBankingConnectionsGetFromConnectionIDResult{
|
|
Connection: &models.OpenBankingConnection{
|
|
ConnectionID: connectionID,
|
|
ConnectorID: s.connectorID,
|
|
Status: models.ConnectionStatusActive,
|
|
},
|
|
PSUID: psuID,
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingConnectionsStoreActivity, mock.Anything, mock.Anything, mock.Anything).Once().Return(nil)
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
Webhook: models.Webhook{
|
|
ID: "test",
|
|
ConnectorID: s.connectorID,
|
|
QueryValues: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Headers: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Body: []byte(`{}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.NoError(err)
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_UserConnectionDisconnected_Success_Without_Connection_Created() {
|
|
connectionID := "test-connection-id"
|
|
pspUserID := "test-psp-user-id"
|
|
psuID := uuid.New()
|
|
reason := "test reason"
|
|
at := time.Now()
|
|
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(nil)
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, req activities.TranslateWebhookRequest) (*models.TranslateWebhookResponse, error) {
|
|
return &models.TranslateWebhookResponse{
|
|
Responses: []models.WebhookResponse{
|
|
{
|
|
UserConnectionDisconnected: &models.PSPUserConnectionDisconnected{
|
|
PSPUserID: pspUserID,
|
|
ConnectionID: connectionID,
|
|
At: at,
|
|
Reason: &reason,
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingConnectionsGetFromConnectionIDActivity, mock.Anything, mock.Anything, mock.Anything).Return(func(ctx context.Context, connectorID models.ConnectorID, connectionID string) (*activities.StorageOpenBankingConnectionsGetFromConnectionIDResult, error) {
|
|
return nil, temporal.NewNonRetryableApplicationError("error-test", "error-test", errors.New("error-test"))
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingForwardedUsersGetByPSPUserIDActivity, mock.Anything, pspUserID, s.connectorID).Return(&models.OpenBankingForwardedUser{
|
|
PsuID: psuID,
|
|
ConnectorID: s.connectorID,
|
|
PSPUserID: &pspUserID,
|
|
}, nil)
|
|
s.env.OnActivity(activities.StorageOpenBankingConnectionsStoreActivity, mock.Anything, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, id uuid.UUID, from models.OpenBankingConnection) error {
|
|
s.Equal(id, psuID)
|
|
s.Equal(from.ConnectionID, connectionID)
|
|
s.Equal(from.ConnectorID, s.connectorID)
|
|
s.Equal(from.Status, models.ConnectionStatusError)
|
|
s.Equal(from.Error, pointer.For("test reason"))
|
|
return nil
|
|
})
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
Webhook: models.Webhook{
|
|
ID: "test",
|
|
ConnectorID: s.connectorID,
|
|
QueryValues: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Headers: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Body: []byte(`{}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.NoError(err)
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_UserConnectionDisconnected_StorageOpenBankingConnectionsGetFromConnectionID_Error() {
|
|
connectionID := "test-connection-id"
|
|
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(nil)
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, req activities.TranslateWebhookRequest) (*models.TranslateWebhookResponse, error) {
|
|
return &models.TranslateWebhookResponse{
|
|
Responses: []models.WebhookResponse{
|
|
{
|
|
UserConnectionDisconnected: &models.PSPUserConnectionDisconnected{
|
|
ConnectionID: connectionID,
|
|
ErrorType: models.ConnectionDisconnectedErrorTypeUserActionNeeded,
|
|
At: time.Now(),
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingConnectionsGetFromConnectionIDActivity, mock.Anything, mock.Anything, mock.Anything).Return(
|
|
(*activities.StorageOpenBankingConnectionsGetFromConnectionIDResult)(nil), temporal.NewNonRetryableApplicationError("error-test", "error-test", errors.New("error-test")),
|
|
)
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
Webhook: models.Webhook{
|
|
ID: "test",
|
|
ConnectorID: s.connectorID,
|
|
QueryValues: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Headers: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Body: []byte(`{}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.Error(err)
|
|
s.ErrorContains(err, "error-test")
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_UserConnectionDisconnected_StorageOpenBankingConnectionsStore_Error() {
|
|
connectionID := "test-connection-id"
|
|
psuID := uuid.New()
|
|
reason := "test reason"
|
|
at := time.Now()
|
|
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(nil)
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, req activities.TranslateWebhookRequest) (*models.TranslateWebhookResponse, error) {
|
|
return &models.TranslateWebhookResponse{
|
|
Responses: []models.WebhookResponse{
|
|
{
|
|
UserConnectionDisconnected: &models.PSPUserConnectionDisconnected{
|
|
ConnectionID: connectionID,
|
|
At: at,
|
|
ErrorType: models.ConnectionDisconnectedErrorTypeUserActionNeeded,
|
|
Reason: &reason,
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingConnectionsGetFromConnectionIDActivity, mock.Anything, mock.Anything, mock.Anything).Return(func(ctx context.Context, connectorID models.ConnectorID, connectionID string) (*activities.StorageOpenBankingConnectionsGetFromConnectionIDResult, error) {
|
|
return &activities.StorageOpenBankingConnectionsGetFromConnectionIDResult{
|
|
Connection: &models.OpenBankingConnection{
|
|
ConnectionID: connectionID,
|
|
ConnectorID: s.connectorID,
|
|
Status: models.ConnectionStatusActive,
|
|
},
|
|
PSUID: psuID,
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingConnectionsStoreActivity, mock.Anything, mock.Anything, mock.Anything).Once().Return(
|
|
temporal.NewNonRetryableApplicationError("error-test", "error-test", errors.New("error-test")),
|
|
)
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
Webhook: models.Webhook{
|
|
ID: "test",
|
|
ConnectorID: s.connectorID,
|
|
QueryValues: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Headers: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Body: []byte(`{}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.Error(err)
|
|
s.ErrorContains(err, "error-test")
|
|
}
|
|
|
|
// UserConnectionReconnected webhook tests
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_UserConnectionReconnected_Success() {
|
|
connectionID := "test-connection-id"
|
|
psuID := uuid.New()
|
|
at := time.Now()
|
|
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(nil)
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, req activities.TranslateWebhookRequest) (*models.TranslateWebhookResponse, error) {
|
|
return &models.TranslateWebhookResponse{
|
|
Responses: []models.WebhookResponse{
|
|
{
|
|
UserConnectionReconnected: &models.PSPUserConnectionReconnected{
|
|
ConnectionID: connectionID,
|
|
At: at,
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingConnectionsGetFromConnectionIDActivity, mock.Anything, mock.Anything, mock.Anything).Return(func(ctx context.Context, connectorID models.ConnectorID, connectionID string) (*activities.StorageOpenBankingConnectionsGetFromConnectionIDResult, error) {
|
|
return &activities.StorageOpenBankingConnectionsGetFromConnectionIDResult{
|
|
Connection: &models.OpenBankingConnection{
|
|
ConnectionID: connectionID,
|
|
ConnectorID: s.connectorID,
|
|
Status: models.ConnectionStatusActive,
|
|
},
|
|
PSUID: psuID,
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingConnectionsStoreActivity, mock.Anything, mock.Anything, mock.Anything).Once().Return(nil)
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
Webhook: models.Webhook{
|
|
ID: "test",
|
|
ConnectorID: s.connectorID,
|
|
QueryValues: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Headers: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Body: []byte(`{}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.NoError(err)
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_UserConnectionReconnected_Success_Without_Connection_Created() {
|
|
connectionID := "test-connection-id"
|
|
pspUserID := "test-psp-user-id"
|
|
psuID := uuid.New()
|
|
at := time.Now()
|
|
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(nil)
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, req activities.TranslateWebhookRequest) (*models.TranslateWebhookResponse, error) {
|
|
return &models.TranslateWebhookResponse{
|
|
Responses: []models.WebhookResponse{
|
|
{
|
|
UserConnectionReconnected: &models.PSPUserConnectionReconnected{
|
|
PSPUserID: pspUserID,
|
|
ConnectionID: connectionID,
|
|
At: at,
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingConnectionsGetFromConnectionIDActivity, mock.Anything, mock.Anything, mock.Anything).Return(func(ctx context.Context, connectorID models.ConnectorID, connectionID string) (*activities.StorageOpenBankingConnectionsGetFromConnectionIDResult, error) {
|
|
return nil, temporal.NewNonRetryableApplicationError("error-test", "error-test", errors.New("error-test"))
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingForwardedUsersGetByPSPUserIDActivity, mock.Anything, pspUserID, s.connectorID).Return(&models.OpenBankingForwardedUser{
|
|
PsuID: psuID,
|
|
ConnectorID: s.connectorID,
|
|
PSPUserID: &pspUserID,
|
|
}, nil)
|
|
s.env.OnActivity(activities.StorageOpenBankingConnectionsStoreActivity, mock.Anything, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, id uuid.UUID, from models.OpenBankingConnection) error {
|
|
s.Equal(id, psuID)
|
|
s.Equal(from.ConnectionID, connectionID)
|
|
s.Equal(from.ConnectorID, s.connectorID)
|
|
s.Equal(from.Status, models.ConnectionStatusActive)
|
|
return nil
|
|
})
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
Webhook: models.Webhook{
|
|
ID: "test",
|
|
ConnectorID: s.connectorID,
|
|
QueryValues: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Headers: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Body: []byte(`{}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.NoError(err)
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_UserConnectionReconnected_StorageOpenBankingConnectionsGetFromConnectionID_Error() {
|
|
connectionID := "test-connection-id"
|
|
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(nil)
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, req activities.TranslateWebhookRequest) (*models.TranslateWebhookResponse, error) {
|
|
return &models.TranslateWebhookResponse{
|
|
Responses: []models.WebhookResponse{
|
|
{
|
|
UserConnectionReconnected: &models.PSPUserConnectionReconnected{
|
|
ConnectionID: connectionID,
|
|
At: time.Now(),
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingConnectionsGetFromConnectionIDActivity, mock.Anything, mock.Anything, mock.Anything).Return(
|
|
(*activities.StorageOpenBankingConnectionsGetFromConnectionIDResult)(nil), temporal.NewNonRetryableApplicationError("error-test", "error-test", errors.New("error-test")),
|
|
)
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
Webhook: models.Webhook{
|
|
ID: "test",
|
|
ConnectorID: s.connectorID,
|
|
QueryValues: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Headers: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Body: []byte(`{}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.Error(err)
|
|
s.ErrorContains(err, "error-test")
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_UserConnectionReconnected_StorageOpenBankingConnectionsStore_Error() {
|
|
connectionID := "test-connection-id"
|
|
psuID := uuid.New()
|
|
at := time.Now()
|
|
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(nil)
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, req activities.TranslateWebhookRequest) (*models.TranslateWebhookResponse, error) {
|
|
return &models.TranslateWebhookResponse{
|
|
Responses: []models.WebhookResponse{
|
|
{
|
|
UserConnectionReconnected: &models.PSPUserConnectionReconnected{
|
|
ConnectionID: connectionID,
|
|
At: at,
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingConnectionsGetFromConnectionIDActivity, mock.Anything, mock.Anything, mock.Anything).Return(func(ctx context.Context, connectorID models.ConnectorID, connectionID string) (*activities.StorageOpenBankingConnectionsGetFromConnectionIDResult, error) {
|
|
return &activities.StorageOpenBankingConnectionsGetFromConnectionIDResult{
|
|
Connection: &models.OpenBankingConnection{
|
|
ConnectionID: connectionID,
|
|
ConnectorID: s.connectorID,
|
|
Status: models.ConnectionStatusActive,
|
|
},
|
|
PSUID: psuID,
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingConnectionsStoreActivity, mock.Anything, mock.Anything, mock.Anything).Once().Return(
|
|
temporal.NewNonRetryableApplicationError("error-test", "error-test", errors.New("error-test")),
|
|
)
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
Webhook: models.Webhook{
|
|
ID: "test",
|
|
ConnectorID: s.connectorID,
|
|
QueryValues: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Headers: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Body: []byte(`{}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.Error(err)
|
|
s.ErrorContains(err, "error-test")
|
|
}
|
|
|
|
// Multiple webhook responses test
|
|
func (s *UnitTestSuite) Test_HandleWebhooks_MultipleResponses_Success() {
|
|
connectionID := "test-connection-id"
|
|
attemptID := uuid.New()
|
|
psuID := uuid.New()
|
|
|
|
s.env.OnActivity(activities.StorageWebhooksStoreActivity, mock.Anything, mock.Anything).Once().Return(nil)
|
|
s.env.OnActivity(activities.PluginTranslateWebhookActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, req activities.TranslateWebhookRequest) (*models.TranslateWebhookResponse, error) {
|
|
return &models.TranslateWebhookResponse{
|
|
Responses: []models.WebhookResponse{
|
|
{
|
|
Account: &s.pspAccount,
|
|
},
|
|
{
|
|
DataReadyToFetch: &models.PSPDataReadyToFetch{
|
|
PSUID: &psuID,
|
|
ConnectionID: &connectionID,
|
|
FromPayload: []byte(`{"test": "data"}`),
|
|
DataToFetch: []models.OpenBankingDataToFetch{
|
|
models.OpenBankingDataToFetchAccountsAndBalances,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
UserLinkSessionFinished: &models.PSPUserLinkSessionFinished{
|
|
AttemptID: attemptID,
|
|
Status: models.OpenBankingConnectionAttemptStatusCompleted,
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
})
|
|
|
|
// Mock for DataReadyToFetch
|
|
s.env.OnActivity(activities.StorageOpenBankingConnectionsGetFromConnectionIDActivity, mock.Anything, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, connectorID models.ConnectorID, connectionID string) (*activities.StorageOpenBankingConnectionsGetFromConnectionIDResult, error) {
|
|
return &activities.StorageOpenBankingConnectionsGetFromConnectionIDResult{
|
|
Connection: &models.OpenBankingConnection{
|
|
ConnectionID: connectionID,
|
|
ConnectorID: s.connectorID,
|
|
Status: models.ConnectionStatusActive,
|
|
},
|
|
PSUID: uuid.New(),
|
|
}, nil
|
|
})
|
|
s.env.OnActivity(activities.StorageOpenBankingForwardedUsersGetActivity, mock.Anything, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, psuID uuid.UUID, connectorID models.ConnectorID) (*models.OpenBankingForwardedUser, error) {
|
|
return &models.OpenBankingForwardedUser{
|
|
ConnectorID: connectorID,
|
|
}, nil
|
|
})
|
|
s.env.OnWorkflow(RunFetchOpenBankingData, mock.Anything, mock.Anything, mock.Anything).Once().Return(func(ctx workflow.Context, req FetchOpenBankingData, tasks []models.ConnectorTaskTree) error {
|
|
return nil
|
|
})
|
|
|
|
// Mock for UserLinkSessionFinished
|
|
s.env.OnActivity(activities.StorageOpenBankingConnectionAttemptsUpdateStatusActivity, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Once().Return(nil)
|
|
|
|
// Mock for Account (default case)
|
|
s.env.OnWorkflow(RunStoreWebhookTranslation, mock.Anything, mock.Anything).Once().Return(func(ctx workflow.Context, req StoreWebhookTranslation) error {
|
|
s.Equal(s.connectorID, req.ConnectorID)
|
|
s.NotNil(req.Account)
|
|
s.Equal(s.accountID.Reference, req.Account.Reference)
|
|
return nil
|
|
})
|
|
|
|
s.env.ExecuteWorkflow(RunHandleWebhooks, HandleWebhooks{
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
Webhook: models.Webhook{
|
|
ID: "test",
|
|
ConnectorID: s.connectorID,
|
|
QueryValues: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Headers: map[string][]string{
|
|
"test": {"test"},
|
|
},
|
|
Body: []byte(`{}`),
|
|
},
|
|
Config: &models.WebhookConfig{
|
|
Name: "test",
|
|
ConnectorID: s.connectorID,
|
|
URLPath: "/test",
|
|
},
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.NoError(err)
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_StoreWebhookTranslation_Empty_Success() {
|
|
s.env.ExecuteWorkflow(RunStoreWebhookTranslation, StoreWebhookTranslation{
|
|
ConnectorID: s.connectorID,
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.NoError(err)
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_StoreWebhookTranslation_Account_Success() {
|
|
s.env.OnActivity(activities.StorageAccountsStoreActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, accounts []models.Account) error {
|
|
s.Len(accounts, 1)
|
|
s.Equal(s.accountID, accounts[0].ID)
|
|
return nil
|
|
})
|
|
|
|
s.env.ExecuteWorkflow(RunStoreWebhookTranslation, StoreWebhookTranslation{
|
|
ConnectorID: s.connectorID,
|
|
Account: &s.pspAccount,
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.NoError(err)
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_StoreWebhookTranslation_Account_StorageAccountsStore_Error() {
|
|
expectedErr := errors.New("error-test")
|
|
s.env.OnActivity(activities.StorageAccountsStoreActivity, mock.Anything, mock.Anything).Once().Return(
|
|
temporal.NewNonRetryableApplicationError("error-test", "STORAGE", expectedErr),
|
|
)
|
|
|
|
s.env.ExecuteWorkflow(RunStoreWebhookTranslation, StoreWebhookTranslation{
|
|
ConnectorID: s.connectorID,
|
|
Account: &s.pspAccount,
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.Error(err)
|
|
s.ErrorContains(err, expectedErr.Error())
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_StoreWebhookTranslation_ExternalAccount_Success() {
|
|
s.env.OnActivity(activities.StorageAccountsStoreActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, accounts []models.Account) error {
|
|
s.Len(accounts, 1)
|
|
s.Equal(s.accountID, accounts[0].ID)
|
|
return nil
|
|
})
|
|
|
|
s.env.ExecuteWorkflow(RunStoreWebhookTranslation, StoreWebhookTranslation{
|
|
ConnectorID: s.connectorID,
|
|
ExternalAccount: &s.pspAccount,
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.NoError(err)
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_StoreWebhookTranslation_ExternalAccount_StorageAccountsStore_Error() {
|
|
expectedErr := errors.New("error-test")
|
|
s.env.OnActivity(activities.StorageAccountsStoreActivity, mock.Anything, mock.Anything).Once().Return(
|
|
temporal.NewNonRetryableApplicationError("error-test", "STORAGE", expectedErr),
|
|
)
|
|
|
|
s.env.ExecuteWorkflow(RunStoreWebhookTranslation, StoreWebhookTranslation{
|
|
ConnectorID: s.connectorID,
|
|
ExternalAccount: &s.pspAccount,
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.Error(err)
|
|
s.ErrorContains(err, "error-test")
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_StoreWebhookTranslation_Payment_Success() {
|
|
s.env.OnActivity(activities.StoragePaymentsStoreActivity, mock.Anything, mock.Anything).Once().Return(func(ctx context.Context, payments []models.Payment) error {
|
|
s.Len(payments, 1)
|
|
s.Equal(s.paymentPayoutID, payments[0].ID)
|
|
return nil
|
|
})
|
|
|
|
s.env.ExecuteWorkflow(RunStoreWebhookTranslation, StoreWebhookTranslation{
|
|
ConnectorID: s.connectorID,
|
|
Payment: &s.pspPayment,
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.NoError(err)
|
|
}
|
|
|
|
func (s *UnitTestSuite) Test_StoreWebhookTranslation_Payment_StoragePaymentsStore_Error() {
|
|
expectedErr := errors.New("error-test")
|
|
s.env.OnActivity(activities.StoragePaymentsStoreActivity, mock.Anything, mock.Anything).Once().Return(
|
|
temporal.NewNonRetryableApplicationError("error-test", "STORAGE", expectedErr),
|
|
)
|
|
|
|
s.env.ExecuteWorkflow(RunStoreWebhookTranslation, StoreWebhookTranslation{
|
|
ConnectorID: s.connectorID,
|
|
Payment: &s.pspPayment,
|
|
})
|
|
|
|
s.True(s.env.IsWorkflowCompleted())
|
|
err := s.env.GetWorkflowError()
|
|
s.Error(err)
|
|
s.ErrorContains(err, expectedErr.Error())
|
|
}
|