581 lines
19 KiB
Go
581 lines
19 KiB
Go
package twilio
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
channelpkg "github.com/gochat/gochat/internal/channel"
|
|
"github.com/gochat/gochat/internal/model"
|
|
)
|
|
|
|
// ============================================================
|
|
// TwilioService tests
|
|
// ============================================================
|
|
|
|
func TestNewTwilioService(t *testing.T) {
|
|
svc := NewTwilioService(nil)
|
|
assert.NotNil(t, svc)
|
|
assert.NotNil(t, svc.client)
|
|
}
|
|
|
|
func TestTwilioService_SendMessage(t *testing.T) {
|
|
svc := NewTwilioService(nil)
|
|
svc.client.SetTransport(&testTransport{handler: func(req *http.Request) (*http.Response, error) {
|
|
return &http.Response{
|
|
StatusCode: 201,
|
|
Body: io.NopCloser(strings.NewReader(`{"sid":"SM123","status":"queued","to":"+1234567890","from":"+1987654321"}`)),
|
|
Header: http.Header{"Content-Type": []string{"application/json"}},
|
|
}, nil
|
|
}})
|
|
|
|
result, err := svc.SendMessage(context.Background(), "AC123", "token", "+1987654321", "+1234567890", "Hello", nil)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "SM123", result.SID)
|
|
assert.Equal(t, "queued", result.Status)
|
|
}
|
|
|
|
func TestTwilioService_SendMessage_WithMedia(t *testing.T) {
|
|
svc := NewTwilioService(nil)
|
|
svc.client.SetTransport(&testTransport{handler: func(req *http.Request) (*http.Response, error) {
|
|
return &http.Response{
|
|
StatusCode: 201,
|
|
Body: io.NopCloser(strings.NewReader(`{"sid":"SM456","status":"queued"}`)),
|
|
Header: http.Header{"Content-Type": []string{"application/json"}},
|
|
}, nil
|
|
}})
|
|
|
|
result, err := svc.SendMessage(context.Background(), "AC123", "token", "+1987654321", "+1234567890", "MMS body", []string{"http://img.jpg"})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "SM456", result.SID)
|
|
}
|
|
|
|
func TestTwilioService_SendMessage_APIError(t *testing.T) {
|
|
svc := NewTwilioService(nil)
|
|
svc.client.SetTransport(&testTransport{handler: func(req *http.Request) (*http.Response, error) {
|
|
return &http.Response{
|
|
StatusCode: 400,
|
|
Body: io.NopCloser(strings.NewReader(`{"code":21211,"message":"Invalid phone number"}`)),
|
|
Header: http.Header{"Content-Type": []string{"application/json"}},
|
|
}, nil
|
|
}})
|
|
|
|
_, err := svc.SendMessage(context.Background(), "AC123", "token", "+1987654321", "invalid", "Hello", nil)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "Invalid phone number")
|
|
}
|
|
|
|
func TestTwilioService_SendMessage_NonJSONError(t *testing.T) {
|
|
svc := NewTwilioService(nil)
|
|
svc.client.SetTransport(&testTransport{handler: func(req *http.Request) (*http.Response, error) {
|
|
return &http.Response{
|
|
StatusCode: 500,
|
|
Body: io.NopCloser(strings.NewReader("Internal Server Error")),
|
|
Header: make(http.Header),
|
|
}, nil
|
|
}})
|
|
|
|
_, err := svc.SendMessage(context.Background(), "AC123", "token", "+1987654321", "+1234567890", "Hello", nil)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "status 500")
|
|
}
|
|
|
|
func TestTwilioService_GetPhoneNumberInfo(t *testing.T) {
|
|
svc := NewTwilioService(nil)
|
|
svc.client.SetTransport(&testTransport{handler: func(req *http.Request) (*http.Response, error) {
|
|
return &http.Response{
|
|
StatusCode: 200,
|
|
Body: io.NopCloser(strings.NewReader(`{"sid":"PN123","phoneNumber":"+1987654321","friendlyName":"Support Line"}`)),
|
|
Header: http.Header{"Content-Type": []string{"application/json"}},
|
|
}, nil
|
|
}})
|
|
|
|
info, err := svc.GetPhoneNumberInfo(context.Background(), "AC123", "token", "PN123")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "PN123", info.SID)
|
|
assert.Equal(t, "+1987654321", info.PhoneNumber)
|
|
assert.Equal(t, "Support Line", info.FriendlyName)
|
|
}
|
|
|
|
func TestTwilioService_GetPhoneNumberInfo_Error(t *testing.T) {
|
|
svc := NewTwilioService(nil)
|
|
svc.client.SetTransport(&testTransport{handler: func(req *http.Request) (*http.Response, error) {
|
|
return &http.Response{
|
|
StatusCode: 404,
|
|
Body: http.NoBody,
|
|
Header: make(http.Header),
|
|
}, nil
|
|
}})
|
|
|
|
_, err := svc.GetPhoneNumberInfo(context.Background(), "AC123", "token", "PN000")
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "status 404")
|
|
}
|
|
|
|
func TestTwilioService_ValidateCredentials(t *testing.T) {
|
|
svc := NewTwilioService(nil)
|
|
svc.client.SetTransport(&testTransport{handler: func(req *http.Request) (*http.Response, error) {
|
|
return &http.Response{
|
|
StatusCode: 200,
|
|
Body: http.NoBody,
|
|
Header: make(http.Header),
|
|
}, nil
|
|
}})
|
|
|
|
err := svc.ValidateCredentials(context.Background(), "AC123", "token")
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestTwilioService_ValidateCredentials_Invalid(t *testing.T) {
|
|
svc := NewTwilioService(nil)
|
|
svc.client.SetTransport(&testTransport{handler: func(req *http.Request) (*http.Response, error) {
|
|
return &http.Response{
|
|
StatusCode: 401,
|
|
Body: http.NoBody,
|
|
Header: make(http.Header),
|
|
}, nil
|
|
}})
|
|
|
|
err := svc.ValidateCredentials(context.Background(), "AC123", "bad-token")
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "status 401")
|
|
}
|
|
|
|
func TestTwilioService_ParsePhoneNumber(t *testing.T) {
|
|
svc := NewTwilioService(nil)
|
|
tests := []struct {
|
|
input string
|
|
want string
|
|
}{
|
|
{"+1-234-567-8900", "+12345678900"},
|
|
{"(123) 456-7890", "+1234567890"},
|
|
{"123.456.7890", "+1234567890"},
|
|
{"+1234567890", "+1234567890"},
|
|
{"1234567890", "+1234567890"},
|
|
}
|
|
for _, tt := range tests {
|
|
assert.Equal(t, tt.want, svc.ParsePhoneNumber(tt.input), "input=%q", tt.input)
|
|
}
|
|
}
|
|
|
|
// ============================================================
|
|
// TwilioProvider tests
|
|
// ============================================================
|
|
|
|
func TestNewTwilioProvider(t *testing.T) {
|
|
svc := NewTwilioService(nil)
|
|
pipe := NewIncomingProcessor(svc)
|
|
provider := NewTwilioProvider(svc, &Repository{}, pipe)
|
|
assert.NotNil(t, provider)
|
|
}
|
|
|
|
func TestTwilioProvider_Identity(t *testing.T) {
|
|
provider := NewTwilioProvider(NewTwilioService(nil), &Repository{}, NewIncomingProcessor(NewTwilioService(nil)))
|
|
assert.Equal(t, channelpkg.ChannelTwilioSMS, provider.Type())
|
|
assert.Equal(t, "Twilio SMS", provider.Name())
|
|
assert.NotEmpty(t, provider.Description())
|
|
}
|
|
|
|
func TestTwilioProvider_ConfigSchema(t *testing.T) {
|
|
provider := NewTwilioProvider(NewTwilioService(nil), &Repository{}, NewIncomingProcessor(NewTwilioService(nil)))
|
|
schema := provider.ConfigSchema()
|
|
require.NotNil(t, schema)
|
|
assert.Equal(t, "object", schema.Type)
|
|
assert.Contains(t, schema.Required, "account_sid")
|
|
assert.Contains(t, schema.Required, "auth_token")
|
|
assert.Contains(t, schema.Required, "phone_number")
|
|
}
|
|
|
|
func TestTwilioProvider_ValidateConfig(t *testing.T) {
|
|
provider := NewTwilioProvider(NewTwilioService(nil), &Repository{}, NewIncomingProcessor(NewTwilioService(nil)))
|
|
ctx := context.Background()
|
|
|
|
t.Run("missing account_sid", func(t *testing.T) {
|
|
err := provider.ValidateConfig(ctx, channelpkg.ChannelConfig{})
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "account_sid")
|
|
})
|
|
|
|
t.Run("missing auth_token", func(t *testing.T) {
|
|
err := provider.ValidateConfig(ctx, channelpkg.ChannelConfig{"account_sid": "AC123"})
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "auth_token")
|
|
})
|
|
|
|
t.Run("missing phone_number", func(t *testing.T) {
|
|
err := provider.ValidateConfig(ctx, channelpkg.ChannelConfig{"account_sid": "AC123", "auth_token": "token"})
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "phone_number")
|
|
})
|
|
|
|
t.Run("invalid account_sid prefix", func(t *testing.T) {
|
|
err := provider.ValidateConfig(ctx, channelpkg.ChannelConfig{
|
|
"account_sid": "XX123",
|
|
"auth_token": "token",
|
|
"phone_number": "+1234567890",
|
|
})
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "must start with 'AC'")
|
|
})
|
|
|
|
t.Run("valid config", func(t *testing.T) {
|
|
err := provider.ValidateConfig(ctx, channelpkg.ChannelConfig{
|
|
"account_sid": "AC123",
|
|
"auth_token": "token",
|
|
"phone_number": "+1234567890",
|
|
})
|
|
assert.NoError(t, err)
|
|
})
|
|
}
|
|
|
|
func TestTwilioProvider_DefaultConfig(t *testing.T) {
|
|
provider := NewTwilioProvider(NewTwilioService(nil), &Repository{}, NewIncomingProcessor(NewTwilioService(nil)))
|
|
config := provider.DefaultConfig()
|
|
assert.NotNil(t, config)
|
|
assert.Contains(t, config, "account_sid")
|
|
assert.Contains(t, config, "auth_token")
|
|
assert.Contains(t, config, "phone_number")
|
|
}
|
|
|
|
func TestTwilioProvider_OnCreate(t *testing.T) {
|
|
svc := NewTwilioService(nil)
|
|
svc.client.SetTransport(&testTransport{handler: func(req *http.Request) (*http.Response, error) {
|
|
return &http.Response{StatusCode: 200, Body: http.NoBody, Header: make(http.Header)}, nil
|
|
}})
|
|
provider := NewTwilioProvider(svc, &Repository{}, NewIncomingProcessor(svc))
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 1}
|
|
config := channelpkg.ChannelConfig{
|
|
"account_sid": "AC123",
|
|
"auth_token": "token",
|
|
"phone_number": "+1234567890",
|
|
}
|
|
result, err := provider.OnCreate(context.Background(), inbox, config)
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, result)
|
|
}
|
|
|
|
func TestTwilioProvider_OnCreate_InvalidCredentials(t *testing.T) {
|
|
svc := NewTwilioService(nil)
|
|
svc.client.SetTransport(&testTransport{handler: func(req *http.Request) (*http.Response, error) {
|
|
return &http.Response{StatusCode: 401, Body: http.NoBody, Header: make(http.Header)}, nil
|
|
}})
|
|
provider := NewTwilioProvider(svc, &Repository{}, NewIncomingProcessor(svc))
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 1}
|
|
config := channelpkg.ChannelConfig{
|
|
"account_sid": "AC123",
|
|
"auth_token": "bad-token",
|
|
"phone_number": "+1234567890",
|
|
}
|
|
result, err := provider.OnCreate(context.Background(), inbox, config)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, true, result["reauthorization_required"])
|
|
}
|
|
|
|
func TestTwilioProvider_OnDestroy(t *testing.T) {
|
|
provider := NewTwilioProvider(NewTwilioService(nil), &Repository{}, NewIncomingProcessor(NewTwilioService(nil)))
|
|
err := provider.OnDestroy(context.Background(), &model.Inbox{}, channelpkg.ChannelConfig{})
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestTwilioProvider_ProcessIncoming(t *testing.T) {
|
|
svc := NewTwilioService(nil)
|
|
pipe := NewIncomingProcessor(svc)
|
|
provider := NewTwilioProvider(svc, &Repository{}, pipe)
|
|
ctx := context.Background()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 1}
|
|
|
|
t.Run("valid SMS", func(t *testing.T) {
|
|
formData := "MessageSid=SM123&AccountSid=AC123&From=%2B1234567890&To=%2B1987654321&Body=Hello+world&NumMedia=0&SmsStatus=received"
|
|
msg, err := provider.ProcessIncoming(ctx, inbox, []byte(formData))
|
|
require.NoError(t, err)
|
|
require.NotNil(t, msg)
|
|
assert.Equal(t, "SM123", msg.SourceID)
|
|
assert.Equal(t, "+1234567890", msg.SenderID)
|
|
assert.Equal(t, "Hello world", msg.Content)
|
|
assert.Equal(t, channelpkg.ContentText, msg.ContentType)
|
|
})
|
|
|
|
t.Run("invalid form data", func(t *testing.T) {
|
|
_, err := provider.ProcessIncoming(ctx, inbox, []byte("%"))
|
|
assert.Error(t, err)
|
|
})
|
|
}
|
|
|
|
func TestTwilioProvider_ValidateWebhookRequest(t *testing.T) {
|
|
provider := NewTwilioProvider(NewTwilioService(nil), &Repository{}, NewIncomingProcessor(NewTwilioService(nil)))
|
|
err := provider.ValidateWebhookRequest(context.Background(), &model.Inbox{}, &channelpkg.WebhookRequest{})
|
|
assert.NoError(t, err) // TODO: always returns nil
|
|
}
|
|
|
|
func TestTwilioProvider_SendMessage(t *testing.T) {
|
|
svc := NewTwilioService(nil)
|
|
svc.client.SetTransport(&testTransport{handler: func(req *http.Request) (*http.Response, error) {
|
|
return &http.Response{
|
|
StatusCode: 201,
|
|
Body: io.NopCloser(strings.NewReader(`{"sid":"SM999","status":"queued"}`)),
|
|
Header: http.Header{"Content-Type": []string{"application/json"}},
|
|
}, nil
|
|
}})
|
|
provider := NewTwilioProvider(svc, &Repository{}, NewIncomingProcessor(svc))
|
|
ctx := context.Background()
|
|
inbox := &model.Inbox{
|
|
Base: model.Base{ID: 1},
|
|
ChannelConfig: `{"account_sid":"AC123","auth_token":"token","phone_number":"+1987654321"}`,
|
|
}
|
|
|
|
t.Run("no contact source_id", func(t *testing.T) {
|
|
contact := &model.Contact{}
|
|
msg := &model.Message{Content: "test"}
|
|
_, err := provider.SendMessage(ctx, inbox, msg, contact)
|
|
assert.Error(t, err)
|
|
})
|
|
|
|
t.Run("valid send with phone number", func(t *testing.T) {
|
|
contact := &model.Contact{SourceID: "+1234567890"}
|
|
msg := &model.Message{Content: "Hello SMS"}
|
|
result, err := provider.SendMessage(ctx, inbox, msg, contact)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "SM999", result.ExternalID)
|
|
})
|
|
|
|
t.Run("valid send with messaging service SID", func(t *testing.T) {
|
|
inboxWithMS := &model.Inbox{
|
|
Base: model.Base{ID: 1},
|
|
ChannelConfig: `{"account_sid":"AC123","auth_token":"token","phone_number":"+1987654321","messaging_service_sid":"MG123"}`,
|
|
}
|
|
contact := &model.Contact{SourceID: "+1234567890"}
|
|
msg := &model.Message{Content: "Hello MMS"}
|
|
result, err := provider.SendMessage(ctx, inboxWithMS, msg, contact)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "SM999", result.ExternalID)
|
|
})
|
|
}
|
|
|
|
func TestTwilioProvider_GetContactProfile(t *testing.T) {
|
|
svc := NewTwilioService(nil)
|
|
provider := NewTwilioProvider(svc, &Repository{}, NewIncomingProcessor(svc))
|
|
profile, err := provider.GetContactProfile(context.Background(), &model.Inbox{}, "+1-234-567-8900")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "+12345678900", profile.Name)
|
|
assert.Equal(t, "+12345678900", profile.Extra["phone_number"])
|
|
}
|
|
|
|
func TestTwilioProvider_Capabilities(t *testing.T) {
|
|
provider := NewTwilioProvider(NewTwilioService(nil), &Repository{}, NewIncomingProcessor(NewTwilioService(nil)))
|
|
caps := provider.Capabilities()
|
|
assert.True(t, caps.SupportsAttachments)
|
|
assert.True(t, caps.SupportsDeliveryStatus)
|
|
assert.Equal(t, int64(5*1024*1024), caps.MaxAttachmentSize)
|
|
assert.Equal(t, 160, caps.MaxTextLength)
|
|
}
|
|
|
|
// ============================================================
|
|
// Pipeline tests
|
|
// ============================================================
|
|
|
|
func TestNewIncomingProcessor(t *testing.T) {
|
|
p := NewIncomingProcessor(NewTwilioService(nil))
|
|
assert.NotNil(t, p)
|
|
}
|
|
|
|
func TestIncomingProcessor_ProcessInboundSMS(t *testing.T) {
|
|
svc := NewTwilioService(nil)
|
|
p := NewIncomingProcessor(svc)
|
|
ctx := context.Background()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 1}
|
|
|
|
t.Run("text SMS", func(t *testing.T) {
|
|
sms := InboundSMS{
|
|
MessageSID: "SM123",
|
|
AccountSID: "AC123",
|
|
From: "+1234567890",
|
|
To: "+1987654321",
|
|
Body: "Hello",
|
|
NumMedia: "0",
|
|
}
|
|
msg, err := p.ProcessInboundSMS(ctx, inbox, sms)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "SM123", msg.SourceID)
|
|
assert.Equal(t, "Hello", msg.Content)
|
|
assert.Equal(t, channelpkg.ContentText, msg.ContentType)
|
|
})
|
|
|
|
t.Run("MMS with media", func(t *testing.T) {
|
|
sms := InboundSMS{
|
|
MessageSID: "SM456",
|
|
From: "+1234567890",
|
|
Body: "MMS text",
|
|
NumMedia: "2",
|
|
MediaURL: []string{"http://img1.jpg", "http://img2.jpg"},
|
|
MediaContentType: []string{"image/jpeg", "image/png"},
|
|
}
|
|
msg, err := p.ProcessInboundSMS(ctx, inbox, sms)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, channelpkg.ContentImage, msg.ContentType)
|
|
assert.Equal(t, "http://img1.jpg", msg.Content)
|
|
assert.Len(t, msg.Attachments, 2)
|
|
assert.Equal(t, "MMS text", msg.Extra["body"])
|
|
})
|
|
|
|
t.Run("MMS with invalid NumMedia", func(t *testing.T) {
|
|
sms := InboundSMS{
|
|
MessageSID: "SM789",
|
|
From: "+1234567890",
|
|
Body: "Text",
|
|
NumMedia: "abc",
|
|
}
|
|
msg, err := p.ProcessInboundSMS(ctx, inbox, sms)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, channelpkg.ContentText, msg.ContentType)
|
|
})
|
|
|
|
t.Run("no From number", func(t *testing.T) {
|
|
sms := InboundSMS{}
|
|
_, err := p.ProcessInboundSMS(ctx, inbox, sms)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "no From number")
|
|
})
|
|
}
|
|
|
|
func TestIncomingProcessor_ProcessDeliveryStatus(t *testing.T) {
|
|
svc := NewTwilioService(nil)
|
|
p := NewIncomingProcessor(svc)
|
|
ctx := context.Background()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 1}
|
|
|
|
t.Run("delivered", func(t *testing.T) {
|
|
status := DeliveryStatus{
|
|
MessageSID: "SM123",
|
|
MessageStatus: "delivered",
|
|
To: "+1234567890",
|
|
}
|
|
msg, err := p.ProcessDeliveryStatus(ctx, inbox, status)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, msg)
|
|
assert.Contains(t, msg.Content, "delivered")
|
|
assert.Equal(t, channelpkg.SenderSystem, msg.SenderType)
|
|
})
|
|
|
|
t.Run("failed", func(t *testing.T) {
|
|
status := DeliveryStatus{
|
|
MessageSID: "SM456",
|
|
MessageStatus: "failed",
|
|
ErrorCode: "30001",
|
|
To: "+1234567890",
|
|
}
|
|
msg, err := p.ProcessDeliveryStatus(ctx, inbox, status)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, msg)
|
|
assert.Contains(t, msg.Content, "failed")
|
|
assert.Equal(t, "30001", msg.Extra["error_code"])
|
|
})
|
|
|
|
t.Run("undelivered", func(t *testing.T) {
|
|
status := DeliveryStatus{
|
|
MessageSID: "SM789",
|
|
MessageStatus: "undelivered",
|
|
To: "+1234567890",
|
|
}
|
|
msg, err := p.ProcessDeliveryStatus(ctx, inbox, status)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, msg)
|
|
assert.Contains(t, msg.Content, "failed")
|
|
})
|
|
|
|
t.Run("unhandled status", func(t *testing.T) {
|
|
status := DeliveryStatus{
|
|
MessageSID: "SM000",
|
|
MessageStatus: "sent",
|
|
To: "+1234567890",
|
|
}
|
|
msg, err := p.ProcessDeliveryStatus(ctx, inbox, status)
|
|
assert.NoError(t, err)
|
|
assert.Nil(t, msg)
|
|
})
|
|
}
|
|
|
|
// ============================================================
|
|
// Helper functions tests
|
|
// ============================================================
|
|
|
|
func TestParseInboxConfig(t *testing.T) {
|
|
assert.Empty(t, parseInboxConfig(""))
|
|
assert.NotEmpty(t, parseInboxConfig(`{"key":"val"}`))
|
|
assert.Empty(t, parseInboxConfig("invalid"))
|
|
}
|
|
|
|
func TestConfigStr(t *testing.T) {
|
|
assert.Equal(t, "default", configStr(channelpkg.ChannelConfig{}, "key", "default"))
|
|
assert.Equal(t, "val", configStr(channelpkg.ChannelConfig{"key": "val"}, "key", "default"))
|
|
assert.Equal(t, "default", configStr(channelpkg.ChannelConfig{"key": ""}, "key", "default"))
|
|
}
|
|
|
|
// ============================================================
|
|
// Repository tests — require a DB
|
|
// ============================================================
|
|
|
|
// ============================================================
|
|
// Types tests
|
|
// ============================================================
|
|
|
|
func TestInboundSMS_JSON(t *testing.T) {
|
|
sms := InboundSMS{
|
|
MessageSID: "SM123",
|
|
From: "+1234567890",
|
|
Body: "Hello",
|
|
}
|
|
data, err := json.Marshal(sms)
|
|
require.NoError(t, err)
|
|
assert.Contains(t, string(data), "SM123")
|
|
|
|
var decoded InboundSMS
|
|
err = json.Unmarshal(data, &decoded)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, sms.MessageSID, decoded.MessageSID)
|
|
}
|
|
|
|
func TestOutboundSMSResponse_JSON(t *testing.T) {
|
|
resp := OutboundSMSResponse{
|
|
SID: "SM123",
|
|
Status: "queued",
|
|
To: "+1234567890",
|
|
}
|
|
data, err := json.Marshal(resp)
|
|
require.NoError(t, err)
|
|
var decoded OutboundSMSResponse
|
|
err = json.Unmarshal(data, &decoded)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, resp.SID, decoded.SID)
|
|
}
|
|
|
|
func TestDeliveryStatus_JSON(t *testing.T) {
|
|
status := DeliveryStatus{
|
|
MessageSID: "SM123",
|
|
MessageStatus: "delivered",
|
|
}
|
|
data, err := json.Marshal(status)
|
|
require.NoError(t, err)
|
|
var decoded DeliveryStatus
|
|
err = json.Unmarshal(data, &decoded)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, status.MessageSID, decoded.MessageSID)
|
|
}
|
|
|
|
// ============================================================
|
|
// Test helpers
|
|
// ============================================================
|
|
|
|
type testTransport struct {
|
|
handler func(*http.Request) (*http.Response, error)
|
|
}
|
|
|
|
func (t *testTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
return t.handler(req)
|
|
}
|