Files
GL/application/settlement/worker_test.go
T

61 lines
2.7 KiB
Go

package settlement
import (
"context"
"errors"
"testing"
"time"
"gl/domain/ledger"
)
type memoryRepository struct{ record ledger.Settlement }
func (m *memoryRepository) ClaimDue(context.Context, string, int, time.Time) ([]ledger.Settlement, error) {
return []ledger.Settlement{m.record}, nil
}
func (m *memoryRepository) Save(_ context.Context, record ledger.Settlement, _ string) error {
m.record = record
return nil
}
type submitter struct {
hash string
err error
}
func (s submitter) Submit(context.Context, ledger.Settlement) (string, error) { return s.hash, s.err }
func TestWorkerPersistsSubmission(t *testing.T) {
repository := &memoryRepository{record: ledger.Settlement{ID: "s1", SourceService: "wallet", SourceTxID: "42", IdempotencyKey: "kuknos:42", Status: ledger.SettlementPending, AvailableAt: time.Unix(1, 0)}}
worker := Worker{Repository: repository, Submitter: submitter{hash: "hash-42"}, WorkerID: "worker-1", Now: func() time.Time { return time.Unix(2, 0) }}
if err := worker.RunOnce(context.Background(), 1); err != nil {
t.Fatal(err)
}
if repository.record.Status != ledger.SettlementConfirmed || repository.record.TransactionHash != "hash-42" || repository.record.Attempts != 1 {
t.Fatalf("unexpected settlement: %+v", repository.record)
}
}
func TestWorkerSchedulesRetryAfterFirstFailedAttempt(t *testing.T) {
repository := &memoryRepository{record: ledger.Settlement{ID: "s1", SourceService: "wallet", SourceTxID: "42", IdempotencyKey: "kuknos:42", Status: ledger.SettlementPending, AvailableAt: time.Unix(1, 0)}}
worker := Worker{Repository: repository, Submitter: submitter{err: errors.New("timeout")}, WorkerID: "worker-1", MaxAttempts: 3, Now: func() time.Time { return time.Unix(2, 0) }}
if err := worker.RunOnce(context.Background(), 1); err != nil {
t.Fatal(err)
}
if repository.record.Status != ledger.SettlementRetryable || repository.record.Attempts != 1 || !repository.record.AvailableAt.Equal(time.Unix(3, 0)) {
t.Fatalf("unexpected settlement: %+v", repository.record)
}
}
func TestWorkerMovesExhaustedSubmissionToManualReview(t *testing.T) {
repository := &memoryRepository{record: ledger.Settlement{ID: "s1", SourceService: "wallet", SourceTxID: "42", IdempotencyKey: "kuknos:42", Status: ledger.SettlementRetryable, Attempts: 2, AvailableAt: time.Unix(1, 0)}}
worker := Worker{Repository: repository, Submitter: submitter{err: errors.New("timeout")}, WorkerID: "worker-1", MaxAttempts: 3, Now: func() time.Time { return time.Unix(2, 0) }}
if err := worker.RunOnce(context.Background(), 1); err != nil {
t.Fatal(err)
}
if repository.record.Status != ledger.SettlementManualReview {
t.Fatalf("status=%s", repository.record.Status)
}
}