package email_test import ( "context" "fmt" "testing" "gateway/internal/model/notification/provider/email" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) const testRecipientEmail = "x@test.com" func TestChain_Send_FailoverToSecondProvider(t *testing.T) { primary := email.NewMockSender( email.WithMockName("primary"), email.WithMockSort(1), email.WithMockError(fmt.Errorf("primary down")), ) backup := email.NewMockSender( email.WithMockName("backup"), email.WithMockSort(2), email.WithMockMessageID("backup-123"), ) chain := email.NewChain(primary, backup) provider, id, err := chain.Send(context.Background(), &email.Message{ From: "noreply@test.com", To: []string{"user@test.com"}, Subject: "verify", Body: "
code
", }) require.NoError(t, err) assert.Equal(t, "backup", provider) assert.Equal(t, "backup-123", id) assert.Len(t, primary.Calls(), 1) assert.Len(t, backup.Calls(), 1) } func TestChain_Send_TriesLowerSortFirst(t *testing.T) { var order []string mk := func(name string, sort int, fail bool) *email.MockSender { m := email.NewMockSender(email.WithMockName(name), email.WithMockSort(sort)) m.SendHook = func(context.Context, *email.Message) (string, error) { order = append(order, name) if fail { return "", fmt.Errorf("%s failed", name) } return name + "-id", nil } return m } // Unsorted registration; chain must try a(1) → b(2) succeed, never c(3). chain := email.NewChain(mk("c", 3, true), mk("a", 1, true), mk("b", 2, false)) provider, _, err := chain.Send(context.Background(), &email.Message{To: []string{testRecipientEmail}}) require.NoError(t, err) assert.Equal(t, "b", provider) assert.Equal(t, []string{"a", "b"}, order) } func TestChain_Send_AllProvidersFail(t *testing.T) { chain := email.NewChain( email.ErrSender("a", 1, fmt.Errorf("a fail")), email.ErrSender("b", 2, fmt.Errorf("b fail")), ) _, _, err := chain.Send(context.Background(), &email.Message{To: []string{testRecipientEmail}}) require.Error(t, err) assert.Contains(t, err.Error(), "all providers failed") } func TestChain_Send_NoSenders(t *testing.T) { chain := email.NewChain() _, _, err := chain.Send(context.Background(), &email.Message{To: []string{testRecipientEmail}}) require.Error(t, err) assert.Contains(t, err.Error(), "no senders") }