package stubprovider import ( "context" "fmt" "sync" "testing" "galaxy/mail/internal/domain/common" deliverydomain "galaxy/mail/internal/domain/delivery" "galaxy/mail/internal/ports" "github.com/stretchr/testify/require" ) func TestProviderSendUsesAcceptedDefault(t *testing.T) { t.Parallel() provider, err := New() require.NoError(t, err) result, err := provider.Send(context.Background(), testMessage(t)) require.NoError(t, err) require.Equal(t, ports.ClassificationAccepted, result.Classification) require.Equal(t, "provider=stub result=accepted", result.Summary) require.Len(t, provider.Inputs(), 1) } func TestProviderSendConsumesScriptedOutcomesInOrder(t *testing.T) { t.Parallel() provider, err := New( ScriptedOutcome{ Classification: ports.ClassificationTransientFailure, Script: "retry_later", }, ScriptedOutcome{ Classification: ports.ClassificationSuppressed, Script: "policy_skip", }, ) require.NoError(t, err) first, err := provider.Send(context.Background(), testMessage(t)) require.NoError(t, err) require.Equal(t, ports.ClassificationTransientFailure, first.Classification) require.Equal(t, "provider=stub result=transient_failure script=retry_later", first.Summary) second, err := provider.Send(context.Background(), testMessage(t)) require.NoError(t, err) require.Equal(t, ports.ClassificationSuppressed, second.Classification) require.Equal(t, "provider=stub result=suppressed script=policy_skip", second.Summary) third, err := provider.Send(context.Background(), testMessage(t)) require.NoError(t, err) require.Equal(t, ports.ClassificationAccepted, third.Classification) } func TestProviderSendConsumesQueueSafelyAcrossGoroutines(t *testing.T) { t.Parallel() const sendCount = 24 initial := make([]ScriptedOutcome, 0, sendCount) for index := 0; index < sendCount; index++ { initial = append(initial, ScriptedOutcome{ Classification: ports.ClassificationAccepted, Script: fmt.Sprintf("case_%02d", index), }) } provider, err := New(initial...) require.NoError(t, err) message := testMessage(t) summaries := make(chan string, sendCount) errs := make(chan error, sendCount) var waitGroup sync.WaitGroup for index := 0; index < sendCount; index++ { waitGroup.Add(1) go func() { defer waitGroup.Done() result, sendErr := provider.Send(context.Background(), message) if sendErr != nil { errs <- sendErr return } summaries <- result.Summary }() } waitGroup.Wait() close(summaries) close(errs) for err := range errs { require.NoError(t, err) } seen := make(map[string]struct{}, sendCount) for summary := range summaries { seen[summary] = struct{}{} } require.Len(t, seen, sendCount) require.Len(t, provider.Inputs(), sendCount) } func testMessage(t *testing.T) ports.Message { t.Helper() message := ports.Message{ Envelope: deliverydomain.Envelope{ To: []common.Email{common.Email("pilot@example.com")}, }, Content: deliverydomain.Content{ Subject: "Turn update", TextBody: "Turn 54 is ready.", }, } require.NoError(t, message.Validate()) return message }