Files
galaxy-game/authsession/internal/adapters/mail/stub_sender_test.go
T
2026-04-17 18:39:16 +02:00

201 lines
5.4 KiB
Go

package mail
import (
"context"
"errors"
"testing"
"galaxy/authsession/internal/domain/common"
"galaxy/authsession/internal/ports"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestStubSenderSendLoginCode(t *testing.T) {
t.Parallel()
t.Run("zero value defaults to sent", func(t *testing.T) {
t.Parallel()
sender := &StubSender{}
result, err := sender.SendLoginCode(context.Background(), validInput())
require.NoError(t, err)
assert.Equal(t, ports.SendLoginCodeOutcomeSent, result.Outcome)
attempts := sender.RecordedAttempts()
require.Len(t, attempts, 1)
assert.Equal(t, StubModeSent, attempts[0].Mode)
assert.Equal(t, validInput(), attempts[0].Input)
})
t.Run("default suppressed", func(t *testing.T) {
t.Parallel()
sender := &StubSender{DefaultMode: StubModeSuppressed}
result, err := sender.SendLoginCode(context.Background(), validInput())
require.NoError(t, err)
assert.Equal(t, ports.SendLoginCodeOutcomeSuppressed, result.Outcome)
attempts := sender.RecordedAttempts()
require.Len(t, attempts, 1)
assert.Equal(t, StubModeSuppressed, attempts[0].Mode)
})
t.Run("default failed uses configured error", func(t *testing.T) {
t.Parallel()
wantErr := errors.New("delivery refused")
sender := &StubSender{
DefaultMode: StubModeFailed,
DefaultError: wantErr,
}
result, err := sender.SendLoginCode(context.Background(), validInput())
require.Error(t, err)
assert.ErrorIs(t, err, wantErr)
assert.Equal(t, ports.SendLoginCodeResult{}, result)
attempts := sender.RecordedAttempts()
require.Len(t, attempts, 1)
assert.Equal(t, StubModeFailed, attempts[0].Mode)
})
t.Run("default failed uses stable fallback error", func(t *testing.T) {
t.Parallel()
sender := &StubSender{DefaultMode: StubModeFailed}
_, err := sender.SendLoginCode(context.Background(), validInput())
require.Error(t, err)
assert.EqualError(t, err, "stub mail sender: forced failure")
})
t.Run("script overrides default and is consumed fifo", func(t *testing.T) {
t.Parallel()
wantErr := errors.New("step failed")
sender := &StubSender{
DefaultMode: StubModeSent,
Script: []StubStep{
{Mode: StubModeSuppressed},
{Mode: StubModeFailed, Err: wantErr},
},
}
first, err := sender.SendLoginCode(context.Background(), validInput())
require.NoError(t, err)
assert.Equal(t, ports.SendLoginCodeOutcomeSuppressed, first.Outcome)
second, err := sender.SendLoginCode(context.Background(), validInput())
require.Error(t, err)
assert.ErrorIs(t, err, wantErr)
assert.Equal(t, ports.SendLoginCodeResult{}, second)
third, err := sender.SendLoginCode(context.Background(), validInput())
require.NoError(t, err)
assert.Equal(t, ports.SendLoginCodeOutcomeSent, third.Outcome)
attempts := sender.RecordedAttempts()
require.Len(t, attempts, 3)
assert.Equal(t, []StubMode{StubModeSuppressed, StubModeFailed, StubModeSent}, []StubMode{
attempts[0].Mode,
attempts[1].Mode,
attempts[2].Mode,
})
assert.Empty(t, sender.Script)
})
t.Run("invalid default mode returns adapter error", func(t *testing.T) {
t.Parallel()
sender := &StubSender{DefaultMode: StubMode("queued")}
_, err := sender.SendLoginCode(context.Background(), validInput())
require.Error(t, err)
assert.ErrorContains(t, err, `default mode "queued" is unsupported`)
assert.Empty(t, sender.RecordedAttempts())
})
t.Run("invalid scripted mode returns adapter error", func(t *testing.T) {
t.Parallel()
sender := &StubSender{
Script: []StubStep{
{Mode: StubMode("queued")},
},
}
_, err := sender.SendLoginCode(context.Background(), validInput())
require.Error(t, err)
assert.ErrorContains(t, err, `mode "queued" is unsupported`)
assert.Empty(t, sender.RecordedAttempts())
assert.Empty(t, sender.Script)
})
}
func TestStubSenderRecordedAttemptsAreDefensive(t *testing.T) {
t.Parallel()
sender := &StubSender{}
_, err := sender.SendLoginCode(context.Background(), validInput())
require.NoError(t, err)
attempts := sender.RecordedAttempts()
require.Len(t, attempts, 1)
attempts[0].Mode = StubModeFailed
attempts[0].Input.Code = "000000"
again := sender.RecordedAttempts()
require.Len(t, again, 1)
assert.Equal(t, StubModeSent, again[0].Mode)
assert.Equal(t, "654321", again[0].Input.Code)
}
func TestStubSenderSendLoginCodeNilContext(t *testing.T) {
t.Parallel()
sender := &StubSender{}
_, err := sender.SendLoginCode(nil, validInput())
require.Error(t, err)
assert.ErrorContains(t, err, "nil context")
assert.Empty(t, sender.RecordedAttempts())
}
func TestStubSenderSendLoginCodeCancelledContext(t *testing.T) {
t.Parallel()
sender := &StubSender{}
ctx, cancel := context.WithCancel(context.Background())
cancel()
_, err := sender.SendLoginCode(ctx, validInput())
require.Error(t, err)
assert.ErrorIs(t, err, context.Canceled)
assert.Empty(t, sender.RecordedAttempts())
}
func TestStubSenderSendLoginCodeInvalidInput(t *testing.T) {
t.Parallel()
sender := &StubSender{}
_, err := sender.SendLoginCode(context.Background(), ports.SendLoginCodeInput{})
require.Error(t, err)
assert.ErrorContains(t, err, "send login code input email")
assert.Empty(t, sender.RecordedAttempts())
}
func validInput() ports.SendLoginCodeInput {
return ports.SendLoginCodeInput{
Email: common.Email("pilot@example.com"),
IdempotencyKey: "challenge-1",
Code: "654321",
Locale: "en",
}
}