Skip to content

Commit d2603dd

Browse files
authored
test: End-to-end Stripe Connect integration test (#918)
* test: End-to-end Stripe Connect integration test Add E2E tests exercising the full Stripe payment flow from billing trigger through webhook processing to ledger posting: - Happy path: payment order -> saga -> Stripe webhook (succeeded) -> ledger entries -> lien execution - Failure path: payment decline -> dunning escalation (Redis ZSET) - Webhook idempotency: replay same Stripe event ID -> no duplicate processing (verified via Redis and call counts) - Multiple distinct webhooks on same payment order - Successful payment does not trigger dunning Uses CockroachDB testcontainer + miniredis for persistence parity. Extends E2E test infra with sagaOrchestrationEnabled option and saga_executions schema. * fix: resolve ineffassign lint issues in stripe e2e test Move lien call count recording after the await settle to avoid redundant assignment, and discard the intentional timeout error with blank identifier. * fix: address CodeRabbit review comments on PR #918 1. Assert saga_executions DDL succeeds instead of silently discarding errors (e2e_test.go:430). 2. TestStripeE2E_SagaExecutionPersisted now queries the saga_executions table directly in CockroachDB and verifies records exist with correct saga_name, status, and payment_order_id. Also auto-wire SagaExecutionRepository into the service when saga orchestration is enabled. * fix: remove unused withSagaExecutionLogger option function Auto-wire SagaExecutionRepository directly when saga orchestration is enabled, eliminating the need for an explicit option. --------- Co-authored-by: Ben Coombs <bjcoombs@users.noreply.github.com>
1 parent 150d4d4 commit d2603dd

2 files changed

Lines changed: 705 additions & 5 deletions

File tree

services/payment-order/e2e/e2e_test.go

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,12 @@ func setupE2E(t *testing.T, opts ...e2eOption) *E2ETestEnvironment {
133133

134134
repo := persistence.NewPaymentOrderRepository(db)
135135

136+
// Auto-wire saga execution logger when saga orchestration is enabled.
137+
var sagaExecLogger domain.SagaExecutionLogger
138+
if cfg.sagaOrchestrationEnabled {
139+
sagaExecLogger = persistence.NewSagaExecutionRepository(db)
140+
}
141+
136142
svc, err := service.NewServiceWithConfig(service.Config{
137143
Repository: repo,
138144
CurrentAccountClient: caClient,
@@ -143,6 +149,8 @@ func setupE2E(t *testing.T, opts ...e2eOption) *E2ETestEnvironment {
143149
IdempotencyService: newMockIdempotencyService(),
144150
Logger: logger,
145151
SagaTimeout: sagaTimeout,
152+
SagaOrchestrationEnabled: cfg.sagaOrchestrationEnabled,
153+
SagaExecutionLogger: sagaExecLogger,
146154
})
147155
require.NoError(t, err)
148156

@@ -161,11 +169,12 @@ func setupE2E(t *testing.T, opts ...e2eOption) *E2ETestEnvironment {
161169

162170
// e2eConfig holds configuration options for E2E test setup.
163171
type e2eConfig struct {
164-
gatewayApprove bool
165-
gatewayReject bool
166-
gatewayDelay time.Duration
167-
insufficientFunds bool
168-
sagaTimeout time.Duration
172+
gatewayApprove bool
173+
gatewayReject bool
174+
gatewayDelay time.Duration
175+
insufficientFunds bool
176+
sagaTimeout time.Duration
177+
sagaOrchestrationEnabled bool
169178
}
170179

171180
type e2eOption func(*e2eConfig)
@@ -195,6 +204,12 @@ func withSagaTimeout(d time.Duration) e2eOption {
195204
}
196205
}
197206

207+
func withSagaOrchestration() e2eOption {
208+
return func(c *e2eConfig) {
209+
c.sagaOrchestrationEnabled = true
210+
}
211+
}
212+
198213
// ============================================================================
199214
// Schema Setup
200215
// ============================================================================
@@ -416,6 +431,26 @@ func applyPaymentOrderSchema(t *testing.T, db *gorm.DB, schemaName string) {
416431
client_ip VARCHAR(45),
417432
user_agent TEXT
418433
)`, auditTable))
434+
435+
// Create saga_executions table for saga audit trail
436+
sagaExecTable := fmt.Sprintf("%s.saga_executions", pq.QuoteIdentifier(schemaName))
437+
_, err = sqlDB.Exec(fmt.Sprintf(`
438+
CREATE TABLE IF NOT EXISTS %s (
439+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
440+
payment_order_id UUID NOT NULL,
441+
saga_name VARCHAR(128) NOT NULL,
442+
saga_version INT NOT NULL DEFAULT 0,
443+
status VARCHAR(32) NOT NULL DEFAULT 'RUNNING',
444+
correlation_id VARCHAR(128) NOT NULL DEFAULT '',
445+
input JSONB NOT NULL DEFAULT '{}',
446+
output JSONB NOT NULL DEFAULT '{}',
447+
error_message TEXT NOT NULL DEFAULT '',
448+
step_count INT NOT NULL DEFAULT 0,
449+
duration_ms BIGINT NOT NULL DEFAULT 0,
450+
started_at TIMESTAMPTZ NOT NULL DEFAULT now(),
451+
completed_at TIMESTAMPTZ
452+
)`, sagaExecTable))
453+
require.NoError(t, err)
419454
}
420455

421456
// ============================================================================

0 commit comments

Comments
 (0)