Files
fgueryandGitHub 599477b709 fix(EN-549): remove config and connector dependencies (#622)
* chore: rename RunNextTasks workflow

* feat: added a trimmed down type for connector only containing the id

* feat: make runNextTask use connectorIdOnly

* feat: added isScheduledForDeletion to plugin interface

* feat: add scheduledForDeletion at plugin level

* feat: refactor manager.Load to take a connector instead of parts of it

* feat: saves the connector's scheduledFOrDeletion into the plugin

* feat: use plugin.IsScheduledForDeletion instead of loading connector

* fix: make e2e tests less flaky

* fix: remove config from most request types

* feat: (WIP) remove config from runNextTask

* fix: remove unneeded method definitions in each plugin

* fix: simplify RunNextFlow as anyway we need to change the parameters

* fix: add a workflow compatible with previous version for runNextTasks

* fix(EN-577): added back RunSendEvents as a deprecated workflow

* fix(EN-577): added back RunUpdatePaymentInitiationFromPayment as a deprecated workflow

* fix: fix linting directives

* fix: replace old usage with refactored one

* fix: added back missing deprecated activities

* fix: ensure fetch_next_balance works with v3.0 code

* fix: simplify a bit the versionning etc

* fix: quick refactor before applying solution elsewhere

* fix: add back RunSendEvents and RunNextTask child workflows where necessary for backward compatibility

* fix: add back missing activity, seems like it's mandatory?

* fix: run payment initiation update as child workflow when necessary

* fix: missing activy call in test, refine some todos

* fix: lint

* fix: ensure we always reload plugins into the manager -- so exposing isScheduledForDeletion

* fix: ensure we stop storing clear config in temporal

* fix: make store config support plain text config

* fix: some comments

* fix: change runSendEvent workflow to be match what we had in 3.0

* feat: enable worker versionning to avoid workflow from new version to get executed on old code

* fix: lint

* fix: revert worker versionning

* fix: minor code review comments

* fix: add context to Encrypt & Decrypt methods

* fix: improve lint, add couple tests

* fix: use atomic to handle isScheduledForDeletion

* fix: make create_events work on migration

* fix: avoid returning channel; just send what is needed in runSendEventAsChildWorkflow and runNextTaskAsChildWorkflow

* fix: remove extra call to installWorkflow on start plugin

* fix: typo in error log line

* fix: simplify errChan initialization

* fix: clarify feature flag names
2026-01-05 11:09:45 +00:00

393 lines
10 KiB
Go

package workflow
import (
"encoding/json"
"math/big"
"testing"
"time"
"github.com/formancehq/go-libs/v3/logging"
"github.com/formancehq/go-libs/v3/pointer"
"github.com/formancehq/payments/internal/connectors"
"github.com/formancehq/payments/internal/connectors/engine/activities"
"github.com/formancehq/payments/internal/connectors/plugins/public/dummypay"
"github.com/formancehq/payments/internal/connectors/plugins/registry"
"github.com/formancehq/payments/internal/models"
"github.com/google/uuid"
"github.com/stretchr/testify/suite"
"go.temporal.io/sdk/testsuite"
temporalworkflow "go.temporal.io/sdk/workflow"
)
type UnitTestSuite struct {
suite.Suite
testsuite.WorkflowTestSuite
w *Workflow
a *activities.Activities
env *testsuite.TestWorkflowEnvironment
connectorID models.ConnectorID
accountID models.AccountID
paymentPayoutID models.PaymentID
paymentInitiationID models.PaymentInitiationID
paymentReversalID models.PaymentInitiationReversalID
connector models.Connector
configuredConnector models.Connector
bankAccount models.BankAccount
paymentServiceUser models.PaymentServiceUser
paymentPayout models.Payment
paymentWithAdjustmentAmount models.Payment
account models.Account
paymentInitiationPayout models.PaymentInitiation
paymentInitiationTransfer models.PaymentInitiation
paymentReversal models.PaymentInitiationReversal
pspAccount models.PSPAccount
pspPayment models.PSPPayment
pspPaymentReversed models.PSPPayment
pspBalance models.PSPBalance
pspOther models.PSPOther
}
func (s *UnitTestSuite) SetupTest() {
s.env = s.NewTestWorkflowEnvironment()
for _, def := range s.w.DefinitionSet() {
s.env.RegisterWorkflowWithOptions(def.Func, temporalworkflow.RegisterOptions{
Name: def.Name,
})
}
s.addData()
}
func (s *UnitTestSuite) AfterTest(suiteName, testName string) {
s.env.AssertExpectations(s.T())
}
func TestUnitTestSuite(t *testing.T) {
logger := logging.Testing()
w := Workflow{
connectors: connectors.NewManager(logger, true, time.Minute, time.Minute),
stackPublicURL: "http://localhost:8080",
stack: "test",
logger: logger,
}
a := activities.Activities{}
suite.Run(t, &UnitTestSuite{w: &w, a: &a})
}
func (s *UnitTestSuite) addData() {
now := s.env.Now().UTC()
s.connectorID = models.ConnectorID{
Reference: uuid.New(),
Provider: "test",
}
registry.RegisterPlugin("test", models.PluginTypePSP, func(_ models.ConnectorID, name string, logger logging.Logger, rm json.RawMessage) (models.Plugin, error) {
return dummypay.New(name, logger, rm)
}, []models.Capability{}, struct{}{}, 25)
dummyConf := json.RawMessage(`{"name":"somename","directory":"/tmp"}`)
connector := models.Connector{
ConnectorBase: models.ConnectorBase{
ID: s.connectorID,
Name: "test",
CreatedAt: now,
Provider: "test",
},
ScheduledForDeletion: false,
Config: dummyConf,
}
s.configuredConnector = connector
_, _, err := s.w.connectors.Load(s.configuredConnector, true, true)
s.NoError(err)
s.accountID = models.AccountID{
Reference: "test",
ConnectorID: s.connectorID,
}
s.paymentPayoutID = models.PaymentID{
PaymentReference: models.PaymentReference{
Reference: "test",
Type: models.PAYMENT_TYPE_PAYOUT,
},
ConnectorID: s.connectorID,
}
s.paymentInitiationID = models.PaymentInitiationID{
Reference: "test",
ConnectorID: s.connectorID,
}
s.paymentReversalID = models.PaymentInitiationReversalID{
Reference: "test",
ConnectorID: s.connectorID,
}
s.bankAccount = models.BankAccount{
ID: uuid.New(),
CreatedAt: now,
Name: "test",
Metadata: map[string]string{
"key": "value",
},
}
s.paymentServiceUser = models.PaymentServiceUser{
ID: uuid.New(),
Name: "test",
CreatedAt: now,
ContactDetails: &models.ContactDetails{
Email: pointer.For("test"),
PhoneNumber: pointer.For("test"),
},
Address: &models.Address{
StreetName: pointer.For("test"),
StreetNumber: pointer.For("test"),
City: pointer.For("test"),
Region: pointer.For("test"),
PostalCode: pointer.For("test"),
Country: pointer.For("test"),
},
BankAccountIDs: []uuid.UUID{
s.bankAccount.ID,
},
Metadata: map[string]string{
"foo": "bar",
},
}
s.paymentPayout = models.Payment{
ID: s.paymentPayoutID,
ConnectorID: s.connectorID,
Reference: "test",
CreatedAt: now,
Type: models.PAYMENT_TYPE_PAYOUT,
Amount: big.NewInt(100),
Asset: "USD/2",
Scheme: models.PAYMENT_SCHEME_A2A,
Status: models.PAYMENT_STATUS_SUCCEEDED,
SourceAccountID: &models.AccountID{
Reference: "test1",
ConnectorID: s.connectorID,
},
DestinationAccountID: &models.AccountID{
Reference: "test2",
ConnectorID: s.connectorID,
},
Metadata: map[string]string{
"key": "value",
},
Adjustments: []models.PaymentAdjustment{
{
ID: models.PaymentAdjustmentID{
PaymentID: s.paymentPayoutID,
Reference: "test",
CreatedAt: now,
Status: models.PAYMENT_STATUS_SUCCEEDED,
},
Reference: "test",
CreatedAt: now,
Status: models.PAYMENT_STATUS_SUCCEEDED,
Amount: big.NewInt(100),
Asset: pointer.For("USD/2"),
Metadata: map[string]string{
"key": "value",
},
Raw: []byte(`{}`),
},
},
}
s.paymentWithAdjustmentAmount = models.Payment{
ID: s.paymentPayoutID,
ConnectorID: s.connectorID,
Reference: "test",
CreatedAt: now,
Type: models.PAYMENT_TYPE_PAYOUT,
Amount: big.NewInt(100),
Asset: "USD/2",
Scheme: models.PAYMENT_SCHEME_A2A,
Status: models.PAYMENT_STATUS_AMOUNT_ADJUSTMENT,
SourceAccountID: &models.AccountID{
Reference: "test1",
ConnectorID: s.connectorID,
},
DestinationAccountID: &models.AccountID{
Reference: "test2",
ConnectorID: s.connectorID,
},
Metadata: map[string]string{
"key": "value",
},
Adjustments: []models.PaymentAdjustment{
{
ID: models.PaymentAdjustmentID{
PaymentID: s.paymentPayoutID,
Reference: "test",
CreatedAt: now,
Status: models.PAYMENT_STATUS_AMOUNT_ADJUSTMENT,
},
Reference: "test",
CreatedAt: now,
Status: models.PAYMENT_STATUS_AMOUNT_ADJUSTMENT,
Amount: big.NewInt(100),
Asset: pointer.For("USD/2"),
Metadata: map[string]string{
"key": "value",
},
Raw: []byte(`{}`),
},
},
}
s.paymentInitiationPayout = models.PaymentInitiation{
ID: s.paymentInitiationID,
ConnectorID: s.connectorID,
Reference: "test",
CreatedAt: s.env.Now().UTC(),
ScheduledAt: s.env.Now().UTC(),
Description: "test_payout",
Type: models.PAYMENT_INITIATION_TYPE_PAYOUT,
SourceAccountID: &models.AccountID{
Reference: "test1",
ConnectorID: s.connectorID,
},
DestinationAccountID: &models.AccountID{
Reference: "test2",
ConnectorID: s.connectorID,
},
Amount: big.NewInt(100),
Asset: "USD/2",
Metadata: map[string]string{
"key": "value",
},
}
s.paymentInitiationTransfer = models.PaymentInitiation{
ID: s.paymentInitiationID,
ConnectorID: s.connectorID,
Reference: "test",
CreatedAt: s.env.Now().UTC(),
ScheduledAt: s.env.Now().UTC(),
Description: "test_payout",
Type: models.PAYMENT_INITIATION_TYPE_TRANSFER,
SourceAccountID: &models.AccountID{
Reference: "test1",
ConnectorID: s.connectorID,
},
DestinationAccountID: &models.AccountID{
Reference: "test2",
ConnectorID: s.connectorID,
},
Amount: big.NewInt(100),
Asset: "USD/2",
Metadata: map[string]string{
"key": "value",
},
}
s.paymentReversal = models.PaymentInitiationReversal{
ID: s.paymentReversalID,
ConnectorID: s.connectorID,
PaymentInitiationID: s.paymentInitiationID,
Reference: "test",
CreatedAt: now,
Description: "test",
Amount: big.NewInt(50),
Asset: "USD/2",
Metadata: map[string]string{
"key": "value",
},
}
s.connector = models.Connector{
ConnectorBase: models.ConnectorBase{
ID: s.connectorID,
Name: "test",
CreatedAt: now,
Provider: "test",
},
ScheduledForDeletion: false,
Config: []byte(`{"name": "test", "pollingPeriod": "2m", "pageSize": 25}`),
}
s.account = models.Account{
ID: models.AccountID{
Reference: "test1",
ConnectorID: s.connectorID,
},
ConnectorID: s.connectorID,
Reference: "test1",
CreatedAt: s.env.Now().UTC(),
Type: models.ACCOUNT_TYPE_INTERNAL,
Name: pointer.For("test1"),
DefaultAsset: pointer.For("USD/2"),
Metadata: map[string]string{
"key": "value",
},
Raw: []byte(`{}`),
}
s.pspAccount = models.PSPAccount{
Reference: "test",
CreatedAt: s.env.Now().UTC(),
Name: pointer.For("test"),
DefaultAsset: pointer.For("USD/2"),
Metadata: map[string]string{
"key": "value",
},
Raw: []byte(`{}`),
}
s.pspPayment = models.PSPPayment{
Reference: "test",
CreatedAt: now,
Type: models.PAYMENT_TYPE_PAYOUT,
Amount: big.NewInt(100),
Asset: "USD/2",
Scheme: models.PAYMENT_SCHEME_A2A,
Status: models.PAYMENT_STATUS_SUCCEEDED,
SourceAccountReference: pointer.For("test1"),
DestinationAccountReference: pointer.For("test2"),
Metadata: map[string]string{
"key": "value",
},
Raw: []byte(`{}`),
}
s.pspPaymentReversed = models.PSPPayment{
Reference: "test",
CreatedAt: now,
Type: models.PAYMENT_TYPE_PAYOUT,
Amount: big.NewInt(100),
Asset: "USD/2",
Scheme: models.PAYMENT_SCHEME_A2A,
Status: models.PAYMENT_STATUS_REFUNDED,
SourceAccountReference: pointer.For("test1"),
DestinationAccountReference: pointer.For("test2"),
Metadata: map[string]string{
"key": "value",
},
Raw: []byte(`{}`),
}
s.pspBalance = models.PSPBalance{
AccountReference: "test",
CreatedAt: now,
Amount: big.NewInt(100),
Asset: "USD/2",
}
s.pspOther = models.PSPOther{
ID: "test",
Other: []byte(`{}`),
}
}