Expand payment remediation test coverage
Adds tests for chargeFailureStatus retryable-vs-definitive classification (429/408/425 -> 503, 4xx declines -> 402), legacy NULL-key refund resume, tip/discount split-record math, and the shared charge helpers adopted by till and gift-card paths.
This commit is contained in:
@@ -3,10 +3,13 @@
|
||||
package payments
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
@@ -345,3 +348,66 @@ type failingDeleteClient struct {
|
||||
func (c *failingDeleteClient) DeleteCardOnFile(ctx context.Context, cardID string) error {
|
||||
return fmt.Errorf("square: network error disabling card %s", cardID)
|
||||
}
|
||||
|
||||
// syncBuffer is a mutex-guarded slog writer so log records can be read safely
|
||||
// under -race.
|
||||
type syncBuffer struct {
|
||||
mu sync.Mutex
|
||||
buf bytes.Buffer
|
||||
}
|
||||
|
||||
func (b *syncBuffer) Write(p []byte) (int, error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
return b.buf.Write(p)
|
||||
}
|
||||
|
||||
func (b *syncBuffer) String() string {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
return b.buf.String()
|
||||
}
|
||||
|
||||
// tokenSafeFailingDeleteClient fails with a token-free error so the
|
||||
// log-redaction test isolates redaction of the square_card_id attribute rather
|
||||
// than the error string.
|
||||
type tokenSafeFailingDeleteClient struct {
|
||||
square.SquareClient
|
||||
}
|
||||
|
||||
func (c *tokenSafeFailingDeleteClient) DeleteCardOnFile(ctx context.Context, cardID string) error {
|
||||
return fmt.Errorf("square: network error disabling card at Square")
|
||||
}
|
||||
|
||||
// TestDeletePaymentMethod_LogsRedactCardToken verifies the local card-delete
|
||||
// warning logs the redacted tokenPrefix form of the square_card_id (a ccof:
|
||||
// token), never the full value (SECURITY: full ccof tokens must not reach
|
||||
// server logs).
|
||||
func TestDeletePaymentMethod_LogsRedactCardToken(t *testing.T) {
|
||||
ctx, tx := testutils.SetupTestTx(t)
|
||||
userID, err := fixtures.CreateTestUser(tx)
|
||||
require.NoError(t, err)
|
||||
fullToken := "ccof:secret_token_123456"
|
||||
cardID, err := fixtures.CreateTestPaymentMethod(tx, userID, fullToken, "VISA", "9999")
|
||||
require.NoError(t, err)
|
||||
|
||||
origClient := SquareClient
|
||||
SquareClient = &tokenSafeFailingDeleteClient{SquareClient: square.NewDevClient()}
|
||||
defer func() { SquareClient = origClient }()
|
||||
|
||||
var sb syncBuffer
|
||||
origLogger := slog.Default()
|
||||
slog.SetDefault(slog.New(slog.NewTextHandler(&sb, nil)))
|
||||
defer slog.SetDefault(origLogger)
|
||||
|
||||
svc := NewPaymentService()
|
||||
require.NoError(t, svc.DeletePaymentMethod(ctx, cardID, userID))
|
||||
|
||||
logs := sb.String()
|
||||
if strings.Contains(logs, fullToken) {
|
||||
t.Errorf("full ccof token %q leaked into logs: %q", fullToken, logs)
|
||||
}
|
||||
if !strings.Contains(logs, "ccof:sec...") {
|
||||
t.Errorf("expected redacted token prefix in logs, got %q", logs)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user