feat: mail service
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user